diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt index e6cf92f573..d3282f4dfd 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt @@ -89,7 +89,10 @@ data class PlatformAsset ( val height: Long? = null, val durationInSeconds: Long, val orientation: Long, - val isFavorite: Boolean + val isFavorite: Boolean, + val adjustmentTime: Long? = null, + val latitude: Double? = null, + val longitude: Double? = null ) { companion object { @@ -104,7 +107,10 @@ data class PlatformAsset ( val durationInSeconds = pigeonVar_list[7] as Long val orientation = pigeonVar_list[8] as Long val isFavorite = pigeonVar_list[9] as Boolean - return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite) + val adjustmentTime = pigeonVar_list[10] as Long? + val latitude = pigeonVar_list[11] as Double? + val longitude = pigeonVar_list[12] as Double? + return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite, adjustmentTime, latitude, longitude) } } fun toList(): List { @@ -119,6 +125,9 @@ data class PlatformAsset ( durationInSeconds, orientation, isFavorite, + adjustmentTime, + latitude, + longitude, ) } override fun equals(other: Any?): Boolean { diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt index b1e9dd7d44..b374ef50f0 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.content.ContentUris import android.content.Context import android.database.Cursor -import android.net.Uri import android.os.Bundle import android.provider.MediaStore import android.util.Base64 diff --git a/mobile/ios/Runner/Sync/Messages.g.swift b/mobile/ios/Runner/Sync/Messages.g.swift index bbe18e7375..c1cc98014b 100644 --- a/mobile/ios/Runner/Sync/Messages.g.swift +++ b/mobile/ios/Runner/Sync/Messages.g.swift @@ -140,6 +140,9 @@ struct PlatformAsset: Hashable { var durationInSeconds: Int64 var orientation: Int64 var isFavorite: Bool + var adjustmentTime: Int64? = nil + var latitude: Double? = nil + var longitude: Double? = nil // swift-format-ignore: AlwaysUseLowerCamelCase @@ -154,6 +157,9 @@ struct PlatformAsset: Hashable { let durationInSeconds = pigeonVar_list[7] as! Int64 let orientation = pigeonVar_list[8] as! Int64 let isFavorite = pigeonVar_list[9] as! Bool + let adjustmentTime: Int64? = nilOrValue(pigeonVar_list[10]) + let latitude: Double? = nilOrValue(pigeonVar_list[11]) + let longitude: Double? = nilOrValue(pigeonVar_list[12]) return PlatformAsset( id: id, @@ -165,7 +171,10 @@ struct PlatformAsset: Hashable { height: height, durationInSeconds: durationInSeconds, orientation: orientation, - isFavorite: isFavorite + isFavorite: isFavorite, + adjustmentTime: adjustmentTime, + latitude: latitude, + longitude: longitude ) } func toList() -> [Any?] { @@ -180,6 +189,9 @@ struct PlatformAsset: Hashable { durationInSeconds, orientation, isFavorite, + adjustmentTime, + latitude, + longitude, ] } static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool { diff --git a/mobile/ios/Runner/Sync/PHAssetExtensions.swift b/mobile/ios/Runner/Sync/PHAssetExtensions.swift index 2b1ef6ac88..f555d75bd0 100644 --- a/mobile/ios/Runner/Sync/PHAssetExtensions.swift +++ b/mobile/ios/Runner/Sync/PHAssetExtensions.swift @@ -12,7 +12,10 @@ extension PHAsset { height: Int64(pixelHeight), durationInSeconds: Int64(duration), orientation: 0, - isFavorite: isFavorite + isFavorite: isFavorite, + adjustmentTime: adjustmentTimestamp, + latitude: location?.coordinate.latitude, + longitude: location?.coordinate.longitude ) } @@ -23,6 +26,13 @@ extension PHAsset { var filename: String? { return value(forKey: "filename") as? String } + + var adjustmentTimestamp: Int64? { + if let date = value(forKey: "adjustmentTimestamp") as? Date { + return Int64(date.timeIntervalSince1970) + } + return nil + } // This method is expected to be slow as it goes through the asset resources to fetch the originalFilename var originalFilename: String? { diff --git a/mobile/lib/domain/models/asset/local_asset.model.dart b/mobile/lib/domain/models/asset/local_asset.model.dart index 6f2f4c06ba..ba64cc40b8 100644 --- a/mobile/lib/domain/models/asset/local_asset.model.dart +++ b/mobile/lib/domain/models/asset/local_asset.model.dart @@ -5,6 +5,10 @@ class LocalAsset extends BaseAsset { final String? remoteAssetId; final int orientation; + final DateTime? adjustmentTime; + final double? latitude; + final double? longitude; + const LocalAsset({ required this.id, String? remoteId, @@ -19,6 +23,9 @@ class LocalAsset extends BaseAsset { super.isFavorite = false, super.livePhotoVideoId, this.orientation = 0, + this.adjustmentTime, + this.latitude, + this.longitude, }) : remoteAssetId = remoteId; @override @@ -33,6 +40,8 @@ class LocalAsset extends BaseAsset { @override String get heroTag => '${id}_${remoteId ?? checksum}'; + bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0; + @override String toString() { return '''LocalAsset { @@ -47,6 +56,9 @@ class LocalAsset extends BaseAsset { remoteId: ${remoteId ?? ""} isFavorite: $isFavorite, orientation: $orientation, + adjustmentTime: $adjustmentTime, + latitude: ${latitude ?? ""}, + longitude: ${longitude ?? ""}, }'''; } @@ -55,11 +67,23 @@ class LocalAsset extends BaseAsset { bool operator ==(Object other) { if (other is! LocalAsset) return false; if (identical(this, other)) return true; - return super == other && id == other.id && orientation == other.orientation; + return super == other && + id == other.id && + orientation == other.orientation && + adjustmentTime == other.adjustmentTime && + latitude == other.latitude && + longitude == other.longitude; } @override - int get hashCode => super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode; + int get hashCode => + super.hashCode ^ + id.hashCode ^ + remoteId.hashCode ^ + orientation.hashCode ^ + adjustmentTime.hashCode ^ + latitude.hashCode ^ + longitude.hashCode; LocalAsset copyWith({ String? id, @@ -74,6 +98,9 @@ class LocalAsset extends BaseAsset { int? durationInSeconds, bool? isFavorite, int? orientation, + DateTime? adjustmentTime, + double? latitude, + double? longitude, }) { return LocalAsset( id: id ?? this.id, @@ -88,6 +115,9 @@ class LocalAsset extends BaseAsset { durationInSeconds: durationInSeconds ?? this.durationInSeconds, isFavorite: isFavorite ?? this.isFavorite, orientation: orientation ?? this.orientation, + adjustmentTime: adjustmentTime ?? this.adjustmentTime, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, ); } } diff --git a/mobile/lib/domain/services/local_sync.service.dart b/mobile/lib/domain/services/local_sync.service.dart index 04eaf04694..facb32bcd4 100644 --- a/mobile/lib/domain/services/local_sync.service.dart +++ b/mobile/lib/domain/services/local_sync.service.dart @@ -376,5 +376,8 @@ extension PlatformToLocalAsset on PlatformAsset { durationInSeconds: durationInSeconds, isFavorite: isFavorite, orientation: orientation, + adjustmentTime: tryFromSecondsSinceEpoch(adjustmentTime, isUtc: true), + latitude: latitude, + longitude: longitude, ); } diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.dart b/mobile/lib/infrastructure/entities/local_asset.entity.dart index 8b253f83a3..d2455b744e 100644 --- a/mobile/lib/infrastructure/entities/local_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/local_asset.entity.dart @@ -16,6 +16,12 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin { IntColumn get orientation => integer().withDefault(const Constant(0))(); + DateTimeColumn get adjustmentTime => dateTime().nullable()(); + + RealColumn get latitude => real().nullable()(); + + RealColumn get longitude => real().nullable()(); + @override Set get primaryKey => {id}; } @@ -34,5 +40,8 @@ extension LocalAssetEntityDataDomainExtension on LocalAssetEntityData { width: width, remoteId: remoteId, orientation: orientation, + adjustmentTime: adjustmentTime, + latitude: latitude, + longitude: longitude, ); } diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart index d0fe742463..22219b1e6e 100644 --- a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart @@ -21,6 +21,9 @@ typedef $$LocalAssetEntityTableCreateCompanionBuilder = i0.Value checksum, i0.Value isFavorite, i0.Value orientation, + i0.Value adjustmentTime, + i0.Value latitude, + i0.Value longitude, }); typedef $$LocalAssetEntityTableUpdateCompanionBuilder = i1.LocalAssetEntityCompanion Function({ @@ -35,6 +38,9 @@ typedef $$LocalAssetEntityTableUpdateCompanionBuilder = i0.Value checksum, i0.Value isFavorite, i0.Value orientation, + i0.Value adjustmentTime, + i0.Value latitude, + i0.Value longitude, }); class $$LocalAssetEntityTableFilterComposer @@ -101,6 +107,21 @@ class $$LocalAssetEntityTableFilterComposer column: $table.orientation, builder: (column) => i0.ColumnFilters(column), ); + + i0.ColumnFilters get adjustmentTime => $composableBuilder( + column: $table.adjustmentTime, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get latitude => $composableBuilder( + column: $table.latitude, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get longitude => $composableBuilder( + column: $table.longitude, + builder: (column) => i0.ColumnFilters(column), + ); } class $$LocalAssetEntityTableOrderingComposer @@ -166,6 +187,21 @@ class $$LocalAssetEntityTableOrderingComposer column: $table.orientation, builder: (column) => i0.ColumnOrderings(column), ); + + i0.ColumnOrderings get adjustmentTime => $composableBuilder( + column: $table.adjustmentTime, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get latitude => $composableBuilder( + column: $table.latitude, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get longitude => $composableBuilder( + column: $table.longitude, + builder: (column) => i0.ColumnOrderings(column), + ); } class $$LocalAssetEntityTableAnnotationComposer @@ -215,6 +251,17 @@ class $$LocalAssetEntityTableAnnotationComposer column: $table.orientation, builder: (column) => column, ); + + i0.GeneratedColumn get adjustmentTime => $composableBuilder( + column: $table.adjustmentTime, + builder: (column) => column, + ); + + i0.GeneratedColumn get latitude => + $composableBuilder(column: $table.latitude, builder: (column) => column); + + i0.GeneratedColumn get longitude => + $composableBuilder(column: $table.longitude, builder: (column) => column); } class $$LocalAssetEntityTableTableManager @@ -268,6 +315,9 @@ class $$LocalAssetEntityTableTableManager i0.Value checksum = const i0.Value.absent(), i0.Value isFavorite = const i0.Value.absent(), i0.Value orientation = const i0.Value.absent(), + i0.Value adjustmentTime = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), }) => i1.LocalAssetEntityCompanion( name: name, type: type, @@ -280,6 +330,9 @@ class $$LocalAssetEntityTableTableManager checksum: checksum, isFavorite: isFavorite, orientation: orientation, + adjustmentTime: adjustmentTime, + latitude: latitude, + longitude: longitude, ), createCompanionCallback: ({ @@ -294,6 +347,9 @@ class $$LocalAssetEntityTableTableManager i0.Value checksum = const i0.Value.absent(), i0.Value isFavorite = const i0.Value.absent(), i0.Value orientation = const i0.Value.absent(), + i0.Value adjustmentTime = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), }) => i1.LocalAssetEntityCompanion.insert( name: name, type: type, @@ -306,6 +362,9 @@ class $$LocalAssetEntityTableTableManager checksum: checksum, isFavorite: isFavorite, orientation: orientation, + adjustmentTime: adjustmentTime, + latitude: latitude, + longitude: longitude, ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) @@ -473,6 +532,39 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity requiredDuringInsert: false, defaultValue: const i4.Constant(0), ); + static const i0.VerificationMeta _adjustmentTimeMeta = + const i0.VerificationMeta('adjustmentTime'); + @override + late final i0.GeneratedColumn adjustmentTime = + i0.GeneratedColumn( + 'adjustment_time', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _latitudeMeta = const i0.VerificationMeta( + 'latitude', + ); + @override + late final i0.GeneratedColumn latitude = i0.GeneratedColumn( + 'latitude', + aliasedName, + true, + type: i0.DriftSqlType.double, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _longitudeMeta = const i0.VerificationMeta( + 'longitude', + ); + @override + late final i0.GeneratedColumn longitude = i0.GeneratedColumn( + 'longitude', + aliasedName, + true, + type: i0.DriftSqlType.double, + requiredDuringInsert: false, + ); @override List get $columns => [ name, @@ -486,6 +578,9 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity checksum, isFavorite, orientation, + adjustmentTime, + latitude, + longitude, ]; @override String get aliasedName => _alias ?? actualTableName; @@ -566,6 +661,27 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity ), ); } + if (data.containsKey('adjustment_time')) { + context.handle( + _adjustmentTimeMeta, + adjustmentTime.isAcceptableOrUnknown( + data['adjustment_time']!, + _adjustmentTimeMeta, + ), + ); + } + if (data.containsKey('latitude')) { + context.handle( + _latitudeMeta, + latitude.isAcceptableOrUnknown(data['latitude']!, _latitudeMeta), + ); + } + if (data.containsKey('longitude')) { + context.handle( + _longitudeMeta, + longitude.isAcceptableOrUnknown(data['longitude']!, _longitudeMeta), + ); + } return context; } @@ -624,6 +740,18 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity i0.DriftSqlType.int, data['${effectivePrefix}orientation'], )!, + adjustmentTime: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}adjustment_time'], + ), + latitude: attachedDatabase.typeMapping.read( + i0.DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + i0.DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), ); } @@ -653,6 +781,9 @@ class LocalAssetEntityData extends i0.DataClass final String? checksum; final bool isFavorite; final int orientation; + final DateTime? adjustmentTime; + final double? latitude; + final double? longitude; const LocalAssetEntityData({ required this.name, required this.type, @@ -665,6 +796,9 @@ class LocalAssetEntityData extends i0.DataClass this.checksum, required this.isFavorite, required this.orientation, + this.adjustmentTime, + this.latitude, + this.longitude, }); @override Map toColumns(bool nullToAbsent) { @@ -692,6 +826,15 @@ class LocalAssetEntityData extends i0.DataClass } map['is_favorite'] = i0.Variable(isFavorite); map['orientation'] = i0.Variable(orientation); + if (!nullToAbsent || adjustmentTime != null) { + map['adjustment_time'] = i0.Variable(adjustmentTime); + } + if (!nullToAbsent || latitude != null) { + map['latitude'] = i0.Variable(latitude); + } + if (!nullToAbsent || longitude != null) { + map['longitude'] = i0.Variable(longitude); + } return map; } @@ -714,6 +857,9 @@ class LocalAssetEntityData extends i0.DataClass checksum: serializer.fromJson(json['checksum']), isFavorite: serializer.fromJson(json['isFavorite']), orientation: serializer.fromJson(json['orientation']), + adjustmentTime: serializer.fromJson(json['adjustmentTime']), + latitude: serializer.fromJson(json['latitude']), + longitude: serializer.fromJson(json['longitude']), ); } @override @@ -733,6 +879,9 @@ class LocalAssetEntityData extends i0.DataClass 'checksum': serializer.toJson(checksum), 'isFavorite': serializer.toJson(isFavorite), 'orientation': serializer.toJson(orientation), + 'adjustmentTime': serializer.toJson(adjustmentTime), + 'latitude': serializer.toJson(latitude), + 'longitude': serializer.toJson(longitude), }; } @@ -748,6 +897,9 @@ class LocalAssetEntityData extends i0.DataClass i0.Value checksum = const i0.Value.absent(), bool? isFavorite, int? orientation, + i0.Value adjustmentTime = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), }) => i1.LocalAssetEntityData( name: name ?? this.name, type: type ?? this.type, @@ -762,6 +914,11 @@ class LocalAssetEntityData extends i0.DataClass checksum: checksum.present ? checksum.value : this.checksum, isFavorite: isFavorite ?? this.isFavorite, orientation: orientation ?? this.orientation, + adjustmentTime: adjustmentTime.present + ? adjustmentTime.value + : this.adjustmentTime, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, ); LocalAssetEntityData copyWithCompanion(i1.LocalAssetEntityCompanion data) { return LocalAssetEntityData( @@ -782,6 +939,11 @@ class LocalAssetEntityData extends i0.DataClass orientation: data.orientation.present ? data.orientation.value : this.orientation, + adjustmentTime: data.adjustmentTime.present + ? data.adjustmentTime.value + : this.adjustmentTime, + latitude: data.latitude.present ? data.latitude.value : this.latitude, + longitude: data.longitude.present ? data.longitude.value : this.longitude, ); } @@ -798,7 +960,10 @@ class LocalAssetEntityData extends i0.DataClass ..write('id: $id, ') ..write('checksum: $checksum, ') ..write('isFavorite: $isFavorite, ') - ..write('orientation: $orientation') + ..write('orientation: $orientation, ') + ..write('adjustmentTime: $adjustmentTime, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude') ..write(')')) .toString(); } @@ -816,6 +981,9 @@ class LocalAssetEntityData extends i0.DataClass checksum, isFavorite, orientation, + adjustmentTime, + latitude, + longitude, ); @override bool operator ==(Object other) => @@ -831,7 +999,10 @@ class LocalAssetEntityData extends i0.DataClass other.id == this.id && other.checksum == this.checksum && other.isFavorite == this.isFavorite && - other.orientation == this.orientation); + other.orientation == this.orientation && + other.adjustmentTime == this.adjustmentTime && + other.latitude == this.latitude && + other.longitude == this.longitude); } class LocalAssetEntityCompanion @@ -847,6 +1018,9 @@ class LocalAssetEntityCompanion final i0.Value checksum; final i0.Value isFavorite; final i0.Value orientation; + final i0.Value adjustmentTime; + final i0.Value latitude; + final i0.Value longitude; const LocalAssetEntityCompanion({ this.name = const i0.Value.absent(), this.type = const i0.Value.absent(), @@ -859,6 +1033,9 @@ class LocalAssetEntityCompanion this.checksum = const i0.Value.absent(), this.isFavorite = const i0.Value.absent(), this.orientation = const i0.Value.absent(), + this.adjustmentTime = const i0.Value.absent(), + this.latitude = const i0.Value.absent(), + this.longitude = const i0.Value.absent(), }); LocalAssetEntityCompanion.insert({ required String name, @@ -872,6 +1049,9 @@ class LocalAssetEntityCompanion this.checksum = const i0.Value.absent(), this.isFavorite = const i0.Value.absent(), this.orientation = const i0.Value.absent(), + this.adjustmentTime = const i0.Value.absent(), + this.latitude = const i0.Value.absent(), + this.longitude = const i0.Value.absent(), }) : name = i0.Value(name), type = i0.Value(type), id = i0.Value(id); @@ -887,6 +1067,9 @@ class LocalAssetEntityCompanion i0.Expression? checksum, i0.Expression? isFavorite, i0.Expression? orientation, + i0.Expression? adjustmentTime, + i0.Expression? latitude, + i0.Expression? longitude, }) { return i0.RawValuesInsertable({ if (name != null) 'name': name, @@ -900,6 +1083,9 @@ class LocalAssetEntityCompanion if (checksum != null) 'checksum': checksum, if (isFavorite != null) 'is_favorite': isFavorite, if (orientation != null) 'orientation': orientation, + if (adjustmentTime != null) 'adjustment_time': adjustmentTime, + if (latitude != null) 'latitude': latitude, + if (longitude != null) 'longitude': longitude, }); } @@ -915,6 +1101,9 @@ class LocalAssetEntityCompanion i0.Value? checksum, i0.Value? isFavorite, i0.Value? orientation, + i0.Value? adjustmentTime, + i0.Value? latitude, + i0.Value? longitude, }) { return i1.LocalAssetEntityCompanion( name: name ?? this.name, @@ -928,6 +1117,9 @@ class LocalAssetEntityCompanion checksum: checksum ?? this.checksum, isFavorite: isFavorite ?? this.isFavorite, orientation: orientation ?? this.orientation, + adjustmentTime: adjustmentTime ?? this.adjustmentTime, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, ); } @@ -969,6 +1161,15 @@ class LocalAssetEntityCompanion if (orientation.present) { map['orientation'] = i0.Variable(orientation.value); } + if (adjustmentTime.present) { + map['adjustment_time'] = i0.Variable(adjustmentTime.value); + } + if (latitude.present) { + map['latitude'] = i0.Variable(latitude.value); + } + if (longitude.present) { + map['longitude'] = i0.Variable(longitude.value); + } return map; } @@ -985,7 +1186,10 @@ class LocalAssetEntityCompanion ..write('id: $id, ') ..write('checksum: $checksum, ') ..write('isFavorite: $isFavorite, ') - ..write('orientation: $orientation') + ..write('orientation: $orientation, ') + ..write('adjustmentTime: $adjustmentTime, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude') ..write(')')) .toString(); } diff --git a/mobile/lib/infrastructure/repositories/local_album.repository.dart b/mobile/lib/infrastructure/repositories/local_album.repository.dart index 59546a4539..f919d777b7 100644 --- a/mobile/lib/infrastructure/repositories/local_album.repository.dart +++ b/mobile/lib/infrastructure/repositories/local_album.repository.dart @@ -244,12 +244,12 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get(); } - Future _upsertAssets(Iterable localAssets) { + Future _upsertAssets(Iterable localAssets) async { if (localAssets.isEmpty) { return Future.value(); } - return _db.batch((batch) async { + await _db.batch((batch) async { for (final asset in localAssets) { final companion = LocalAssetEntityCompanion.insert( name: asset.name, @@ -262,11 +262,35 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { id: asset.id, orientation: Value(asset.orientation), isFavorite: Value(asset.isFavorite), + adjustmentTime: Value(asset.adjustmentTime), + latitude: Value(asset.latitude), + longitude: Value(asset.longitude), ); batch.insert<$LocalAssetEntityTable, LocalAssetEntityData>( + _db.localAssetEntity, + companion.copyWith(checksum: const Value(null)), + onConflict: DoUpdate( + (old) => companion, + where: (old) => CurrentPlatform.isAndroid + ? old.updatedAt.isNotValue(asset.updatedAt) + : old.latitude.equalsNullable(asset.latitude).not() | + old.longitude.equalsNullable(asset.longitude).not() | + old.createdAt.isNotValue(asset.createdAt), + ), + ); + } + }); + + // Reset checksum if asset changed + return _db.batch((batch) async { + for (final asset in localAssets) { + final companion = const LocalAssetEntityCompanion(checksum: Value(null)); + batch.update( _db.localAssetEntity, companion, - onConflict: DoUpdate((_) => companion, where: (old) => old.updatedAt.isNotValue(asset.updatedAt)), + where: (row) => CurrentPlatform.isIOS + ? row.adjustmentTime.equalsNullable(asset.adjustmentTime).not() + : row.updatedAt.isNotValue(asset.updatedAt), ); } }); diff --git a/mobile/lib/platform/native_sync_api.g.dart b/mobile/lib/platform/native_sync_api.g.dart index 34ed7a5e2b..1c3b4b083e 100644 --- a/mobile/lib/platform/native_sync_api.g.dart +++ b/mobile/lib/platform/native_sync_api.g.dart @@ -41,6 +41,9 @@ class PlatformAsset { required this.durationInSeconds, required this.orientation, required this.isFavorite, + this.adjustmentTime, + this.latitude, + this.longitude, }); String id; @@ -63,8 +66,28 @@ class PlatformAsset { bool isFavorite; + int? adjustmentTime; + + double? latitude; + + double? longitude; + List _toList() { - return [id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite]; + return [ + id, + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + orientation, + isFavorite, + adjustmentTime, + latitude, + longitude, + ]; } Object encode() { @@ -84,6 +107,9 @@ class PlatformAsset { durationInSeconds: result[7]! as int, orientation: result[8]! as int, isFavorite: result[9]! as bool, + adjustmentTime: result[10] as int?, + latitude: result[11] as double?, + longitude: result[12] as double?, ); } diff --git a/mobile/lib/presentation/pages/drift_asset_troubleshoot.page.dart b/mobile/lib/presentation/pages/drift_asset_troubleshoot.page.dart index 752ab5ba37..2df80b6ff6 100644 --- a/mobile/lib/presentation/pages/drift_asset_troubleshoot.page.dart +++ b/mobile/lib/presentation/pages/drift_asset_troubleshoot.page.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart'; +import 'package:immich_mobile/extensions/platform_extensions.dart'; import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; @RoutePage() @@ -129,6 +130,13 @@ class _AssetPropertiesSectionState extends ConsumerState<_AssetPropertiesSection properties.insert(4, _PropertyItem(label: 'Orientation', value: asset.orientation.toString())); final albums = await ref.read(assetServiceProvider).getSourceAlbums(asset.id); properties.add(_PropertyItem(label: 'Album', value: albums.map((a) => a.name).join(', '))); + if (CurrentPlatform.isIOS) { + properties.add(_PropertyItem(label: 'Adjustment Time', value: asset.adjustmentTime?.toString())); + } + _PropertyItem( + label: 'GPS Coordinates', + value: asset.hasCoordinates ? '${asset.latitude}, ${asset.longitude}' : null, + ); } Future _addRemoteAssetProperties(RemoteAsset asset) async { diff --git a/mobile/pigeon/native_sync_api.dart b/mobile/pigeon/native_sync_api.dart index 822e2eddb3..ec28afb008 100644 --- a/mobile/pigeon/native_sync_api.dart +++ b/mobile/pigeon/native_sync_api.dart @@ -27,6 +27,10 @@ class PlatformAsset { final int orientation; final bool isFavorite; + final int? adjustmentTime; + final double? latitude; + final double? longitude; + const PlatformAsset({ required this.id, required this.name, @@ -38,6 +42,9 @@ class PlatformAsset { this.durationInSeconds = 0, this.orientation = 0, this.isFavorite = false, + this.adjustmentTime, + this.latitude, + this.longitude, }); }