From 3e2e4aa4d9597ff853e5c877beca161fb586a6a1 Mon Sep 17 00:00:00 2001 From: Janez Troha Date: Thu, 4 Dec 2025 18:33:00 +0100 Subject: [PATCH] feat: Add setting to disable map tab for battery savings Add a new "Disable Map" toggle in settings that allows users to hide the map tab entirely. This is useful for scenarios where the map is not needed and battery conservation is a priority. Changes: - Add disableMap and disableMapDescription localized strings (all languages) - Add isMapEnabled state to AppProvider with persistence - Update HomeScreen to dynamically adjust tab count based on setting - Make onNavigateToMap optional in MessagesTab and ContactsTab - Add toggle switch in Settings screen under Interface section --- lib/l10n/app_de.arb | 10 +++ lib/l10n/app_en.arb | 10 +++ lib/l10n/app_es.arb | 10 +++ lib/l10n/app_fr.arb | 10 +++ lib/l10n/app_hr.arb | 4 + lib/l10n/app_it.arb | 10 +++ lib/l10n/app_localizations.dart | 12 +++ lib/l10n/app_localizations_de.dart | 7 ++ lib/l10n/app_localizations_en.dart | 7 ++ lib/l10n/app_localizations_es.dart | 7 ++ lib/l10n/app_localizations_fr.dart | 7 ++ lib/l10n/app_localizations_hr.dart | 6 ++ lib/l10n/app_localizations_it.dart | 7 ++ lib/l10n/app_localizations_sl.dart | 7 ++ lib/l10n/app_sl.arb | 4 + lib/providers/app_provider.dart | 27 +++++++ lib/screens/home_screen.dart | 116 +++++++++++++++++++++++------ lib/screens/messages_tab.dart | 14 ++-- lib/screens/settings_screen.dart | 13 ++++ 19 files changed, 258 insertions(+), 30 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index a461bb7..d8097f2 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -217,6 +217,16 @@ "description": "Beschreibung für die Einstellung des einfachen Modus" }, + "disableMap": "Karte deaktivieren", + "@disableMap": { + "description": "Einstellung zum Deaktivieren des Karten-Tabs" + }, + + "disableMapDescription": "Karten-Tab ausblenden, um Akku zu sparen", + "@disableMapDescription": { + "description": "Beschreibung für die Einstellung zum Deaktivieren der Karte" + }, + "language": "Sprache", "@language": { "description": "Beschriftung der Spracheinstellung" diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 491c6a2..51e1914 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -217,6 +217,16 @@ "description": "Description for simple mode setting" }, + "disableMap": "Disable Map", + "@disableMap": { + "description": "Setting to disable the map tab" + }, + + "disableMapDescription": "Hide the map tab to reduce battery usage", + "@disableMapDescription": { + "description": "Description for disable map setting" + }, + "language": "Language", "@language": { "description": "Language setting label" diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 9674470..f6ca905 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -217,6 +217,16 @@ "description": "Descripción de la configuración del modo simple" }, + "disableMap": "Desactivar mapa", + "@disableMap": { + "description": "Configuración para desactivar la pestaña del mapa" + }, + + "disableMapDescription": "Ocultar la pestaña del mapa para reducir el uso de batería", + "@disableMapDescription": { + "description": "Descripción de la configuración para desactivar el mapa" + }, + "language": "Idioma", "@language": { "description": "Etiqueta de la configuración de idioma" diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 3f5c883..7f1932b 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -217,6 +217,16 @@ "description": "Description du paramètre du mode simple" }, + "disableMap": "Désactiver la carte", + "@disableMap": { + "description": "Paramètre pour désactiver l'onglet carte" + }, + + "disableMapDescription": "Masquer l'onglet carte pour réduire la consommation de batterie", + "@disableMapDescription": { + "description": "Description du paramètre pour désactiver la carte" + }, + "language": "Langue", "@language": { "description": "Libellé du paramètre de langue" diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb index 6b121f7..00eeccd 100644 --- a/lib/l10n/app_hr.arb +++ b/lib/l10n/app_hr.arb @@ -79,6 +79,10 @@ "simpleModeDescription": "Sakrij nevažne informacije u porukama i kontaktima", + "disableMap": "Onemogući kartu", + + "disableMapDescription": "Sakrij karticu karte za uštedu baterije", + "language": "Jezik", "chooseLanguage": "Odaberite jezik", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 87b849e..daf172a 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -217,6 +217,16 @@ "description": "Descrizione per l'impostazione della modalità semplice" }, + "disableMap": "Disabilita mappa", + "@disableMap": { + "description": "Impostazione per disabilitare la scheda mappa" + }, + + "disableMapDescription": "Nascondi la scheda mappa per ridurre il consumo della batteria", + "@disableMapDescription": { + "description": "Descrizione per l'impostazione di disabilitazione mappa" + }, + "language": "Lingua", "@language": { "description": "Etichetta impostazione lingua" diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index ec6a3ac..fb4f651 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -342,6 +342,18 @@ abstract class AppLocalizations { /// **'Hide non-essential information in messages and contacts'** String get simpleModeDescription; + /// Setting to disable the map tab + /// + /// In en, this message translates to: + /// **'Disable Map'** + String get disableMap; + + /// Description for disable map setting + /// + /// In en, this message translates to: + /// **'Hide the map tab to reduce battery usage'** + String get disableMapDescription; + /// Language setting label /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 93af170..c015052 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -137,6 +137,13 @@ class AppLocalizationsDe extends AppLocalizations { String get simpleModeDescription => 'Nicht wesentliche Informationen in Nachrichten und Kontakten ausblenden'; + @override + String get disableMap => 'Karte deaktivieren'; + + @override + String get disableMapDescription => + 'Karten-Tab ausblenden, um Akku zu sparen'; + @override String get language => 'Sprache'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index d493be5..3937a1d 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -136,6 +136,13 @@ class AppLocalizationsEn extends AppLocalizations { String get simpleModeDescription => 'Hide non-essential information in messages and contacts'; + @override + String get disableMap => 'Disable Map'; + + @override + String get disableMapDescription => + 'Hide the map tab to reduce battery usage'; + @override String get language => 'Language'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 74e819e..1d27cbb 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -136,6 +136,13 @@ class AppLocalizationsEs extends AppLocalizations { String get simpleModeDescription => 'Ocultar información no esencial en mensajes y contactos'; + @override + String get disableMap => 'Desactivar mapa'; + + @override + String get disableMapDescription => + 'Ocultar la pestaña del mapa para reducir el uso de batería'; + @override String get language => 'Idioma'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index e9792a7..bd08705 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -137,6 +137,13 @@ class AppLocalizationsFr extends AppLocalizations { String get simpleModeDescription => 'Masquer les informations non essentielles dans les messages et les contacts'; + @override + String get disableMap => 'Désactiver la carte'; + + @override + String get disableMapDescription => + 'Masquer l\'onglet carte pour réduire la consommation de batterie'; + @override String get language => 'Langue'; diff --git a/lib/l10n/app_localizations_hr.dart b/lib/l10n/app_localizations_hr.dart index b83ad23..48f6e71 100644 --- a/lib/l10n/app_localizations_hr.dart +++ b/lib/l10n/app_localizations_hr.dart @@ -136,6 +136,12 @@ class AppLocalizationsHr extends AppLocalizations { String get simpleModeDescription => 'Sakrij nevažne informacije u porukama i kontaktima'; + @override + String get disableMap => 'Onemogući kartu'; + + @override + String get disableMapDescription => 'Sakrij karticu karte za uštedu baterije'; + @override String get language => 'Jezik'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index ea13eb0..b62a61f 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -136,6 +136,13 @@ class AppLocalizationsIt extends AppLocalizations { String get simpleModeDescription => 'Nascondi informazioni non essenziali nei messaggi e contatti'; + @override + String get disableMap => 'Disabilita mappa'; + + @override + String get disableMapDescription => + 'Nascondi la scheda mappa per ridurre il consumo della batteria'; + @override String get language => 'Lingua'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index ce83f37..4bed713 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -136,6 +136,13 @@ class AppLocalizationsSl extends AppLocalizations { String get simpleModeDescription => 'Skrij nepomembne informacije v sporočilih in kontaktih'; + @override + String get disableMap => 'Onemogoči zemljevid'; + + @override + String get disableMapDescription => + 'Skrij zavihek z zemljevidom za varčevanje z baterijo'; + @override String get language => 'Jezik'; diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 4ace88d..60b39f8 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -79,6 +79,10 @@ "simpleModeDescription": "Skrij nepomembne informacije v sporočilih in kontaktih", + "disableMap": "Onemogoči zemljevid", + + "disableMapDescription": "Skrij zavihek z zemljevidom za varčevanje z baterijo", + "language": "Jezik", "chooseLanguage": "Izberite jezik", diff --git a/lib/providers/app_provider.dart b/lib/providers/app_provider.dart index 1a88c87..06703e3 100644 --- a/lib/providers/app_provider.dart +++ b/lib/providers/app_provider.dart @@ -28,6 +28,9 @@ class AppProvider with ChangeNotifier { bool _isSimpleMode = true; bool get isSimpleMode => _isSimpleMode; + bool _isMapEnabled = true; + bool get isMapEnabled => _isMapEnabled; + AppProvider({ required this.connectionProvider, required this.contactsProvider, @@ -40,6 +43,7 @@ class AppProvider with ChangeNotifier { _initializeTileCache(); _initializeLocationTracking(); _loadSimpleMode(); + _loadMapEnabled(); _syncDrawingsOnStartup(); // Sync drawings immediately after providers load _isInitialized = true; } @@ -84,6 +88,29 @@ class AppProvider with ChangeNotifier { } } + /// Load map enabled setting from shared preferences + Future _loadMapEnabled() async { + try { + final prefs = await SharedPreferences.getInstance(); + _isMapEnabled = prefs.getBool('map_enabled') ?? true; + notifyListeners(); + } catch (e) { + debugPrint('Error loading map enabled setting: $e'); + } + } + + /// Toggle map on/off + Future toggleMapEnabled(bool enabled) async { + try { + _isMapEnabled = enabled; + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool('map_enabled', enabled); + notifyListeners(); + } catch (e) { + debugPrint('Error saving map enabled setting: $e'); + } + } + /// Initialize tile cache service Future _initializeTileCache() async { try { diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 1cb4e42..3a2c59b 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -47,20 +47,12 @@ class _HomeScreenState extends State int _currentIndex = 0; bool _isMapFullscreen = false; bool _showRxTxIndicators = true; + bool _isMapEnabled = true; @override void initState() { super.initState(); - _tabController = TabController(length: 3, vsync: this); - _tabController.addListener(() { - setState(() { - _currentIndex = _tabController.index; - // Exit fullscreen when switching away from map tab - if (_currentIndex != 2) { - _isMapFullscreen = false; - } - }); - }); + _loadMapEnabledAndInitTabs(); _loadRxTxPreference(); // Show permission dialog after the first frame if needed @@ -71,6 +63,63 @@ class _HomeScreenState extends State } } + Future _loadMapEnabledAndInitTabs() async { + final prefs = await SharedPreferences.getInstance(); + final mapEnabled = prefs.getBool('map_enabled') ?? true; + if (mapEnabled != _isMapEnabled) { + _isMapEnabled = mapEnabled; + } + _initTabController(); + if (mounted) { + setState(() {}); + } + } + + void _initTabController() { + final tabCount = _isMapEnabled ? 3 : 2; + _tabController = TabController(length: tabCount, vsync: this); + _tabController.addListener(_onTabChanged); + } + + void _onTabChanged() { + setState(() { + _currentIndex = _tabController.index; + // Exit fullscreen when switching away from map tab (only if map is enabled and is tab 2) + if (_isMapEnabled && _currentIndex != 2) { + _isMapFullscreen = false; + } + }); + } + + void _updateTabController(bool mapEnabled) { + if (_isMapEnabled == mapEnabled) return; + + // Save current index before rebuilding + final oldIndex = _tabController.index; + + // Remove old listener and dispose + _tabController.removeListener(_onTabChanged); + _tabController.dispose(); + + // Update state + _isMapEnabled = mapEnabled; + + // Create new controller + final tabCount = mapEnabled ? 3 : 2; + _tabController = TabController(length: tabCount, vsync: this); + _tabController.addListener(_onTabChanged); + + // Restore index (clamp to valid range) + if (oldIndex < tabCount) { + _tabController.index = oldIndex; + _currentIndex = oldIndex; + } else { + _currentIndex = tabCount - 1; + } + + setState(() {}); + } + Future _loadRxTxPreference() async { final prefs = await SharedPreferences.getInstance(); if (mounted) { @@ -82,6 +131,7 @@ class _HomeScreenState extends State @override void dispose() { + _tabController.removeListener(_onTabChanged); _tabController.dispose(); super.dispose(); } @@ -225,8 +275,16 @@ class _HomeScreenState extends State messagesProvider.setLocalizations(localizations); } + // Check if map enabled setting changed and update tab controller + final appProvider = context.watch(); + if (_isMapEnabled != appProvider.isMapEnabled) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _updateTabController(appProvider.isMapEnabled); + }); + } + // Determine if we should hide the UI (only in fullscreen on map tab) - final shouldHideUI = _isMapFullscreen && _currentIndex == 2; + final shouldHideUI = _isMapEnabled && _isMapFullscreen && _currentIndex == 2; return Scaffold( appBar: shouldHideUI @@ -308,16 +366,25 @@ class _HomeScreenState extends State body: TabBarView( controller: _tabController, children: [ - MessagesTab(onNavigateToMap: () => _tabController.animateTo(2)), - ContactsTab(onNavigateToMap: () => _tabController.animateTo(2)), - MapTab( - onFullscreenChanged: (isFullscreen) { - setState(() { - _isMapFullscreen = isFullscreen; - }); - }, - onNavigateToMessages: () => _tabController.animateTo(0), + MessagesTab( + onNavigateToMap: _isMapEnabled + ? () => _tabController.animateTo(2) + : null, ), + ContactsTab( + onNavigateToMap: _isMapEnabled + ? () => _tabController.animateTo(2) + : null, + ), + if (_isMapEnabled) + MapTab( + onFullscreenChanged: (isFullscreen) { + setState(() { + _isMapFullscreen = isFullscreen; + }); + }, + onNavigateToMessages: () => _tabController.animateTo(0), + ), ], ), bottomNavigationBar: shouldHideUI @@ -354,10 +421,11 @@ class _HomeScreenState extends State ), text: AppLocalizations.of(context)!.contacts, ), - Tab( - icon: const Icon(Icons.map), - text: AppLocalizations.of(context)!.map, - ), + if (_isMapEnabled) + Tab( + icon: const Icon(Icons.map), + text: AppLocalizations.of(context)!.map, + ), ], ), ); diff --git a/lib/screens/messages_tab.dart b/lib/screens/messages_tab.dart index 8ba95d3..58ff4d5 100644 --- a/lib/screens/messages_tab.dart +++ b/lib/screens/messages_tab.dart @@ -18,9 +18,9 @@ import '../utils/toast_logger.dart'; import '../l10n/app_localizations.dart'; class MessagesTab extends StatefulWidget { - final VoidCallback onNavigateToMap; + final VoidCallback? onNavigateToMap; - const MessagesTab({super.key, required this.onNavigateToMap}); + const MessagesTab({super.key, this.onNavigateToMap}); @override State createState() => _MessagesTabState(); @@ -780,7 +780,8 @@ class _MessagesTabState extends State { isHighlighted: isHighlighted, onNavigateToMap: widget.onNavigateToMap, onTap: - message.isSarMarker && + widget.onNavigateToMap != null && + message.isSarMarker && message.sarGpsCoordinates != null ? () { final mapProvider = context @@ -789,9 +790,10 @@ class _MessagesTabState extends State { location: message.sarGpsCoordinates!, zoom: 15.0, ); - widget.onNavigateToMap(); + widget.onNavigateToMap?.call(); } - : message.isDrawing && message.drawingId != null + : widget.onNavigateToMap != null && + message.isDrawing && message.drawingId != null ? () { debugPrint('🗺️ [MessagesTab] Drawing tapped! ID: ${message.drawingId}'); final mapProvider = context @@ -802,7 +804,7 @@ class _MessagesTabState extends State { message.drawingId!, drawingProvider, ); - widget.onNavigateToMap(); + widget.onNavigateToMap?.call(); } : null, ); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 40dadbf..41fb109 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -528,6 +528,19 @@ class _SettingsScreenState extends State { }, ), ), + Consumer( + builder: (context, appProvider, child) => SwitchListTile( + secondary: const Icon(Icons.map_outlined), + title: Text(AppLocalizations.of(context)!.disableMap), + subtitle: Text( + AppLocalizations.of(context)!.disableMapDescription, + ), + value: !appProvider.isMapEnabled, + onChanged: (value) async { + await appProvider.toggleMapEnabled(!value); + }, + ), + ), ListTile( leading: const Icon(Icons.language), title: Text(AppLocalizations.of(context)!.language),