delete_file_util.dart 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'dart:math';
  4. import 'package:flutter/widgets.dart';
  5. import 'package:logging/logging.dart';
  6. import 'package:photo_manager/photo_manager.dart';
  7. import 'package:photos/core/event_bus.dart';
  8. import 'package:photos/db/files_db.dart';
  9. import 'package:photos/events/collection_updated_event.dart';
  10. import 'package:photos/events/files_updated_event.dart';
  11. import 'package:photos/events/local_photos_updated_event.dart';
  12. import 'package:photos/models/file.dart';
  13. import 'package:photos/services/remote_sync_service.dart';
  14. import 'package:photos/services/sync_service.dart';
  15. import 'package:photos/utils/dialog_util.dart';
  16. import 'package:photos/utils/toast_util.dart';
  17. final _logger = Logger("DeleteFileUtil");
  18. Future<void> deleteFilesFromEverywhere(
  19. BuildContext context, List<File> files) async {
  20. final dialog = createProgressDialog(context, "deleting...");
  21. await dialog.show();
  22. _logger.info("Trying to delete files " + files.toString());
  23. final List<String> localIDs = [];
  24. final List<String> alreadyDeletedIDs = []; // to ignore already deleted files
  25. for (final file in files) {
  26. if (file.localID != null) {
  27. final asset = await file.getAsset();
  28. if (asset == null || !(await asset.exists)) {
  29. _logger.warning("Already deleted " + file.toString());
  30. alreadyDeletedIDs.add(file.localID);
  31. } else {
  32. localIDs.add(file.localID);
  33. }
  34. }
  35. }
  36. Set<String> deletedIDs = Set<String>();
  37. try {
  38. deletedIDs = (await PhotoManager.editor.deleteWithIds(localIDs)).toSet();
  39. } catch (e, s) {
  40. _logger.severe("Could not delete file", e, s);
  41. }
  42. final updatedCollectionIDs = Set<int>();
  43. final List<int> uploadedFileIDsToBeDeleted = [];
  44. final List<File> deletedFiles = [];
  45. for (final file in files) {
  46. if (file.localID != null) {
  47. // Remove only those files that have already been removed from disk
  48. if (deletedIDs.contains(file.localID) ||
  49. alreadyDeletedIDs.contains(file.localID)) {
  50. deletedFiles.add(file);
  51. if (file.uploadedFileID != null) {
  52. uploadedFileIDsToBeDeleted.add(file.uploadedFileID);
  53. updatedCollectionIDs.add(file.collectionID);
  54. } else {
  55. await FilesDB.instance.deleteLocalFile(file.localID);
  56. }
  57. }
  58. } else {
  59. updatedCollectionIDs.add(file.collectionID);
  60. deletedFiles.add(file);
  61. uploadedFileIDsToBeDeleted.add(file.uploadedFileID);
  62. }
  63. }
  64. if (uploadedFileIDsToBeDeleted.isNotEmpty) {
  65. try {
  66. await SyncService.instance
  67. .deleteFilesOnServer(uploadedFileIDsToBeDeleted);
  68. await FilesDB.instance
  69. .deleteMultipleUploadedFiles(uploadedFileIDsToBeDeleted);
  70. } catch (e) {
  71. _logger.severe(e);
  72. await dialog.hide();
  73. showGenericErrorDialog(context);
  74. throw e;
  75. }
  76. for (final collectionID in updatedCollectionIDs) {
  77. Bus.instance.fire(CollectionUpdatedEvent(
  78. collectionID,
  79. deletedFiles
  80. .where((file) => file.collectionID == collectionID)
  81. .toList(),
  82. type: EventType.deleted,
  83. ));
  84. }
  85. }
  86. if (deletedFiles.isNotEmpty) {
  87. Bus.instance
  88. .fire(LocalPhotosUpdatedEvent(deletedFiles, type: EventType.deleted));
  89. }
  90. await dialog.hide();
  91. showToast("deleted from everywhere");
  92. if (uploadedFileIDsToBeDeleted.isNotEmpty) {
  93. RemoteSyncService.instance.sync(silently: true);
  94. }
  95. }
  96. Future<void> deleteFilesOnDeviceOnly(
  97. BuildContext context, List<File> files) async {
  98. final dialog = createProgressDialog(context, "deleting...");
  99. await dialog.show();
  100. _logger.info("Trying to delete files " + files.toString());
  101. final List<String> localIDs = [];
  102. final List<String> alreadyDeletedIDs = []; // to ignore already deleted files
  103. for (final file in files) {
  104. if (file.localID != null) {
  105. final asset = await file.getAsset();
  106. if (asset == null || !(await asset.exists)) {
  107. _logger.warning("Already deleted " + file.toString());
  108. alreadyDeletedIDs.add(file.localID);
  109. } else {
  110. localIDs.add(file.localID);
  111. }
  112. }
  113. }
  114. Set<String> deletedIDs = Set<String>();
  115. try {
  116. deletedIDs = (await PhotoManager.editor.deleteWithIds(localIDs)).toSet();
  117. } catch (e, s) {
  118. _logger.severe("Could not delete file", e, s);
  119. }
  120. final List<File> deletedFiles = [];
  121. for (final file in files) {
  122. // Remove only those files that have been removed from disk
  123. if (deletedIDs.contains(file.localID) ||
  124. alreadyDeletedIDs.contains(file.localID)) {
  125. deletedFiles.add(file);
  126. file.localID = null;
  127. FilesDB.instance.update(file);
  128. }
  129. }
  130. if (deletedFiles.isNotEmpty || alreadyDeletedIDs.isNotEmpty) {
  131. Bus.instance
  132. .fire(LocalPhotosUpdatedEvent(deletedFiles, type: EventType.deleted));
  133. }
  134. await dialog.hide();
  135. }
  136. Future<void> deleteLocalFiles(List<String> localIDs) async {
  137. List<String> deletedIDs = [];
  138. if (Platform.isAndroid) {
  139. const batchSize = 100;
  140. for (int index = 0; index < localIDs.length; index += batchSize) {
  141. final ids = localIDs
  142. .getRange(index, min(localIDs.length, index + batchSize))
  143. .toList();
  144. _logger.info("Trying to delete " + ids.toString());
  145. try {
  146. deletedIDs.addAll(await PhotoManager.editor.deleteWithIds(ids));
  147. _logger.info("Deleted " + ids.toString());
  148. } catch (e, s) {
  149. _logger.severe("Could not delete batch " + ids.toString(), e, s);
  150. for (final id in ids) {
  151. try {
  152. deletedIDs.addAll(await PhotoManager.editor.deleteWithIds([id]));
  153. _logger.info("Deleted " + id);
  154. } catch (e, s) {
  155. _logger.severe("Could not delete file " + id, e, s);
  156. }
  157. }
  158. }
  159. }
  160. } else {
  161. try {
  162. deletedIDs.addAll(await PhotoManager.editor.deleteWithIds(localIDs));
  163. } catch (e, s) {
  164. _logger.severe("Could not delete files ", e, s);
  165. }
  166. }
  167. if (deletedIDs.isNotEmpty) {
  168. final deletedFiles = await FilesDB.instance.getLocalFiles(deletedIDs);
  169. await FilesDB.instance.deleteLocalFiles(deletedIDs);
  170. _logger.info(deletedFiles.length.toString() + " files deleted locally");
  171. Bus.instance
  172. .fire(LocalPhotosUpdatedEvent(deletedFiles, type: EventType.deleted));
  173. }
  174. }