ente/lib/services/ignored_files_service.dart

146 lines
4.6 KiB
Dart
Raw Normal View History

import 'dart:async';
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:photos/db/ignored_files_db.dart';
2023-08-25 04:39:30 +00:00
import 'package:photos/models/file/file.dart';
import 'package:photos/models/ignored_file.dart';
class IgnoredFilesService {
final _logger = Logger("IgnoredFilesService");
final _db = IgnoredFilesDB.instance;
IgnoredFilesService._privateConstructor();
static final IgnoredFilesService instance =
IgnoredFilesService._privateConstructor();
2023-08-23 08:56:06 +00:00
Future<Map<String, String>>? _idsToReasonMap;
2023-08-23 08:56:06 +00:00
Future<Map<String, String>> get idToIgnoreReasonMap async {
// lazily instantiate the db the first time it is accessed
2023-08-23 08:56:06 +00:00
_idsToReasonMap ??= _loadIDsToReasonMap();
return _idsToReasonMap!;
}
Future<void> cacheAndInsert(List<IgnoredFile> ignoredFiles) async {
2023-08-23 08:56:06 +00:00
final existingIDs = await idToIgnoreReasonMap;
for (IgnoredFile iFile in ignoredFiles) {
final id = _idForIgnoredFile(iFile);
if (id != null) {
2023-08-23 08:56:06 +00:00
existingIDs[id] = iFile.reason;
}
}
return _db.insertMultiple(ignoredFiles);
}
// shouldSkipUpload takes IDs to ignore and file for which it will return
// whether either true or false. This helper method takes ignoredIDs as input
// to avoid making it async in nature.
2021-10-29 06:32:58 +00:00
// This syntax is intentional as we want to ensure that ignoredIDs are loaded
// from the DB before calling this method.
2023-08-24 16:56:24 +00:00
bool shouldSkipUpload(Map<String, String> idToReasonMap, EnteFile file) {
final id = _getIgnoreID(file.localID, file.deviceFolder, file.title);
if (id != null && id.isNotEmpty) {
2023-08-23 08:56:06 +00:00
return idToReasonMap.containsKey(id);
}
return false;
}
2023-08-24 16:56:24 +00:00
String? getUploadSkipReason(Map<String, String> idToReasonMap, EnteFile file) {
final id = _getIgnoreID(file.localID, file.deviceFolder, file.title);
if (id != null && id.isNotEmpty) {
return idToReasonMap[id];
}
return null;
}
2023-08-24 16:56:24 +00:00
Future<bool> shouldSkipUploadAsync(EnteFile file) async {
2023-08-23 08:56:06 +00:00
final ignoredID = await idToIgnoreReasonMap;
2023-05-16 11:43:54 +00:00
return shouldSkipUpload(ignoredID, file);
}
// removeIgnoredMappings is used to remove the ignore mapping for the given
// set of files so that they can be uploaded.
2023-08-24 16:56:24 +00:00
Future<void> removeIgnoredMappings(List<EnteFile> files) async {
2022-08-29 18:05:13 +00:00
final List<IgnoredFile> ignoredFiles = [];
final Set<String> idsToRemoveFromCache = {};
2023-08-23 08:56:06 +00:00
final Map<String, String> currentlyIgnoredIDs = await idToIgnoreReasonMap;
for (final file in files) {
// check if upload is not skipped for file. If not, no need to remove
// any mapping
if (!shouldSkipUpload(currentlyIgnoredIDs, file)) {
continue;
}
// _shouldSkipUpload checks for null ignoreID
final id = _getIgnoreID(file.localID, file.deviceFolder, file.title)!;
idsToRemoveFromCache.add(id);
ignoredFiles.add(
IgnoredFile(file.localID, file.title, file.deviceFolder, ""),
);
}
if (ignoredFiles.isNotEmpty) {
await _db.removeIgnoredEntries(ignoredFiles);
2023-08-23 08:56:06 +00:00
for (final id in idsToRemoveFromCache) {
currentlyIgnoredIDs.remove(id);
}
}
}
Future<void> reset() async {
await _db.clearTable();
2023-08-23 08:56:06 +00:00
_idsToReasonMap = null;
}
2023-08-23 08:56:06 +00:00
Future<Map<String, String>> _loadIDsToReasonMap() async {
2021-10-29 04:57:52 +00:00
_logger.fine('loading existing IDs');
final dbResult = await _db.getAll();
2023-08-23 08:56:06 +00:00
final Map<String, String> result = <String, String>{};
for (IgnoredFile iFile in dbResult) {
final id = _idForIgnoredFile(iFile);
if (id != null) {
2023-08-23 08:56:06 +00:00
result[id] = iFile.reason;
}
}
return result;
}
String? _idForIgnoredFile(IgnoredFile ignoredFile) {
return _getIgnoreID(
2022-06-11 08:23:52 +00:00
ignoredFile.localID,
ignoredFile.deviceFolder,
ignoredFile.title,
);
}
2023-08-24 16:56:24 +00:00
String? getIgnoredIDForFile(EnteFile file) {
2023-01-09 08:28:43 +00:00
return _getIgnoreID(
file.localID,
file.deviceFolder,
file.title,
);
}
// _getIgnoreID will return null if don't have sufficient information
2021-10-29 06:32:58 +00:00
// to ignore the file based on the platform. Uploads from web or files shared to
// end usually don't have local id.
// For Android: It returns deviceFolder-title as ID for Android.
// For iOS, it returns localID as localID is uuid and the title or deviceFolder (aka
// album name) can be missing due to various reasons.
String? _getIgnoreID(String? localID, String? deviceFolder, String? title) {
// file was not uploaded from mobile device
if (localID == null || localID.isEmpty) {
return null;
}
if (Platform.isAndroid) {
if (deviceFolder == null || title == null) {
return null;
}
return '$deviceFolder-$title';
} else {
return localID;
}
}
}