From 329974a8f08e565fa96640a7ce5602620c0a6dc0 Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Sat, 9 May 2026 22:02:36 +0000 Subject: [PATCH] Feature: Keep screen on while using app. Initial working. --- lib/app_state.dart | 6 +++++- lib/screens/advanced_settings_screen.dart | 3 +++ .../sections/keep_screen_awake_section.dart | 21 +++++++++++++++++++ lib/state/settings_state.dart | 18 +++++++++++++++- lib/widgets/map_view.dart | 18 ++++++++++++++++ pubspec.yaml | 1 + 6 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 lib/screens/settings/sections/keep_screen_awake_section.dart diff --git a/lib/app_state.dart b/lib/app_state.dart index a593c18..c59cebb 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -156,6 +156,7 @@ class AppState extends ChangeNotifier { int get maxNodes => _settingsState.maxNodes; UploadMode get uploadMode => _settingsState.uploadMode; FollowMeMode get followMeMode => _settingsState.followMeMode; + bool get keepScreenAwake => _settingsState.keepScreenAwake; bool get proximityAlertsEnabled => _settingsState.proximityAlertsEnabled; int get proximityAlertDistance => _settingsState.proximityAlertDistance; @@ -172,7 +173,6 @@ class AppState extends ChangeNotifier { TileType? get selectedTileType => _settingsState.selectedTileType; TileProvider? get selectedTileProvider => _settingsState.selectedTileProvider; - // Upload queue state int get pendingCount => _uploadQueueState.pendingCount; @@ -678,6 +678,10 @@ class AppState extends ChangeNotifier { } } + Future setKeepScreenAwake(bool enabled) async { + await _settingsState.setKeepScreenAwake(enabled); + } + Future setPauseQueueProcessing(bool enabled) async { await _settingsState.setPauseQueueProcessing(enabled); if (!enabled) { diff --git a/lib/screens/advanced_settings_screen.dart b/lib/screens/advanced_settings_screen.dart index b5630a4..275f11a 100644 --- a/lib/screens/advanced_settings_screen.dart +++ b/lib/screens/advanced_settings_screen.dart @@ -3,6 +3,7 @@ import 'settings/sections/max_nodes_section.dart'; import 'settings/sections/proximity_alerts_section.dart'; import 'settings/sections/suspected_locations_section.dart'; import 'settings/sections/tile_provider_section.dart'; +import 'settings/sections/keep_screen_awake_section.dart'; import '../services/localization_service.dart'; class AdvancedSettingsScreen extends StatelessWidget { @@ -32,6 +33,8 @@ class AdvancedSettingsScreen extends StatelessWidget { Divider(), SuspectedLocationsSection(), Divider(), + KeepScreenAwakeSection(), + Divider(), // NetworkStatusSection(), // Commented out - network status indicator now defaults to enabled // Divider(), TileProviderSection(), diff --git a/lib/screens/settings/sections/keep_screen_awake_section.dart b/lib/screens/settings/sections/keep_screen_awake_section.dart new file mode 100644 index 0000000..5bb0ffe --- /dev/null +++ b/lib/screens/settings/sections/keep_screen_awake_section.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../../app_state.dart'; + +class KeepScreenAwakeSection extends StatelessWidget { + const KeepScreenAwakeSection({super.key}); + + @override + Widget build(BuildContext context) { + final appState = context.watch(); + + return SwitchListTile( + title: const Text('Keep screen awake while using app'), + subtitle: const Text('Prevents the screen from turning off automatically while using the app'), + value: appState.keepScreenAwake, + onChanged: (bool value) { + appState.setKeepScreenAwake(value); + }, + ); + } +} \ No newline at end of file diff --git a/lib/state/settings_state.dart b/lib/state/settings_state.dart index e884086..9fa1268 100644 --- a/lib/state/settings_state.dart +++ b/lib/state/settings_state.dart @@ -39,9 +39,11 @@ class SettingsState extends ChangeNotifier { static const String _pauseQueueProcessingPrefsKey = 'pause_queue_processing'; static const String _navigationAvoidanceDistancePrefsKey = 'navigation_avoidance_distance'; static const String _distanceUnitPrefsKey = 'distance_unit'; + static const String _keepScreenAwakePrefsKey = 'keep_screen_awake'; bool _offlineMode = false; bool _pauseQueueProcessing = false; + bool _keepScreenAwake = false; int _maxNodes = kDefaultMaxNodes; // Default must account for missing secrets (preview builds) even before init() runs UploadMode _uploadMode = (kEnableDevelopmentModes || !kHasOsmSecrets) ? UploadMode.simulate : UploadMode.production; @@ -65,6 +67,7 @@ class SettingsState extends ChangeNotifier { int get proximityAlertDistance => _proximityAlertDistance; bool get networkStatusIndicatorEnabled => _networkStatusIndicatorEnabled; int get suspectedLocationMinDistance => _suspectedLocationMinDistance; + bool get keepScreenAwake => _keepScreenAwake; List get tileProviders => List.unmodifiable(_tileProviders); String get selectedTileTypeId => _selectedTileTypeId; int get navigationAvoidanceDistance => _navigationAvoidanceDistance; @@ -138,6 +141,9 @@ class SettingsState extends ChangeNotifier { // Load suspected location minimum distance _suspectedLocationMinDistance = prefs.getInt(_suspectedLocationMinDistancePrefsKey) ?? 100; + + // Load keep screen awake setting + _keepScreenAwake = prefs.getBool(_keepScreenAwakePrefsKey) ?? false; // Load upload mode (including migration from old test_mode bool) if (prefs.containsKey(_uploadModePrefsKey)) { @@ -397,7 +403,17 @@ class SettingsState extends ChangeNotifier { } } - // Set distance for avoidance of nodes during navigation + /// Set keep screen awake enabled/disabled + Future setKeepScreenAwake(bool enabled) async { + if (_keepScreenAwake != enabled) { + _keepScreenAwake = enabled; + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_keepScreenAwakePrefsKey, enabled); + notifyListeners(); + } + } + + /// Set distance for avoidance of nodes during navigation Future setNavigationAvoidanceDistance(int distance) async { if (_navigationAvoidanceDistance != distance) { _navigationAvoidanceDistance = distance; diff --git a/lib/widgets/map_view.dart b/lib/widgets/map_view.dart index 1c817a4..65ad200 100644 --- a/lib/widgets/map_view.dart +++ b/lib/widgets/map_view.dart @@ -3,6 +3,7 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map_animations/flutter_map_animations.dart'; import 'package:latlong2/latlong.dart'; import 'package:provider/provider.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; import '../app_state.dart' show AppState, FollowMeMode; import '../services/offline_area_service.dart'; @@ -84,7 +85,20 @@ class MapViewState extends State { // Track active pointers to suppress follow-me animations during touch int _activePointers = 0; + bool _isWakelockEnabled = false; + void _updateWakelock(bool shouldBeAwake) { + if (_isWakelockEnabled != shouldBeAwake) { + _isWakelockEnabled = shouldBeAwake; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (shouldBeAwake) { + WakelockPlus.enable(); + } else { + WakelockPlus.disable(); + } + }); + } + } @override void initState() { @@ -213,6 +227,7 @@ class MapViewState extends State { _nodeController.dispose(); _tileManager.dispose(); _gpsController.dispose(); + WakelockPlus.disable(); // PrefetchAreaService no longer used - replaced with NodeDataManager super.dispose(); } @@ -278,6 +293,9 @@ class MapViewState extends State { final session = appState.session; final editSession = appState.editSession; + // Call the safe tracker using appState instead + _updateWakelock(appState.keepScreenAwake); + // Check if enabled profiles changed and refresh nodes if needed _nodeController.checkAndHandleProfileChanges( currentEnabledProfiles: appState.enabledProfiles, diff --git a/pubspec.yaml b/pubspec.yaml index ac3484d..cd7d423 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: package_info_plus: ^9.0.0 csv: ^6.0.0 collection: ^1.18.0 + wakelock_plus: ^1.5.2 dev_dependencies: flutter_test: