156 lines
4.5 KiB
Dart
156 lines
4.5 KiB
Dart
// lib/remote/collection_source_remote_ext.dart
|
|
|
|
import 'package:aves/model/entry/entry.dart';
|
|
import 'package:aves/model/source/collection_source.dart';
|
|
import 'package:aves/model/source/events.dart';
|
|
import 'package:aves/services/common/services.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'remote_origin.dart';
|
|
import 'package:aves/remote/remote_sync_bus.dart';
|
|
|
|
extension CollectionSourceRemoteExt on CollectionSource {
|
|
// ============================================================
|
|
// CACHE INTERNA (PRO)
|
|
// ============================================================
|
|
|
|
static Map<String, AvesEntry> _cacheMem = {};
|
|
static Map<String, AvesEntry> _cacheDb = {};
|
|
static bool _cacheValid = false;
|
|
|
|
void _rebuildCacheFromMemory() {
|
|
_cacheMem = {
|
|
for (final e in allEntries)
|
|
if (e.origin == RemoteOrigin.value &&
|
|
!e.trashed &&
|
|
e.remoteId != null &&
|
|
e.remoteId!.isNotEmpty)
|
|
e.remoteId!: e,
|
|
};
|
|
_cacheValid = true;
|
|
}
|
|
|
|
// ============================================================
|
|
// SYNC REMOTI (DIFF PRO)
|
|
// ============================================================
|
|
|
|
Future<void> appendRemoteEntriesFromDb() async {
|
|
// 1) carica dal DB tutte le entry remote
|
|
final Set<AvesEntry> remotiDb =
|
|
await localMediaDb.loadEntries(origin: RemoteOrigin.value);
|
|
|
|
// costruisci cache DB
|
|
_cacheDb = {
|
|
for (final e in remotiDb)
|
|
if (e.remoteId != null && e.remoteId!.isNotEmpty) e.remoteId!: e,
|
|
};
|
|
|
|
// costruisci cache memoria se non valida
|
|
if (!_cacheValid) {
|
|
_rebuildCacheFromMemory();
|
|
}
|
|
|
|
// 2) diff
|
|
final idsDb = _cacheDb.keys.toSet();
|
|
final idsMem = _cacheMem.keys.toSet();
|
|
|
|
final idsToAdd = idsDb.difference(idsMem);
|
|
final idsToRemove = idsMem.difference(idsDb);
|
|
|
|
// UPDATE: remoti presenti in entrambi ma con metadata cambiati
|
|
final idsToUpdate = <String>{};
|
|
for (final id in idsDb.intersection(idsMem)) {
|
|
final db = _cacheDb[id]!;
|
|
final mem = _cacheMem[id]!;
|
|
|
|
if (db.dateModifiedMillis != mem.dateModifiedMillis ||
|
|
db.sizeBytes != mem.sizeBytes ||
|
|
db.remoteRotation != mem.remoteRotation ||
|
|
db.width != mem.width ||
|
|
db.height != mem.height) {
|
|
idsToUpdate.add(id);
|
|
}
|
|
}
|
|
|
|
debugPrint(
|
|
'[remote-diff-pro] add=${idsToAdd.length} del=${idsToRemove.length} upd=${idsToUpdate.length}');
|
|
|
|
// ============================================================
|
|
// APPLY DEL
|
|
// ============================================================
|
|
|
|
if (idsToRemove.isNotEmpty) {
|
|
final urisToRemove = idsToRemove
|
|
.map((id) => _cacheMem[id]?.uri)
|
|
.whereType<String>()
|
|
.toSet();
|
|
|
|
removeEntries(
|
|
urisToRemove,
|
|
includeTrash: false,
|
|
);
|
|
|
|
// aggiorna cache
|
|
for (final id in idsToRemove) {
|
|
_cacheMem.remove(id);
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// APPLY ADD
|
|
// ============================================================
|
|
|
|
if (idsToAdd.isNotEmpty) {
|
|
final toAdd = idsToAdd.map((id) => _cacheDb[id]!).toSet();
|
|
addEntries(toAdd);
|
|
|
|
// aggiorna cache
|
|
for (final e in toAdd) {
|
|
_cacheMem[e.remoteId!] = e;
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// APPLY UPDATE
|
|
// ============================================================
|
|
|
|
if (idsToUpdate.isNotEmpty) {
|
|
final toUpdate = idsToUpdate.map((id) => _cacheDb[id]!).toSet();
|
|
|
|
await refreshEntries(
|
|
toUpdate,
|
|
EntryDataType.values.toSet(),
|
|
);
|
|
|
|
// aggiorna cache
|
|
for (final e in toUpdate) {
|
|
_cacheMem[e.remoteId!] = e;
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// NOTIFICA LENS
|
|
// ============================================================
|
|
|
|
if (idsToAdd.isNotEmpty) {
|
|
eventBus.fire(
|
|
EntryAddedEvent(idsToAdd.map((id) => _cacheDb[id]!).toSet()),
|
|
);
|
|
}
|
|
|
|
if (idsToRemove.isNotEmpty || idsToUpdate.isNotEmpty) {
|
|
eventBus.fire(EntryRefreshedEvent(const {}));
|
|
}
|
|
|
|
debugPrint('[remote-diff-pro] done: mem=${_cacheMem.length}');
|
|
}
|
|
}
|
|
|
|
/// Visibilità dei remoti (usata da CollectionLens)
|
|
extension RemoteVisibilityExt on CollectionSource {
|
|
bool get remoteVisible {
|
|
final state = RemoteSyncBus.instance.stateNotifier.value;
|
|
return state == RemoteSyncState.syncing ||
|
|
state == RemoteSyncState.upToDate;
|
|
}
|
|
}
|