mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix: use adjustment time in iOS for hash reset (#24047)
* use adjustment time in iOS for hash reset * migration * fix equals check --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
4be9a5ebf8
commit
bbba1bfe8c
18 changed files with 176 additions and 15 deletions
|
|
@ -89,7 +89,10 @@ data class PlatformAsset (
|
||||||
val height: Long? = null,
|
val height: Long? = null,
|
||||||
val durationInSeconds: Long,
|
val durationInSeconds: Long,
|
||||||
val orientation: Long,
|
val orientation: Long,
|
||||||
val isFavorite: Boolean
|
val isFavorite: Boolean,
|
||||||
|
val adjustmentTime: Long? = null,
|
||||||
|
val latitude: Double? = null,
|
||||||
|
val longitude: Double? = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -104,7 +107,10 @@ data class PlatformAsset (
|
||||||
val durationInSeconds = pigeonVar_list[7] as Long
|
val durationInSeconds = pigeonVar_list[7] as Long
|
||||||
val orientation = pigeonVar_list[8] as Long
|
val orientation = pigeonVar_list[8] as Long
|
||||||
val isFavorite = pigeonVar_list[9] as Boolean
|
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<Any?> {
|
fun toList(): List<Any?> {
|
||||||
|
|
@ -119,6 +125,9 @@ data class PlatformAsset (
|
||||||
durationInSeconds,
|
durationInSeconds,
|
||||||
orientation,
|
orientation,
|
||||||
isFavorite,
|
isFavorite,
|
||||||
|
adjustmentTime,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import android.annotation.SuppressLint
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
|
|
||||||
BIN
mobile/drift_schemas/main/drift_schema_v14.json
generated
Normal file
BIN
mobile/drift_schemas/main/drift_schema_v14.json
generated
Normal file
Binary file not shown.
|
|
@ -140,6 +140,9 @@ struct PlatformAsset: Hashable {
|
||||||
var durationInSeconds: Int64
|
var durationInSeconds: Int64
|
||||||
var orientation: Int64
|
var orientation: Int64
|
||||||
var isFavorite: Bool
|
var isFavorite: Bool
|
||||||
|
var adjustmentTime: Int64? = nil
|
||||||
|
var latitude: Double? = nil
|
||||||
|
var longitude: Double? = nil
|
||||||
|
|
||||||
|
|
||||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||||
|
|
@ -154,6 +157,9 @@ struct PlatformAsset: Hashable {
|
||||||
let durationInSeconds = pigeonVar_list[7] as! Int64
|
let durationInSeconds = pigeonVar_list[7] as! Int64
|
||||||
let orientation = pigeonVar_list[8] as! Int64
|
let orientation = pigeonVar_list[8] as! Int64
|
||||||
let isFavorite = pigeonVar_list[9] as! Bool
|
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(
|
return PlatformAsset(
|
||||||
id: id,
|
id: id,
|
||||||
|
|
@ -165,7 +171,10 @@ struct PlatformAsset: Hashable {
|
||||||
height: height,
|
height: height,
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
isFavorite: isFavorite
|
isFavorite: isFavorite,
|
||||||
|
adjustmentTime: adjustmentTime,
|
||||||
|
latitude: latitude,
|
||||||
|
longitude: longitude
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
func toList() -> [Any?] {
|
func toList() -> [Any?] {
|
||||||
|
|
@ -180,6 +189,9 @@ struct PlatformAsset: Hashable {
|
||||||
durationInSeconds,
|
durationInSeconds,
|
||||||
orientation,
|
orientation,
|
||||||
isFavorite,
|
isFavorite,
|
||||||
|
adjustmentTime,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool {
|
static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@ extension PHAsset {
|
||||||
height: Int64(pixelHeight),
|
height: Int64(pixelHeight),
|
||||||
durationInSeconds: Int64(duration),
|
durationInSeconds: Int64(duration),
|
||||||
orientation: 0,
|
orientation: 0,
|
||||||
isFavorite: isFavorite
|
isFavorite: isFavorite,
|
||||||
|
adjustmentTime: adjustmentTimestamp,
|
||||||
|
latitude: location?.coordinate.latitude,
|
||||||
|
longitude: location?.coordinate.longitude
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,6 +27,13 @@ extension PHAsset {
|
||||||
return value(forKey: "filename") as? 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
|
// This method is expected to be slow as it goes through the asset resources to fetch the originalFilename
|
||||||
var originalFilename: String? {
|
var originalFilename: String? {
|
||||||
return getResource()?.originalFilename
|
return getResource()?.originalFilename
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ class LocalAsset extends BaseAsset {
|
||||||
final String? remoteAssetId;
|
final String? remoteAssetId;
|
||||||
final int orientation;
|
final int orientation;
|
||||||
|
|
||||||
|
final DateTime? adjustmentTime;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
|
|
||||||
const LocalAsset({
|
const LocalAsset({
|
||||||
required this.id,
|
required this.id,
|
||||||
String? remoteId,
|
String? remoteId,
|
||||||
|
|
@ -19,6 +23,9 @@ class LocalAsset extends BaseAsset {
|
||||||
super.isFavorite = false,
|
super.isFavorite = false,
|
||||||
super.livePhotoVideoId,
|
super.livePhotoVideoId,
|
||||||
this.orientation = 0,
|
this.orientation = 0,
|
||||||
|
this.adjustmentTime,
|
||||||
|
this.latitude,
|
||||||
|
this.longitude,
|
||||||
}) : remoteAssetId = remoteId;
|
}) : remoteAssetId = remoteId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -33,6 +40,8 @@ class LocalAsset extends BaseAsset {
|
||||||
@override
|
@override
|
||||||
String get heroTag => '${id}_${remoteId ?? checksum}';
|
String get heroTag => '${id}_${remoteId ?? checksum}';
|
||||||
|
|
||||||
|
bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return '''LocalAsset {
|
return '''LocalAsset {
|
||||||
|
|
@ -47,6 +56,9 @@ class LocalAsset extends BaseAsset {
|
||||||
remoteId: ${remoteId ?? "<NA>"}
|
remoteId: ${remoteId ?? "<NA>"}
|
||||||
isFavorite: $isFavorite,
|
isFavorite: $isFavorite,
|
||||||
orientation: $orientation,
|
orientation: $orientation,
|
||||||
|
adjustmentTime: $adjustmentTime,
|
||||||
|
latitude: ${latitude ?? "<NA>"},
|
||||||
|
longitude: ${longitude ?? "<NA>"},
|
||||||
}''';
|
}''';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,11 +67,23 @@ class LocalAsset extends BaseAsset {
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
if (other is! LocalAsset) return false;
|
if (other is! LocalAsset) return false;
|
||||||
if (identical(this, other)) return true;
|
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
|
@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({
|
LocalAsset copyWith({
|
||||||
String? id,
|
String? id,
|
||||||
|
|
@ -74,6 +98,9 @@ class LocalAsset extends BaseAsset {
|
||||||
int? durationInSeconds,
|
int? durationInSeconds,
|
||||||
bool? isFavorite,
|
bool? isFavorite,
|
||||||
int? orientation,
|
int? orientation,
|
||||||
|
DateTime? adjustmentTime,
|
||||||
|
double? latitude,
|
||||||
|
double? longitude,
|
||||||
}) {
|
}) {
|
||||||
return LocalAsset(
|
return LocalAsset(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
|
|
@ -88,6 +115,9 @@ class LocalAsset extends BaseAsset {
|
||||||
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
isFavorite: isFavorite ?? this.isFavorite,
|
||||||
orientation: orientation ?? this.orientation,
|
orientation: orientation ?? this.orientation,
|
||||||
|
adjustmentTime: adjustmentTime ?? this.adjustmentTime,
|
||||||
|
latitude: latitude ?? this.latitude,
|
||||||
|
longitude: longitude ?? this.longitude,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,7 @@ class LocalSyncService {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _assetsEqual(LocalAsset a, LocalAsset b) {
|
bool _assetsEqual(LocalAsset a, LocalAsset b) {
|
||||||
|
if (CurrentPlatform.isAndroid) {
|
||||||
return a.updatedAt.isAtSameMomentAs(b.updatedAt) &&
|
return a.updatedAt.isAtSameMomentAs(b.updatedAt) &&
|
||||||
a.createdAt.isAtSameMomentAs(b.createdAt) &&
|
a.createdAt.isAtSameMomentAs(b.createdAt) &&
|
||||||
a.width == b.width &&
|
a.width == b.width &&
|
||||||
|
|
@ -293,6 +294,17 @@ class LocalSyncService {
|
||||||
a.durationInSeconds == b.durationInSeconds;
|
a.durationInSeconds == b.durationInSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final firstAdjustment = a.adjustmentTime?.millisecondsSinceEpoch ?? 0;
|
||||||
|
final secondAdjustment = b.adjustmentTime?.millisecondsSinceEpoch ?? 0;
|
||||||
|
return firstAdjustment == secondAdjustment &&
|
||||||
|
a.createdAt.isAtSameMomentAs(b.createdAt) &&
|
||||||
|
a.width == b.width &&
|
||||||
|
a.height == b.height &&
|
||||||
|
a.durationInSeconds == b.durationInSeconds &&
|
||||||
|
a.latitude == b.latitude &&
|
||||||
|
a.longitude == b.longitude;
|
||||||
|
}
|
||||||
|
|
||||||
bool _albumsEqual(LocalAlbum a, LocalAlbum b) {
|
bool _albumsEqual(LocalAlbum a, LocalAlbum b) {
|
||||||
return a.name == b.name && a.assetCount == b.assetCount && a.updatedAt.isAtSameMomentAs(b.updatedAt);
|
return a.name == b.name && a.assetCount == b.assetCount && a.updatedAt.isAtSameMomentAs(b.updatedAt);
|
||||||
}
|
}
|
||||||
|
|
@ -376,5 +388,8 @@ extension PlatformToLocalAsset on PlatformAsset {
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
|
adjustmentTime: tryFromSecondsSinceEpoch(adjustmentTime, isUtc: true),
|
||||||
|
latitude: latitude,
|
||||||
|
longitude: longitude,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,12 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
|
||||||
|
|
||||||
IntColumn get orientation => integer().withDefault(const Constant(0))();
|
IntColumn get orientation => integer().withDefault(const Constant(0))();
|
||||||
|
|
||||||
|
DateTimeColumn get adjustmentTime => dateTime().nullable()();
|
||||||
|
|
||||||
|
RealColumn get latitude => real().nullable()();
|
||||||
|
|
||||||
|
RealColumn get longitude => real().nullable()();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column> get primaryKey => {id};
|
Set<Column> get primaryKey => {id};
|
||||||
}
|
}
|
||||||
|
|
@ -34,5 +40,8 @@ extension LocalAssetEntityDataDomainExtension on LocalAssetEntityData {
|
||||||
width: width,
|
width: width,
|
||||||
remoteId: remoteId,
|
remoteId: remoteId,
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
|
adjustmentTime: adjustmentTime,
|
||||||
|
latitude: latitude,
|
||||||
|
longitude: longitude,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -10,7 +10,6 @@ import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
||||||
|
|
@ -21,6 +20,7 @@ import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.d
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/stack.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.steps.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.steps.dart';
|
||||||
|
|
@ -95,7 +95,7 @@ class Drift extends $Drift implements IDatabaseRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 13;
|
int get schemaVersion => 14;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration => MigrationStrategy(
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
|
|
@ -185,6 +185,11 @@ class Drift extends $Drift implements IDatabaseRepository {
|
||||||
await m.createIndex(v13.idxTrashedLocalAssetChecksum);
|
await m.createIndex(v13.idxTrashedLocalAssetChecksum);
|
||||||
await m.createIndex(v13.idxTrashedLocalAssetAlbum);
|
await m.createIndex(v13.idxTrashedLocalAssetAlbum);
|
||||||
},
|
},
|
||||||
|
from13To14: (m, v14) async {
|
||||||
|
await m.addColumn(v14.localAssetEntity, v14.localAssetEntity.adjustmentTime);
|
||||||
|
await m.addColumn(v14.localAssetEntity, v14.localAssetEntity.latitude);
|
||||||
|
await m.addColumn(v14.localAssetEntity, v14.localAssetEntity.longitude);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
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';
|
||||||
|
|
@ -244,7 +246,56 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||||
return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
|
return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _upsertAssets(Iterable<LocalAsset> localAssets) {
|
Future<void> Function(Iterable<LocalAsset>) get _upsertAssets =>
|
||||||
|
CurrentPlatform.isIOS ? _upsertAssetsDarwin : _upsertAssetsAndroid;
|
||||||
|
|
||||||
|
Future<void> _upsertAssetsDarwin(Iterable<LocalAsset> localAssets) async {
|
||||||
|
if (localAssets.isEmpty) {
|
||||||
|
return Future.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset checksum if asset changed
|
||||||
|
await _db.batch((batch) async {
|
||||||
|
for (final asset in localAssets) {
|
||||||
|
final companion = LocalAssetEntityCompanion(
|
||||||
|
checksum: const Value(null),
|
||||||
|
adjustmentTime: Value(asset.adjustmentTime),
|
||||||
|
);
|
||||||
|
batch.update(
|
||||||
|
_db.localAssetEntity,
|
||||||
|
companion,
|
||||||
|
where: (row) => row.id.equals(asset.id) & row.adjustmentTime.isNotExp(Variable(asset.adjustmentTime)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return _db.batch((batch) async {
|
||||||
|
for (final asset in localAssets) {
|
||||||
|
final companion = LocalAssetEntityCompanion.insert(
|
||||||
|
name: asset.name,
|
||||||
|
type: asset.type,
|
||||||
|
createdAt: Value(asset.createdAt),
|
||||||
|
updatedAt: Value(asset.updatedAt),
|
||||||
|
width: Value(asset.width),
|
||||||
|
height: Value(asset.height),
|
||||||
|
durationInSeconds: Value(asset.durationInSeconds),
|
||||||
|
id: asset.id,
|
||||||
|
orientation: Value(asset.orientation),
|
||||||
|
isFavorite: Value(asset.isFavorite),
|
||||||
|
latitude: Value(asset.latitude),
|
||||||
|
longitude: Value(asset.longitude),
|
||||||
|
adjustmentTime: Value(asset.adjustmentTime),
|
||||||
|
);
|
||||||
|
batch.insert<$LocalAssetEntityTable, LocalAssetEntityData>(
|
||||||
|
_db.localAssetEntity,
|
||||||
|
companion.copyWith(checksum: const Value(null)),
|
||||||
|
onConflict: DoUpdate((old) => companion),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _upsertAssetsAndroid(Iterable<LocalAsset> localAssets) async {
|
||||||
if (localAssets.isEmpty) {
|
if (localAssets.isEmpty) {
|
||||||
return Future.value();
|
return Future.value();
|
||||||
}
|
}
|
||||||
|
|
@ -260,6 +311,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||||
height: Value(asset.height),
|
height: Value(asset.height),
|
||||||
durationInSeconds: Value(asset.durationInSeconds),
|
durationInSeconds: Value(asset.durationInSeconds),
|
||||||
id: asset.id,
|
id: asset.id,
|
||||||
|
checksum: const Value(null),
|
||||||
orientation: Value(asset.orientation),
|
orientation: Value(asset.orientation),
|
||||||
isFavorite: Value(asset.isFavorite),
|
isFavorite: Value(asset.isFavorite),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
BIN
mobile/lib/platform/native_sync_api.g.dart
generated
BIN
mobile/lib/platform/native_sync_api.g.dart
generated
Binary file not shown.
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.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';
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
|
@ -129,6 +130,15 @@ class _AssetPropertiesSectionState extends ConsumerState<_AssetPropertiesSection
|
||||||
properties.insert(4, _PropertyItem(label: 'Orientation', value: asset.orientation.toString()));
|
properties.insert(4, _PropertyItem(label: 'Orientation', value: asset.orientation.toString()));
|
||||||
final albums = await ref.read(assetServiceProvider).getSourceAlbums(asset.id);
|
final albums = await ref.read(assetServiceProvider).getSourceAlbums(asset.id);
|
||||||
properties.add(_PropertyItem(label: 'Album', value: albums.map((a) => a.name).join(', ')));
|
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()));
|
||||||
|
}
|
||||||
|
properties.add(
|
||||||
|
_PropertyItem(
|
||||||
|
label: 'GPS Coordinates',
|
||||||
|
value: asset.hasCoordinates ? '${asset.latitude}, ${asset.longitude}' : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addRemoteAssetProperties(RemoteAsset asset) async {
|
Future<void> _addRemoteAssetProperties(RemoteAsset asset) async {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ Future<void> migrateDatabaseIfNeeded(Isar db, Drift drift) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version < 19 && Store.isBetaTimelineEnabled) {
|
if (version < 19 && Store.isBetaTimelineEnabled) {
|
||||||
if (!await _populateUpdatedAtTime(drift)) {
|
if (!await _populateLocalAssetTime(drift)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -229,7 +229,7 @@ Future<void> _migrateDeviceAsset(Isar db) async {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _populateUpdatedAtTime(Drift db) async {
|
Future<bool> _populateLocalAssetTime(Drift db) async {
|
||||||
try {
|
try {
|
||||||
final nativeApi = NativeSyncApi();
|
final nativeApi = NativeSyncApi();
|
||||||
final albums = await nativeApi.getAlbums();
|
final albums = await nativeApi.getAlbums();
|
||||||
|
|
@ -240,6 +240,9 @@ Future<bool> _populateUpdatedAtTime(Drift db) async {
|
||||||
batch.update(
|
batch.update(
|
||||||
db.localAssetEntity,
|
db.localAssetEntity,
|
||||||
LocalAssetEntityCompanion(
|
LocalAssetEntityCompanion(
|
||||||
|
longitude: Value(asset.longitude),
|
||||||
|
latitude: Value(asset.latitude),
|
||||||
|
adjustmentTime: Value(tryFromSecondsSinceEpoch(asset.adjustmentTime, isUtc: true)),
|
||||||
updatedAt: Value(tryFromSecondsSinceEpoch(asset.updatedAt, isUtc: true) ?? DateTime.timestamp()),
|
updatedAt: Value(tryFromSecondsSinceEpoch(asset.updatedAt, isUtc: true) ?? DateTime.timestamp()),
|
||||||
),
|
),
|
||||||
where: (t) => t.id.equals(asset.id),
|
where: (t) => t.id.equals(asset.id),
|
||||||
|
|
@ -250,7 +253,7 @@ Future<bool> _populateUpdatedAtTime(Drift db) async {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dPrint(() => "[MIGRATION] Error while populating updatedAt time: $error");
|
dPrint(() => "[MIGRATION] Error while populating asset time: $error");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ class PlatformAsset {
|
||||||
final int orientation;
|
final int orientation;
|
||||||
final bool isFavorite;
|
final bool isFavorite;
|
||||||
|
|
||||||
|
final int? adjustmentTime;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
|
|
||||||
const PlatformAsset({
|
const PlatformAsset({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
|
@ -38,6 +42,9 @@ class PlatformAsset {
|
||||||
this.durationInSeconds = 0,
|
this.durationInSeconds = 0,
|
||||||
this.orientation = 0,
|
this.orientation = 0,
|
||||||
this.isFavorite = false,
|
this.isFavorite = false,
|
||||||
|
this.adjustmentTime,
|
||||||
|
this.latitude,
|
||||||
|
this.longitude,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
BIN
mobile/test/drift/main/generated/schema.dart
generated
BIN
mobile/test/drift/main/generated/schema.dart
generated
Binary file not shown.
BIN
mobile/test/drift/main/generated/schema_v14.dart
generated
Normal file
BIN
mobile/test/drift/main/generated/schema_v14.dart
generated
Normal file
Binary file not shown.
Loading…
Reference in a new issue