diff --git a/mobile/android/app/src/main/kotlin/com/example/mobile/BackgroundServicePlugin.kt b/mobile/android/app/src/main/kotlin/com/example/mobile/BackgroundServicePlugin.kt index c3fb7a209e..04aa6f1b3d 100644 --- a/mobile/android/app/src/main/kotlin/com/example/mobile/BackgroundServicePlugin.kt +++ b/mobile/android/app/src/main/kotlin/com/example/mobile/BackgroundServicePlugin.kt @@ -69,26 +69,8 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler { "isEnabled" -> { result.success(BackupWorker.isEnabled(ctx)) } - "disableBatteryOptimizations" -> { - if(!BackupWorker.isIgnoringBatteryOptimizations(ctx)) { - val args = call.arguments>()!! - val text = args.get(0) as String - Toast.makeText(ctx, text, Toast.LENGTH_LONG).show() - val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - intent.setData(Uri.parse("package:" + ctx.getPackageName())) - try { - ctx.startActivity(intent) - } catch(e: Exception) { - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - try { - ctx.startActivity(intent) - } catch (e2: Exception) { - return result.success(false) - } - } - } - result.success(true) + "isIgnoringBatteryOptimizations" -> { + result.success(BackupWorker.isIgnoringBatteryOptimizations(ctx)) } else -> result.notImplemented() } diff --git a/mobile/assets/i18n/en-US.json b/mobile/assets/i18n/en-US.json index f9e7e843d4..1412b1fe78 100644 --- a/mobile/assets/i18n/en-US.json +++ b/mobile/assets/i18n/en-US.json @@ -17,7 +17,6 @@ "backup_album_selection_page_total_assets": "Total unique assets", "backup_all": "All", "backup_background_service_default_notification": "Checking for new assets…", - "backup_background_service_disable_battery_optimizations": "Please disable battery optimization for Immich to enable background backup", "backup_background_service_upload_failure_notification": "Failed to upload {}", "backup_background_service_in_progress_notification": "Backing up your assets…", "backup_background_service_current_upload_notification": "Uploading {}", @@ -36,6 +35,10 @@ "backup_controller_page_background_turn_on": "Turn on background service", "backup_controller_page_background_turn_off": "Turn off background service", "backup_controller_page_background_configure_error": "Failed to configure the background service", + "backup_controller_page_background_battery_info_title": "Battery optimizations", + "backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.", + "backup_controller_page_background_battery_info_link": "Show me how", + "backup_controller_page_background_battery_info_ok": "OK", "backup_controller_page_cancel": "Cancel", "backup_controller_page_created": "Created on: {}", "backup_controller_page_desc_backup": "Turn on backup to automatically upload new assets to the server.", diff --git a/mobile/assets/i18n/ko-KR.json b/mobile/assets/i18n/ko-KR.json index dd4acf1568..22e843fcc4 100644 --- a/mobile/assets/i18n/ko-KR.json +++ b/mobile/assets/i18n/ko-KR.json @@ -17,7 +17,6 @@ "backup_album_selection_page_total_assets": "총 미디어파일 수", "backup_all": "모두", "backup_background_service_default_notification": "새 미디어파일 확인중...", - "backup_background_service_disable_battery_optimizations": "백그라운드 백업을 활성화하려면 Immich에 대한 배터리최적화를 비활성화 해야합니다.", "backup_background_service_upload_failure_notification": "{} 업로드 실패", "backup_background_service_in_progress_notification": "미디어파일 백업 중...", "backup_background_service_current_upload_notification": "{} 업로드 중", diff --git a/mobile/assets/i18n/nl-NL.json b/mobile/assets/i18n/nl-NL.json index 0f3a0bc200..d27232b533 100644 --- a/mobile/assets/i18n/nl-NL.json +++ b/mobile/assets/i18n/nl-NL.json @@ -17,7 +17,6 @@ "backup_album_selection_page_total_assets": "Totaal unieke items", "backup_all": "Alle", "backup_background_service_default_notification": "Controleren op nieuw items…", - "backup_background_service_disable_battery_optimizations": "Schakel batterij optimalisatie uit voor Immich om achtergrond backup in te schakelen", "backup_background_service_upload_failure_notification": "Fout bij upload {}", "backup_background_service_in_progress_notification": "Backuppen van items…", "backup_background_service_current_upload_notification": "Uploaden {}", diff --git a/mobile/assets/i18n/pt-BR.json b/mobile/assets/i18n/pt-BR.json index b0e96ad31d..6b3ec1dd65 100644 --- a/mobile/assets/i18n/pt-BR.json +++ b/mobile/assets/i18n/pt-BR.json @@ -17,7 +17,6 @@ "backup_album_selection_page_total_assets": "Total de recursos exclusivos", "backup_all": "Todos", "backup_background_service_default_notification": "Checking for new assets…", - "backup_background_service_disable_battery_optimizations": "Por favor, desabilite a otimização da bateria para Immich para habilitar o backup em segundo plano", "backup_background_service_upload_failure_notification": "Falha ao carregar {}", "backup_background_service_in_progress_notification": "Fazendo backup de seus ativos…", "backup_background_service_current_upload_notification": "Enviando {}", diff --git a/mobile/lib/modules/backup/background_service/background.service.dart b/mobile/lib/modules/backup/background_service/background.service.dart index 5581831513..44c47aacd0 100644 --- a/mobile/lib/modules/backup/background_service/background.service.dart +++ b/mobile/lib/modules/backup/background_service/background.service.dart @@ -122,8 +122,8 @@ class BackgroundService { } } - /// Opens an activity to let the user disable battery optimizations for Immich - Future disableBatteryOptimizations() async { + /// Returns `true` if battery optimizations are disabled + Future isIgnoringBatteryOptimizations() async { if (!Platform.isAndroid) { return true; } @@ -131,12 +131,8 @@ class BackgroundService { if (!_isForegroundInitialized) { await _initialize(); } - final String message = - "backup_background_service_disable_battery_optimizations".tr(); - return await _foregroundChannel.invokeMethod( - 'disableBatteryOptimizations', - message, - ); + return await _foregroundChannel + .invokeMethod('isIgnoringBatteryOptimizations'); } catch (error) { return false; } diff --git a/mobile/lib/modules/backup/providers/backup.provider.dart b/mobile/lib/modules/backup/providers/backup.provider.dart index 37082bfe98..545448197e 100644 --- a/mobile/lib/modules/backup/providers/backup.provider.dart +++ b/mobile/lib/modules/backup/providers/backup.provider.dart @@ -117,6 +117,7 @@ class BackupNotifier extends StateNotifier { bool? requireWifi, bool? requireCharging, required void Function(String msg) onError, + required void Function() onBatteryInfo, }) async { assert(enabled != null || requireWifi != null || requireCharging != null); if (Platform.isAndroid) { @@ -131,7 +132,9 @@ class BackupNotifier extends StateNotifier { if (state.backgroundBackup) { if (!wasEnabled) { - await _backgroundService.disableBatteryOptimizations(); + if (!await _backgroundService.isIgnoringBatteryOptimizations()) { + onBatteryInfo(); + } } final bool success = await _backgroundService.stopService() && await _backgroundService.startService( diff --git a/mobile/lib/modules/backup/views/backup_controller_page.dart b/mobile/lib/modules/backup/views/backup_controller_page.dart index 75ff14c67d..715b449f7c 100644 --- a/mobile/lib/modules/backup/views/backup_controller_page.dart +++ b/mobile/lib/modules/backup/views/backup_controller_page.dart @@ -14,6 +14,7 @@ import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/shared/providers/websocket.provider.dart'; import 'package:immich_mobile/modules/backup/ui/backup_info_card.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; +import 'package:url_launcher/url_launcher.dart'; class BackupControllerPage extends HookConsumerWidget { const BackupControllerPage({Key? key}) : super(key: key); @@ -156,6 +157,46 @@ class BackupControllerPage extends HookConsumerWidget { ScaffoldMessenger.of(context).showSnackBar(snackBar); } + void _showBatteryOptimizationInfoToUser() { + final buttonTextColor = Theme.of(context).primaryColor; + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text( + 'backup_controller_page_background_battery_info_title', + ).tr(), + content: SingleChildScrollView( + child: const Text( + 'backup_controller_page_background_battery_info_message', + ).tr(), + ), + actions: [ + TextButton( + onPressed: () => launchUrl( + Uri.parse('https://dontkillmyapp.com'), + mode: LaunchMode.externalApplication), + child: Text( + "backup_controller_page_background_battery_info_link", + style: TextStyle(color: buttonTextColor), + ).tr(), + ), + TextButton( + child: Text( + 'backup_controller_page_background_battery_info_ok', + style: TextStyle(color: buttonTextColor), + ).tr(), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + ListTile _buildBackgroundBackupController() { final bool isBackgroundEnabled = backupState.backgroundBackup; final bool isWifiRequired = backupState.backupRequireWifi; @@ -197,6 +238,7 @@ class BackupControllerPage extends HookConsumerWidget { .configureBackgroundBackup( requireWifi: isChecked, onError: _showErrorToUser, + onBatteryInfo: _showBatteryOptimizationInfoToUser, ) : null, ), @@ -217,6 +259,7 @@ class BackupControllerPage extends HookConsumerWidget { .configureBackgroundBackup( requireCharging: isChecked, onError: _showErrorToUser, + onBatteryInfo: _showBatteryOptimizationInfoToUser, ) : null, ), @@ -225,6 +268,7 @@ class BackupControllerPage extends HookConsumerWidget { ref.read(backupProvider.notifier).configureBackgroundBackup( enabled: !isBackgroundEnabled, onError: _showErrorToUser, + onBatteryInfo: _showBatteryOptimizationInfoToUser, ), child: Text( isBackgroundEnabled