From a86cbfa6ebd5483860cf0cabfa3e9ca6df7560b9 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Sun, 2 Oct 2022 19:25:07 +0200 Subject: [PATCH] #326 date added sourced from Media Store --- .../deckers/thibault/aves/model/SourceEntry.kt | 3 +++ .../aves/model/provider/FileImageProvider.kt | 7 ++++++- .../model/provider/MediaStoreImageProvider.kt | 7 ++++++- lib/model/db/db_metadata.dart | 2 -- lib/model/db/db_metadata_sqflite.dart | 3 --- lib/model/entry.dart | 1 + lib/model/source/collection_source.dart | 2 +- lib/model/source/media_store_source.dart | 16 ++-------------- test/fake/metadata_db.dart | 3 --- 9 files changed, 19 insertions(+), 25 deletions(-) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt index 4e7ff6ca3..9d5749561 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt @@ -41,6 +41,7 @@ class SourceEntry { var height: Int? = null private var sourceRotationDegrees: Int? = null private var sizeBytes: Long? = null + private var dateAddedSecs: Long? = null private var dateModifiedSecs: Long? = null private var sourceDateTakenMillis: Long? = null private var durationMillis: Long? = null @@ -61,6 +62,7 @@ class SourceEntry { sourceRotationDegrees = map["sourceRotationDegrees"] as Int? sizeBytes = toLong(map["sizeBytes"]) title = map["title"] as String? + dateAddedSecs = toLong(map["dateAddedSecs"]) dateModifiedSecs = toLong(map["dateModifiedSecs"]) sourceDateTakenMillis = toLong(map["sourceDateTakenMillis"]) durationMillis = toLong(map["durationMillis"]) @@ -83,6 +85,7 @@ class SourceEntry { "sourceRotationDegrees" to (sourceRotationDegrees ?: 0), "sizeBytes" to sizeBytes, "title" to title, + "dateAddedSecs" to dateAddedSecs, "dateModifiedSecs" to dateModifiedSecs, "sourceDateTakenMillis" to sourceDateTakenMillis, "durationMillis" to durationMillis, diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/FileImageProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/FileImageProvider.kt index 66d6f1035..3c3a624d5 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/FileImageProvider.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/FileImageProvider.kt @@ -22,7 +22,12 @@ internal class FileImageProvider : ImageProvider() { try { val file = File(path) if (file.exists()) { - entry.initFromFile(path, file.name, file.length(), file.lastModified() / 1000) + entry.initFromFile( + path = path, + title = file.name, + sizeBytes = file.length(), + dateModifiedSecs = file.lastModified() / 1000, + ) } } catch (e: SecurityException) { callback.onFailure(e) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt index 0a7876534..d13143269 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt @@ -86,7 +86,7 @@ class MediaStoreImageProvider : ImageProvider() { val alwaysValid: NewEntryChecker = fun(_: Int, _: Int): Boolean = true val onSuccess: NewEntryHandler = fun(entry: FieldMap) { fetched.add(entry) } if (id != null) { - if (!found && (sourceMimeType == null || isImage(sourceMimeType))) { + if (sourceMimeType == null || isImage(sourceMimeType)) { val contentUri = ContentUris.withAppendedId(IMAGE_CONTENT_URI, id) found = fetchFrom(context, alwaysValid, onSuccess, contentUri, IMAGE_PROJECTION) } @@ -189,6 +189,7 @@ class MediaStoreImageProvider : ImageProvider() { val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE) val widthColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.WIDTH) val heightColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.HEIGHT) + val dateAddedColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED) val dateModifiedColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED) val dateTakenColumn = cursor.getColumnIndex(MediaColumns.DATE_TAKEN) @@ -224,6 +225,7 @@ class MediaStoreImageProvider : ImageProvider() { "height" to height, "sourceRotationDegrees" to if (orientationColumn != -1) cursor.getInt(orientationColumn) else 0, "sizeBytes" to cursor.getLong(sizeColumn), + "dateAddedSecs" to cursor.getInt(dateAddedColumn), "dateModifiedSecs" to dateModifiedSecs, "sourceDateTakenMillis" to if (dateTakenColumn != -1) cursor.getLong(dateTakenColumn) else null, "durationMillis" to durationMillis, @@ -789,6 +791,7 @@ class MediaStoreImageProvider : ImageProvider() { // we retrieve updated fields as the renamed/moved file became a new entry in the Media Store val projection = arrayOf( + MediaStore.MediaColumns.DATE_ADDED, MediaStore.MediaColumns.DATE_MODIFIED, ) try { @@ -798,6 +801,7 @@ class MediaStoreImageProvider : ImageProvider() { newFields["uri"] = uri.toString() newFields["contentId"] = uri.tryParseId() newFields["path"] = path + cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED).let { if (it != -1) newFields["dateAddedSecs"] = cursor.getInt(it) } cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED).let { if (it != -1) newFields["dateModifiedSecs"] = cursor.getInt(it) } cursor.close() return newFields @@ -871,6 +875,7 @@ class MediaStoreImageProvider : ImageProvider() { MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.WIDTH, MediaStore.MediaColumns.HEIGHT, + MediaStore.MediaColumns.DATE_ADDED, MediaStore.MediaColumns.DATE_MODIFIED, MediaColumns.DATE_TAKEN, ) diff --git a/lib/model/db/db_metadata.dart b/lib/model/db/db_metadata.dart index 7f5d70ea4..cc23707bf 100644 --- a/lib/model/db/db_metadata.dart +++ b/lib/model/db/db_metadata.dart @@ -10,8 +10,6 @@ import 'package:aves/model/video_playback.dart'; abstract class MetadataDb { int get nextId; - int get timestampSecs; - Future init(); Future dbFileSize(); diff --git a/lib/model/db/db_metadata_sqflite.dart b/lib/model/db/db_metadata_sqflite.dart index 8ad1aa3fe..3e12a018a 100644 --- a/lib/model/db/db_metadata_sqflite.dart +++ b/lib/model/db/db_metadata_sqflite.dart @@ -34,9 +34,6 @@ class SqfliteMetadataDb implements MetadataDb { @override int get nextId => ++_lastId; - @override - int get timestampSecs => DateTime.now().millisecondsSinceEpoch ~/ 1000; - @override Future init() async { _db = await openDatabase( diff --git a/lib/model/entry.dart b/lib/model/entry.dart index 0922c3694..23d05ce2e 100644 --- a/lib/model/entry.dart +++ b/lib/model/entry.dart @@ -150,6 +150,7 @@ class AvesEntry { 'sourceRotationDegrees': sourceRotationDegrees, 'sizeBytes': sizeBytes, 'title': sourceTitle, + 'dateAddedSecs': dateAddedSecs, 'dateModifiedSecs': dateModifiedSecs, 'sourceDateTakenMillis': sourceDateTakenMillis, 'durationMillis': durationMillis, diff --git a/lib/model/source/collection_source.dart b/lib/model/source/collection_source.dart index a22626a98..94424e2b5 100644 --- a/lib/model/source/collection_source.dart +++ b/lib/model/source/collection_source.dart @@ -310,7 +310,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM contentId: newFields['contentId'] as int?, // title can change when moved files are automatically renamed to avoid conflict title: newFields['title'] as String?, - dateAddedSecs: metadataDb.timestampSecs, + dateAddedSecs: newFields['dateAddedSecs'] as int?, dateModifiedSecs: newFields['dateModifiedSecs'] as int?, )); } else { diff --git a/lib/model/source/media_store_source.dart b/lib/model/source/media_store_source.dart index 18e6d4d44..d11cc5f1d 100644 --- a/lib/model/source/media_store_source.dart +++ b/lib/model/source/media_store_source.dart @@ -159,13 +159,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; - if (existingEntry != null) { - entry.id = existingEntry.id; - entry.dateAddedSecs = existingEntry.dateAddedSecs; - } else { - entry.id = metadataDb.nextId; - entry.dateAddedSecs = metadataDb.timestampSecs; - } + entry.id = existingEntry?.id ?? metadataDb.nextId; pendingNewEntries.add(entry); if (pendingNewEntries.length >= refreshCount) { @@ -250,13 +244,7 @@ class MediaStoreSource extends CollectionSource { final newPath = sourceEntry.path; final volume = newPath != null ? androidFileUtils.getStorageVolume(newPath) : null; if (volume != null) { - if (existingEntry != null) { - sourceEntry.id = existingEntry.id; - sourceEntry.dateAddedSecs = existingEntry.dateAddedSecs; - } else { - sourceEntry.id = metadataDb.nextId; - sourceEntry.dateAddedSecs = metadataDb.timestampSecs; - } + sourceEntry.id = existingEntry?.id ?? metadataDb.nextId; newEntries.add(sourceEntry); final existingDirectory = existingEntry?.directory; if (existingDirectory != null) { diff --git a/test/fake/metadata_db.dart b/test/fake/metadata_db.dart index 49e36feba..1d8fdc1a1 100644 --- a/test/fake/metadata_db.dart +++ b/test/fake/metadata_db.dart @@ -15,9 +15,6 @@ class FakeMetadataDb extends Fake implements MetadataDb { @override int get nextId => ++_lastId; - @override - int get timestampSecs => DateTime.now().millisecondsSinceEpoch ~/ 1000; - @override Future init() => SynchronousFuture(null);