mirror of
https://github.com/immich-app/immich.git
synced 2025-12-17 09:13:17 +03:00
more fixes
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/extensions/num_extensions.dart';
|
||||||
|
|
||||||
part 'local_asset.model.dart';
|
part 'local_asset.model.dart';
|
||||||
part 'remote_asset.model.dart';
|
part 'remote_asset.model.dart';
|
||||||
|
|||||||
@@ -42,8 +42,13 @@ class LocalAsset extends BaseAsset {
|
|||||||
@override
|
@override
|
||||||
String get heroTag => '${id}_${remoteId ?? checksum}';
|
String get heroTag => '${id}_${remoteId ?? checksum}';
|
||||||
|
|
||||||
String get eTag =>
|
String get eTag {
|
||||||
"${createdAt.millisecondsSinceEpoch ~/ 1000}$kUploadETagDelimiter${(adjustmentTime?.millisecondsSinceEpoch ?? 0) ~/ 1000}$kUploadETagDelimiter${latitude ?? 0}$kUploadETagDelimiter${longitude ?? 0}";
|
final createdAt = this.createdAt.millisecondsSinceEpoch ~/ 1000;
|
||||||
|
final adjustmentTime = this.adjustmentTime?.millisecondsSinceEpoch ?? 0;
|
||||||
|
final latitude = this.latitude?.truncateTo(2).toStringAsFixed(2) ?? "0.00";
|
||||||
|
final longitude = this.longitude?.truncateTo(2).toStringAsFixed(2) ?? "0.00";
|
||||||
|
return "$createdAt$kUploadETagDelimiter$adjustmentTime$kUploadETagDelimiter$latitude$kUploadETagDelimiter$longitude";
|
||||||
|
}
|
||||||
|
|
||||||
bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
|
bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
|
||||||
import 'package:immich_mobile/domain/models/asset/asset_metadata.model.dart';
|
import 'package:immich_mobile/domain/models/asset/asset_metadata.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
||||||
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
||||||
@@ -33,12 +34,12 @@ Future<void> syncCloudIds(ProviderContainer ref) async {
|
|||||||
for (final mapping in mappingsToUpdate) {
|
for (final mapping in mappingsToUpdate) {
|
||||||
final mobileMeta = AssetMetadataUpsertItemDto(
|
final mobileMeta = AssetMetadataUpsertItemDto(
|
||||||
key: AssetMetadataKey.mobileApp,
|
key: AssetMetadataKey.mobileApp,
|
||||||
value: RemoteAssetMobileAppMetadata(cloudId: mapping.cloudId, eTag: mapping.eTag),
|
value: RemoteAssetMobileAppMetadata(cloudId: mapping.localAsset.cloudId, eTag: mapping.localAsset.eTag),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await assetApi.updateAssetMetadata(mapping.assetId, AssetMetadataUpsertDto(items: [mobileMeta]));
|
await assetApi.updateAssetMetadata(mapping.remoteAssetId, AssetMetadataUpsertDto(items: [mobileMeta]));
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
Logger('migrateCloudIds').warning('Failed to update metadata for asset ${mapping.assetId}', error, stack);
|
Logger('migrateCloudIds').warning('Failed to update metadata for asset ${mapping.remoteAssetId}', error, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,47 +53,30 @@ Future<void> _populateCloudIds(Drift drift) async {
|
|||||||
await DriftLocalAlbumRepository(drift).updateCloudMapping(cloudMapping);
|
await DriftLocalAlbumRepository(drift).updateCloudMapping(cloudMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef _CloudIdMapping = ({String assetId, String cloudId, String eTag});
|
typedef _CloudIdMapping = ({String remoteAssetId, LocalAsset localAsset});
|
||||||
|
|
||||||
Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift, String userId) async {
|
Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift, String userId) async {
|
||||||
final query =
|
final query =
|
||||||
drift.remoteAssetEntity.selectOnly().join([
|
drift.remoteAssetEntity.select().join([
|
||||||
leftOuterJoin(
|
leftOuterJoin(
|
||||||
drift.localAssetEntity,
|
drift.localAssetEntity,
|
||||||
drift.localAssetEntity.checksum.equalsExp(drift.remoteAssetEntity.checksum),
|
drift.localAssetEntity.checksum.equalsExp(drift.remoteAssetEntity.checksum),
|
||||||
useColumns: false,
|
),
|
||||||
),
|
leftOuterJoin(
|
||||||
leftOuterJoin(
|
drift.remoteAssetCloudIdEntity,
|
||||||
drift.remoteAssetCloudIdEntity,
|
drift.localAssetEntity.iCloudId.equalsExp(drift.remoteAssetCloudIdEntity.cloudId),
|
||||||
drift.localAssetEntity.iCloudId.equalsExp(drift.remoteAssetCloudIdEntity.cloudId),
|
useColumns: false,
|
||||||
useColumns: false,
|
),
|
||||||
),
|
])..where(
|
||||||
])
|
drift.localAssetEntity.id.isNotNull() &
|
||||||
..addColumns([
|
drift.localAssetEntity.iCloudId.isNotNull() &
|
||||||
drift.remoteAssetEntity.id,
|
drift.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
drift.localAssetEntity.iCloudId,
|
drift.remoteAssetCloudIdEntity.cloudId.isNull(),
|
||||||
drift.localAssetEntity.createdAt,
|
);
|
||||||
drift.localAssetEntity.adjustmentTime,
|
|
||||||
drift.localAssetEntity.latitude,
|
|
||||||
drift.localAssetEntity.longitude,
|
|
||||||
])
|
|
||||||
..where(
|
|
||||||
drift.localAssetEntity.id.isNotNull() &
|
|
||||||
drift.localAssetEntity.iCloudId.isNotNull() &
|
|
||||||
drift.remoteAssetEntity.ownerId.equals(userId) &
|
|
||||||
drift.remoteAssetCloudIdEntity.cloudId.isNull(),
|
|
||||||
);
|
|
||||||
return query.map((row) {
|
return query.map((row) {
|
||||||
final createdAt = row.read(drift.localAssetEntity.createdAt)!;
|
|
||||||
final adjustmentTime = row.read(drift.localAssetEntity.adjustmentTime);
|
|
||||||
final latitude = row.read(drift.localAssetEntity.latitude);
|
|
||||||
final longitude = row.read(drift.localAssetEntity.longitude);
|
|
||||||
final eTag =
|
|
||||||
"${createdAt.millisecondsSinceEpoch ~/ 1000}$kUploadETagDelimiter${(adjustmentTime?.millisecondsSinceEpoch ?? 0) ~/ 1000}$kUploadETagDelimiter${latitude ?? 0}$kUploadETagDelimiter${longitude ?? 0}";
|
|
||||||
return (
|
return (
|
||||||
assetId: row.read(drift.remoteAssetEntity.id)!,
|
remoteAssetId: row.read(drift.remoteAssetEntity.id)!,
|
||||||
cloudId: row.read(drift.localAssetEntity.iCloudId)!,
|
localAsset: row.readTable(drift.localAssetEntity).toDto(),
|
||||||
eTag: eTag,
|
|
||||||
);
|
);
|
||||||
}).get();
|
}).get();
|
||||||
}
|
}
|
||||||
|
|||||||
17
mobile/lib/extensions/drift_extensions.dart
Normal file
17
mobile/lib/extensions/drift_extensions.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
// ignore: invalid_use_of_internal_member, implementation_imports
|
||||||
|
import 'package:drift/src/runtime/query_builder/expressions/internal.dart';
|
||||||
|
|
||||||
|
extension DoubleTruncateExpression<T extends num> on Expression<T> {
|
||||||
|
Expression<T> truncateTo(int fractionDigits) {
|
||||||
|
final mod = Constant(pow(10, fractionDigits).toDouble());
|
||||||
|
return BaseInfixOperator(
|
||||||
|
BaseInfixOperator(this, '*', mod, precedence: Precedence.mulDivide).cast(DriftSqlType.int),
|
||||||
|
'/',
|
||||||
|
mod,
|
||||||
|
precedence: Precedence.mulDivide,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
mobile/lib/extensions/num_extensions.dart
Normal file
8
mobile/lib/extensions/num_extensions.dart
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
extension DoubleTruncate on double {
|
||||||
|
double truncateTo(int fractionDigits) {
|
||||||
|
final mod = math.pow(10.0, fractionDigits);
|
||||||
|
return ((this * mod).truncate() / mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,10 @@ SELECT
|
|||||||
rae.live_photo_video_id,
|
rae.live_photo_video_id,
|
||||||
0 as orientation,
|
0 as orientation,
|
||||||
rae.stack_id,
|
rae.stack_id,
|
||||||
NULL as i_cloud_id
|
NULL as i_cloud_id,
|
||||||
|
NULL as latitude,
|
||||||
|
NULL as longitude,
|
||||||
|
NULL as adjustmentTime
|
||||||
FROM
|
FROM
|
||||||
remote_asset_entity rae
|
remote_asset_entity rae
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
@@ -55,7 +58,10 @@ SELECT
|
|||||||
NULL as live_photo_video_id,
|
NULL as live_photo_video_id,
|
||||||
lae.orientation,
|
lae.orientation,
|
||||||
NULL as stack_id,
|
NULL as stack_id,
|
||||||
lae.i_cloud_id
|
lae.i_cloud_id,
|
||||||
|
lae.latitude,
|
||||||
|
lae.longitude,
|
||||||
|
lae.adjustment_time
|
||||||
FROM
|
FROM
|
||||||
local_asset_entity lae
|
local_asset_entity lae
|
||||||
WHERE NOT EXISTS (
|
WHERE NOT EXISTS (
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class MergedAssetDrift extends i1.ModularAccessor {
|
|||||||
);
|
);
|
||||||
$arrayStartIndex += generatedlimit.amountOfVariables;
|
$arrayStartIndex += generatedlimit.amountOfVariables;
|
||||||
return customSelect(
|
return customSelect(
|
||||||
'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, NULL AS i_cloud_id FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, lae.i_cloud_id FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}',
|
'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, NULL AS i_cloud_id, NULL AS latitude, NULL AS longitude, NULL AS adjustmentTime FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, lae.i_cloud_id, lae.latitude, lae.longitude, lae.adjustment_time FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}',
|
||||||
variables: [
|
variables: [
|
||||||
for (var $ in userIds) i0.Variable<String>($),
|
for (var $ in userIds) i0.Variable<String>($),
|
||||||
...generatedlimit.introducedVariables,
|
...generatedlimit.introducedVariables,
|
||||||
@@ -63,6 +63,9 @@ class MergedAssetDrift extends i1.ModularAccessor {
|
|||||||
orientation: row.read<int>('orientation'),
|
orientation: row.read<int>('orientation'),
|
||||||
stackId: row.readNullable<String>('stack_id'),
|
stackId: row.readNullable<String>('stack_id'),
|
||||||
iCloudId: row.readNullable<String>('i_cloud_id'),
|
iCloudId: row.readNullable<String>('i_cloud_id'),
|
||||||
|
latitude: row.readNullable<double>('latitude'),
|
||||||
|
longitude: row.readNullable<double>('longitude'),
|
||||||
|
adjustmentTime: row.readNullable<DateTime>('adjustmentTime'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -131,6 +134,9 @@ class MergedAssetResult {
|
|||||||
final int orientation;
|
final int orientation;
|
||||||
final String? stackId;
|
final String? stackId;
|
||||||
final String? iCloudId;
|
final String? iCloudId;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
|
final DateTime? adjustmentTime;
|
||||||
MergedAssetResult({
|
MergedAssetResult({
|
||||||
this.remoteId,
|
this.remoteId,
|
||||||
this.localId,
|
this.localId,
|
||||||
@@ -149,6 +155,9 @@ class MergedAssetResult {
|
|||||||
required this.orientation,
|
required this.orientation,
|
||||||
this.stackId,
|
this.stackId,
|
||||||
this.iCloudId,
|
this.iCloudId,
|
||||||
|
this.latitude,
|
||||||
|
this.longitude,
|
||||||
|
this.adjustmentTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.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';
|
||||||
|
import 'package:immich_mobile/extensions/drift_extensions.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_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
@@ -133,10 +136,17 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, String>> getHashMappingFromCloudId() async {
|
Future<Map<String, String>> getHashMappingFromCloudId() async {
|
||||||
final createdAt = coalesce([_db.localAssetEntity.createdAt.strftime('%s'), const Constant('0')]);
|
final createdAt = _db.localAssetEntity.createdAt.strftime('%s');
|
||||||
final adjustmentTime = coalesce([_db.localAssetEntity.adjustmentTime.strftime('%s'), const Constant('0')]);
|
final adjustmentTime = coalesce([_db.localAssetEntity.adjustmentTime.strftime('%s'), const Constant('0')]);
|
||||||
final latitude = coalesce([_db.localAssetEntity.latitude.cast(DriftSqlType.string), const Constant('0')]);
|
final latitude = coalesce([
|
||||||
final longitude = coalesce([_db.localAssetEntity.longitude.cast(DriftSqlType.string), const Constant('0')]);
|
_db.localAssetEntity.latitude,
|
||||||
|
const Constant(0.0),
|
||||||
|
]).truncateTo(2).cast(DriftSqlType.string);
|
||||||
|
final longitude = coalesce([
|
||||||
|
_db.localAssetEntity.longitude,
|
||||||
|
const Constant(0.0),
|
||||||
|
]).truncateTo(2).cast(DriftSqlType.string);
|
||||||
|
|
||||||
final delimiter = const Constant(kUploadETagDelimiter);
|
final delimiter = const Constant(kUploadETagDelimiter);
|
||||||
final eTag = createdAt + delimiter + adjustmentTime + delimiter + latitude + delimiter + longitude;
|
final eTag = createdAt + delimiter + adjustmentTime + delimiter + latitude + delimiter + longitude;
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
durationInSeconds: row.durationInSeconds,
|
durationInSeconds: row.durationInSeconds,
|
||||||
orientation: row.orientation,
|
orientation: row.orientation,
|
||||||
cloudId: row.iCloudId,
|
cloudId: row.iCloudId,
|
||||||
|
latitude: row.latitude,
|
||||||
|
longitude: row.longitude,
|
||||||
|
adjustmentTime: row.adjustmentTime,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.get();
|
.get();
|
||||||
|
|||||||
Reference in New Issue
Block a user