diff --git a/mobile/lib/core/configuration.dart b/mobile/lib/core/configuration.dart index 2ac65b3c78..0245e82eae 100644 --- a/mobile/lib/core/configuration.dart +++ b/mobile/lib/core/configuration.dart @@ -33,7 +33,6 @@ import 'package:photos/services/sync/sync_service.dart'; import 'package:photos/utils/file_uploader.dart'; import "package:photos/utils/lock_screen_settings.dart"; import 'package:photos/utils/validator_util.dart'; -import "package:photos/utils/wakelock_util.dart"; import 'package:shared_preferences/shared_preferences.dart'; import "package:tuple/tuple.dart"; import 'package:uuid/uuid.dart'; @@ -53,10 +52,6 @@ class Configuration { static const keyKey = "key"; static const keyShouldBackupOverMobileData = "should_backup_over_mobile_data"; static const keyShouldBackupVideos = "should_backup_videos"; - - // keyShouldKeepDeviceAwake is used to determine whether the device screen - // should be kept on while the app is in foreground. - static const keyShouldKeepDeviceAwake = "should_keep_device_awake"; static const keyShowSystemLockScreen = "should_show_lock_screen"; static const keyHasSelectedAnyBackupFolder = "has_selected_any_folder_for_backup"; @@ -578,16 +573,6 @@ class Configuration { } } - bool shouldKeepDeviceAwake() { - final keepAwake = _preferences.get(keyShouldKeepDeviceAwake); - return keepAwake == null ? false : keepAwake as bool; - } - - Future setShouldKeepDeviceAwake(bool value) async { - await _preferences.setBool(keyShouldKeepDeviceAwake, value); - await EnteWakeLock.toggle(enable: value); - } - Future setShouldBackupVideos(bool value) async { await _preferences.setBool(keyShouldBackupVideos, value); if (value) { diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 0018c5f096..c4ae34fa28 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -44,6 +44,7 @@ import 'package:photos/services/search_service.dart'; import 'package:photos/services/sync/local_sync_service.dart'; import 'package:photos/services/sync/remote_sync_service.dart'; import "package:photos/services/sync/sync_service.dart"; +import "package:photos/services/wake_lock_service.dart"; import 'package:photos/ui/tools/app_lock.dart'; import 'package:photos/ui/tools/lock_screen.dart'; import "package:photos/utils/email_util.dart"; @@ -276,6 +277,7 @@ Future _init(bool isBackground, {String via = ''}) async { MLDataDB.instance, preferences, ); + EnteWakeLockService.instance.init(preferences); logLocalSettings(); initComplete = true; _logger.info("Initialization done $tlog"); diff --git a/mobile/lib/services/wake_lock_service.dart b/mobile/lib/services/wake_lock_service.dart new file mode 100644 index 0000000000..1e72481b32 --- /dev/null +++ b/mobile/lib/services/wake_lock_service.dart @@ -0,0 +1,51 @@ +import "package:shared_preferences/shared_preferences.dart"; +import "package:wakelock_plus/wakelock_plus.dart"; + +enum WakeLockFor { + videoPlayback, + fasterBackupsOniOSByKeepingScreenAwake, + machineLearningSettingsScreen, + handlingMediaKitEdgeCase, +} + +/// Use this wrapper to use wakelock. This class makes sure that the wakelock +/// setting across sessions if set is respected when wakelock is updated for +/// other non across session purposes. +/// Only place where this wrapper is not used for accessing wakelock APIs is +/// in media_kit package. +class EnteWakeLockService { + static const String kKeepAppAwakeAcrossSessions = + "keepAppAwakeAcrossSessions"; + + EnteWakeLockService._privateConstructor(); + + static final EnteWakeLockService instance = + EnteWakeLockService._privateConstructor(); + + late SharedPreferences _prefs; + + void init(SharedPreferences prefs) { + _prefs = prefs; + if (_prefs.getBool(kKeepAppAwakeAcrossSessions) ?? false) { + WakelockPlus.enable(); + } + } + + void updateWakeLock({ + required bool enable, + required WakeLockFor wakeLockFor, + }) { + if (wakeLockFor == WakeLockFor.fasterBackupsOniOSByKeepingScreenAwake || + wakeLockFor == WakeLockFor.handlingMediaKitEdgeCase) { + WakelockPlus.toggle(enable: enable); + _prefs.setBool(kKeepAppAwakeAcrossSessions, enable); + } else { + if (!shouldKeepAppAwakeAcrossSessions) { + WakelockPlus.toggle(enable: enable); + } + } + } + + bool get shouldKeepAppAwakeAcrossSessions => + _prefs.getBool(kKeepAppAwakeAcrossSessions) ?? false; +} diff --git a/mobile/lib/ui/settings/backup/backup_settings_screen.dart b/mobile/lib/ui/settings/backup/backup_settings_screen.dart index 8f87fb6037..3824a1158b 100644 --- a/mobile/lib/ui/settings/backup/backup_settings_screen.dart +++ b/mobile/lib/ui/settings/backup/backup_settings_screen.dart @@ -1,9 +1,10 @@ -import 'dart:io'; +import "dart:io"; import 'package:flutter/material.dart'; import 'package:photos/core/configuration.dart'; import "package:photos/generated/l10n.dart"; import "package:photos/service_locator.dart"; +import "package:photos/services/wake_lock_service.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import 'package:photos/ui/components/captioned_text_widget.dart'; @@ -134,13 +135,15 @@ class BackupSettingsScreen extends StatelessWidget { ), menuItemColor: colorScheme.fillFaint, trailingWidget: ToggleSwitchWidget( - value: () => Configuration.instance - .shouldKeepDeviceAwake(), - onChanged: () { - return Configuration.instance - .setShouldKeepDeviceAwake( - !Configuration.instance - .shouldKeepDeviceAwake(), + value: () => EnteWakeLockService.instance + .shouldKeepAppAwakeAcrossSessions, + onChanged: () async { + EnteWakeLockService.instance + .updateWakeLock( + enable: !EnteWakeLockService.instance + .shouldKeepAppAwakeAcrossSessions, + wakeLockFor: WakeLockFor + .fasterBackupsOniOSByKeepingScreenAwake, ); }, ), diff --git a/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart b/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart index 9a95d7dfcb..5db7a028ac 100644 --- a/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart +++ b/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart @@ -12,6 +12,7 @@ import "package:photos/services/machine_learning/semantic_search/clip/clip_image import "package:photos/services/machine_learning/semantic_search/clip/clip_text_encoder.dart"; import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart'; import "package:photos/services/remote_assets_service.dart"; +import "package:photos/services/wake_lock_service.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/common/loading_widget.dart"; import "package:photos/ui/common/web_page.dart"; @@ -31,7 +32,6 @@ import "package:photos/ui/settings/ml/enable_ml_consent.dart"; import "package:photos/ui/settings/ml/ml_user_dev_screen.dart"; import "package:photos/utils/ml_util.dart"; import "package:photos/utils/network_util.dart"; -import "package:photos/utils/wakelock_util.dart"; class MachineLearningSettingsPage extends StatefulWidget { const MachineLearningSettingsPage({super.key}); @@ -43,7 +43,6 @@ class MachineLearningSettingsPage extends StatefulWidget { class _MachineLearningSettingsPageState extends State { - final EnteWakeLock _wakeLock = EnteWakeLock(); Timer? _timer; int _titleTapCount = 0; Timer? _advancedOptionsTimer; @@ -51,7 +50,10 @@ class _MachineLearningSettingsPageState @override void initState() { super.initState(); - _wakeLock.enable(); + EnteWakeLockService.instance.updateWakeLock( + enable: true, + wakeLockFor: WakeLockFor.machineLearningSettingsScreen, + ); machineLearningController.forceOverrideML(turnOn: true); if (!MLIndexingIsolate.instance.areModelsDownloaded) { _timer = Timer.periodic(const Duration(seconds: 10), (timer) { @@ -68,7 +70,10 @@ class _MachineLearningSettingsPageState @override void dispose() { super.dispose(); - _wakeLock.disable(); + EnteWakeLockService.instance.updateWakeLock( + enable: false, + wakeLockFor: WakeLockFor.machineLearningSettingsScreen, + ); machineLearningController.forceOverrideML(turnOn: false); _timer?.cancel(); _advancedOptionsTimer?.cancel(); diff --git a/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart b/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart index b0919260a4..97fb663577 100644 --- a/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart +++ b/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart @@ -16,6 +16,7 @@ import "package:photos/models/file/extensions/file_props.dart"; import "package:photos/models/file/file.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/files_service.dart"; +import "package:photos/services/wake_lock_service.dart"; import "package:photos/theme/colors.dart"; import "package:photos/ui/actions/file/file_actions.dart"; import "package:photos/ui/common/loading_widget.dart"; @@ -161,6 +162,12 @@ class _VideoWidgetMediaKitNewState extends State WidgetsBinding.instance.removeObserver(this); player.dispose(); _captionUpdatedSubscription.cancel(); + if (EnteWakeLockService.instance.shouldKeepAppAwakeAcrossSessions) { + EnteWakeLockService.instance.updateWakeLock( + enable: true, + wakeLockFor: WakeLockFor.handlingMediaKitEdgeCase, + ); + } super.dispose(); } diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index a6256d965a..f4b63c2ed4 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -20,6 +20,7 @@ import "package:photos/models/file/file.dart"; import "package:photos/models/preview/playlist_data.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/files_service.dart"; +import "package:photos/services/wake_lock_service.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/actions/file/file_actions.dart"; @@ -126,6 +127,9 @@ class _VideoWidgetNativeState extends State } } }); + + EnteWakeLockService.instance + .updateWakeLock(enable: true, wakeLockFor: WakeLockFor.videoPlayback); } Future setVideoSource() async { @@ -220,6 +224,8 @@ class _VideoWidgetNativeState extends State _debouncer.cancelDebounceTimer(); _elTooltipController.dispose(); _captionUpdatedSubscription.cancel(); + EnteWakeLockService.instance + .updateWakeLock(enable: false, wakeLockFor: WakeLockFor.videoPlayback); super.dispose(); } @@ -478,6 +484,8 @@ class _VideoWidgetNativeState extends State widget.playbackCallback!(false); } } + + _handleWakeLockOnPlaybackChanges(); } void _onError(String errorMessage) { @@ -544,6 +552,21 @@ class _VideoWidgetNativeState extends State } } + void _handleWakeLockOnPlaybackChanges() { + final playbackStatus = _controller?.playbackStatus; + if (playbackStatus == PlaybackStatus.playing) { + EnteWakeLockService.instance.updateWakeLock( + enable: true, + wakeLockFor: WakeLockFor.videoPlayback, + ); + } else { + EnteWakeLockService.instance.updateWakeLock( + enable: false, + wakeLockFor: WakeLockFor.videoPlayback, + ); + } + } + Widget _getLoadingWidget() { return Stack( key: const ValueKey("video_loading"), diff --git a/mobile/lib/utils/wakelock_util.dart b/mobile/lib/utils/wakelock_util.dart deleted file mode 100644 index 7e810dc0b3..0000000000 --- a/mobile/lib/utils/wakelock_util.dart +++ /dev/null @@ -1,38 +0,0 @@ -import "dart:async" show unawaited; - -import "package:wakelock_plus/wakelock_plus.dart"; - -class EnteWakeLock { - bool _wakeLockEnabledHere = false; - - void enable() { - WakelockPlus.enabled.then((value) { - if (value == false) { - WakelockPlus.enable(); - //wakeLockEnabledHere will not be set to true if wakeLock is already enabled from settings on iOS. - //We shouldn't disable when video is not playing if it was enabled manually by the user from ente settings by user. - _wakeLockEnabledHere = true; - } - }); - } - - void disable() { - if (_wakeLockEnabledHere) { - WakelockPlus.disable(); - } - } - - void dispose() { - if (_wakeLockEnabledHere) { - unawaited( - WakelockPlus.enabled.then((isEnabled) { - isEnabled ? WakelockPlus.disable() : null; - }), - ); - } - } - - static Future toggle({required bool enable}) async { - await WakelockPlus.toggle(enable: enable); - } -}