#971 duplicate detection
This commit is contained in:
parent
2c41e82444
commit
306025380f
23 changed files with 179 additions and 121 deletions
|
@ -32,7 +32,7 @@ class Covers {
|
|||
Covers._private();
|
||||
|
||||
Future<void> init() async {
|
||||
_rows = await metadataDb.loadAllCovers();
|
||||
_rows = await localMediaDb.loadAllCovers();
|
||||
}
|
||||
|
||||
int get count => _rows.length;
|
||||
|
@ -59,7 +59,7 @@ class Covers {
|
|||
|
||||
final oldRows = _rows.where((row) => row.filter == filter).toSet();
|
||||
_rows.removeAll(oldRows);
|
||||
await metadataDb.removeCovers({filter});
|
||||
await localMediaDb.removeCovers({filter});
|
||||
|
||||
final oldRow = oldRows.firstOrNull;
|
||||
final oldEntry = oldRow?.entryId;
|
||||
|
@ -74,7 +74,7 @@ class Covers {
|
|||
color: color,
|
||||
);
|
||||
_rows.add(row);
|
||||
await metadataDb.addCovers({row});
|
||||
await localMediaDb.addCovers({row});
|
||||
}
|
||||
|
||||
if (oldEntry != entryId) _entryChangeStreamController.add({filter});
|
||||
|
@ -103,7 +103,7 @@ class Covers {
|
|||
}
|
||||
|
||||
Future<void> clear() async {
|
||||
await metadataDb.clearCovers();
|
||||
await localMediaDb.clearCovers();
|
||||
_rows.clear();
|
||||
|
||||
_entryChangeStreamController.add(null);
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:aves/model/metadata/trash.dart';
|
|||
import 'package:aves/model/vaults/details.dart';
|
||||
import 'package:aves/model/viewer/video_playback.dart';
|
||||
|
||||
abstract class MetadataDb {
|
||||
abstract class LocalMediaDb {
|
||||
int get nextId;
|
||||
|
||||
Future<void> init();
|
||||
|
@ -27,12 +27,14 @@ abstract class MetadataDb {
|
|||
|
||||
Future<Set<AvesEntry>> loadEntriesById(Set<int> ids);
|
||||
|
||||
Future<void> saveEntries(Set<AvesEntry> entries);
|
||||
Future<void> insertEntries(Set<AvesEntry> entries);
|
||||
|
||||
Future<void> updateEntry(int id, AvesEntry entry);
|
||||
|
||||
Future<Set<AvesEntry>> searchLiveEntries(String query, {int? limit});
|
||||
|
||||
Future<Set<AvesEntry>> searchLiveDuplicates(int origin, Set<AvesEntry>? entries);
|
||||
|
||||
// date taken
|
||||
|
||||
Future<void> clearDates();
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/db/db_metadata_sqflite_upgrade.dart';
|
||||
import 'package:aves/model/db/db.dart';
|
||||
import 'package:aves/model/db/db_sqflite_upgrade.dart';
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
@ -16,7 +16,7 @@ import 'package:collection/collection.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class SqfliteMetadataDb implements MetadataDb {
|
||||
class SqfliteLocalMediaDb implements LocalMediaDb {
|
||||
late Database _db;
|
||||
|
||||
Future<String> get path async => pContext.join(await getDatabasesPath(), 'metadata.db');
|
||||
|
@ -108,7 +108,7 @@ class SqfliteMetadataDb implements MetadataDb {
|
|||
', resumeTimeMillis INTEGER'
|
||||
')');
|
||||
},
|
||||
onUpgrade: MetadataDbUpgrader.upgradeDb,
|
||||
onUpgrade: LocalMediaDbUpgrader.upgradeDb,
|
||||
version: 11,
|
||||
);
|
||||
|
||||
|
@ -209,7 +209,7 @@ class SqfliteMetadataDb implements MetadataDb {
|
|||
Future<Set<AvesEntry>> loadEntriesById(Set<int> ids) => _getByIds(ids, entryTable, AvesEntry.fromMap);
|
||||
|
||||
@override
|
||||
Future<void> saveEntries(Set<AvesEntry> entries) async {
|
||||
Future<void> insertEntries(Set<AvesEntry> entries) async {
|
||||
if (entries.isEmpty) return;
|
||||
final stopwatch = Stopwatch()..start();
|
||||
final batch = _db.batch();
|
||||
|
@ -246,6 +246,35 @@ class SqfliteMetadataDb implements MetadataDb {
|
|||
return rows.map(AvesEntry.fromMap).toSet();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Set<AvesEntry>> searchLiveDuplicates(int origin, Set<AvesEntry>? entries) async {
|
||||
String where = 'origin = ? AND trashed = ?';
|
||||
if (entries != null) {
|
||||
where += ' AND contentId IN (${entries.map((v) => v.contentId).join(',')})';
|
||||
}
|
||||
final rows = await _db.query(
|
||||
entryTable,
|
||||
where: where,
|
||||
whereArgs: [origin, 0],
|
||||
groupBy: 'contentId',
|
||||
having: 'COUNT(id) > 1',
|
||||
);
|
||||
final duplicates = rows.map(AvesEntry.fromMap).toSet();
|
||||
if (duplicates.isEmpty) {
|
||||
return {};
|
||||
}
|
||||
|
||||
debugPrint('Found duplicates=$duplicates');
|
||||
if (entries != null) {
|
||||
// return duplicates among the provided entries
|
||||
final duplicateIds = duplicates.map((v) => v.id).toSet();
|
||||
return entries.where((v) => duplicateIds.contains(v.id)).toSet();
|
||||
} else {
|
||||
// return latest duplicates for each content ID
|
||||
return duplicates.groupFoldBy<int?, AvesEntry>((v) => v.contentId, (prev, v) => prev != null && prev.id > v.id ? prev : v).values.toSet();
|
||||
}
|
||||
}
|
||||
|
||||
// date taken
|
||||
|
||||
@override
|
|
@ -1,18 +1,18 @@
|
|||
import 'package:aves/model/db/db_metadata_sqflite.dart';
|
||||
import 'package:aves/model/db/db_sqflite.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class MetadataDbUpgrader {
|
||||
static const entryTable = SqfliteMetadataDb.entryTable;
|
||||
static const dateTakenTable = SqfliteMetadataDb.dateTakenTable;
|
||||
static const metadataTable = SqfliteMetadataDb.metadataTable;
|
||||
static const addressTable = SqfliteMetadataDb.addressTable;
|
||||
static const favouriteTable = SqfliteMetadataDb.favouriteTable;
|
||||
static const coverTable = SqfliteMetadataDb.coverTable;
|
||||
static const vaultTable = SqfliteMetadataDb.vaultTable;
|
||||
static const trashTable = SqfliteMetadataDb.trashTable;
|
||||
static const videoPlaybackTable = SqfliteMetadataDb.videoPlaybackTable;
|
||||
class LocalMediaDbUpgrader {
|
||||
static const entryTable = SqfliteLocalMediaDb.entryTable;
|
||||
static const dateTakenTable = SqfliteLocalMediaDb.dateTakenTable;
|
||||
static const metadataTable = SqfliteLocalMediaDb.metadataTable;
|
||||
static const addressTable = SqfliteLocalMediaDb.addressTable;
|
||||
static const favouriteTable = SqfliteLocalMediaDb.favouriteTable;
|
||||
static const coverTable = SqfliteLocalMediaDb.coverTable;
|
||||
static const vaultTable = SqfliteLocalMediaDb.vaultTable;
|
||||
static const trashTable = SqfliteLocalMediaDb.trashTable;
|
||||
static const videoPlaybackTable = SqfliteLocalMediaDb.videoPlaybackTable;
|
||||
|
||||
// warning: "ALTER TABLE ... RENAME COLUMN ..." is not supported
|
||||
// on SQLite <3.25.0, bundled on older Android devices
|
|
@ -432,8 +432,8 @@ class AvesEntry with AvesEntryBase {
|
|||
if (isFlipped is bool) this.isFlipped = isFlipped;
|
||||
|
||||
if (persist) {
|
||||
await metadataDb.saveEntries({this});
|
||||
if (catalogMetadata != null) await metadataDb.saveCatalogMetadata({catalogMetadata!});
|
||||
await localMediaDb.updateEntry(id, this);
|
||||
if (catalogMetadata != null) await localMediaDb.saveCatalogMetadata({catalogMetadata!});
|
||||
}
|
||||
|
||||
await _onVisualFieldChanged(oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
|
||||
|
@ -451,7 +451,7 @@ class AvesEntry with AvesEntryBase {
|
|||
_tags = null;
|
||||
|
||||
if (persist) {
|
||||
await metadataDb.removeIds({id}, dataTypes: dataTypes);
|
||||
await localMediaDb.removeIds({id}, dataTypes: dataTypes);
|
||||
}
|
||||
|
||||
final updatedEntry = await mediaFetchService.getEntry(uri, mimeType);
|
||||
|
|
|
@ -15,7 +15,7 @@ class Favourites with ChangeNotifier {
|
|||
Favourites._private();
|
||||
|
||||
Future<void> init() async {
|
||||
_rows = await metadataDb.loadAllFavourites();
|
||||
_rows = await localMediaDb.loadAllFavourites();
|
||||
}
|
||||
|
||||
int get count => _rows.length;
|
||||
|
@ -29,7 +29,7 @@ class Favourites with ChangeNotifier {
|
|||
Future<void> add(Set<AvesEntry> entries) async {
|
||||
final newRows = entries.map(_entryToRow).toSet();
|
||||
|
||||
await metadataDb.addFavourites(newRows);
|
||||
await localMediaDb.addFavourites(newRows);
|
||||
_rows.addAll(newRows);
|
||||
|
||||
notifyListeners();
|
||||
|
@ -40,14 +40,14 @@ class Favourites with ChangeNotifier {
|
|||
Future<void> removeIds(Set<int> entryIds) async {
|
||||
final removedRows = _rows.where((row) => entryIds.contains(row.entryId)).toSet();
|
||||
|
||||
await metadataDb.removeFavourites(removedRows);
|
||||
await localMediaDb.removeFavourites(removedRows);
|
||||
removedRows.forEach(_rows.remove);
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> clear() async {
|
||||
await metadataDb.clearFavourites();
|
||||
await localMediaDb.clearFavourites();
|
||||
_rows.clear();
|
||||
|
||||
notifyListeners();
|
||||
|
|
|
@ -136,7 +136,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
late Map<int?, int?> _savedDates;
|
||||
|
||||
Future<void> loadDates() async {
|
||||
_savedDates = Map.unmodifiable(await metadataDb.loadDates());
|
||||
_savedDates = Map.unmodifiable(await localMediaDb.loadDates());
|
||||
}
|
||||
|
||||
Set<CollectionFilter> _getAppHiddenFilters() => {
|
||||
|
@ -217,7 +217,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
final ids = entries.map((entry) => entry.id).toSet();
|
||||
await favourites.removeIds(ids);
|
||||
await covers.removeIds(ids);
|
||||
await metadataDb.removeIds(ids);
|
||||
await localMediaDb.removeIds(ids);
|
||||
|
||||
ids.forEach((id) => _entryById.remove);
|
||||
_rawEntries.removeAll(entries);
|
||||
|
@ -278,10 +278,10 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
if (persist) {
|
||||
await covers.moveEntry(entry);
|
||||
final id = entry.id;
|
||||
await metadataDb.updateEntry(id, entry);
|
||||
await metadataDb.updateCatalogMetadata(id, entry.catalogMetadata);
|
||||
await metadataDb.updateAddress(id, entry.addressDetails);
|
||||
await metadataDb.updateTrash(id, entry.trashDetails);
|
||||
await localMediaDb.updateEntry(id, entry);
|
||||
await localMediaDb.updateCatalogMetadata(id, entry.catalogMetadata);
|
||||
await localMediaDb.updateAddress(id, entry.addressDetails);
|
||||
await localMediaDb.updateTrash(id, entry.trashDetails);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +352,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
if (sourceEntry != null) {
|
||||
fromAlbums.add(sourceEntry.directory);
|
||||
movedEntries.add(sourceEntry.copyWith(
|
||||
id: metadataDb.nextId,
|
||||
id: localMediaDb.nextId,
|
||||
uri: newFields['uri'] as String?,
|
||||
path: newFields['path'] as String?,
|
||||
contentId: newFields['contentId'] as int?,
|
||||
|
@ -366,9 +366,9 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
debugPrint('failed to find source entry with uri=$sourceUri');
|
||||
}
|
||||
});
|
||||
await metadataDb.saveEntries(movedEntries);
|
||||
await metadataDb.saveCatalogMetadata(movedEntries.map((entry) => entry.catalogMetadata).whereNotNull().toSet());
|
||||
await metadataDb.saveAddresses(movedEntries.map((entry) => entry.addressDetails).whereNotNull().toSet());
|
||||
await localMediaDb.insertEntries(movedEntries);
|
||||
await localMediaDb.saveCatalogMetadata(movedEntries.map((entry) => entry.catalogMetadata).whereNotNull().toSet());
|
||||
await localMediaDb.saveAddresses(movedEntries.map((entry) => entry.addressDetails).whereNotNull().toSet());
|
||||
} else {
|
||||
await Future.forEach<MoveOpEvent>(movedOps, (movedOp) async {
|
||||
final newFields = movedOp.newFields;
|
||||
|
@ -455,7 +455,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
await deviceService.requestGarbageCollection();
|
||||
await Future.forEach(entries, (entry) async {
|
||||
await entry.catalog(background: background, force: dataTypes.contains(EntryDataType.catalog), persist: persist);
|
||||
await metadataDb.updateCatalogMetadata(entry.id, entry.catalogMetadata);
|
||||
await localMediaDb.updateCatalogMetadata(entry.id, entry.catalogMetadata);
|
||||
});
|
||||
onCatalogMetadataChanged();
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
|||
if (dataTypes.contains(EntryDataType.address)) {
|
||||
await Future.forEach(entries, (entry) async {
|
||||
await entry.locate(background: background, force: dataTypes.contains(EntryDataType.address), geocoderLocale: settings.appliedLocale);
|
||||
await metadataDb.updateAddress(entry.id, entry.addressDetails);
|
||||
await localMediaDb.updateAddress(entry.id, entry.addressDetails);
|
||||
});
|
||||
onAddressMetadataChanged();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ mixin LocationMixin on CountryMixin, StateMixin {
|
|||
List<String> sortedPlaces = List.unmodifiable([]);
|
||||
|
||||
Future<void> loadAddresses({Set<int>? ids}) async {
|
||||
final saved = await (ids != null ? metadataDb.loadAddressesById(ids) : metadataDb.loadAddresses());
|
||||
final saved = await (ids != null ? localMediaDb.loadAddressesById(ids) : localMediaDb.loadAddresses());
|
||||
final idMap = entryById;
|
||||
saved.forEach((metadata) => idMap[metadata.id]?.addressDetails = metadata);
|
||||
invalidateEntries();
|
||||
|
@ -37,7 +37,7 @@ mixin LocationMixin on CountryMixin, StateMixin {
|
|||
|
||||
final unlocatedIds = candidateEntries.where((entry) => !entry.hasGps).map((entry) => entry.id).toSet();
|
||||
if (unlocatedIds.isNotEmpty) {
|
||||
await metadataDb.removeIds(unlocatedIds, dataTypes: {EntryDataType.address});
|
||||
await localMediaDb.removeIds(unlocatedIds, dataTypes: {EntryDataType.address});
|
||||
onAddressMetadataChanged();
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ mixin LocationMixin on CountryMixin, StateMixin {
|
|||
setProgress(done: ++progressDone, total: progressTotal);
|
||||
});
|
||||
if (newAddresses.isNotEmpty) {
|
||||
await metadataDb.saveAddresses(Set.unmodifiable(newAddresses));
|
||||
await localMediaDb.saveAddresses(Set.unmodifiable(newAddresses));
|
||||
onAddressMetadataChanged();
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ mixin LocationMixin on CountryMixin, StateMixin {
|
|||
if (entry.hasFineAddress) {
|
||||
newAddresses.add(entry.addressDetails!);
|
||||
if (newAddresses.length >= commitCountThreshold) {
|
||||
await metadataDb.saveAddresses(Set.unmodifiable(newAddresses));
|
||||
await localMediaDb.saveAddresses(Set.unmodifiable(newAddresses));
|
||||
onAddressMetadataChanged();
|
||||
newAddresses.clear();
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ mixin LocationMixin on CountryMixin, StateMixin {
|
|||
setProgress(done: ++progressDone, total: progressTotal);
|
||||
}
|
||||
if (newAddresses.isNotEmpty) {
|
||||
await metadataDb.saveAddresses(Set.unmodifiable(newAddresses));
|
||||
await localMediaDb.saveAddresses(Set.unmodifiable(newAddresses));
|
||||
onAddressMetadataChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ class MediaStoreSource extends CollectionSource {
|
|||
Future<void> _loadEssentials() async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
state = SourceState.loading;
|
||||
await metadataDb.init();
|
||||
await localMediaDb.init();
|
||||
await vaults.init();
|
||||
await favourites.init();
|
||||
await covers.init();
|
||||
|
@ -67,8 +67,8 @@ class MediaStoreSource extends CollectionSource {
|
|||
if (currentTimeZoneOffset != catalogTimeZoneOffset) {
|
||||
// clear catalog metadata to get correct date/times when moving to a different time zone
|
||||
debugPrint('$runtimeType clear catalog metadata to get correct date/times');
|
||||
await metadataDb.clearDates();
|
||||
await metadataDb.clearCatalogMetadata();
|
||||
await localMediaDb.clearDates();
|
||||
await localMediaDb.clearCatalogMetadata();
|
||||
settings.catalogTimeZoneRawOffsetMillis = currentTimeZoneOffset;
|
||||
}
|
||||
}
|
||||
|
@ -92,13 +92,13 @@ class MediaStoreSource extends CollectionSource {
|
|||
final topIds = settings.topEntryIds?.toSet();
|
||||
if (topIds != null) {
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} load ${topIds.length} top entries');
|
||||
topEntries.addAll(await metadataDb.loadEntriesById(topIds));
|
||||
topEntries.addAll(await localMediaDb.loadEntriesById(topIds));
|
||||
addEntries(topEntries);
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} fetch known entries');
|
||||
final knownEntries = await metadataDb.loadEntries(origin: EntryOrigins.mediaStoreContent, directory: directory);
|
||||
final knownEntries = await localMediaDb.loadEntries(origin: EntryOrigins.mediaStoreContent, directory: directory);
|
||||
final knownLiveEntries = knownEntries.where((entry) => !entry.trashed).toSet();
|
||||
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} check obsolete entries');
|
||||
|
@ -146,7 +146,7 @@ class MediaStoreSource extends CollectionSource {
|
|||
// clean up obsolete entries
|
||||
if (removedEntries.isNotEmpty) {
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} remove obsolete entries');
|
||||
await metadataDb.removeIds(removedEntries.map((entry) => entry.id).toSet());
|
||||
await localMediaDb.removeIds(removedEntries.map((entry) => entry.id).toSet());
|
||||
}
|
||||
|
||||
// verify paths because some apps move files without updating their `last modified date`
|
||||
|
@ -185,7 +185,7 @@ class MediaStoreSource extends CollectionSource {
|
|||
// reuse known entry ID to overwrite it while preserving favourites, etc.
|
||||
final contentId = entry.contentId;
|
||||
final existingEntry = knownContentIds.contains(contentId) ? knownLiveEntries.firstWhereOrNull((entry) => entry.contentId == contentId) : null;
|
||||
entry.id = existingEntry?.id ?? metadataDb.nextId;
|
||||
entry.id = existingEntry?.id ?? localMediaDb.nextId;
|
||||
|
||||
pendingNewEntries.add(entry);
|
||||
if (pendingNewEntries.length >= refreshCount) {
|
||||
|
@ -198,7 +198,13 @@ class MediaStoreSource extends CollectionSource {
|
|||
|
||||
if (allNewEntries.isNotEmpty) {
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} save new entries');
|
||||
await metadataDb.saveEntries(allNewEntries);
|
||||
await localMediaDb.insertEntries(allNewEntries);
|
||||
|
||||
// TODO TLAD [971] check duplicates
|
||||
final duplicates = await localMediaDb.searchLiveDuplicates(EntryOrigins.mediaStoreContent, allNewEntries);
|
||||
if (duplicates.isNotEmpty) {
|
||||
unawaited(reportService.recordError(Exception('Loading entries yielded duplicates=${duplicates.join(', ')}'), StackTrace.current));
|
||||
}
|
||||
|
||||
// new entries include existing entries with obsolete paths
|
||||
// so directories may be added, but also removed or simply have their content summary changed
|
||||
|
@ -276,7 +282,7 @@ class MediaStoreSource extends CollectionSource {
|
|||
if (existingEntry != null) {
|
||||
entriesToRefresh.add(existingEntry);
|
||||
} else {
|
||||
sourceEntry.id = metadataDb.nextId;
|
||||
sourceEntry.id = localMediaDb.nextId;
|
||||
newEntries.add(sourceEntry);
|
||||
}
|
||||
final existingDirectory = existingEntry?.directory;
|
||||
|
@ -304,7 +310,14 @@ class MediaStoreSource extends CollectionSource {
|
|||
|
||||
if (newEntries.isNotEmpty) {
|
||||
addEntries(newEntries);
|
||||
await metadataDb.saveEntries(newEntries);
|
||||
await localMediaDb.insertEntries(newEntries);
|
||||
|
||||
// TODO TLAD [971] check duplicates
|
||||
final duplicates = await localMediaDb.searchLiveDuplicates(EntryOrigins.mediaStoreContent, newEntries);
|
||||
if (duplicates.isNotEmpty) {
|
||||
unawaited(reportService.recordError(Exception('Refreshing entries yielded duplicates=${duplicates.join(', ')}'), StackTrace.current));
|
||||
}
|
||||
|
||||
await analyze(analysisController, entries: newEntries);
|
||||
}
|
||||
|
||||
|
@ -346,7 +359,7 @@ class MediaStoreSource extends CollectionSource {
|
|||
// vault
|
||||
|
||||
Future<void> _loadVaultEntries(String? directory) async {
|
||||
addEntries(await metadataDb.loadEntries(origin: EntryOrigins.vault, directory: directory));
|
||||
addEntries(await localMediaDb.loadEntries(origin: EntryOrigins.vault, directory: directory));
|
||||
}
|
||||
|
||||
Future<void> _refreshVaultEntries({
|
||||
|
@ -367,7 +380,7 @@ class MediaStoreSource extends CollectionSource {
|
|||
final sourceEntry = await mediaFetchService.getEntry(uri, null, allowUnsized: true);
|
||||
if (sourceEntry != null) {
|
||||
newEntries.add(sourceEntry.copyWith(
|
||||
id: metadataDb.nextId,
|
||||
id: localMediaDb.nextId,
|
||||
origin: EntryOrigins.vault,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ mixin TagMixin on SourceBase {
|
|||
List<String> sortedTags = List.unmodifiable([]);
|
||||
|
||||
Future<void> loadCatalogMetadata({Set<int>? ids}) async {
|
||||
final saved = await (ids != null ? metadataDb.loadCatalogMetadataById(ids) : metadataDb.loadCatalogMetadata());
|
||||
final saved = await (ids != null ? localMediaDb.loadCatalogMetadataById(ids) : localMediaDb.loadCatalogMetadata());
|
||||
final idMap = entryById;
|
||||
saved.forEach((metadata) => idMap[metadata.id]?.catalogMetadata = metadata);
|
||||
invalidateEntries();
|
||||
|
@ -48,7 +48,7 @@ mixin TagMixin on SourceBase {
|
|||
if (entry.isCatalogued) {
|
||||
newMetadata.add(entry.catalogMetadata!);
|
||||
if (newMetadata.length >= commitCountThreshold) {
|
||||
await metadataDb.saveCatalogMetadata(Set.unmodifiable(newMetadata));
|
||||
await localMediaDb.saveCatalogMetadata(Set.unmodifiable(newMetadata));
|
||||
onCatalogMetadataChanged();
|
||||
newMetadata.clear();
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ mixin TagMixin on SourceBase {
|
|||
}
|
||||
setProgress(done: ++progressDone, total: progressTotal);
|
||||
}
|
||||
await metadataDb.saveCatalogMetadata(Set.unmodifiable(newMetadata));
|
||||
await localMediaDb.saveCatalogMetadata(Set.unmodifiable(newMetadata));
|
||||
onCatalogMetadataChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ mixin TrashMixin on SourceBase {
|
|||
static const Duration binKeepDuration = Duration(days: 30);
|
||||
|
||||
Future<void> loadTrashDetails() async {
|
||||
final saved = await metadataDb.loadAllTrashDetails();
|
||||
final saved = await localMediaDb.loadAllTrashDetails();
|
||||
final idMap = entryById;
|
||||
saved.forEach((details) => idMap[details.id]?.trashDetails = details);
|
||||
}
|
||||
|
@ -63,13 +63,13 @@ mixin TrashMixin on SourceBase {
|
|||
entry.trashed = true;
|
||||
entry.trashDetails = _buildTrashDetails(id);
|
||||
// persist
|
||||
await metadataDb.updateEntry(id, entry);
|
||||
await metadataDb.updateTrash(id, entry.trashDetails);
|
||||
await localMediaDb.updateEntry(id, entry);
|
||||
await localMediaDb.updateTrash(id, entry.trashDetails);
|
||||
} else {
|
||||
// there is no matching entry
|
||||
final sourceEntry = await mediaFetchService.getEntry(uri, null, allowUnsized: true);
|
||||
if (sourceEntry != null) {
|
||||
final id = metadataDb.nextId;
|
||||
final id = localMediaDb.nextId;
|
||||
sourceEntry.id = id;
|
||||
sourceEntry.path = pContext.join(recoveryPath, pContext.basename(untrackedPath));
|
||||
sourceEntry.trashed = true;
|
||||
|
|
|
@ -23,7 +23,7 @@ class Vaults extends ChangeNotifier {
|
|||
Vaults._private();
|
||||
|
||||
Future<void> init() async {
|
||||
_rows = await metadataDb.loadAllVaults();
|
||||
_rows = await localMediaDb.loadAllVaults();
|
||||
_vaultDirPaths = null;
|
||||
final screenStateStream = Platform.isAndroid ? AvesScreenState().screenStateStream : null;
|
||||
if (screenStateStream != null) {
|
||||
|
@ -44,7 +44,7 @@ class Vaults extends ChangeNotifier {
|
|||
VaultDetails? detailsForPath(String dirPath) => _rows.firstWhereOrNull((v) => v.path == dirPath);
|
||||
|
||||
Future<void> create(VaultDetails details) async {
|
||||
await metadataDb.addVaults({details});
|
||||
await localMediaDb.addVaults({details});
|
||||
|
||||
_rows.add(details);
|
||||
_vaultDirPaths = null;
|
||||
|
@ -56,7 +56,7 @@ class Vaults extends ChangeNotifier {
|
|||
final details = dirPaths.map(detailsForPath).whereNotNull().toSet();
|
||||
if (details.isEmpty) return;
|
||||
|
||||
await metadataDb.removeVaults(details);
|
||||
await localMediaDb.removeVaults(details);
|
||||
|
||||
await Future.forEach(details, (v) => securityService.writeValue(v.passKey, null));
|
||||
|
||||
|
@ -74,7 +74,7 @@ class Vaults extends ChangeNotifier {
|
|||
if (newName == null) return;
|
||||
|
||||
final newDetails = oldDetails.copyWith(name: newName);
|
||||
await metadataDb.updateVault(oldDetails.name, newDetails);
|
||||
await localMediaDb.updateVault(oldDetails.name, newDetails);
|
||||
|
||||
final pass = await securityService.readValue(oldDetails.passKey);
|
||||
if (pass != null) {
|
||||
|
@ -96,7 +96,7 @@ class Vaults extends ChangeNotifier {
|
|||
final oldDetails = detailsForPath(newDetails.path);
|
||||
if (oldDetails == null) return;
|
||||
|
||||
await metadataDb.updateVault(newDetails.name, newDetails);
|
||||
await localMediaDb.updateVault(newDetails.name, newDetails);
|
||||
|
||||
_rows
|
||||
..remove(oldDetails)
|
||||
|
@ -104,7 +104,7 @@ class Vaults extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future<void> clear() async {
|
||||
await metadataDb.clearVaults();
|
||||
await localMediaDb.clearVaults();
|
||||
_rows.clear();
|
||||
_vaultDirPaths = null;
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ class Vaults extends ChangeNotifier {
|
|||
final newEntries = await recoverUntrackedItems(source, dirPath);
|
||||
if (newEntries.isNotEmpty) {
|
||||
source.addEntries(newEntries);
|
||||
await metadataDb.saveEntries(newEntries);
|
||||
await localMediaDb.insertEntries(newEntries);
|
||||
unawaited(source.analyze(null, entries: newEntries));
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ class Vaults extends ChangeNotifier {
|
|||
final uri = Uri.file(untrackedPath).toString();
|
||||
final sourceEntry = await mediaFetchService.getEntry(uri, null, allowUnsized: true);
|
||||
if (sourceEntry != null) {
|
||||
sourceEntry.id = metadataDb.nextId;
|
||||
sourceEntry.id = localMediaDb.nextId;
|
||||
sourceEntry.origin = EntryOrigins.vault;
|
||||
newEntries.add(sourceEntry);
|
||||
} else {
|
||||
|
|
|
@ -48,7 +48,7 @@ Future<void> _init() async {
|
|||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initPlatformServices();
|
||||
await androidFileUtils.init();
|
||||
await metadataDb.init();
|
||||
await localMediaDb.init();
|
||||
await device.init();
|
||||
await mobileServices.init();
|
||||
await settings.init(monitorPlatformSettings: false);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/db/db_metadata_sqflite.dart';
|
||||
import 'package:aves/model/db/db.dart';
|
||||
import 'package:aves/model/db/db_sqflite.dart';
|
||||
import 'package:aves/model/settings/store_shared_pref.dart';
|
||||
import 'package:aves/services/app_service.dart';
|
||||
import 'package:aves/services/device_service.dart';
|
||||
|
@ -32,7 +32,7 @@ final SettingsStore settingsStore = SharedPrefSettingsStore();
|
|||
|
||||
final p.Context pContext = getIt<p.Context>();
|
||||
final AvesAvailability availability = getIt<AvesAvailability>();
|
||||
final MetadataDb metadataDb = getIt<MetadataDb>();
|
||||
final LocalMediaDb localMediaDb = getIt<LocalMediaDb>();
|
||||
final AvesVideoControllerFactory videoControllerFactory = getIt<AvesVideoControllerFactory>();
|
||||
final AvesVideoMetadataFetcher videoMetadataFetcher = getIt<AvesVideoMetadataFetcher>();
|
||||
|
||||
|
@ -54,7 +54,7 @@ final WindowService windowService = getIt<WindowService>();
|
|||
void initPlatformServices() {
|
||||
getIt.registerLazySingleton<p.Context>(p.Context.new);
|
||||
getIt.registerLazySingleton<AvesAvailability>(LiveAvesAvailability.new);
|
||||
getIt.registerLazySingleton<MetadataDb>(SqfliteMetadataDb.new);
|
||||
getIt.registerLazySingleton<LocalMediaDb>(SqfliteLocalMediaDb.new);
|
||||
getIt.registerLazySingleton<AvesVideoControllerFactory>(MpvVideoControllerFactory.new);
|
||||
getIt.registerLazySingleton<AvesVideoMetadataFetcher>(FfmpegVideoMetadataFetcher.new);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Future<void> _init() async {
|
|||
|
||||
// service initialization for path context, database
|
||||
initPlatformServices();
|
||||
await metadataDb.init();
|
||||
await localMediaDb.init();
|
||||
|
||||
// `intl` initialization for date formatting
|
||||
await initializeDateFormatting();
|
||||
|
@ -55,8 +55,8 @@ Future<List<Map<String, String?>>> _getSuggestions(dynamic args) async {
|
|||
debugPrint('getSuggestions query=$query, locale=$locale use24hour=$use24hour');
|
||||
|
||||
if (query is String && locale is String) {
|
||||
final entries = (await metadataDb.searchLiveEntries(query, limit: 9)).toList();
|
||||
final catalogMetadata = await metadataDb.loadCatalogMetadataById(entries.map((entry) => entry.id).toSet());
|
||||
final entries = (await localMediaDb.searchLiveEntries(query, limit: 9)).toList();
|
||||
final catalogMetadata = await localMediaDb.loadCatalogMetadataById(entries.map((entry) => entry.id).toSet());
|
||||
catalogMetadata.forEach((metadata) => entries.firstWhereOrNull((entry) => entry.id == metadata.id)?.catalogMetadata = metadata);
|
||||
entries.sort(AvesEntrySort.compareByDate);
|
||||
|
||||
|
|
|
@ -647,10 +647,12 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
|
||||
Future<void> _onAnalysisCompletion() async {
|
||||
debugPrint('Analysis completed');
|
||||
if (_mediaStoreSource.initState != SourceInitializationState.none) {
|
||||
await _mediaStoreSource.loadCatalogMetadata();
|
||||
await _mediaStoreSource.loadAddresses();
|
||||
_mediaStoreSource.updateDerivedFilters();
|
||||
}
|
||||
}
|
||||
|
||||
void _onError(String? error) => reportService.recordError(error, null);
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.reset().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.reset().then((_) => _reload()),
|
||||
child: const Text('Reset'),
|
||||
),
|
||||
],
|
||||
|
@ -93,7 +93,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.clearEntries().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.clearEntries().then((_) => _reload()),
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
|
@ -114,7 +114,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.clearDates().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.clearDates().then((_) => _reload()),
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
|
@ -135,7 +135,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.clearCatalogMetadata().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.clearCatalogMetadata().then((_) => _reload()),
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
|
@ -156,7 +156,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.clearAddresses().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.clearAddresses().then((_) => _reload()),
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
|
@ -177,7 +177,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.clearTrashDetails().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.clearTrashDetails().then((_) => _reload()),
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
|
@ -261,7 +261,7 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () => metadataDb.clearVideoPlayback().then((_) => _reload()),
|
||||
onPressed: () => localMediaDb.clearVideoPlayback().then((_) => _reload()),
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
|
@ -281,16 +281,16 @@ class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with
|
|||
}
|
||||
|
||||
void _startDbReport() {
|
||||
_dbFileSizeLoader = metadataDb.dbFileSize();
|
||||
_dbEntryLoader = metadataDb.loadEntries();
|
||||
_dbDateLoader = metadataDb.loadDates();
|
||||
_dbMetadataLoader = metadataDb.loadCatalogMetadata();
|
||||
_dbAddressLoader = metadataDb.loadAddresses();
|
||||
_dbTrashLoader = metadataDb.loadAllTrashDetails();
|
||||
_dbVaultsLoader = metadataDb.loadAllVaults();
|
||||
_dbFavouritesLoader = metadataDb.loadAllFavourites();
|
||||
_dbCoversLoader = metadataDb.loadAllCovers();
|
||||
_dbVideoPlaybackLoader = metadataDb.loadAllVideoPlayback();
|
||||
_dbFileSizeLoader = localMediaDb.dbFileSize();
|
||||
_dbEntryLoader = localMediaDb.loadEntries();
|
||||
_dbDateLoader = localMediaDb.loadDates();
|
||||
_dbMetadataLoader = localMediaDb.loadCatalogMetadata();
|
||||
_dbAddressLoader = localMediaDb.loadAddresses();
|
||||
_dbTrashLoader = localMediaDb.loadAllTrashDetails();
|
||||
_dbVaultsLoader = localMediaDb.loadAllVaults();
|
||||
_dbFavouritesLoader = localMediaDb.loadAllFavourites();
|
||||
_dbCoversLoader = localMediaDb.loadAllCovers();
|
||||
_dbVideoPlaybackLoader = localMediaDb.loadAllVideoPlayback();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ class _HomePageState extends State<HomePage> {
|
|||
|
||||
Future<void> _initViewerEssentials() async {
|
||||
// for video playback storage
|
||||
await metadataDb.init();
|
||||
await localMediaDb.init();
|
||||
}
|
||||
|
||||
bool _isViewerSourceable(AvesEntry? viewerEntry) {
|
||||
|
|
|
@ -40,12 +40,12 @@ class _DbTabState extends State<DbTab> {
|
|||
|
||||
void _loadDatabase() {
|
||||
final id = entry.id;
|
||||
_dbDateLoader = metadataDb.loadDates().then((values) => values[id]);
|
||||
_dbEntryLoader = metadataDb.loadEntriesById({id}).then((values) => values.firstOrNull);
|
||||
_dbMetadataLoader = metadataDb.loadCatalogMetadata().then((values) => values.firstWhereOrNull((row) => row.id == id));
|
||||
_dbAddressLoader = metadataDb.loadAddresses().then((values) => values.firstWhereOrNull((row) => row.id == id));
|
||||
_dbTrashDetailsLoader = metadataDb.loadAllTrashDetails().then((values) => values.firstWhereOrNull((row) => row.id == id));
|
||||
_dbVideoPlaybackLoader = metadataDb.loadVideoPlayback(id);
|
||||
_dbDateLoader = localMediaDb.loadDates().then((values) => values[id]);
|
||||
_dbEntryLoader = localMediaDb.loadEntriesById({id}).then((values) => values.firstOrNull);
|
||||
_dbMetadataLoader = localMediaDb.loadCatalogMetadata().then((values) => values.firstWhereOrNull((row) => row.id == id));
|
||||
_dbAddressLoader = localMediaDb.loadAddresses().then((values) => values.firstWhereOrNull((row) => row.id == id));
|
||||
_dbTrashDetailsLoader = localMediaDb.loadAllTrashDetails().then((values) => values.firstWhereOrNull((row) => row.id == id));
|
||||
_dbVideoPlaybackLoader = localMediaDb.loadVideoPlayback(id);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,15 @@ class _DbTabState extends State<DbTab> {
|
|||
},
|
||||
child: const Text('Untrack entry'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final duplicates = {entry.copyWith(id: localMediaDb.nextId)};
|
||||
final source = context.read<CollectionSource>();
|
||||
source.addEntries(duplicates);
|
||||
await localMediaDb.insertEntries(duplicates);
|
||||
},
|
||||
child: const Text('Duplicate entry'),
|
||||
),
|
||||
InfoRowGroup(
|
||||
info: {
|
||||
'uri': data.uri,
|
||||
|
@ -184,7 +193,7 @@ class _DbTabState extends State<DbTab> {
|
|||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
entry.trashDetails = null;
|
||||
await metadataDb.updateTrash(entry.id, entry.trashDetails);
|
||||
await localMediaDb.updateTrash(entry.id, entry.trashDetails);
|
||||
_loadDatabase();
|
||||
},
|
||||
child: const Text('Remove details'),
|
||||
|
|
|
@ -568,9 +568,12 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
|||
} else if (notification is CastNotification) {
|
||||
_cast(notification.enabled);
|
||||
} else if (notification is FullImageLoadedNotification) {
|
||||
final viewStateController = context.read<ViewStateConductor>().getOrCreateController(notification.entry);
|
||||
// microtask so that listeners do not trigger during build
|
||||
scheduleMicrotask(() => viewStateController.fullImageNotifier.value = notification.image);
|
||||
scheduleMicrotask(() {
|
||||
if (!mounted) return;
|
||||
final viewStateController = context.read<ViewStateConductor>().getController(notification.entry);
|
||||
viewStateController?.fullImageNotifier.value = notification.image;
|
||||
});
|
||||
} else if (notification is EntryDeletedNotification) {
|
||||
_onEntryRemoved(context, notification.entries);
|
||||
} else if (notification is EntryMovedNotification) {
|
||||
|
|
|
@ -16,12 +16,12 @@ class DatabasePlaybackStateHandler extends PlaybackStateHandler {
|
|||
|
||||
@override
|
||||
Future<int?> getResumeTime({required int entryId, required BuildContext context}) async {
|
||||
final playback = await metadataDb.loadVideoPlayback(entryId);
|
||||
final playback = await localMediaDb.loadVideoPlayback(entryId);
|
||||
final resumeTime = playback?.resumeTimeMillis ?? 0;
|
||||
if (resumeTime == 0) return null;
|
||||
|
||||
// clear on retrieval
|
||||
await metadataDb.removeVideoPlayback({entryId});
|
||||
await localMediaDb.removeVideoPlayback({entryId});
|
||||
|
||||
switch (settings.videoResumptionMode) {
|
||||
case VideoResumptionMode.never:
|
||||
|
@ -54,14 +54,14 @@ class DatabasePlaybackStateHandler extends PlaybackStateHandler {
|
|||
@override
|
||||
Future<void> saveResumeTime({required int entryId, required int position, required double progress}) async {
|
||||
if (resumeTimeSaveMinProgress < progress && progress < resumeTimeSaveMaxProgress) {
|
||||
await metadataDb.addVideoPlayback({
|
||||
await localMediaDb.addVideoPlayback({
|
||||
VideoPlaybackRow(
|
||||
entryId: entryId,
|
||||
resumeTimeMillis: position,
|
||||
)
|
||||
});
|
||||
} else {
|
||||
await metadataDb.removeVideoPlayback({entryId});
|
||||
await localMediaDb.removeVideoPlayback({entryId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/db/db.dart';
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
@ -10,7 +10,7 @@ import 'package:aves/model/vaults/details.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:test/fake.dart';
|
||||
|
||||
class FakeMetadataDb extends Fake implements MetadataDb {
|
||||
class FakeAvesDb extends Fake implements LocalMediaDb {
|
||||
static int _lastId = 0;
|
||||
|
||||
@override
|
||||
|
@ -28,7 +28,7 @@ class FakeMetadataDb extends Fake implements MetadataDb {
|
|||
Future<Set<AvesEntry>> loadEntries({int? origin, String? directory}) => SynchronousFuture({});
|
||||
|
||||
@override
|
||||
Future<void> saveEntries(Set<AvesEntry> entries) => SynchronousFuture(null);
|
||||
Future<void> insertEntries(Set<AvesEntry> entries) => SynchronousFuture(null);
|
||||
|
||||
@override
|
||||
Future<void> updateEntry(int id, AvesEntry entry) => SynchronousFuture(null);
|
|
@ -3,7 +3,7 @@ import 'dart:async';
|
|||
import 'package:aves/l10n/l10n.dart';
|
||||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/db/db.dart';
|
||||
import 'package:aves/model/entry/extensions/favourites.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
|
@ -35,7 +35,7 @@ import '../fake/availability.dart';
|
|||
import '../fake/device_service.dart';
|
||||
import '../fake/media_fetch_service.dart';
|
||||
import '../fake/media_store_service.dart';
|
||||
import '../fake/metadata_db.dart';
|
||||
import '../fake/db.dart';
|
||||
import '../fake/metadata_fetch_service.dart';
|
||||
import '../fake/report_service.dart';
|
||||
import '../fake/storage_service.dart';
|
||||
|
@ -58,7 +58,7 @@ void main() {
|
|||
// specify Posix style path context for consistent behaviour when running tests on Windows
|
||||
getIt.registerLazySingleton<p.Context>(() => p.Context(style: p.Style.posix));
|
||||
getIt.registerLazySingleton<AvesAvailability>(FakeAvesAvailability.new);
|
||||
getIt.registerLazySingleton<MetadataDb>(FakeMetadataDb.new);
|
||||
getIt.registerLazySingleton<LocalMediaDb>(FakeAvesDb.new);
|
||||
|
||||
getIt.registerLazySingleton<AppService>(FakeAppService.new);
|
||||
getIt.registerLazySingleton<DeviceService>(FakeDeviceService.new);
|
||||
|
|
Loading…
Reference in a new issue