mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 09:12:57 +02:00
feat(mobile): iOS background sync (#1758)
* first run of getting background sync working in iOS * got background sync calling into flutter * added background task * added necessary sync files * fixed some names and added more implementations * got as far as Hive.initFlutter * brute force got to await Hive.initFlutter * lots of print statements to figure out where execution is failing, and its failing at the root asset bundle in the localization.dart service * first time working, got plugins registered * removed broken cleanup code * refactored * linters * now can pass user settings * background service plugin uses app background processing instead of fetch * renamed backgroundFetch to backgroundProcessing to make it clearer * don't use max delay * adds fetch back in * fixes require charging default values and backup controller page * fixes background fetch * fixes ios not importing photos * guarded path provider ios * lint * adds max tries for heartbeat to work in iOS * fail after seconds * timeout instead of fail after seconds * removes release lock from system stop * restores checkLockReleasedWithHeartbeat to Future<void> * removes max tries from acquire lock * fixes lock timeout with iOS * restored for loop * adds comments, made the AppRefresh task only run while not requiring network or charge * fixed compile issue * now both are registered and added better comments. also added ability for task to cancel itself * added the podfile and pubspec * added backup diagnostics to IOS and removed iOS ignored backup options and fixed network connectivity always required * Added Alex's dev team * styled debug list item, fixed refresh task not set bug, fixed enable / disable background service on platform channel --------- Co-authored-by: Marty Fuhry <marty@fuhry.farm> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
parent
2cf42e867c
commit
87fea29e32
16 changed files with 926 additions and 284 deletions
mobile/lib/modules/backup/views
|
@ -7,6 +7,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
|
||||
import 'package:immich_mobile/modules/backup/ui/current_backup_asset_info_box.dart';
|
||||
import 'package:immich_mobile/modules/backup/ui/ios_debug_info_tile.dart';
|
||||
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
|
||||
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
|
||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||
|
@ -195,7 +196,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
ListTile buildBackgroundBackupController() {
|
||||
Widget buildBackgroundBackupController() {
|
||||
final bool isBackgroundEnabled = backupState.backgroundBackup;
|
||||
final bool isWifiRequired = backupState.backupRequireWifi;
|
||||
final bool isChargingRequired = backupState.backupRequireCharging;
|
||||
|
@ -240,118 +241,126 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||
final triggerDelay =
|
||||
useState(backupDelayToSliderValue(backupState.backupTriggerDelay));
|
||||
|
||||
return ListTile(
|
||||
isThreeLine: true,
|
||||
leading: isBackgroundEnabled
|
||||
? Icon(
|
||||
Icons.cloud_sync_rounded,
|
||||
color: activeColor,
|
||||
)
|
||||
: const Icon(Icons.cloud_sync_rounded),
|
||||
title: Text(
|
||||
isBackgroundEnabled
|
||||
? "backup_controller_page_background_is_on"
|
||||
: "backup_controller_page_background_is_off",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
|
||||
).tr(),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isBackgroundEnabled)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child:
|
||||
const Text("backup_controller_page_background_description")
|
||||
.tr(),
|
||||
),
|
||||
if (isBackgroundEnabled)
|
||||
SwitchListTile(
|
||||
title:
|
||||
const Text("backup_controller_page_background_wifi").tr(),
|
||||
secondary: Icon(
|
||||
Icons.wifi,
|
||||
color: isWifiRequired ? activeColor : null,
|
||||
),
|
||||
dense: true,
|
||||
activeColor: activeColor,
|
||||
value: isWifiRequired,
|
||||
onChanged: hasExclusiveAccess
|
||||
? (isChecked) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
requireWifi: isChecked,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (isBackgroundEnabled)
|
||||
SwitchListTile(
|
||||
title: const Text("backup_controller_page_background_charging")
|
||||
.tr(),
|
||||
secondary: Icon(
|
||||
Icons.charging_station,
|
||||
color: isChargingRequired ? activeColor : null,
|
||||
),
|
||||
dense: true,
|
||||
activeColor: activeColor,
|
||||
value: isChargingRequired,
|
||||
onChanged: hasExclusiveAccess
|
||||
? (isChecked) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
requireCharging: isChecked,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (isBackgroundEnabled)
|
||||
ListTile(
|
||||
isThreeLine: false,
|
||||
dense: true,
|
||||
enabled: hasExclusiveAccess,
|
||||
title: const Text(
|
||||
'backup_controller_page_background_delay',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
isThreeLine: true,
|
||||
leading: isBackgroundEnabled
|
||||
? Icon(
|
||||
Icons.cloud_sync_rounded,
|
||||
color: activeColor,
|
||||
)
|
||||
: const Icon(Icons.cloud_sync_rounded),
|
||||
title: Text(
|
||||
isBackgroundEnabled
|
||||
? "backup_controller_page_background_is_on"
|
||||
: "backup_controller_page_background_is_off",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
|
||||
).tr(),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isBackgroundEnabled)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child:
|
||||
const Text("backup_controller_page_background_description")
|
||||
.tr(),
|
||||
),
|
||||
).tr(args: [formatBackupDelaySliderValue(triggerDelay.value)]),
|
||||
subtitle: Slider(
|
||||
value: triggerDelay.value,
|
||||
onChanged: hasExclusiveAccess
|
||||
? (double v) => triggerDelay.value = v
|
||||
: null,
|
||||
onChangeEnd: (double v) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
triggerDelay: backupDelayToMilliseconds(v),
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
if (isBackgroundEnabled && Platform.isAndroid)
|
||||
SwitchListTile(
|
||||
title:
|
||||
const Text("backup_controller_page_background_wifi").tr(),
|
||||
secondary: Icon(
|
||||
Icons.wifi,
|
||||
color: isWifiRequired ? activeColor : null,
|
||||
),
|
||||
dense: true,
|
||||
activeColor: activeColor,
|
||||
value: isWifiRequired,
|
||||
onChanged: hasExclusiveAccess
|
||||
? (isChecked) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
requireWifi: isChecked,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (isBackgroundEnabled)
|
||||
SwitchListTile(
|
||||
title: const Text("backup_controller_page_background_charging")
|
||||
.tr(),
|
||||
secondary: Icon(
|
||||
Icons.charging_station,
|
||||
color: isChargingRequired ? activeColor : null,
|
||||
),
|
||||
dense: true,
|
||||
activeColor: activeColor,
|
||||
value: isChargingRequired,
|
||||
onChanged: hasExclusiveAccess
|
||||
? (isChecked) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
requireCharging: isChecked,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (isBackgroundEnabled && Platform.isAndroid)
|
||||
ListTile(
|
||||
isThreeLine: false,
|
||||
dense: true,
|
||||
enabled: hasExclusiveAccess,
|
||||
title: const Text(
|
||||
'backup_controller_page_background_delay',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
max: 3.0,
|
||||
divisions: 3,
|
||||
label: formatBackupDelaySliderValue(triggerDelay.value),
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
).tr(args: [formatBackupDelaySliderValue(triggerDelay.value)]),
|
||||
subtitle: Slider(
|
||||
value: triggerDelay.value,
|
||||
onChanged: hasExclusiveAccess
|
||||
? (double v) => triggerDelay.value = v
|
||||
: null,
|
||||
onChangeEnd: (double v) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
triggerDelay: backupDelayToMilliseconds(v),
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
),
|
||||
max: 3.0,
|
||||
divisions: 3,
|
||||
label: formatBackupDelaySliderValue(triggerDelay.value),
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
enabled: !isBackgroundEnabled,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
),
|
||||
child: Text(
|
||||
isBackgroundEnabled
|
||||
? "backup_controller_page_background_turn_off"
|
||||
: "backup_controller_page_background_turn_on",
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
||||
).tr(),
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
enabled: !isBackgroundEnabled,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
),
|
||||
child: Text(
|
||||
isBackgroundEnabled
|
||||
? "backup_controller_page_background_turn_off"
|
||||
: "backup_controller_page_background_turn_on",
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
||||
).tr(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isBackgroundEnabled)
|
||||
IosDebugInfoTile(
|
||||
key: ValueKey(isChargingRequired),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -592,8 +601,8 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||
),
|
||||
const Divider(),
|
||||
buildAutoBackupController(),
|
||||
if (Platform.isAndroid) const Divider(),
|
||||
if (Platform.isAndroid) buildBackgroundBackupController(),
|
||||
const Divider(),
|
||||
buildBackgroundBackupController(),
|
||||
const Divider(),
|
||||
buildStorageInformation(),
|
||||
const Divider(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue