Skip to content

Commit 69d7510

Browse files
shenlong-tanwenmidzelis
authored andcommitted
refactor(mobile): device asset entity to use modified time (#17064)
* refactor: device asset entity to use modified time * chore: cleanup * refactor: remove album media dependency from hashservice * refactor: return updated copy of asset * add hash service tests * chore: rename hash batch constants * chore: log the number of assets processed during migration * chore: more logs * refactor: use lookup and more tests * use sort approach * refactor hash service to use for loop instead * refactor: rename to getByIds --------- Co-authored-by: shenlong-tanwen <[email protected]>
1 parent 1d4815d commit 69d7510

23 files changed

+1799
-183
lines changed

mobile/analysis_options.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ custom_lint:
6161
# refactor to make the providers and services testable
6262
- lib/providers/backup/{backup,manual_upload}.provider.dart # uses only PMProgressHandler
6363
- lib/services/{background,backup}.service.dart # uses only PMProgressHandler
64+
- test/**.dart
6465
- import_rule_isar:
6566
message: isar must only be used in entities and repositories
6667
restrict: package:isar
@@ -150,7 +151,6 @@ dart_code_metrics:
150151
- avoid-unnecessary-continue
151152
- avoid-unnecessary-nullable-return-type: false
152153
- binary-expression-operand-order
153-
- move-variable-outside-iteration
154154
- pattern-fields-ordering
155155
- prefer-abstract-final-static-class
156156
- prefer-commenting-future-delayed

mobile/lib/constants/constants.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ const double downloadFailed = -2;
44

55
// Number of log entries to retain on app start
66
const int kLogTruncateLimit = 250;
7+
8+
const int kBatchHashFileLimit = 128;
9+
const int kBatchHashSizeLimit = 1024 * 1024 * 1024; // 1GB
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import 'dart:async';
2+
3+
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
4+
import 'package:immich_mobile/domain/models/device_asset.model.dart';
5+
6+
abstract interface class IDeviceAssetRepository implements IDatabaseRepository {
7+
Future<bool> updateAll(List<DeviceAsset> assetHash);
8+
9+
Future<List<DeviceAsset>> getByIds(List<String> localIds);
10+
11+
Future<void> deleteIds(List<String> ids);
12+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import 'dart:typed_data';
2+
3+
class DeviceAsset {
4+
final String assetId;
5+
final Uint8List hash;
6+
final DateTime modifiedTime;
7+
8+
const DeviceAsset({
9+
required this.assetId,
10+
required this.hash,
11+
required this.modifiedTime,
12+
});
13+
14+
@override
15+
bool operator ==(covariant DeviceAsset other) {
16+
if (identical(this, other)) return true;
17+
18+
return other.assetId == assetId &&
19+
other.hash == hash &&
20+
other.modifiedTime == modifiedTime;
21+
}
22+
23+
@override
24+
int get hashCode {
25+
return assetId.hashCode ^ hash.hashCode ^ modifiedTime.hashCode;
26+
}
27+
28+
@override
29+
String toString() {
30+
return 'DeviceAsset(assetId: $assetId, hash: $hash, modifiedTime: $modifiedTime)';
31+
}
32+
33+
DeviceAsset copyWith({
34+
String? assetId,
35+
Uint8List? hash,
36+
DateTime? modifiedTime,
37+
}) {
38+
return DeviceAsset(
39+
assetId: assetId ?? this.assetId,
40+
hash: hash ?? this.hash,
41+
modifiedTime: modifiedTime ?? this.modifiedTime,
42+
);
43+
}
44+
}

mobile/lib/entities/asset.entity.dart

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:immich_mobile/extensions/string_extensions.dart';
66
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
77
as entity;
88
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
9+
import 'package:immich_mobile/utils/diff.dart';
910
import 'package:immich_mobile/utils/hash.dart';
1011
import 'package:isar/isar.dart';
1112
import 'package:openapi/api.dart';
@@ -358,23 +359,23 @@ class Asset {
358359
// take most values from newer asset
359360
// keep vales that can never be set by the asset not in DB
360361
if (a.isRemote) {
361-
return a._copyWith(
362+
return a.copyWith(
362363
id: id,
363364
localId: localId,
364365
width: a.width ?? width,
365366
height: a.height ?? height,
366367
exifInfo: a.exifInfo?.copyWith(assetId: id) ?? exifInfo,
367368
);
368369
} else if (isRemote) {
369-
return _copyWith(
370+
return copyWith(
370371
localId: localId ?? a.localId,
371372
width: width ?? a.width,
372373
height: height ?? a.height,
373374
exifInfo: exifInfo ?? a.exifInfo?.copyWith(assetId: id),
374375
);
375376
} else {
376377
// TODO: Revisit this and remove all bool field assignments
377-
return a._copyWith(
378+
return a.copyWith(
378379
id: id,
379380
remoteId: remoteId,
380381
livePhotoVideoId: livePhotoVideoId,
@@ -394,7 +395,7 @@ class Asset {
394395
// fill in potentially missing values, i.e. merge assets
395396
if (a.isRemote) {
396397
// values from remote take precedence
397-
return _copyWith(
398+
return copyWith(
398399
remoteId: a.remoteId,
399400
width: a.width,
400401
height: a.height,
@@ -416,7 +417,7 @@ class Asset {
416417
);
417418
} else {
418419
// add only missing values (and set isLocal to true)
419-
return _copyWith(
420+
return copyWith(
420421
localId: localId ?? a.localId,
421422
width: width ?? a.width,
422423
height: height ?? a.height,
@@ -427,7 +428,7 @@ class Asset {
427428
}
428429
}
429430

430-
Asset _copyWith({
431+
Asset copyWith({
431432
Id? id,
432433
String? checksum,
433434
String? remoteId,
@@ -488,6 +489,9 @@ class Asset {
488489

489490
static int compareById(Asset a, Asset b) => a.id.compareTo(b.id);
490491

492+
static int compareByLocalId(Asset a, Asset b) =>
493+
compareToNullable(a.localId, b.localId);
494+
491495
static int compareByChecksum(Asset a, Asset b) =>
492496
a.checksum.compareTo(b.checksum);
493497

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import 'dart:typed_data';
2+
3+
import 'package:immich_mobile/domain/models/device_asset.model.dart';
4+
import 'package:immich_mobile/utils/hash.dart';
5+
import 'package:isar/isar.dart';
6+
7+
part 'device_asset.entity.g.dart';
8+
9+
@Collection(inheritance: false)
10+
class DeviceAssetEntity {
11+
Id get id => fastHash(assetId);
12+
13+
@Index(replace: true, unique: true, type: IndexType.hash)
14+
final String assetId;
15+
@Index(unique: false, type: IndexType.hash)
16+
final List<byte> hash;
17+
final DateTime modifiedTime;
18+
19+
const DeviceAssetEntity({
20+
required this.assetId,
21+
required this.hash,
22+
required this.modifiedTime,
23+
});
24+
25+
DeviceAsset toModel() => DeviceAsset(
26+
assetId: assetId,
27+
hash: Uint8List.fromList(hash),
28+
modifiedTime: modifiedTime,
29+
);
30+
31+
static DeviceAssetEntity fromDto(DeviceAsset dto) => DeviceAssetEntity(
32+
assetId: dto.assetId,
33+
hash: dto.hash,
34+
modifiedTime: dto.modifiedTime,
35+
);
36+
}

0 commit comments

Comments
 (0)