Compare commits
2 commits
migrate_fi
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ae61fc9c6f | ||
![]() |
c291fa70d3 |
15 changed files with 662 additions and 922 deletions
|
@ -22,55 +22,61 @@ extension DeviceFiles on FilesDB {
|
|||
ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.ignore,
|
||||
}) async {
|
||||
debugPrint("Inserting missing PathIDToLocalIDMapping");
|
||||
final parameterSets = <List<Object?>>[];
|
||||
final db = await database;
|
||||
var batch = db.batch();
|
||||
int batchCounter = 0;
|
||||
for (MapEntry e in mappingToAdd.entries) {
|
||||
final String pathID = e.key;
|
||||
for (String localID in e.value) {
|
||||
parameterSets.add([localID, pathID]);
|
||||
batchCounter++;
|
||||
|
||||
if (batchCounter == 400) {
|
||||
await _insertBatch(parameterSets, conflictAlgorithm);
|
||||
parameterSets.clear();
|
||||
await batch.commit(noResult: true);
|
||||
batch = db.batch();
|
||||
batchCounter = 0;
|
||||
}
|
||||
batch.insert(
|
||||
"device_files",
|
||||
{
|
||||
"id": localID,
|
||||
"path_id": pathID,
|
||||
},
|
||||
conflictAlgorithm: conflictAlgorithm,
|
||||
);
|
||||
batchCounter++;
|
||||
}
|
||||
}
|
||||
await _insertBatch(parameterSets, conflictAlgorithm);
|
||||
parameterSets.clear();
|
||||
batchCounter = 0;
|
||||
await batch.commit(noResult: true);
|
||||
}
|
||||
|
||||
Future<void> deletePathIDToLocalIDMapping(
|
||||
Map<String, Set<String>> mappingsToRemove,
|
||||
) async {
|
||||
debugPrint("removing PathIDToLocalIDMapping");
|
||||
final parameterSets = <List<Object?>>[];
|
||||
final db = await database;
|
||||
var batch = db.batch();
|
||||
int batchCounter = 0;
|
||||
for (MapEntry e in mappingsToRemove.entries) {
|
||||
final String pathID = e.key;
|
||||
|
||||
for (String localID in e.value) {
|
||||
parameterSets.add([localID, pathID]);
|
||||
batchCounter++;
|
||||
|
||||
if (batchCounter == 400) {
|
||||
await _deleteBatch(parameterSets);
|
||||
parameterSets.clear();
|
||||
await batch.commit(noResult: true);
|
||||
batch = db.batch();
|
||||
batchCounter = 0;
|
||||
}
|
||||
batch.delete(
|
||||
"device_files",
|
||||
where: 'id = ? AND path_id = ?',
|
||||
whereArgs: [localID, pathID],
|
||||
);
|
||||
batchCounter++;
|
||||
}
|
||||
}
|
||||
await _deleteBatch(parameterSets);
|
||||
parameterSets.clear();
|
||||
batchCounter = 0;
|
||||
await batch.commit(noResult: true);
|
||||
}
|
||||
|
||||
Future<Map<String, int>> getDevicePathIDToImportedFileCount() async {
|
||||
try {
|
||||
final db = await sqliteAsyncDB;
|
||||
final rows = await db.getAll(
|
||||
final db = await database;
|
||||
final rows = await db.rawQuery(
|
||||
'''
|
||||
SELECT count(*) as count, path_id
|
||||
FROM device_files
|
||||
|
@ -90,8 +96,8 @@ extension DeviceFiles on FilesDB {
|
|||
|
||||
Future<Map<String, Set<String>>> getDevicePathIDToLocalIDMap() async {
|
||||
try {
|
||||
final db = await sqliteAsyncDB;
|
||||
final rows = await db.getAll(
|
||||
final db = await database;
|
||||
final rows = await db.rawQuery(
|
||||
''' SELECT id, path_id FROM device_files; ''',
|
||||
);
|
||||
final result = <String, Set<String>>{};
|
||||
|
@ -110,8 +116,8 @@ extension DeviceFiles on FilesDB {
|
|||
}
|
||||
|
||||
Future<Set<String>> getDevicePathIDs() async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final rows = await db.getAll(
|
||||
final Database db = await database;
|
||||
final rows = await db.rawQuery(
|
||||
'''
|
||||
SELECT id FROM device_collections
|
||||
''',
|
||||
|
@ -127,42 +133,34 @@ extension DeviceFiles on FilesDB {
|
|||
List<LocalPathAsset> localPathAssets, {
|
||||
bool shouldAutoBackup = false,
|
||||
}) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final Database db = await database;
|
||||
final Map<String, Set<String>> pathIDToLocalIDsMap = {};
|
||||
try {
|
||||
final batch = db.batch();
|
||||
final Set<String> existingPathIds = await getDevicePathIDs();
|
||||
final parameterSetsForUpdate = <List<Object?>>[];
|
||||
final parameterSetsForInsert = <List<Object?>>[];
|
||||
for (LocalPathAsset localPathAsset in localPathAssets) {
|
||||
if (localPathAsset.localIDs.isNotEmpty) {
|
||||
pathIDToLocalIDsMap[localPathAsset.pathID] = localPathAsset.localIDs;
|
||||
}
|
||||
if (existingPathIds.contains(localPathAsset.pathID)) {
|
||||
parameterSetsForUpdate
|
||||
.add([localPathAsset.pathName, localPathAsset.pathID]);
|
||||
batch.rawUpdate(
|
||||
"UPDATE device_collections SET name = ? where id = "
|
||||
"?",
|
||||
[localPathAsset.pathName, localPathAsset.pathID],
|
||||
);
|
||||
} else if (localPathAsset.localIDs.isNotEmpty) {
|
||||
parameterSetsForInsert.add([
|
||||
localPathAsset.pathID,
|
||||
localPathAsset.pathName,
|
||||
shouldAutoBackup ? _sqlBoolTrue : _sqlBoolFalse,
|
||||
]);
|
||||
batch.insert(
|
||||
"device_collections",
|
||||
{
|
||||
"id": localPathAsset.pathID,
|
||||
"name": localPathAsset.pathName,
|
||||
"should_backup": shouldAutoBackup ? _sqlBoolTrue : _sqlBoolFalse,
|
||||
},
|
||||
conflictAlgorithm: ConflictAlgorithm.ignore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await db.executeBatch(
|
||||
'''
|
||||
INSERT OR IGNORE INTO device_collections (id, name, should_backup) VALUES (?, ?, ?);
|
||||
''',
|
||||
parameterSetsForInsert,
|
||||
);
|
||||
|
||||
await db.executeBatch(
|
||||
'''
|
||||
UPDATE device_collections SET name = ? WHERE id = ?;
|
||||
''',
|
||||
parameterSetsForUpdate,
|
||||
);
|
||||
|
||||
await batch.commit(noResult: true);
|
||||
// add the mappings for localIDs
|
||||
if (pathIDToLocalIDsMap.isNotEmpty) {
|
||||
await insertPathIDToLocalIDMapping(pathIDToLocalIDsMap);
|
||||
|
@ -179,7 +177,7 @@ extension DeviceFiles on FilesDB {
|
|||
}) async {
|
||||
bool hasUpdated = false;
|
||||
try {
|
||||
final db = await sqliteAsyncDB;
|
||||
final Database db = await database;
|
||||
final Set<String> existingPathIds = await getDevicePathIDs();
|
||||
for (Tuple2<AssetPathEntity, String> tup in devicePathInfo) {
|
||||
final AssetPathEntity pathEntity = tup.item1;
|
||||
|
@ -187,42 +185,35 @@ extension DeviceFiles on FilesDB {
|
|||
final String localID = tup.item2;
|
||||
final bool shouldUpdate = existingPathIds.contains(pathEntity.id);
|
||||
if (shouldUpdate) {
|
||||
final rowUpdated = await db.writeTransaction((tx) async {
|
||||
await tx.execute(
|
||||
"UPDATE device_collections SET name = ?, cover_id = ?, count"
|
||||
" = ? where id = ? AND (name != ? OR cover_id != ? OR count != ?)",
|
||||
[
|
||||
pathEntity.name,
|
||||
localID,
|
||||
assetCount,
|
||||
pathEntity.id,
|
||||
pathEntity.name,
|
||||
localID,
|
||||
assetCount,
|
||||
],
|
||||
);
|
||||
final result = await tx.get("SELECT changes();");
|
||||
return result["changes()"] as int;
|
||||
});
|
||||
|
||||
final rowUpdated = await db.rawUpdate(
|
||||
"UPDATE device_collections SET name = ?, cover_id = ?, count"
|
||||
" = ? where id = ? AND (name != ? OR cover_id != ? OR count != ?)",
|
||||
[
|
||||
pathEntity.name,
|
||||
localID,
|
||||
assetCount,
|
||||
pathEntity.id,
|
||||
pathEntity.name,
|
||||
localID,
|
||||
assetCount,
|
||||
],
|
||||
);
|
||||
if (rowUpdated > 0) {
|
||||
_logger.fine("Updated $rowUpdated rows for ${pathEntity.name}");
|
||||
hasUpdated = true;
|
||||
}
|
||||
} else {
|
||||
hasUpdated = true;
|
||||
await db.execute(
|
||||
'''
|
||||
INSERT INTO device_collections (id, name, count, cover_id, should_backup)
|
||||
VALUES (?, ?, ?, ?, ?);
|
||||
''',
|
||||
[
|
||||
pathEntity.id,
|
||||
pathEntity.name,
|
||||
assetCount,
|
||||
localID,
|
||||
shouldBackup ? _sqlBoolTrue : _sqlBoolFalse,
|
||||
],
|
||||
await db.insert(
|
||||
"device_collections",
|
||||
{
|
||||
"id": pathEntity.id,
|
||||
"name": pathEntity.name,
|
||||
"count": assetCount,
|
||||
"cover_id": localID,
|
||||
"should_backup": shouldBackup ? _sqlBoolTrue : _sqlBoolFalse,
|
||||
},
|
||||
conflictAlgorithm: ConflictAlgorithm.ignore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -240,17 +231,15 @@ extension DeviceFiles on FilesDB {
|
|||
// feature, where we delete files which are backed up. Deleting such
|
||||
// entries here result in us losing out on the information that
|
||||
// those folders were marked for automatic backup.
|
||||
await db.execute(
|
||||
'''
|
||||
DELETE FROM device_collections WHERE id = ? AND should_backup = $_sqlBoolFalse;
|
||||
''',
|
||||
[pathID],
|
||||
await db.delete(
|
||||
"device_collections",
|
||||
where: 'id = ? and should_backup = $_sqlBoolFalse ',
|
||||
whereArgs: [pathID],
|
||||
);
|
||||
await db.execute(
|
||||
'''
|
||||
DELETE FROM device_files WHERE path_id = ?;
|
||||
''',
|
||||
[pathID],
|
||||
await db.delete(
|
||||
"device_files",
|
||||
where: 'path_id = ?',
|
||||
whereArgs: [pathID],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -264,8 +253,8 @@ extension DeviceFiles on FilesDB {
|
|||
// getDeviceSyncCollectionIDs returns the collectionIDs for the
|
||||
// deviceCollections which are marked for auto-backup
|
||||
Future<Set<int>> getDeviceSyncCollectionIDs() async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final rows = await db.getAll(
|
||||
final Database db = await database;
|
||||
final rows = await db.rawQuery(
|
||||
'''
|
||||
SELECT collection_id FROM device_collections where should_backup =
|
||||
$_sqlBoolTrue
|
||||
|
@ -279,47 +268,40 @@ extension DeviceFiles on FilesDB {
|
|||
return result;
|
||||
}
|
||||
|
||||
Future<void> updateDevicePathSyncStatus(
|
||||
Map<String, bool> syncStatus,
|
||||
) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
Future<void> updateDevicePathSyncStatus(Map<String, bool> syncStatus) async {
|
||||
final db = await database;
|
||||
var batch = db.batch();
|
||||
int batchCounter = 0;
|
||||
final parameterSets = <List<Object?>>[];
|
||||
for (MapEntry e in syncStatus.entries) {
|
||||
final String pathID = e.key;
|
||||
parameterSets.add([e.value ? _sqlBoolTrue : _sqlBoolFalse, pathID]);
|
||||
batchCounter++;
|
||||
|
||||
if (batchCounter == 400) {
|
||||
await db.executeBatch(
|
||||
'''
|
||||
UPDATE device_collections SET should_backup = ? WHERE id = ?;
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
parameterSets.clear();
|
||||
await batch.commit(noResult: true);
|
||||
batch = db.batch();
|
||||
batchCounter = 0;
|
||||
}
|
||||
batch.update(
|
||||
"device_collections",
|
||||
{
|
||||
"should_backup": e.value ? _sqlBoolTrue : _sqlBoolFalse,
|
||||
},
|
||||
where: 'id = ?',
|
||||
whereArgs: [pathID],
|
||||
);
|
||||
batchCounter++;
|
||||
}
|
||||
|
||||
await db.executeBatch(
|
||||
'''
|
||||
UPDATE device_collections SET should_backup = ? WHERE id = ?;
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
await batch.commit(noResult: true);
|
||||
}
|
||||
|
||||
Future<void> updateDeviceCollection(
|
||||
String pathID,
|
||||
int collectionID,
|
||||
) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
await db.execute(
|
||||
'''
|
||||
UPDATE device_collections SET collection_id = ? WHERE id = ?;
|
||||
''',
|
||||
[collectionID, pathID],
|
||||
final db = await database;
|
||||
await db.update(
|
||||
"device_collections",
|
||||
{"collection_id": collectionID},
|
||||
where: 'id = ?',
|
||||
whereArgs: [pathID],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -332,7 +314,7 @@ extension DeviceFiles on FilesDB {
|
|||
int? limit,
|
||||
bool? asc,
|
||||
}) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final db = await database;
|
||||
final order = (asc ?? false ? 'ASC' : 'DESC');
|
||||
final String rawQuery = '''
|
||||
SELECT *
|
||||
|
@ -347,7 +329,7 @@ extension DeviceFiles on FilesDB {
|
|||
ORDER BY ${FilesDB.columnCreationTime} $order , ${FilesDB.columnModificationTime} $order
|
||||
''' +
|
||||
(limit != null ? ' limit $limit;' : ';');
|
||||
final results = await db.getAll(rawQuery);
|
||||
final results = await db.rawQuery(rawQuery);
|
||||
final files = convertToFiles(results);
|
||||
final dedupe = deduplicateByLocalID(files);
|
||||
return FileLoadResult(dedupe, files.length == limit);
|
||||
|
@ -357,7 +339,7 @@ extension DeviceFiles on FilesDB {
|
|||
String pathID,
|
||||
int ownerID,
|
||||
) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final db = await database;
|
||||
const String rawQuery = '''
|
||||
SELECT ${FilesDB.columnLocalID}, ${FilesDB.columnUploadedFileID},
|
||||
${FilesDB.columnFileSize}
|
||||
|
@ -369,7 +351,7 @@ extension DeviceFiles on FilesDB {
|
|||
${FilesDB.columnLocalID} IN
|
||||
(SELECT id FROM device_files where path_id = ?)
|
||||
''';
|
||||
final results = await db.getAll(rawQuery, [ownerID, pathID]);
|
||||
final results = await db.rawQuery(rawQuery, [ownerID, pathID]);
|
||||
final localIDs = <String>{};
|
||||
final uploadedIDs = <int>{};
|
||||
int localSize = 0;
|
||||
|
@ -393,17 +375,17 @@ extension DeviceFiles on FilesDB {
|
|||
"$includeCoverThumbnail",
|
||||
);
|
||||
try {
|
||||
final db = await sqliteAsyncDB;
|
||||
final db = await database;
|
||||
final coverFiles = <EnteFile>[];
|
||||
if (includeCoverThumbnail) {
|
||||
final fileRows = await db.getAll(
|
||||
final fileRows = await db.rawQuery(
|
||||
'''SELECT * FROM FILES where local_id in (select cover_id from device_collections) group by local_id;
|
||||
''',
|
||||
);
|
||||
final files = convertToFiles(fileRows);
|
||||
coverFiles.addAll(files);
|
||||
}
|
||||
final deviceCollectionRows = await db.getAll(
|
||||
final deviceCollectionRows = await db.rawQuery(
|
||||
'''SELECT * from device_collections''',
|
||||
);
|
||||
final List<DeviceCollection> deviceCollections = [];
|
||||
|
@ -451,8 +433,8 @@ extension DeviceFiles on FilesDB {
|
|||
|
||||
Future<EnteFile?> getDeviceCollectionThumbnail(String pathID) async {
|
||||
debugPrint("Call fallback method to get potential thumbnail");
|
||||
final db = await sqliteAsyncDB;
|
||||
final fileRows = await db.getAll(
|
||||
final db = await database;
|
||||
final fileRows = await db.rawQuery(
|
||||
'''SELECT * FROM FILES f JOIN device_files df on f.local_id = df.id
|
||||
and df.path_id= ? order by f.creation_time DESC limit 1;
|
||||
''',
|
||||
|
@ -465,28 +447,4 @@ extension DeviceFiles on FilesDB {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _insertBatch(
|
||||
List<List<Object?>> parameterSets,
|
||||
ConflictAlgorithm conflictAlgorithm,
|
||||
) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
await db.executeBatch(
|
||||
'''
|
||||
INSERT OR ${conflictAlgorithm.name.toUpperCase()}
|
||||
INTO device_files (id, path_id) VALUES (?, ?);
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _deleteBatch(List<List<Object?>> parameterSets) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
await db.executeBatch(
|
||||
'''
|
||||
DELETE FROM device_files WHERE id = ? AND path_id = ?;
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,78 +10,53 @@ extension EntitiesDB on FilesDB {
|
|||
ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.replace,
|
||||
}) async {
|
||||
debugPrint("entitiesDB: upsertEntities ${data.length} entities");
|
||||
final db = await sqliteAsyncDB;
|
||||
final parameterSets = <List<Object?>>[];
|
||||
final db = await database;
|
||||
var batch = db.batch();
|
||||
int batchCounter = 0;
|
||||
for (LocalEntityData e in data) {
|
||||
parameterSets.add([
|
||||
e.id,
|
||||
e.type.name,
|
||||
e.ownerID,
|
||||
e.data,
|
||||
e.updatedAt,
|
||||
]);
|
||||
batchCounter++;
|
||||
|
||||
if (batchCounter == 400) {
|
||||
await db.executeBatch(
|
||||
'''
|
||||
INSERT OR ${conflictAlgorithm.name.toUpperCase()}
|
||||
INTO entities (id, type, ownerID, data, updatedAt)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
parameterSets.clear();
|
||||
await batch.commit(noResult: true);
|
||||
batch = db.batch();
|
||||
batchCounter = 0;
|
||||
}
|
||||
batch.insert(
|
||||
"entities",
|
||||
e.toJson(),
|
||||
conflictAlgorithm: conflictAlgorithm,
|
||||
);
|
||||
batchCounter++;
|
||||
}
|
||||
await db.executeBatch(
|
||||
'''
|
||||
INSERT OR ${conflictAlgorithm.name.toUpperCase()}
|
||||
INTO entities (id, type, ownerID, data, updatedAt)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
await batch.commit(noResult: true);
|
||||
}
|
||||
|
||||
Future<void> deleteEntities(
|
||||
List<String> ids,
|
||||
) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final parameterSets = <List<Object?>>[];
|
||||
final db = await database;
|
||||
var batch = db.batch();
|
||||
int batchCounter = 0;
|
||||
for (String id in ids) {
|
||||
parameterSets.add(
|
||||
[id],
|
||||
);
|
||||
batchCounter++;
|
||||
|
||||
if (batchCounter == 400) {
|
||||
await db.executeBatch(
|
||||
'''
|
||||
DELETE FROM entities WHERE id = ?
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
parameterSets.clear();
|
||||
await batch.commit(noResult: true);
|
||||
batch = db.batch();
|
||||
batchCounter = 0;
|
||||
}
|
||||
batch.delete(
|
||||
"entities",
|
||||
where: "id = ?",
|
||||
whereArgs: [id],
|
||||
);
|
||||
batchCounter++;
|
||||
}
|
||||
await db.executeBatch(
|
||||
'''
|
||||
DELETE FROM entities WHERE id = ?
|
||||
''',
|
||||
parameterSets,
|
||||
);
|
||||
await batch.commit(noResult: true);
|
||||
}
|
||||
|
||||
Future<List<LocalEntityData>> getEntities(EntityType type) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final List<Map<String, dynamic>> maps = await db.getAll(
|
||||
'SELECT * FROM entities WHERE type = ?',
|
||||
[type.name],
|
||||
final db = await database;
|
||||
final List<Map<String, dynamic>> maps = await db.query(
|
||||
"entities",
|
||||
where: "type = ?",
|
||||
whereArgs: [type.typeToString()],
|
||||
);
|
||||
return List.generate(maps.length, (i) {
|
||||
return LocalEntityData.fromJson(maps[i]);
|
||||
|
@ -89,10 +64,11 @@ extension EntitiesDB on FilesDB {
|
|||
}
|
||||
|
||||
Future<LocalEntityData?> getEntity(EntityType type, String id) async {
|
||||
final db = await sqliteAsyncDB;
|
||||
final List<Map<String, dynamic>> maps = await db.getAll(
|
||||
'SELECT * FROM entities WHERE type = ? AND id = ?',
|
||||
[type.name, id],
|
||||
final db = await database;
|
||||
final List<Map<String, dynamic>> maps = await db.query(
|
||||
"entities",
|
||||
where: "type = ? AND id = ?",
|
||||
whereArgs: [type.typeToString(), id],
|
||||
);
|
||||
if (maps.isEmpty) {
|
||||
return null;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -151,7 +151,9 @@ class FavoritesService {
|
|||
final collectionID = await _getOrCreateFavoriteCollectionID();
|
||||
final List<EnteFile> files = [file];
|
||||
if (file.uploadedFileID == null) {
|
||||
throw AssertionError("Can only favorite uploaded items");
|
||||
file.collectionID = collectionID;
|
||||
await _filesDB.insert(file);
|
||||
Bus.instance.fire(CollectionUpdatedEvent(collectionID, files, "addTFav"));
|
||||
} else {
|
||||
await _collectionsService.addOrCopyToCollection(collectionID, files);
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ class LocalFileUpdateService {
|
|||
} else if (e.reason == InvalidReason.imageToLivePhotoTypeChanged) {
|
||||
fileType = FileType.livePhoto;
|
||||
}
|
||||
await FilesDB.instance.markFilesForReUpload(
|
||||
final int count = await FilesDB.instance.markFilesForReUpload(
|
||||
userID,
|
||||
file.localID!,
|
||||
file.title,
|
||||
|
@ -202,7 +202,8 @@ class LocalFileUpdateService {
|
|||
file.modificationTime!,
|
||||
fileType,
|
||||
);
|
||||
_logger.fine('fileType changed for ${file.tag} to ${e.reason} for ');
|
||||
_logger.fine('fileType changed for ${file.tag} to ${e.reason} for '
|
||||
'$count files');
|
||||
} else {
|
||||
_logger.severe("failed to check hash: invalid file ${file.tag}", e);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ import "package:photos/services/ignored_files_service.dart";
|
|||
import 'package:photos/services/local/local_sync_util.dart';
|
||||
import "package:photos/utils/debouncer.dart";
|
||||
import "package:photos/utils/photo_manager_util.dart";
|
||||
import "package:photos/utils/sqlite_util.dart";
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class LocalSyncService {
|
||||
|
@ -184,7 +184,7 @@ class LocalSyncService {
|
|||
if (hasUnsyncedFiles) {
|
||||
await _db.insertMultiple(
|
||||
localDiffResult.uniqueLocalFiles!,
|
||||
conflictAlgorithm: SqliteAsyncConflictAlgorithm.ignore,
|
||||
conflictAlgorithm: ConflictAlgorithm.ignore,
|
||||
);
|
||||
_logger.info(
|
||||
"Inserted ${localDiffResult.uniqueLocalFiles?.length} "
|
||||
|
@ -321,7 +321,7 @@ class LocalSyncService {
|
|||
files.removeWhere((file) => existingLocalDs.contains(file.localID));
|
||||
await _db.insertMultiple(
|
||||
files,
|
||||
conflictAlgorithm: SqliteAsyncConflictAlgorithm.ignore,
|
||||
conflictAlgorithm: ConflictAlgorithm.ignore,
|
||||
);
|
||||
_logger.info('Inserted ${files.length} files');
|
||||
Bus.instance.fire(
|
||||
|
|
|
@ -580,9 +580,6 @@ class FaceMlService {
|
|||
_isIndexingOrClusteringRunning = true;
|
||||
final clusterAllImagesTime = DateTime.now();
|
||||
|
||||
_logger.info('Pulling remote feedback before actually clustering');
|
||||
await PersonService.instance.fetchRemoteClusterFeedback();
|
||||
|
||||
try {
|
||||
// Get a sense of the total number of faces in the database
|
||||
final int totalFaces = await FaceMLDataDB.instance
|
||||
|
|
|
@ -73,7 +73,7 @@ class PersonService {
|
|||
Future<void> reconcileClusters() async {
|
||||
final EnteWatch? w = kDebugMode ? EnteWatch("reconcileClusters") : null;
|
||||
w?.start();
|
||||
await fetchRemoteClusterFeedback();
|
||||
await storeRemoteFeedback();
|
||||
w?.log("Stored remote feedback");
|
||||
final dbPersonClusterInfo =
|
||||
await faceMLDataDB.getPersonToClusterIdToFaceIds();
|
||||
|
@ -225,7 +225,7 @@ class PersonService {
|
|||
Bus.instance.fire(PeopleChangedEvent());
|
||||
}
|
||||
|
||||
Future<void> fetchRemoteClusterFeedback() async {
|
||||
Future<void> storeRemoteFeedback() async {
|
||||
await entityService.syncEntities();
|
||||
final entities = await entityService.getEntities(EntityType.person);
|
||||
entities.sort((a, b) => a.updatedAt.compareTo(b.updatedAt));
|
||||
|
|
|
@ -193,7 +193,7 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
|
|||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
await PersonService.instance.fetchRemoteClusterFeedback();
|
||||
await PersonService.instance.storeRemoteFeedback();
|
||||
FaceMlService.instance.debugIndexingDisabled = false;
|
||||
await FaceMlService.instance
|
||||
.clusterAllImages(clusterInBuckets: true);
|
||||
|
|
|
@ -371,7 +371,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
|
|||
);
|
||||
}
|
||||
}
|
||||
newFile.generatedID = await FilesDB.instance.insertAndGetId(newFile);
|
||||
newFile.generatedID = await FilesDB.instance.insert(newFile);
|
||||
Bus.instance.fire(LocalPhotosUpdatedEvent([newFile], source: "editSave"));
|
||||
unawaited(SyncService.instance.sync());
|
||||
showShortToast(context, S.of(context).editsSaved);
|
||||
|
|
|
@ -146,8 +146,6 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
|||
late final StreamSubscription<LocalPhotosUpdatedEvent> _filesUpdateEvent;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
final collectionsToHide =
|
||||
CollectionsService.instance.archivedOrHiddenCollectionIds();
|
||||
fileLoadResult = FilesDB.instance
|
||||
|
@ -181,6 +179,8 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
|||
});
|
||||
|
||||
galleryHeaderWidget = const GalleryHeaderWidget();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -161,43 +161,45 @@ class _ClusterPageState extends State<ClusterPage> {
|
|||
),
|
||||
),
|
||||
showNamingBanner
|
||||
? Dismissible(
|
||||
key: const Key("namingBanner"),
|
||||
direction: DismissDirection.horizontal,
|
||||
onDismissed: (direction) {
|
||||
setState(() {
|
||||
userDismissedNamingBanner = true;
|
||||
});
|
||||
},
|
||||
child: PeopleBanner(
|
||||
type: PeopleBannerType.addName,
|
||||
faceWidget: PersonFaceWidget(
|
||||
files.first,
|
||||
clusterID: widget.clusterID,
|
||||
),
|
||||
actionIcon: Icons.add_outlined,
|
||||
text: S.of(context).addAName,
|
||||
subText: S.of(context).findPeopleByName,
|
||||
onTap: () async {
|
||||
if (widget.personID == null) {
|
||||
final result = await showAssignPersonAction(
|
||||
context,
|
||||
clusterID: widget.clusterID,
|
||||
);
|
||||
if (result != null &&
|
||||
result is (PersonEntity, EnteFile)) {
|
||||
Navigator.pop(context);
|
||||
// ignore: unawaited_futures
|
||||
routeToPage(context, PeoplePage(person: result.$1));
|
||||
} else if (result != null && result is PersonEntity) {
|
||||
Navigator.pop(context);
|
||||
// ignore: unawaited_futures
|
||||
routeToPage(context, PeoplePage(person: result));
|
||||
}
|
||||
} else {
|
||||
showShortToast(context, "No personID or clusterID");
|
||||
}
|
||||
? SafeArea(
|
||||
child: Dismissible(
|
||||
key: const Key("namingBanner"),
|
||||
direction: DismissDirection.horizontal,
|
||||
onDismissed: (direction) {
|
||||
setState(() {
|
||||
userDismissedNamingBanner = true;
|
||||
});
|
||||
},
|
||||
child: PeopleBanner(
|
||||
type: PeopleBannerType.addName,
|
||||
faceWidget: PersonFaceWidget(
|
||||
files.first,
|
||||
clusterID: widget.clusterID,
|
||||
),
|
||||
actionIcon: Icons.add_outlined,
|
||||
text: S.of(context).addAName,
|
||||
subText: S.of(context).findPeopleByName,
|
||||
onTap: () async {
|
||||
if (widget.personID == null) {
|
||||
final result = await showAssignPersonAction(
|
||||
context,
|
||||
clusterID: widget.clusterID,
|
||||
);
|
||||
if (result != null &&
|
||||
result is (PersonEntity, EnteFile)) {
|
||||
Navigator.pop(context);
|
||||
// ignore: unawaited_futures
|
||||
routeToPage(context, PeoplePage(person: result.$1));
|
||||
} else if (result != null && result is PersonEntity) {
|
||||
Navigator.pop(context);
|
||||
// ignore: unawaited_futures
|
||||
routeToPage(context, PeoplePage(person: result));
|
||||
}
|
||||
} else {
|
||||
showShortToast(context, "No personID or clusterID");
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
///This is useful when you want to pass a primitive by reference.
|
||||
|
||||
class PrimitiveWrapper {
|
||||
var value;
|
||||
PrimitiveWrapper(this.value);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
enum SqliteAsyncConflictAlgorithm {
|
||||
/// When a constraint violation occurs, an immediate ROLLBACK occurs,
|
||||
/// thus ending the current transaction, and the command aborts with a
|
||||
/// return code of SQLITE_CONSTRAINT. If no transaction is active
|
||||
/// (other than the implied transaction that is created on every command)
|
||||
/// then this algorithm works the same as ABORT.
|
||||
rollback,
|
||||
|
||||
/// When a constraint violation occurs,no ROLLBACK is executed
|
||||
/// so changes from prior commands within the same transaction
|
||||
/// are preserved. This is the default behavior.
|
||||
abort,
|
||||
|
||||
/// When a constraint violation occurs, the command aborts with a return
|
||||
/// code SQLITE_CONSTRAINT. But any changes to the database that
|
||||
/// the command made prior to encountering the constraint violation
|
||||
/// are preserved and are not backed out.
|
||||
fail,
|
||||
|
||||
/// When a constraint violation occurs, the one row that contains
|
||||
/// the constraint violation is not inserted or changed.
|
||||
/// But the command continues executing normally. Other rows before and
|
||||
/// after the row that contained the constraint violation continue to be
|
||||
/// inserted or updated normally. No error is returned.
|
||||
ignore,
|
||||
|
||||
/// When a UNIQUE constraint violation occurs, the pre-existing rows that
|
||||
/// are causing the constraint violation are removed prior to inserting
|
||||
/// or updating the current row. Thus the insert or update always occurs.
|
||||
/// The command continues executing normally. No error is returned.
|
||||
/// If a NOT NULL constraint violation occurs, the NULL value is replaced
|
||||
/// by the default value for that column. If the column has no default
|
||||
/// value, then the ABORT algorithm is used. If a CHECK constraint
|
||||
/// violation occurs then the IGNORE algorithm is used. When this conflict
|
||||
/// resolution strategy deletes rows in order to satisfy a constraint,
|
||||
/// it does not invoke delete triggers on those rows.
|
||||
/// This behavior might change in a future release.
|
||||
replace,
|
||||
}
|
|
@ -12,7 +12,7 @@ description: ente photos application
|
|||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
|
||||
version: 0.8.113+637
|
||||
version: 0.8.112+636
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
|
Loading…
Add table
Reference in a new issue