mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
remove trashed asset model
remove trash_sync.service refactor DriftTrashedLocalAssetRepository, LocalSyncService
This commit is contained in:
parent
ebfab4b01b
commit
df0ed1e8da
5 changed files with 81 additions and 262 deletions
|
|
@ -1,117 +0,0 @@
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
||||||
|
|
||||||
class TrashedAsset extends LocalAsset {
|
|
||||||
final String albumId;
|
|
||||||
|
|
||||||
const TrashedAsset({
|
|
||||||
required this.albumId,
|
|
||||||
required super.id,
|
|
||||||
super.remoteId,
|
|
||||||
required super.name,
|
|
||||||
super.checksum,
|
|
||||||
required super.type,
|
|
||||||
required super.createdAt,
|
|
||||||
required super.updatedAt,
|
|
||||||
super.width,
|
|
||||||
super.height,
|
|
||||||
super.durationInSeconds,
|
|
||||||
super.isFavorite = false,
|
|
||||||
super.livePhotoVideoId,
|
|
||||||
super.orientation = 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
TrashedAsset copyWith({
|
|
||||||
String? id,
|
|
||||||
String? remoteId,
|
|
||||||
String? name,
|
|
||||||
String? checksum,
|
|
||||||
AssetType? type,
|
|
||||||
DateTime? createdAt,
|
|
||||||
DateTime? updatedAt,
|
|
||||||
int? width,
|
|
||||||
int? height,
|
|
||||||
int? durationInSeconds,
|
|
||||||
bool? isFavorite,
|
|
||||||
String? livePhotoVideoId,
|
|
||||||
int? orientation,
|
|
||||||
String? albumId,
|
|
||||||
}) {
|
|
||||||
return TrashedAsset(
|
|
||||||
id: id ?? this.id,
|
|
||||||
remoteId: remoteId ?? this.remoteId,
|
|
||||||
name: name ?? this.name,
|
|
||||||
checksum: checksum ?? this.checksum,
|
|
||||||
type: type ?? this.type,
|
|
||||||
createdAt: createdAt ?? this.createdAt,
|
|
||||||
updatedAt: updatedAt ?? this.updatedAt,
|
|
||||||
width: width ?? this.width,
|
|
||||||
height: height ?? this.height,
|
|
||||||
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
|
||||||
livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId,
|
|
||||||
orientation: orientation ?? this.orientation,
|
|
||||||
albumId: albumId ?? this.albumId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is TrashedAsset &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
// LocalAsset identity
|
|
||||||
id == other.id &&
|
|
||||||
name == other.name &&
|
|
||||||
remoteId == other.remoteId &&
|
|
||||||
checksum == other.checksum &&
|
|
||||||
type == other.type &&
|
|
||||||
createdAt == other.createdAt &&
|
|
||||||
updatedAt == other.updatedAt &&
|
|
||||||
width == other.width &&
|
|
||||||
height == other.height &&
|
|
||||||
durationInSeconds == other.durationInSeconds &&
|
|
||||||
isFavorite == other.isFavorite &&
|
|
||||||
livePhotoVideoId == other.livePhotoVideoId &&
|
|
||||||
orientation == other.orientation &&
|
|
||||||
// TrashedAsset extras
|
|
||||||
albumId == other.albumId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
remoteId,
|
|
||||||
checksum,
|
|
||||||
type,
|
|
||||||
createdAt,
|
|
||||||
updatedAt,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
durationInSeconds,
|
|
||||||
isFavorite,
|
|
||||||
livePhotoVideoId,
|
|
||||||
orientation,
|
|
||||||
albumId,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'TrashedAsset('
|
|
||||||
'id: $id, '
|
|
||||||
'remoteId: $remoteId, '
|
|
||||||
'name: $name, '
|
|
||||||
'checksum: $checksum, '
|
|
||||||
'type: $type, '
|
|
||||||
'createdAt: $createdAt, '
|
|
||||||
'updatedAt: $updatedAt, '
|
|
||||||
'width: $width, '
|
|
||||||
'height: $height, '
|
|
||||||
'durationInSeconds: $durationInSeconds, '
|
|
||||||
'isFavorite: $isFavorite, '
|
|
||||||
'livePhotoVideoId: $livePhotoVideoId, '
|
|
||||||
'orientation: $orientation, '
|
|
||||||
'albumId: $albumId, '
|
|
||||||
')';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,6 @@ import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/trashed_asset.model.dart';
|
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/trashed_local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/trashed_local_asset.repository.dart';
|
||||||
|
|
@ -299,15 +298,9 @@ class LocalSyncService {
|
||||||
if (trashUpdates.isEmpty) {
|
if (trashUpdates.isEmpty) {
|
||||||
return Future.value();
|
return Future.value();
|
||||||
}
|
}
|
||||||
final trashedAssets = <TrashedAsset>[];
|
final trashedAssets = delta.toTrashedAssets();
|
||||||
for (final update in trashUpdates) {
|
_log.info("updateLocalTrashChanges trashedAssets: ${trashedAssets.map((e) => e.asset.id)}");
|
||||||
final albums = delta.assetAlbums.cast<String, List<Object?>>();
|
await _trashedLocalAssetRepository.applyDelta(trashedAssets);
|
||||||
for (final String id in albums[update.id]!.cast<String?>().nonNulls) {
|
|
||||||
trashedAssets.add(update.toTrashedAsset(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_log.info("updateLocalTrashChanges trashedAssets: ${trashedAssets.map((e) => e.id)}");
|
|
||||||
await _trashedLocalAssetRepository.saveTrashedAssets(trashedAssets);
|
|
||||||
await _applyRemoteRestoreToLocal();
|
await _applyRemoteRestoreToLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -321,7 +314,7 @@ class LocalSyncService {
|
||||||
_log.info("syncDeviceTrashSnapshot prepare, album: ${album.id}/${album.name}");
|
_log.info("syncDeviceTrashSnapshot prepare, album: ${album.id}/${album.name}");
|
||||||
final trashedPlatformAssets = await _nativeSyncApi.getTrashedAssetsForAlbum(album.id);
|
final trashedPlatformAssets = await _nativeSyncApi.getTrashedAssetsForAlbum(album.id);
|
||||||
final trashedAssets = trashedPlatformAssets.toTrashedAssets(album.id);
|
final trashedAssets = trashedPlatformAssets.toTrashedAssets(album.id);
|
||||||
await _trashedLocalAssetRepository.applyTrashSnapshot(trashedAssets, album.id);
|
await _trashedLocalAssetRepository.applyTrashSnapshot(trashedAssets);
|
||||||
}
|
}
|
||||||
await _applyRemoteRestoreToLocal();
|
await _applyRemoteRestoreToLocal();
|
||||||
}
|
}
|
||||||
|
|
@ -352,33 +345,22 @@ extension on Iterable<PlatformAlbum> {
|
||||||
|
|
||||||
extension on Iterable<PlatformAsset> {
|
extension on Iterable<PlatformAsset> {
|
||||||
List<LocalAsset> toLocalAssets() {
|
List<LocalAsset> toLocalAssets() {
|
||||||
return map(
|
return map((e) => e.toLocalAsset()).toList();
|
||||||
(e) => LocalAsset(
|
}
|
||||||
id: e.id,
|
|
||||||
name: e.name,
|
Iterable<TrashedAsset> toTrashedAssets(String albumId) {
|
||||||
checksum: null,
|
return map((e) => (albumId: albumId, asset: e.toLocalAsset()));
|
||||||
type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other,
|
|
||||||
createdAt: tryFromSecondsSinceEpoch(e.createdAt, isUtc: true) ?? DateTime.timestamp(),
|
|
||||||
updatedAt: tryFromSecondsSinceEpoch(e.updatedAt, isUtc: true) ?? DateTime.timestamp(),
|
|
||||||
width: e.width,
|
|
||||||
height: e.height,
|
|
||||||
durationInSeconds: e.durationInSeconds,
|
|
||||||
orientation: e.orientation,
|
|
||||||
isFavorite: e.isFavorite,
|
|
||||||
),
|
|
||||||
).toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension on PlatformAsset {
|
extension on PlatformAsset {
|
||||||
TrashedAsset toTrashedAsset(String albumId) => TrashedAsset(
|
LocalAsset toLocalAsset() => LocalAsset(
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
checksum: null,
|
checksum: null,
|
||||||
type: AssetType.values.elementAtOrNull(type) ?? AssetType.other,
|
type: AssetType.values.elementAtOrNull(type) ?? AssetType.other,
|
||||||
createdAt: tryFromSecondsSinceEpoch(createdAt) ?? DateTime.now(),
|
createdAt: tryFromSecondsSinceEpoch(createdAt, isUtc: true) ?? DateTime.timestamp(),
|
||||||
updatedAt: tryFromSecondsSinceEpoch(updatedAt) ?? DateTime.now(),
|
updatedAt: tryFromSecondsSinceEpoch(createdAt, isUtc: true) ?? DateTime.timestamp(),
|
||||||
albumId: albumId,
|
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
|
|
@ -387,8 +369,12 @@ extension on PlatformAsset {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PlatformAssetsExtension on Iterable<PlatformAsset> {
|
extension SyncDeltaExtension on SyncDelta {
|
||||||
Iterable<TrashedAsset> toTrashedAssets(String albumId) {
|
Iterable<TrashedAsset> toTrashedAssets() {
|
||||||
return map((e) => e.toTrashedAsset(albumId));
|
return updates.map((e) {
|
||||||
|
final albums = assetAlbums.cast<String, List<Object?>>();
|
||||||
|
final albumId = albums[e.id]!.cast<String>().first;
|
||||||
|
return (albumId: albumId, asset: e.toLocalAsset());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/trashed_local_asset.repository.dart';
|
|
||||||
import 'package:immich_mobile/repositories/local_files_manager.repository.dart';
|
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
|
|
||||||
class TrashSyncService {
|
|
||||||
final AppSettingsService _appSettingsService;
|
|
||||||
final DriftLocalAssetRepository _localAssetRepository;
|
|
||||||
final DriftTrashedLocalAssetRepository _trashedLocalAssetRepository;
|
|
||||||
final LocalFilesManagerRepository _localFilesManager;
|
|
||||||
final StorageRepository _storageRepository;
|
|
||||||
final Logger _logger = Logger('TrashService');
|
|
||||||
|
|
||||||
TrashSyncService({
|
|
||||||
required AppSettingsService appSettingsService,
|
|
||||||
required DriftLocalAssetRepository localAssetRepository,
|
|
||||||
required DriftTrashedLocalAssetRepository trashedLocalAssetRepository,
|
|
||||||
required LocalFilesManagerRepository localFilesManager,
|
|
||||||
required StorageRepository storageRepository,
|
|
||||||
}) : _appSettingsService = appSettingsService,
|
|
||||||
_localAssetRepository = localAssetRepository,
|
|
||||||
_trashedLocalAssetRepository = trashedLocalAssetRepository,
|
|
||||||
_localFilesManager = localFilesManager,
|
|
||||||
_storageRepository = storageRepository;
|
|
||||||
|
|
||||||
bool get isTrashSyncMode =>
|
|
||||||
CurrentPlatform.isAndroid && _appSettingsService.getSetting<bool>(AppSettingsEnum.manageLocalMediaAndroid);
|
|
||||||
|
|
||||||
Future<void> handleRemoteTrashed(Iterable<String> checksums) async {
|
|
||||||
if (checksums.isEmpty) {
|
|
||||||
return Future.value();
|
|
||||||
} else {
|
|
||||||
final localAssetsToTrash = await _localAssetRepository.getAssetsFromBackupAlbums(checksums);
|
|
||||||
if (localAssetsToTrash.isNotEmpty) {
|
|
||||||
final mediaUrls = await Future.wait(
|
|
||||||
localAssetsToTrash.values
|
|
||||||
.expand((e) => e)
|
|
||||||
.map((localAsset) => _storageRepository.getAssetEntityForAsset(localAsset).then((e) => e?.getMediaUrl())),
|
|
||||||
);
|
|
||||||
_logger.info("Moving to trash ${mediaUrls.join(", ")} assets");
|
|
||||||
final result = await _localFilesManager.moveToTrash(mediaUrls.nonNulls.toList());
|
|
||||||
if (result) {
|
|
||||||
await _trashedLocalAssetRepository.trashLocalAsset(localAssetsToTrash);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_logger.info("No assets found in backup-enabled albums for assets: $checksums");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/trashed_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
|
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
@ -23,10 +23,9 @@ class TrashedLocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TrashedLocalAssetEntityDataDomainExtension on TrashedLocalAssetEntityData {
|
extension TrashedLocalAssetEntityDataDomainExtension on TrashedLocalAssetEntityData {
|
||||||
TrashedAsset toDto() => TrashedAsset(
|
LocalAsset toLocalAsset() => LocalAsset(
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
albumId: albumId,
|
|
||||||
checksum: checksum,
|
checksum: checksum,
|
||||||
type: type,
|
type: type,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@ import 'package:collection/collection.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/trashed_asset.model.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
||||||
|
|
||||||
|
typedef TrashedAsset = ({String albumId, LocalAsset asset});
|
||||||
|
|
||||||
class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
|
|
||||||
|
|
@ -30,12 +31,12 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Iterable<TrashedAsset>> getAssetsToHash(Iterable<String> albumIds) {
|
Future<Iterable<LocalAsset>> getAssetsToHash(Iterable<String> albumIds) {
|
||||||
final query = _db.trashedLocalAssetEntity.select()..where((r) => r.albumId.isIn(albumIds) & r.checksum.isNull());
|
final query = _db.trashedLocalAssetEntity.select()..where((r) => r.albumId.isIn(albumIds) & r.checksum.isNull());
|
||||||
return query.map((row) => row.toDto()).get();
|
return query.map((row) => row.toLocalAsset()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Iterable<TrashedAsset>> getToRestore() async {
|
Future<Iterable<LocalAsset>> getToRestore() async {
|
||||||
final selectedAlbumIds = (_db.selectOnly(_db.localAlbumEntity)
|
final selectedAlbumIds = (_db.selectOnly(_db.localAlbumEntity)
|
||||||
..addColumns([_db.localAlbumEntity.id])
|
..addColumns([_db.localAlbumEntity.id])
|
||||||
..where(_db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected)));
|
..where(_db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected)));
|
||||||
|
|
@ -52,55 +53,54 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
return rows.map((result) => result.readTable(_db.trashedLocalAssetEntity).toDto());
|
return rows.map((result) => result.readTable(_db.trashedLocalAssetEntity).toLocalAsset());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies resulted snapshot of trashed assets:
|
/// Applies resulted snapshot of trashed assets:
|
||||||
/// - upserts incoming rows
|
/// - upserts incoming rows
|
||||||
/// - deletes rows that are not present in the snapshot
|
/// - deletes rows that are not present in the snapshot
|
||||||
Future<void> applyTrashSnapshot(Iterable<TrashedAsset> assets, String albumId) async {
|
Future<void> applyTrashSnapshot(Iterable<TrashedAsset> trashedAssets) async {
|
||||||
if (assets.isEmpty) {
|
if (trashedAssets.isEmpty) {
|
||||||
await _db.delete(_db.trashedLocalAssetEntity).go();
|
await _db.delete(_db.trashedLocalAssetEntity).go();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, String> localChecksumById = await _getCachedChecksums(assets);
|
final assetIds = trashedAssets.map((e) => e.asset.id).toSet();
|
||||||
|
Map<String, String> localChecksumById = await _getCachedChecksums(assetIds);
|
||||||
|
|
||||||
return _db.transaction(() async {
|
return _db.transaction(() async {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
for (final asset in assets) {
|
for (final item in trashedAssets) {
|
||||||
final effectiveChecksum = localChecksumById[asset.id] ?? asset.checksum;
|
final effectiveChecksum = localChecksumById[item.asset.id] ?? item.asset.checksum;
|
||||||
final companion = TrashedLocalAssetEntityCompanion.insert(
|
final companion = TrashedLocalAssetEntityCompanion.insert(
|
||||||
id: asset.id,
|
id: item.asset.id,
|
||||||
albumId: albumId,
|
albumId: item.albumId,
|
||||||
checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum),
|
checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum),
|
||||||
name: asset.name,
|
name: item.asset.name,
|
||||||
type: asset.type,
|
type: item.asset.type,
|
||||||
createdAt: Value(asset.createdAt),
|
createdAt: Value(item.asset.createdAt),
|
||||||
updatedAt: Value(asset.updatedAt),
|
updatedAt: Value(item.asset.updatedAt),
|
||||||
width: Value(asset.width),
|
width: Value(item.asset.width),
|
||||||
height: Value(asset.height),
|
height: Value(item.asset.height),
|
||||||
durationInSeconds: Value(asset.durationInSeconds),
|
durationInSeconds: Value(item.asset.durationInSeconds),
|
||||||
isFavorite: Value(asset.isFavorite),
|
isFavorite: Value(item.asset.isFavorite),
|
||||||
orientation: Value(asset.orientation),
|
orientation: Value(item.asset.orientation),
|
||||||
);
|
);
|
||||||
|
|
||||||
batch.insert<$TrashedLocalAssetEntityTable, TrashedLocalAssetEntityData>(
|
batch.insert<$TrashedLocalAssetEntityTable, TrashedLocalAssetEntityData>(
|
||||||
_db.trashedLocalAssetEntity,
|
_db.trashedLocalAssetEntity,
|
||||||
companion,
|
companion,
|
||||||
onConflict: DoUpdate((_) => companion, where: (old) => old.updatedAt.isNotValue(asset.updatedAt)),
|
onConflict: DoUpdate((_) => companion, where: (old) => old.updatedAt.isNotValue(item.asset.updatedAt)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final keepIds = assets.map((asset) => asset.id);
|
if (assetIds.length <= 32000) {
|
||||||
|
await (_db.delete(_db.trashedLocalAssetEntity)..where((row) => row.id.isNotIn(assetIds))).go();
|
||||||
if (keepIds.length <= 32000) {
|
|
||||||
await (_db.delete(_db.trashedLocalAssetEntity)..where((row) => row.id.isNotIn(keepIds))).go();
|
|
||||||
} else {
|
} else {
|
||||||
final keepIdsSet = keepIds.toSet();
|
|
||||||
final existingIds = await (_db.selectOnly(
|
final existingIds = await (_db.selectOnly(
|
||||||
_db.trashedLocalAssetEntity,
|
_db.trashedLocalAssetEntity,
|
||||||
)..addColumns([_db.trashedLocalAssetEntity.id])).map((r) => r.read(_db.trashedLocalAssetEntity.id)!).get();
|
)..addColumns([_db.trashedLocalAssetEntity.id])).map((r) => r.read(_db.trashedLocalAssetEntity.id)!).get();
|
||||||
final idToDelete = existingIds.where((id) => !keepIdsSet.contains(id));
|
final idToDelete = existingIds.where((id) => !assetIds.contains(id));
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
for (final id in idToDelete) {
|
for (final id in idToDelete) {
|
||||||
batch.deleteWhere(_db.trashedLocalAssetEntity, (row) => row.id.equals(id));
|
batch.deleteWhere(_db.trashedLocalAssetEntity, (row) => row.id.equals(id));
|
||||||
|
|
@ -110,33 +110,33 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveTrashedAssets(Iterable<TrashedAsset> assets) async {
|
Future<void> applyDelta(Iterable<TrashedAsset> trashedAssets) async {
|
||||||
if (assets.isEmpty) {
|
if (trashedAssets.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final assetIds = trashedAssets.map((e) => e.asset.id).toSet();
|
||||||
Map<String, String> localChecksumById = await _getCachedChecksums(assets);
|
Map<String, String> localChecksumById = await _getCachedChecksums(assetIds);
|
||||||
|
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
for (final asset in assets) {
|
for (final item in trashedAssets) {
|
||||||
final effectiveChecksum = localChecksumById[asset.id] ?? asset.checksum;
|
final effectiveChecksum = localChecksumById[item.asset.id] ?? item.asset.checksum;
|
||||||
final companion = TrashedLocalAssetEntityCompanion.insert(
|
final companion = TrashedLocalAssetEntityCompanion.insert(
|
||||||
id: asset.id,
|
id: item.asset.id,
|
||||||
albumId: asset.albumId,
|
albumId: item.albumId,
|
||||||
name: asset.name,
|
name: item.asset.name,
|
||||||
type: asset.type,
|
type: item.asset.type,
|
||||||
checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum),
|
checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum),
|
||||||
createdAt: Value(asset.createdAt),
|
createdAt: Value(item.asset.createdAt),
|
||||||
width: Value(asset.width),
|
width: Value(item.asset.width),
|
||||||
height: Value(asset.height),
|
height: Value(item.asset.height),
|
||||||
durationInSeconds: Value(asset.durationInSeconds),
|
durationInSeconds: Value(item.asset.durationInSeconds),
|
||||||
isFavorite: Value(asset.isFavorite),
|
isFavorite: Value(item.asset.isFavorite),
|
||||||
orientation: Value(asset.orientation),
|
orientation: Value(item.asset.orientation),
|
||||||
);
|
);
|
||||||
batch.insert<$TrashedLocalAssetEntityTable, TrashedLocalAssetEntityData>(
|
batch.insert<$TrashedLocalAssetEntityTable, TrashedLocalAssetEntityData>(
|
||||||
_db.trashedLocalAssetEntity,
|
_db.trashedLocalAssetEntity,
|
||||||
companion,
|
companion,
|
||||||
onConflict: DoUpdate((_) => companion, where: (old) => old.updatedAt.isNotValue(asset.updatedAt)),
|
onConflict: DoUpdate((_) => companion, where: (old) => old.updatedAt.isNotValue(item.asset.updatedAt)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -171,7 +171,7 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||||
TrashedLocalAssetEntityCompanion(
|
TrashedLocalAssetEntityCompanion(
|
||||||
id: Value(asset.id),
|
id: Value(asset.id),
|
||||||
name: Value(asset.name),
|
name: Value(asset.name),
|
||||||
albumId: Value(entry.key),
|
// albumId: Value(entry.key),
|
||||||
checksum: asset.checksum == null ? const Value.absent() : Value(asset.checksum),
|
checksum: asset.checksum == null ? const Value.absent() : Value(asset.checksum),
|
||||||
type: Value(asset.type),
|
type: Value(asset.type),
|
||||||
width: Value(asset.width),
|
width: Value(asset.width),
|
||||||
|
|
@ -237,17 +237,21 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
//attempt to reuse existing checksums
|
//attempt to reuse existing checksums
|
||||||
Future<Map<String, String>> _getCachedChecksums(Iterable<TrashedAsset> trashUpdates) async {
|
Future<Map<String, String>> _getCachedChecksums(Set<String> assetIds) async {
|
||||||
final ids = trashUpdates.map((e) => e.id).toSet();
|
final localChecksumById = <String, String>{};
|
||||||
final rows =
|
|
||||||
await (_db.selectOnly(_db.localAssetEntity)
|
for (final slice in assetIds.slices(32000)) {
|
||||||
..where(_db.localAssetEntity.id.isIn(ids) & _db.localAssetEntity.checksum.isNotNull())
|
final rows =
|
||||||
..addColumns([_db.localAssetEntity.id, _db.localAssetEntity.checksum]))
|
await (_db.selectOnly(_db.localAssetEntity)
|
||||||
.get();
|
..where(_db.localAssetEntity.id.isIn(slice) & _db.localAssetEntity.checksum.isNotNull())
|
||||||
|
..addColumns([_db.localAssetEntity.id, _db.localAssetEntity.checksum]))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
for (final r in rows) {
|
||||||
|
localChecksumById[r.read(_db.localAssetEntity.id)!] = r.read(_db.localAssetEntity.checksum)!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final localChecksumById = {
|
|
||||||
for (final r in rows) r.read(_db.localAssetEntity.id)!: r.read(_db.localAssetEntity.checksum)!,
|
|
||||||
};
|
|
||||||
return localChecksumById;
|
return localChecksumById;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue