From 714aecd7e6685ee5ddc4e44d859c51a87fe4272c Mon Sep 17 00:00:00 2001 From: Winston Lowe Date: Sun, 18 Jan 2026 01:05:46 -0800 Subject: [PATCH] Added GPS enable and interval settings --- lib/l10n/app_bg.arb | 7 +- lib/l10n/app_de.arb | 7 +- lib/l10n/app_en.arb | 5 + lib/l10n/app_es.arb | 7 +- lib/l10n/app_fr.arb | 7 +- lib/l10n/app_it.arb | 7 +- lib/l10n/app_localizations.dart | 26 ++- lib/l10n/app_localizations_bg.dart | 14 ++ lib/l10n/app_localizations_de.dart | 14 ++ lib/l10n/app_localizations_en.dart | 16 +- lib/l10n/app_localizations_es.dart | 14 ++ lib/l10n/app_localizations_fr.dart | 14 ++ lib/l10n/app_localizations_it.dart | 14 ++ lib/l10n/app_localizations_nl.dart | 14 ++ lib/l10n/app_localizations_pl.dart | 14 ++ lib/l10n/app_localizations_pt.dart | 14 ++ lib/l10n/app_localizations_sk.dart | 14 ++ lib/l10n/app_localizations_sl.dart | 14 ++ lib/l10n/app_localizations_sv.dart | 14 ++ lib/l10n/app_localizations_zh.dart | 12 + lib/l10n/app_nl.arb | 7 +- lib/l10n/app_pl.arb | 7 +- lib/l10n/app_pt.arb | 7 +- lib/l10n/app_sk.arb | 7 +- lib/l10n/app_sl.arb | 7 +- lib/l10n/app_sv.arb | 7 +- lib/l10n/app_zh.arb | 7 +- lib/screens/settings_screen.dart | 346 +++++++++++++++++++---------- 28 files changed, 495 insertions(+), 148 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 30a2c1b..effbd6c 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.", - "common_reload": "Презареди", "common_clear": "Изчисти", "path_currentPath": "Текущ път: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Сканирайте QR код", "channels_scanQrCodeComingSoon": "Ще излезе скоро", "channels_enterHashtag": "Въведете хаштаг", - "channels_hashtagHint": "напр. #отбор" + "channels_hashtagHint": "напр. #отбор", + "settings_locationIntervalSec": "Интервал (Секунди)", + "settings_locationGPSEnableSubtitle": "Активирайте GPS, за автоматично изпращане на данни за местоположението (ако е поддържано).", + "settings_locationIntervalInvalid": "Интервалът трябва да бъде поне 60 секунди и по-малко от 86400 секунди.", + "settings_locationGPSEnable": "Активиране на GPS" } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9d2701f..dead738 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.", - "common_reload": "Neu laden", "common_clear": "Löschen", "path_currentPath": "Aktiver Pfad: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Scannen Sie einen QR-Code", "channels_scanQrCodeComingSoon": "Bald verfügbar", "channels_enterHashtag": "Gib Hashtag ein", - "channels_hashtagHint": "z.B. #team" + "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." } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 203f64f..9b2547c 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -86,6 +86,11 @@ "settings_locationUpdated": "Location updated", "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_locationIntervalInvalid": "Interval must be at least 60 seconds, and less than 86400 seconds.", + "settings_locationUpdated": "GPS settings updated.", "settings_latitude": "Latitude", "settings_longitude": "Longitude", "settings_privacyMode": "Privacy Mode", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index b23cfce..bf90fe4 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.", - "common_reload": "Recargar", "common_clear": "Borrar", "path_currentPath": "Ruta actual: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Escanear un Código QR", "channels_scanQrCodeComingSoon": "Próximamente", "channels_enterHashtag": "Introducir hashtag", - "channels_hashtagHint": "ej. #equipo" + "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_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 0e7b952..82d73d7 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Connexion échouée. Soit le mot de passe est incorrect, soit le relais est injoignable.", - "common_reload": "Recharger", "common_clear": "Effacer", "path_currentPath": "Chemin actuel : {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Scanner un code QR", "channels_scanQrCodeComingSoon": "Bientôt disponible", "channels_enterHashtag": "Entrez le hashtag", - "channels_hashtagHint": "ex. #équipe" + "channels_hashtagHint": "ex. #équipe", + "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." } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index b77450f..f9828e5 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.", - "common_reload": "Ricaricare", "common_clear": "Cancella", "path_currentPath": "Percorso corrente: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Scansiona un codice QR", "channels_scanQrCodeComingSoon": "Arriverà presto", "channels_enterHashtag": "Inserisci hashtag", - "channels_hashtagHint": "es. #team" + "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_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 bedd407..cfe77e2 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -465,7 +465,7 @@ abstract class AppLocalizations { /// No description provided for @settings_locationUpdated. /// /// In en, this message translates to: - /// **'Location updated'** + /// **'GPS settings updated.'** String get settings_locationUpdated; /// No description provided for @settings_locationBothRequired. @@ -480,6 +480,30 @@ abstract class AppLocalizations { /// **'Invalid latitude or longitude.'** String get settings_locationInvalid; + /// No description provided for @settings_locationGPSEnable. + /// + /// In en, this message translates to: + /// **'GPS Enable'** + String get settings_locationGPSEnable; + + /// No description provided for @settings_locationGPSEnableSubtitle. + /// + /// In en, this message translates to: + /// **'Enable 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)'** + String get settings_locationIntervalSec; + + /// No description provided for @settings_locationIntervalInvalid. + /// + /// In en, this message translates to: + /// **'Interval must be at least 60 seconds, and less than 86400 seconds.'** + String get settings_locationIntervalInvalid; + /// No description provided for @settings_latitude. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index cf2b35c..2b5d9c7 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -201,6 +201,20 @@ class AppLocalizationsBg extends AppLocalizations { @override String get settings_locationInvalid => 'Невалидна ширина или дължина.'; + @override + String get settings_locationGPSEnable => 'Активиране на GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Активирайте GPS, за автоматично изпращане на данни за местоположението (ако е поддържано).'; + + @override + String get settings_locationIntervalSec => 'Интервал (Секунди)'; + + @override + String get settings_locationIntervalInvalid => + 'Интервалът трябва да бъде поне 60 секунди и по-малко от 86400 секунди.'; + @override String get settings_latitude => 'Широчина'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 3d0cbcd..0161533 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -200,6 +200,20 @@ class AppLocalizationsDe extends AppLocalizations { @override String get settings_locationInvalid => 'Ungültige Breiten- oder Längengrade.'; + @override + String get settings_locationGPSEnable => 'GPS aktivieren'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Aktivieren Sie GPS, um Standortdaten automatisch zu senden (falls unterstützt).'; + + @override + String get settings_locationIntervalSec => 'Zeitintervall (Sekunden)'; + + @override + String get settings_locationIntervalInvalid => + 'Der Zeitraum muss mindestens 60 Sekunden betragen und weniger als 86400 Sekunden sein.'; + @override String get settings_latitude => 'Breitengrad'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index b8c4f90..e7ea0cf 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -190,7 +190,7 @@ class AppLocalizationsEn extends AppLocalizations { String get settings_locationSubtitle => 'GPS coordinates'; @override - String get settings_locationUpdated => 'Location updated'; + String get settings_locationUpdated => 'GPS settings updated.'; @override String get settings_locationBothRequired => @@ -199,6 +199,20 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_locationInvalid => 'Invalid latitude or longitude.'; + @override + String get settings_locationGPSEnable => 'GPS Enable'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Enable GPS to automatically send location data (if supported)'; + + @override + String get settings_locationIntervalSec => 'Interval (Seconds)'; + + @override + String get settings_locationIntervalInvalid => + 'Interval must be at least 60 seconds, and less than 86400 seconds.'; + @override String get settings_latitude => 'Latitude'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 21aad2c..497dd2a 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -200,6 +200,20 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settings_locationInvalid => 'Latitud o longitud inválidos.'; + @override + String get settings_locationGPSEnable => 'Habilitar GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Habilitar GPS para enviar automáticamente datos de ubicación (si está disponible).'; + + @override + String get settings_locationIntervalSec => 'Intervalo (Segundos)'; + + @override + String get settings_locationIntervalInvalid => + 'El intervalo debe ser de al menos 60 segundos y menor que 86400 segundos.'; + @override String get settings_latitude => 'Latitud'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 21f63b5..50beba2 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -200,6 +200,20 @@ class AppLocalizationsFr extends AppLocalizations { @override String get settings_locationInvalid => 'Latitude ou longitude invalide.'; + @override + String get settings_locationGPSEnable => 'Activer le GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Activer le GPS pour envoyer automatiquement les données de localisation (si pris en charge).'; + + @override + String get settings_locationIntervalSec => 'Intervalle (Secondes)'; + + @override + String get settings_locationIntervalInvalid => + 'L\'intervalle doit être d\'au moins 60 secondes et inférieur à 86400 secondes.'; + @override String get settings_latitude => 'Latitude'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 1cc567c..875e793 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -200,6 +200,20 @@ class AppLocalizationsIt extends AppLocalizations { @override String get settings_locationInvalid => 'Latitudine o longitudine non valida.'; + @override + String get settings_locationGPSEnable => 'Abilita GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Abilita il GPS per inviare automaticamente i dati di posizione (se supportato).'; + + @override + String get settings_locationIntervalSec => 'Intervallo (Secondi)'; + + @override + String get settings_locationIntervalInvalid => + 'L\'intervallo deve essere di almeno 60 secondi e inferiore a 86400 secondi.'; + @override String get settings_latitude => 'Latitudine'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index db1f68e..a7112bd 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -200,6 +200,20 @@ class AppLocalizationsNl extends AppLocalizations { String get settings_locationInvalid => 'Ongeldige breedtegraad of lengtegraad.'; + @override + String get settings_locationGPSEnable => 'GPS inschakelen'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Zijze GPS inschakelen om locatiegegevens automatisch te verzenden (indien ondersteund).'; + + @override + String get settings_locationIntervalSec => 'Interval (Seconden)'; + + @override + String get settings_locationIntervalInvalid => + 'De intervallen moeten minstens 60 seconden zijn en minder dan 86400 seconden.'; + @override String get settings_latitude => 'Breedtegraad'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index e4373d1..3e727c0 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -202,6 +202,20 @@ class AppLocalizationsPl extends AppLocalizations { String get settings_locationInvalid => 'Nieprawidłowa szerokość geograficzna lub długość geograficzna.'; + @override + String get settings_locationGPSEnable => 'Włącz GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Włącz GPS, aby automatycznie wysyłać dane o lokalizacji (jeśli jest obsługiwane).'; + + @override + String get settings_locationIntervalSec => 'Interwał (Sekundy)'; + + @override + String get settings_locationIntervalInvalid => + 'Interwał musi wynosić co najmniej 60 sekund i mniej niż 86400 sekund.'; + @override String get settings_latitude => 'Szerokość'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 2aaa940..769853e 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -201,6 +201,20 @@ class AppLocalizationsPt extends AppLocalizations { @override String get settings_locationInvalid => 'Latitude ou longitude inválidos.'; + @override + String get settings_locationGPSEnable => 'Ativar GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Habilite o GPS para enviar dados de localização automaticamente (se suportado).'; + + @override + String get settings_locationIntervalSec => 'Intervalo (Segundos)'; + + @override + String get settings_locationIntervalInvalid => + 'O intervalo deve ser de pelo menos 60 segundos e inferior a 86400 segundos.'; + @override String get settings_latitude => 'Latitude'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index ffd327a..aac0ced 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -200,6 +200,20 @@ class AppLocalizationsSk extends AppLocalizations { @override String get settings_locationInvalid => 'Neplatná šírka alebo dĺžka.'; + @override + String get settings_locationGPSEnable => 'Aktivovať GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Zapnite GPS na automatické posielanie dát o polohe (ak je podporované).'; + + @override + String get settings_locationIntervalSec => 'Interval (Sekundy)'; + + @override + String get settings_locationIntervalInvalid => + 'Interval musí byť aspoň 60 sekúnd a menej ako 86400 sekúnd.'; + @override String get settings_latitude => 'Súradnica'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 994b7fa..61e4033 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -200,6 +200,20 @@ class AppLocalizationsSl extends AppLocalizations { String get settings_locationInvalid => 'Neveljna zemeljska širina ali dolžina.'; + @override + String get settings_locationGPSEnable => 'Omogoči GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Omogoči GPS za samodejno pošiljanje podatkov o lokaciji (če je podprto).'; + + @override + String get settings_locationIntervalSec => 'Interval (Sekunde)'; + + @override + String get settings_locationIntervalInvalid => + 'Intervallo mora biti vsaj 60 sekund in manj kot 86400 sekund.'; + @override String get settings_latitude => 'Širina'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index a4765a9..2348e95 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -199,6 +199,20 @@ class AppLocalizationsSv extends AppLocalizations { @override String get settings_locationInvalid => 'Ogiltig latitud eller longitud.'; + @override + String get settings_locationGPSEnable => 'Aktivera GPS'; + + @override + String get settings_locationGPSEnableSubtitle => + 'Aktivera GPS för att automatiskt skicka platsdata (om det stöds).'; + + @override + String get settings_locationIntervalSec => 'Tidsintervall (Sekunder)'; + + @override + String get settings_locationIntervalInvalid => + 'Intervalet måste vara minst 60 sekunder och mindre än 86400 sekunder.'; + @override String get settings_latitude => 'Latitud'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 99f4e90..c68a38b 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -196,6 +196,18 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settings_locationInvalid => '无效的纬度或经度。'; + @override + String get settings_locationGPSEnable => '启用GPS'; + + @override + String get settings_locationGPSEnableSubtitle => '启用GPS自动发送位置数据(如果支持)。'; + + @override + String get settings_locationIntervalSec => '时间间隔(秒)'; + + @override + String get settings_locationIntervalInvalid => '时间间隔必须至少为60秒,且小于86400秒。'; + @override String get settings_latitude => '纬度'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index b7e1a35..a0ddfe8 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.", - "common_reload": "Opnieuw laden", "common_clear": "Schoonmaken", "path_currentPath": "Huidige pad: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Scan een QR-code", "channels_scanQrCodeComingSoon": "Komt later", "channels_enterHashtag": "Voer hashtag in", - "channels_hashtagHint": "bijv. #team" + "channels_hashtagHint": "bijv. #team", + "settings_locationGPSEnable": "GPS inschakelen", + "settings_locationGPSEnableSubtitle": "Zijze GPS inschakelen om locatiegegevens automatisch te verzenden (indien ondersteund).", + "settings_locationIntervalInvalid": "De intervallen moeten minstens 60 seconden zijn en minder dan 86400 seconden.", + "settings_locationIntervalSec": "Interval (Seconden)" } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 56fe869..23938a5 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Logowanie nie powiodło się. Hasło jest nieprawidłowe albo repeater jest nieosiągalny.", - "common_reload": "Ponownie załadować", "common_clear": "Wyczyść", "path_currentPath": "Aktualny ścieżka: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Skanuj kod QR", "channels_scanQrCodeComingSoon": "Wkrótce", "channels_enterHashtag": "Wprowadź hashtag", - "channels_hashtagHint": "np. #zespół" + "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_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 99da374..b49f286 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Falha no login. A senha está incorreta ou o repetidor está inacessível.", - "common_reload": "Recarregar", "common_clear": "Limpar", "path_currentPath": "Caminho atual: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Digitalizar um Código QR", "channels_scanQrCodeComingSoon": "Em breve", "channels_enterHashtag": "Insira hashtag", - "channels_hashtagHint": "ex. #equipe" + "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." } diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 1ffb197..aa242c3 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.", - "common_reload": "Načítať", "common_clear": "Zmazať", "path_currentPath": "Aktívna cesta: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Skenujte QR kód", "channels_scanQrCodeComingSoon": "Čoskoro", "channels_enterHashtag": "Zadajte hashtag", - "channels_hashtagHint": "napr. #tím" + "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_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 bac8b2b..e078d40 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Prijava je bila neuspešna. Geslo je napačno ali pa je repetitor nedosegljiv.", - "common_reload": "Ponovno naloži", "common_clear": "Ponoviti", "path_currentPath": "Trenutna pot: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Skeniraj QR kodo", "channels_scanQrCodeComingSoon": "Prihajajoča", "channels_enterHashtag": "Vnesite hashtag", - "channels_hashtagHint": "npr. #ekipa" + "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." } diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 3c8d470..2f580cb 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "Inloggning misslyckades. Antingen är lösenordet fel eller så går det inte att nå repeatern.", - "common_reload": "Ladda om", "common_clear": "Rensa", "path_currentPath": "Nuvarande sökväg: {path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "Skanna en QR-kod", "channels_scanQrCodeComingSoon": "Kommer snart", "channels_enterHashtag": "Ange hashtag", - "channels_hashtagHint": "t.ex. #team" + "channels_hashtagHint": "t.ex. #team", + "settings_locationGPSEnable": "Aktivera GPS", + "settings_locationIntervalSec": "Tidsintervall (Sekunder)", + "settings_locationGPSEnableSubtitle": "Aktivera GPS för att automatiskt skicka platsdata (om det stöds).", + "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 fc5ac55..fa9e64d 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -822,7 +822,6 @@ } }, "login_failedMessage": "登录失败。密码不正确或中继器不可达。", - "common_reload": "重新加载", "common_clear": "清除", "path_currentPath": "当前路径:{path}", @@ -1349,5 +1348,9 @@ "channels_scanQrCode": "扫描二维码", "channels_scanQrCodeComingSoon": "即将到来", "channels_enterHashtag": "输入标签", - "channels_hashtagHint": "例如 #团队" + "channels_hashtagHint": "例如 #团队", + "settings_locationGPSEnableSubtitle": "启用GPS自动发送位置数据(如果支持)。", + "settings_locationGPSEnable": "启用GPS", + "settings_locationIntervalSec": "时间间隔(秒)", + "settings_locationIntervalInvalid": "时间间隔必须至少为60秒,且小于86400秒。" } diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 8e23825..d925c30 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -38,10 +38,7 @@ class _SettingsScreenState extends State { Widget build(BuildContext context) { final l10n = context.l10n; return Scaffold( - appBar: AppBar( - title: Text(l10n.settings_title), - centerTitle: true, - ), + appBar: AppBar(title: Text(l10n.settings_title), centerTitle: true), body: SafeArea( top: false, child: Consumer( @@ -68,7 +65,10 @@ class _SettingsScreenState extends State { ); } - Widget _buildDeviceInfoCard(BuildContext context, MeshCoreConnector connector) { + Widget _buildDeviceInfoCard( + BuildContext context, + MeshCoreConnector connector, + ) { final l10n = context.l10n; return Card( child: Padding( @@ -83,21 +83,38 @@ class _SettingsScreenState extends State { const SizedBox(height: 16), _buildInfoRow(l10n.settings_infoName, connector.deviceDisplayName), _buildInfoRow(l10n.settings_infoId, connector.deviceIdLabel), - _buildInfoRow(l10n.settings_infoStatus, connector.isConnected ? l10n.common_connected : l10n.common_disconnected), + _buildInfoRow( + l10n.settings_infoStatus, + connector.isConnected + ? l10n.common_connected + : l10n.common_disconnected, + ), _buildBatteryInfoRow(context, connector), if (connector.selfName != null) _buildInfoRow(l10n.settings_nodeName, connector.selfName!), if (connector.selfPublicKey != null) - _buildInfoRow(l10n.settings_infoPublicKey, '${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...'), - _buildInfoRow(l10n.settings_infoContactsCount, '${connector.contacts.length}'), - _buildInfoRow(l10n.settings_infoChannelCount, '${connector.channels.length}'), + _buildInfoRow( + l10n.settings_infoPublicKey, + '${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...', + ), + _buildInfoRow( + l10n.settings_infoContactsCount, + '${connector.contacts.length}', + ), + _buildInfoRow( + l10n.settings_infoChannelCount, + '${connector.channels.length}', + ), ], ), ), ); } - Widget _buildBatteryInfoRow(BuildContext context, MeshCoreConnector connector) { + Widget _buildBatteryInfoRow( + BuildContext context, + MeshCoreConnector connector, + ) { final l10n = context.l10n; final percent = connector.batteryPercent; final millivolts = connector.batteryMillivolts; @@ -167,7 +184,10 @@ class _SettingsScreenState extends State { ); } - Widget _buildNodeSettingsCard(BuildContext context, MeshCoreConnector connector) { + Widget _buildNodeSettingsCard( + BuildContext context, + MeshCoreConnector connector, + ) { final l10n = context.l10n; return Card( child: Column( @@ -298,7 +318,9 @@ class _SettingsScreenState extends State { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => const BleDebugLogScreen()), + MaterialPageRoute( + builder: (context) => const BleDebugLogScreen(), + ), ); }, ), @@ -311,7 +333,9 @@ class _SettingsScreenState extends State { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => const AppDebugLogScreen()), + MaterialPageRoute( + builder: (context) => const AppDebugLogScreen(), + ), ); }, ), @@ -334,20 +358,14 @@ class _SettingsScreenState extends State { children: [ Row( children: [ - if (leading != null) ...[ - leading, - const SizedBox(width: 8), - ], + if (leading != null) ...[leading, const SizedBox(width: 8)], Text(label, style: TextStyle(color: Colors.grey[600])), ], ), Flexible( child: Text( value, - style: TextStyle( - fontWeight: FontWeight.w500, - color: valueColor, - ), + style: TextStyle(fontWeight: FontWeight.w500, color: valueColor), overflow: TextOverflow.ellipsis, ), ), @@ -413,75 +431,152 @@ class _SettingsScreenState extends State { final l10n = context.l10n; final latController = TextEditingController(); final lonController = TextEditingController(); + final intervalController = TextEditingController(); + intervalController.text = "900"; + latController.text = connector.selfLatitude?.toStringAsFixed(6) ?? ''; + lonController.text = connector.selfLongitude?.toStringAsFixed(6) ?? ''; + bool isGPSEnabled = false; + showDialog( context: context, - builder: (context) => AlertDialog( - title: Text(l10n.settings_location), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: latController, - decoration: InputDecoration( - labelText: l10n.settings_latitude, - border: const OutlineInputBorder(), + builder: (dialogContext) => StatefulBuilder( + builder: (context, setDialogState) => AlertDialog( + title: Text(l10n.settings_location), + 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, + ), + ), + 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: intervalController, + decoration: InputDecoration( + labelText: l10n.settings_locationIntervalSec, + border: const OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions( + decimal: false, + signed: false, + ), + ), + }, + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(l10n.common_cancel), ), - const SizedBox(height: 16), - TextField( - controller: lonController, - decoration: InputDecoration( - labelText: l10n.settings_longitude, - border: const OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), + TextButton( + onPressed: () async { + Navigator.pop(context); + if (isGPSEnabled) { + final intervalText = intervalController.text.trim(); + if (intervalText.isEmpty) { + return; + } + final interval = int.tryParse(intervalText); + if (interval == null || interval < 60) { + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(l10n.settings_locationIntervalInvalid), + ), + ); + 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; + } + + await connector.setCustomVar("gps:0"); + 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), ), ], ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text(l10n.common_cancel), - ), - TextButton( - onPressed: () async { - Navigator.pop(context); - 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; - } - - 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), - ), - ], ), ); } @@ -530,17 +625,17 @@ class _SettingsScreenState extends State { void _sendAdvert(BuildContext context, MeshCoreConnector connector) { final l10n = context.l10n; connector.sendSelfAdvert(flood: true); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(l10n.settings_advertisementSent)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.settings_advertisementSent))); } void _syncTime(BuildContext context, MeshCoreConnector connector) { final l10n = context.l10n; connector.syncTime(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(l10n.settings_timeSynchronized)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.settings_timeSynchronized))); } void _confirmReboot(BuildContext context, MeshCoreConnector connector) { @@ -560,7 +655,10 @@ class _SettingsScreenState extends State { Navigator.pop(context); connector.rebootDevice(); }, - child: Text(l10n.common_reboot, style: const TextStyle(color: Colors.orange)), + child: Text( + l10n.common_reboot, + style: const TextStyle(color: Colors.orange), + ), ), ], ), @@ -572,7 +670,9 @@ class _SettingsScreenState extends State { showAboutDialog( context: context, applicationName: l10n.appTitle, - applicationVersion: _appVersion.isEmpty ? l10n.common_loading : _appVersion, + applicationVersion: _appVersion.isEmpty + ? l10n.common_loading + : _appVersion, applicationLegalese: l10n.settings_aboutLegalese, children: [ const SizedBox(height: 16), @@ -604,7 +704,8 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { // Populate with current settings if available if (widget.connector.currentFreqHz != null) { - _frequencyController.text = (widget.connector.currentFreqHz! / 1000.0).toStringAsFixed(3); + _frequencyController.text = (widget.connector.currentFreqHz! / 1000.0) + .toStringAsFixed(3); } else { _frequencyController.text = '915.0'; } @@ -670,26 +771,31 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { final txPower = int.tryParse(_txPowerController.text); if (freqMHz == null || freqMHz < 300 || freqMHz > 2500) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(l10n.settings_frequencyInvalid)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.settings_frequencyInvalid))); return; } if (txPower == null || txPower < 0 || txPower > 22) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(l10n.settings_txPowerInvalid)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.settings_txPowerInvalid))); return; } final freqHz = (freqMHz * 1000).round(); final bwHz = _bandwidth.hz; final sf = _spreadingFactor.value; - final cr = _toDeviceCodingRate(_codingRate.value, widget.connector.currentCr); + final cr = _toDeviceCodingRate( + _codingRate.value, + widget.connector.currentCr, + ); try { - await widget.connector.sendFrame(buildSetRadioParamsFrame(freqHz, bwHz, sf, cr)); + await widget.connector.sendFrame( + buildSetRadioParamsFrame(freqHz, bwHz, sf, cr), + ); await widget.connector.sendFrame(buildSetRadioTxPowerFrame(txPower)); await widget.connector.refreshDeviceInfo(); @@ -727,7 +833,10 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(l10n.settings_presets, style: const TextStyle(fontWeight: FontWeight.bold)), + Text( + l10n.settings_presets, + style: const TextStyle(fontWeight: FontWeight.bold), + ), const SizedBox(height: 8), Wrap( spacing: 8, @@ -762,7 +871,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { border: const OutlineInputBorder(), helperText: l10n.settings_frequencyHelper, ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), + keyboardType: const TextInputType.numberWithOptions( + decimal: true, + ), ), const SizedBox(height: 16), DropdownButtonFormField( @@ -772,10 +883,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { border: const OutlineInputBorder(), ), items: LoRaBandwidth.values - .map((bw) => DropdownMenuItem( - value: bw, - child: Text(bw.label), - )) + .map( + (bw) => DropdownMenuItem(value: bw, child: Text(bw.label)), + ) .toList(), onChanged: (value) { if (value != null) setState(() => _bandwidth = value); @@ -789,10 +899,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { border: const OutlineInputBorder(), ), items: LoRaSpreadingFactor.values - .map((sf) => DropdownMenuItem( - value: sf, - child: Text(sf.label), - )) + .map( + (sf) => DropdownMenuItem(value: sf, child: Text(sf.label)), + ) .toList(), onChanged: (value) { if (value != null) setState(() => _spreadingFactor = value); @@ -806,10 +915,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { border: const OutlineInputBorder(), ), items: LoRaCodingRate.values - .map((cr) => DropdownMenuItem( - value: cr, - child: Text(cr.label), - )) + .map( + (cr) => DropdownMenuItem(value: cr, child: Text(cr.label)), + ) .toList(), onChanged: (value) { if (value != null) setState(() => _codingRate = value); @@ -833,10 +941,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { onPressed: () => Navigator.pop(context), child: Text(l10n.common_cancel), ), - FilledButton( - onPressed: _saveSettings, - child: Text(l10n.common_save), - ), + FilledButton(onPressed: _saveSettings, child: Text(l10n.common_save)), ], ); } @@ -850,9 +955,6 @@ class _PresetChip extends StatelessWidget { @override Widget build(BuildContext context) { - return ActionChip( - label: Text(label), - onPressed: onTap, - ); + return ActionChip(label: Text(label), onPressed: onTap); } }