mirror of
https://github.com/immich-app/immich.git
synced 2026-07-15 21:32:32 +03:00
fix(mobile): show memories with no showAt/hideAt in the timeline lane (#29158)
This commit is contained in:
@@ -25,8 +25,8 @@ class DriftMemoryRepository extends DriftDatabaseRepository {
|
||||
])
|
||||
..where(_db.memoryEntity.ownerId.equals(ownerId))
|
||||
..where(_db.memoryEntity.deletedAt.isNull())
|
||||
..where(_db.memoryEntity.showAt.isSmallerOrEqualValue(localUtc))
|
||||
..where(_db.memoryEntity.hideAt.isBiggerOrEqualValue(localUtc))
|
||||
..where(_db.memoryEntity.showAt.isNull() | _db.memoryEntity.showAt.isSmallerOrEqualValue(localUtc))
|
||||
..where(_db.memoryEntity.hideAt.isNull() | _db.memoryEntity.hideAt.isBiggerOrEqualValue(localUtc))
|
||||
..orderBy([OrderingTerm.desc(_db.memoryEntity.memoryAt), OrderingTerm.asc(_db.remoteAssetEntity.createdAt)]);
|
||||
|
||||
final rows = await query.get();
|
||||
|
||||
108
mobile/test/medium/repositories/memory_repository_test.dart
Normal file
108
mobile/test/medium/repositories/memory_repository_test.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/memory.repository.dart';
|
||||
|
||||
import '../repository_context.dart';
|
||||
|
||||
void main() {
|
||||
late MediumRepositoryContext ctx;
|
||||
late DriftMemoryRepository sut;
|
||||
|
||||
setUp(() {
|
||||
ctx = MediumRepositoryContext();
|
||||
sut = DriftMemoryRepository(ctx.db);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await ctx.dispose();
|
||||
});
|
||||
|
||||
group('getAll', () {
|
||||
// #24745: memories created via the API have no showAt/hideAt. before the fix
|
||||
// the window filter (show_at <= now AND hide_at >= now) drops them because a
|
||||
// NULL comparison is never true.
|
||||
test('includes a memory with null showAt/hideAt', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final memory = await ctx.newMemory(ownerId: user.id);
|
||||
await ctx.newMemoryAsset(memoryId: memory.id, assetId: asset.id);
|
||||
|
||||
final result = await sut.getAll(user.id);
|
||||
|
||||
expect(result, hasLength(1));
|
||||
expect(result.first.id, memory.id);
|
||||
expect(result.first.assets.single.id, asset.id);
|
||||
});
|
||||
|
||||
test('includes a memory whose window covers today', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final now = DateTime.now().toUtc();
|
||||
final memory = await ctx.newMemory(
|
||||
ownerId: user.id,
|
||||
showAt: now.subtract(const Duration(days: 10)),
|
||||
hideAt: now.add(const Duration(days: 10)),
|
||||
);
|
||||
await ctx.newMemoryAsset(memoryId: memory.id, assetId: asset.id);
|
||||
|
||||
final result = await sut.getAll(user.id);
|
||||
|
||||
expect(result.map((m) => m.id), [memory.id]);
|
||||
});
|
||||
|
||||
test('excludes a memory whose hideAt is in the past', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final now = DateTime.now().toUtc();
|
||||
final memory = await ctx.newMemory(
|
||||
ownerId: user.id,
|
||||
showAt: now.subtract(const Duration(days: 20)),
|
||||
hideAt: now.subtract(const Duration(days: 10)),
|
||||
);
|
||||
await ctx.newMemoryAsset(memoryId: memory.id, assetId: asset.id);
|
||||
|
||||
final result = await sut.getAll(user.id);
|
||||
|
||||
expect(result, isEmpty);
|
||||
});
|
||||
|
||||
test('excludes a memory whose showAt is in the future', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final now = DateTime.now().toUtc();
|
||||
final memory = await ctx.newMemory(
|
||||
ownerId: user.id,
|
||||
showAt: now.add(const Duration(days: 10)),
|
||||
hideAt: now.add(const Duration(days: 20)),
|
||||
);
|
||||
await ctx.newMemoryAsset(memoryId: memory.id, assetId: asset.id);
|
||||
|
||||
final result = await sut.getAll(user.id);
|
||||
|
||||
expect(result, isEmpty);
|
||||
});
|
||||
|
||||
test('includes a memory with showAt in the past and null hideAt', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final now = DateTime.now().toUtc();
|
||||
final memory = await ctx.newMemory(ownerId: user.id, showAt: now.subtract(const Duration(days: 10)));
|
||||
await ctx.newMemoryAsset(memoryId: memory.id, assetId: asset.id);
|
||||
|
||||
final result = await sut.getAll(user.id);
|
||||
|
||||
expect(result.map((m) => m.id), [memory.id]);
|
||||
});
|
||||
|
||||
test('excludes a memory with null showAt and hideAt in the past', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final now = DateTime.now().toUtc();
|
||||
final memory = await ctx.newMemory(ownerId: user.id, hideAt: now.subtract(const Duration(days: 10)));
|
||||
await ctx.newMemoryAsset(memoryId: memory.id, assetId: asset.id);
|
||||
|
||||
final result = await sut.getAll(user.id);
|
||||
|
||||
expect(result, isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -3,11 +3,14 @@ import 'package:drift/native.dart';
|
||||
import 'package:immich_mobile/domain/models/album/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/memory.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart';
|
||||
@@ -309,4 +312,37 @@ class MediumRepositoryContext {
|
||||
Future<void> newLocalAlbumAsset({required String albumId, required String assetId}) => db
|
||||
.into(db.localAlbumAssetEntity)
|
||||
.insert(LocalAlbumAssetEntityCompanion(albumId: .new(albumId), assetId: .new(assetId)));
|
||||
|
||||
Future<MemoryEntityData> newMemory({
|
||||
String? id,
|
||||
String? ownerId,
|
||||
MemoryTypeEnum? type,
|
||||
int? year,
|
||||
DateTime? memoryAt,
|
||||
DateTime? showAt,
|
||||
DateTime? hideAt,
|
||||
DateTime? deletedAt,
|
||||
bool? isSaved,
|
||||
}) async {
|
||||
id ??= TestUtils.uuid();
|
||||
return db
|
||||
.into(db.memoryEntity)
|
||||
.insertReturning(
|
||||
MemoryEntityCompanion(
|
||||
id: .new(id),
|
||||
ownerId: .new(TestUtils.uuid(ownerId)),
|
||||
type: .new(type ?? MemoryTypeEnum.onThisDay),
|
||||
data: .new(MemoryData(year: year ?? 2020).toJson()),
|
||||
isSaved: .new(isSaved ?? false),
|
||||
memoryAt: .new(TestUtils.date(memoryAt)),
|
||||
showAt: .new(showAt),
|
||||
hideAt: .new(hideAt),
|
||||
deletedAt: .new(deletedAt),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> newMemoryAsset({required String memoryId, required String assetId}) => db
|
||||
.into(db.memoryAssetEntity)
|
||||
.insert(MemoryAssetEntityCompanion(memoryId: .new(memoryId), assetId: .new(assetId)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user