file_sync_util.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import 'dart:math';
  2. import 'package:computer/computer.dart';
  3. import 'package:logging/logging.dart';
  4. import 'package:photo_manager/photo_manager.dart';
  5. import 'package:photos/models/file.dart';
  6. final _logger = Logger("FileSyncUtil");
  7. Future<List<File>> getDeviceFiles(
  8. int fromTime, int toTime, Computer computer) async {
  9. final pathEntities = await _getGalleryList(fromTime, toTime);
  10. List<File> files = [];
  11. AssetPathEntity recents;
  12. for (AssetPathEntity pathEntity in pathEntities) {
  13. if (pathEntity.name == "Recent" || pathEntity.name == "Recents") {
  14. recents = pathEntity;
  15. } else {
  16. files = await _computeFiles(pathEntity, fromTime, files, computer);
  17. }
  18. }
  19. if (recents != null) {
  20. files = await _computeFiles(recents, fromTime, files, computer);
  21. }
  22. files.sort(
  23. (first, second) => first.creationTime.compareTo(second.creationTime));
  24. return files;
  25. }
  26. Future<List<LocalAsset>> getAllLocalAssets() async {
  27. final filterOptionGroup = FilterOptionGroup();
  28. final assetPaths = await PhotoManager.getAssetPathList(
  29. hasAll: true,
  30. type: RequestType.common,
  31. filterOption: filterOptionGroup,
  32. );
  33. final List<LocalAsset> assets = [];
  34. for (final assetPath in assetPaths) {
  35. for (final asset in await assetPath.assetList) {
  36. assets.add(LocalAsset(asset.id, assetPath.name));
  37. }
  38. }
  39. return assets;
  40. }
  41. Future<List<File>> getUnsyncedFiles(List<LocalAsset> assets,
  42. Set<String> existingIDs, Set<String> invalidIDs, Computer computer) async {
  43. final args = Map<String, dynamic>();
  44. args['assets'] = assets;
  45. args['existingIDs'] = existingIDs;
  46. args['invalidIDs'] = invalidIDs;
  47. final unsyncedAssets =
  48. await computer.compute(_getUnsyncedAssets, param: args);
  49. if (unsyncedAssets.isEmpty) {
  50. return [];
  51. }
  52. return _convertToFiles(unsyncedAssets, computer);
  53. }
  54. List<LocalAsset> _getUnsyncedAssets(Map<String, dynamic> args) {
  55. final List<LocalAsset> assets = args['assets'];
  56. final Set<String> existingIDs = args['existingIDs'];
  57. final Set<String> invalidIDs = args['invalidIDs'];
  58. final List<LocalAsset> unsyncedAssets = [];
  59. for (final asset in assets) {
  60. if (!existingIDs.contains(asset.id) && !invalidIDs.contains(asset.id)) {
  61. unsyncedAssets.add(asset);
  62. }
  63. }
  64. return unsyncedAssets;
  65. }
  66. Future<List<File>> _convertToFiles(
  67. List<LocalAsset> assets, Computer computer) async {
  68. final List<LocalAsset> recents = [];
  69. final List<LocalAssetEntity> entities = [];
  70. for (final asset in assets) {
  71. if (asset.path == "Recent" || asset.path == "Recents") {
  72. recents.add(asset);
  73. } else {
  74. entities.add(
  75. LocalAssetEntity(await AssetEntity.fromId(asset.id), asset.path));
  76. }
  77. }
  78. // Ignore duplicate items in recents
  79. for (final recent in recents) {
  80. bool presentInOthers = false;
  81. for (final entity in entities) {
  82. if (recent.id == entity.entity.id) {
  83. presentInOthers = true;
  84. break;
  85. }
  86. }
  87. if (!presentInOthers) {
  88. entities.add(
  89. LocalAssetEntity(await AssetEntity.fromId(recent.id), recent.path));
  90. }
  91. }
  92. return await computer.compute(_getFilesFromAssets, param: entities);
  93. }
  94. Future<List<AssetPathEntity>> _getGalleryList(
  95. final int fromTime, final int toTime) async {
  96. final filterOptionGroup = FilterOptionGroup();
  97. filterOptionGroup.setOption(AssetType.image, FilterOption(needTitle: true));
  98. filterOptionGroup.setOption(AssetType.video, FilterOption(needTitle: true));
  99. filterOptionGroup.createTimeCond = DateTimeCond(
  100. min: DateTime.fromMicrosecondsSinceEpoch(fromTime),
  101. max: DateTime.fromMicrosecondsSinceEpoch(toTime),
  102. );
  103. filterOptionGroup.updateTimeCond = DateTimeCond(
  104. min: DateTime.fromMicrosecondsSinceEpoch(fromTime),
  105. max: DateTime.fromMicrosecondsSinceEpoch(toTime),
  106. );
  107. final galleryList = await PhotoManager.getAssetPathList(
  108. hasAll: true,
  109. type: RequestType.common,
  110. filterOption: filterOptionGroup,
  111. );
  112. galleryList.sort((s1, s2) {
  113. return s2.assetCount.compareTo(s1.assetCount);
  114. });
  115. return galleryList;
  116. }
  117. Future<List<File>> _computeFiles(AssetPathEntity pathEntity, int fromTime,
  118. List<File> files, Computer computer) async {
  119. final args = Map<String, dynamic>();
  120. args["pathEntity"] = pathEntity;
  121. args["assetList"] = await pathEntity.assetList;
  122. args["fromTime"] = fromTime;
  123. args["files"] = files;
  124. return await computer.compute(_getFiles, param: args);
  125. }
  126. Future<List<File>> _getFiles(Map<String, dynamic> args) async {
  127. final pathEntity = args["pathEntity"];
  128. final assetList = args["assetList"];
  129. final fromTime = args["fromTime"];
  130. final files = args["files"];
  131. for (AssetEntity entity in assetList) {
  132. if (max(entity.createDateTime.microsecondsSinceEpoch,
  133. entity.modifiedDateTime.microsecondsSinceEpoch) >
  134. fromTime) {
  135. try {
  136. final file = await File.fromAsset(pathEntity.name, entity);
  137. if (!files.contains(file)) {
  138. files.add(file);
  139. }
  140. } catch (e) {
  141. _logger.severe(e);
  142. }
  143. }
  144. }
  145. return files;
  146. }
  147. Future<List<File>> _getFilesFromAssets(List<LocalAssetEntity> assets) async {
  148. final List<File> files = [];
  149. for (final asset in assets) {
  150. files.add(await File.fromAsset(
  151. asset.path,
  152. asset.entity,
  153. ));
  154. }
  155. return files;
  156. }
  157. class LocalAsset {
  158. final String id;
  159. final String path;
  160. LocalAsset(
  161. this.id,
  162. this.path,
  163. );
  164. }
  165. class LocalAssetEntity {
  166. final AssetEntity entity;
  167. final String path;
  168. LocalAssetEntity(this.entity, this.path);
  169. }