backup.provider.dart 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import 'dart:async';
  2. import 'package:dio/dio.dart';
  3. import 'package:flutter/foundation.dart';
  4. import 'package:hive_flutter/hive_flutter.dart';
  5. import 'package:hooks_riverpod/hooks_riverpod.dart';
  6. import 'package:immich_mobile/constants/hive_box.dart';
  7. import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
  8. import 'package:immich_mobile/shared/services/server_info.service.dart';
  9. import 'package:immich_mobile/shared/models/backup_state.model.dart';
  10. import 'package:immich_mobile/shared/models/server_info.model.dart';
  11. import 'package:immich_mobile/shared/services/backup.service.dart';
  12. import 'package:photo_manager/photo_manager.dart';
  13. class BackupNotifier extends StateNotifier<BackUpState> {
  14. BackupNotifier({this.ref})
  15. : super(
  16. BackUpState(
  17. backupProgress: BackUpProgressEnum.idle,
  18. backingUpAssetCount: 0,
  19. assetOnDatabase: 0,
  20. totalAssetCount: 0,
  21. progressInPercentage: 0,
  22. cancelToken: CancelToken(),
  23. serverInfo: ServerInfo(
  24. diskAvailable: "0",
  25. diskAvailableRaw: 0,
  26. diskSize: "0",
  27. diskSizeRaw: 0,
  28. diskUsagePercentage: 0.0,
  29. diskUse: "0",
  30. diskUseRaw: 0,
  31. ),
  32. ),
  33. );
  34. Ref? ref;
  35. final BackupService _backupService = BackupService();
  36. final ServerInfoService _serverInfoService = ServerInfoService();
  37. final StreamController _onAssetBackupStreamCtrl =
  38. StreamController.broadcast();
  39. void getBackupInfo() async {
  40. _updateServerInfo();
  41. List<AssetPathEntity> list = await PhotoManager.getAssetPathList(
  42. onlyAll: true, type: RequestType.common);
  43. List<String> didBackupAsset = await _backupService.getDeviceBackupAsset();
  44. if (list.isEmpty) {
  45. debugPrint("No Asset On Device");
  46. state = state.copyWith(
  47. backupProgress: BackUpProgressEnum.idle,
  48. totalAssetCount: 0,
  49. assetOnDatabase: didBackupAsset.length);
  50. return;
  51. }
  52. int totalAsset = list[0].assetCount;
  53. state = state.copyWith(
  54. totalAssetCount: totalAsset, assetOnDatabase: didBackupAsset.length);
  55. }
  56. void startBackupProcess() async {
  57. _updateServerInfo();
  58. state = state.copyWith(backupProgress: BackUpProgressEnum.inProgress);
  59. var authResult = await PhotoManager.requestPermissionExtend();
  60. if (authResult.isAuth) {
  61. await PhotoManager.clearFileCache();
  62. // await PhotoManager.presentLimited();
  63. // Gather assets info
  64. List<AssetPathEntity> list = await PhotoManager.getAssetPathList(
  65. hasAll: true, onlyAll: true, type: RequestType.common);
  66. // Get device assets info from database
  67. // Compare and find different assets that has not been backing up
  68. // Backup those assets
  69. List<String> backupAsset = await _backupService.getDeviceBackupAsset();
  70. if (list.isEmpty) {
  71. debugPrint("No Asset On Device - Abort Backup Process");
  72. state = state.copyWith(
  73. backupProgress: BackUpProgressEnum.idle,
  74. totalAssetCount: 0,
  75. assetOnDatabase: backupAsset.length);
  76. return;
  77. }
  78. int totalAsset = list[0].assetCount;
  79. List<AssetEntity> currentAssets =
  80. await list[0].getAssetListRange(start: 0, end: totalAsset);
  81. state = state.copyWith(
  82. totalAssetCount: totalAsset, assetOnDatabase: backupAsset.length);
  83. // Remove item that has already been backed up
  84. for (var backupAssetId in backupAsset) {
  85. currentAssets.removeWhere((e) => e.id == backupAssetId);
  86. }
  87. if (currentAssets.isEmpty) {
  88. state = state.copyWith(backupProgress: BackUpProgressEnum.idle);
  89. }
  90. state = state.copyWith(backingUpAssetCount: currentAssets.length);
  91. // Perform Backup
  92. state = state.copyWith(cancelToken: CancelToken());
  93. _backupService.backupAsset(currentAssets, state.cancelToken,
  94. _onAssetUploaded, _onUploadProgress);
  95. } else {
  96. PhotoManager.openSetting();
  97. }
  98. }
  99. void cancelBackup() {
  100. state.cancelToken.cancel('Cancel Backup');
  101. state = state.copyWith(
  102. backupProgress: BackUpProgressEnum.idle, progressInPercentage: 0.0);
  103. }
  104. void _onAssetUploaded(String deviceAssetId, String deviceId) {
  105. state = state.copyWith(
  106. backingUpAssetCount: state.backingUpAssetCount - 1,
  107. assetOnDatabase: state.assetOnDatabase + 1);
  108. if (state.backingUpAssetCount == 0) {
  109. state = state.copyWith(
  110. backupProgress: BackUpProgressEnum.done, progressInPercentage: 0.0);
  111. }
  112. _updateServerInfo();
  113. }
  114. void _onUploadProgress(int sent, int total) {
  115. state = state.copyWith(
  116. progressInPercentage: (sent.toDouble() / total.toDouble() * 100));
  117. }
  118. void _updateServerInfo() async {
  119. var serverInfo = await _serverInfoService.getServerInfo();
  120. // Update server info
  121. state = state.copyWith(
  122. serverInfo: ServerInfo(
  123. diskSize: serverInfo.diskSize,
  124. diskUse: serverInfo.diskUse,
  125. diskAvailable: serverInfo.diskAvailable,
  126. diskSizeRaw: serverInfo.diskSizeRaw,
  127. diskUseRaw: serverInfo.diskUseRaw,
  128. diskAvailableRaw: serverInfo.diskAvailableRaw,
  129. diskUsagePercentage: serverInfo.diskUsagePercentage,
  130. ),
  131. );
  132. }
  133. void resumeBackup() {
  134. var authState = ref?.read(authenticationProvider);
  135. // Check if user is login
  136. var accessKey = Hive.box(userInfoBox).get(accessTokenKey);
  137. // User has been logged out return
  138. if (authState != null) {
  139. if (accessKey == null || !authState.isAuthenticated) {
  140. debugPrint("[resumeBackup] not authenticated - abort");
  141. return;
  142. }
  143. // Check if this device is enable backup by the user
  144. if ((authState.deviceInfo.deviceId == authState.deviceId) &&
  145. authState.deviceInfo.isAutoBackup) {
  146. // check if backup is alreayd in process - then return
  147. if (state.backupProgress == BackUpProgressEnum.inProgress) {
  148. debugPrint("[resumeBackup] Backup is already in progress - abort");
  149. return;
  150. }
  151. // Run backup
  152. debugPrint("[resumeBackup] Start back up");
  153. startBackupProcess();
  154. }
  155. return;
  156. }
  157. }
  158. }
  159. final backupProvider =
  160. StateNotifierProvider<BackupNotifier, BackUpState>((ref) {
  161. return BackupNotifier(ref: ref);
  162. });