123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- // @dart=2.9
- import 'dart:async';
- import 'package:dio/dio.dart';
- import 'package:logging/logging.dart';
- import 'package:photos/core/configuration.dart';
- import 'package:photos/core/event_bus.dart';
- import 'package:photos/core/network.dart';
- import 'package:photos/db/trash_db.dart';
- import 'package:photos/events/collection_updated_event.dart';
- import 'package:photos/events/force_reload_trash_page_event.dart';
- import 'package:photos/events/trash_updated_event.dart';
- import 'package:photos/models/file.dart';
- import 'package:photos/models/ignored_file.dart';
- import 'package:photos/models/trash_file.dart';
- import 'package:photos/models/trash_item_request.dart';
- import 'package:photos/services/ignored_files_service.dart';
- import 'package:photos/utils/trash_diff_fetcher.dart';
- import 'package:shared_preferences/shared_preferences.dart';
- class TrashSyncService {
- final _logger = Logger("TrashSyncService");
- final _diffFetcher = TrashDiffFetcher();
- final _trashDB = TrashDB.instance;
- static const kLastTrashSyncTime = "last_trash_sync_time";
- static const kTrashBatchSize = 999;
- SharedPreferences _prefs;
- TrashSyncService._privateConstructor();
- static final TrashSyncService instance =
- TrashSyncService._privateConstructor();
- final _dio = Network.instance.getDio();
- Future<void> init() async {
- _prefs = await SharedPreferences.getInstance();
- }
- Future<void> syncTrash() async {
- final lastSyncTime = _getSyncTime();
- bool isLocalTrashUpdated = false;
- _logger.fine('sync trash sinceTime : $lastSyncTime');
- final diff = await _diffFetcher.getTrashFilesDiff(lastSyncTime);
- if (diff.trashedFiles.isNotEmpty) {
- isLocalTrashUpdated = true;
- _logger.fine("inserting ${diff.trashedFiles.length} items in trash");
- await _trashDB.insertMultiple(diff.trashedFiles);
- }
- if (diff.deletedUploadIDs.isNotEmpty) {
- _logger.fine("discard ${diff.deletedUploadIDs.length} deleted items");
- final itemsDeleted = await _trashDB.delete(diff.deletedUploadIDs);
- isLocalTrashUpdated = isLocalTrashUpdated || itemsDeleted > 0;
- }
- if (diff.restoredFiles.isNotEmpty) {
- _logger.fine("discard ${diff.restoredFiles.length} restored items");
- final itemsDeleted = await _trashDB
- .delete(diff.restoredFiles.map((e) => e.uploadedFileID).toList());
- isLocalTrashUpdated = isLocalTrashUpdated || itemsDeleted > 0;
- }
- await _updateIgnoredFiles(diff);
- if (diff.lastSyncedTimeStamp != 0) {
- await _setSyncTime(diff.lastSyncedTimeStamp);
- }
- if (isLocalTrashUpdated) {
- _logger
- .fine('local trash updated, fire ${(TrashUpdatedEvent).toString()}');
- Bus.instance.fire(TrashUpdatedEvent());
- }
- if (diff.hasMore) {
- return await syncTrash();
- } else if (diff.trashedFiles.isNotEmpty ||
- diff.deletedUploadIDs.isNotEmpty) {
- _logger.fine('refresh gallery');
- Bus.instance.fire(CollectionUpdatedEvent(0, <File>[]));
- }
- }
- Future<void> _updateIgnoredFiles(Diff diff) async {
- final ignoredFiles = <IgnoredFile>[];
- for (TrashFile t in diff.trashedFiles) {
- final file = IgnoredFile.fromTrashItem(t);
- if (file != null) {
- ignoredFiles.add(file);
- }
- }
- if (ignoredFiles.isNotEmpty) {
- _logger.fine('updating ${ignoredFiles.length} ignored files ');
- await IgnoredFilesService.instance.cacheAndInsert(ignoredFiles);
- }
- }
- Future<void> _setSyncTime(int time) async {
- return _prefs.setInt(kLastTrashSyncTime, time);
- }
- int _getSyncTime() {
- return _prefs.getInt(kLastTrashSyncTime) ?? 0;
- }
- Future<void> trashFilesOnServer(List<TrashRequest> trashRequestItems) async {
- final includedFileIDs = <int>{};
- final uniqueItems = <TrashRequest>[];
- for (final item in trashRequestItems) {
- if (!includedFileIDs.contains(item.fileID)) {
- uniqueItems.add(item);
- includedFileIDs.add(item.fileID);
- }
- }
- int currentBatchSize = 0;
- final requestData = <String, dynamic>{};
- requestData["items"] = [];
- for (final item in uniqueItems) {
- currentBatchSize++;
- requestData["items"].add(item.toJson());
- if (currentBatchSize >= kTrashBatchSize) {
- await _trashFiles(requestData);
- requestData["items"] = [];
- currentBatchSize = 0;
- }
- }
- if (currentBatchSize > 0) {
- return await _trashFiles(requestData);
- }
- }
- Future<Response<dynamic>> _trashFiles(
- Map<String, dynamic> requestData,
- ) async {
- return _dio.post(
- Configuration.instance.getHttpEndpoint() + "/files/trash",
- options: Options(
- headers: {
- "X-Auth-Token": Configuration.instance.getToken(),
- },
- ),
- data: requestData,
- );
- }
- Future<void> deleteFromTrash(List<File> files) async {
- final params = <String, dynamic>{};
- final uniqueFileIds = files.map((e) => e.uploadedFileID).toSet().toList();
- params["fileIDs"] = [];
- for (final fileID in uniqueFileIds) {
- params["fileIDs"].add(fileID);
- }
- try {
- await _dio.post(
- Configuration.instance.getHttpEndpoint() + "/trash/delete",
- options: Options(
- headers: {
- "X-Auth-Token": Configuration.instance.getToken(),
- },
- ),
- data: params,
- );
- await _trashDB.delete(uniqueFileIds);
- Bus.instance.fire(TrashUpdatedEvent());
- // no need to await on syncing trash from remote
- unawaited(syncTrash());
- } catch (e, s) {
- _logger.severe("failed to delete from trash", e, s);
- rethrow;
- }
- }
- Future<void> emptyTrash() async {
- final params = <String, dynamic>{};
- params["lastUpdatedAt"] = _getSyncTime();
- try {
- await _dio.post(
- Configuration.instance.getHttpEndpoint() + "/trash/empty",
- options: Options(
- headers: {
- "X-Auth-Token": Configuration.instance.getToken(),
- },
- ),
- data: params,
- );
- await _trashDB.clearTable();
- unawaited(syncTrash());
- Bus.instance.fire(TrashUpdatedEvent());
- Bus.instance.fire(ForceReloadTrashPageEvent());
- } catch (e, s) {
- _logger.severe("failed to empty trash", e, s);
- rethrow;
- }
- }
- }
|