mirror of
https://github.com/immich-app/immich.git
synced 2026-07-07 13:07:04 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dfea8c21a6 |
@@ -79,6 +79,17 @@ sealed class BaseAsset {
|
||||
bool get isLocalOnly => storage == AssetState.local;
|
||||
bool get isRemoteOnly => storage == AssetState.remote;
|
||||
|
||||
// Same asset even if localId is known on one side but not the other (heroTag isn't stable then)
|
||||
bool isSameAsset(BaseAsset other) {
|
||||
if (remoteId != null && other.remoteId != null) {
|
||||
return remoteId == other.remoteId;
|
||||
}
|
||||
if (localId != null && other.localId != null) {
|
||||
return localId == other.localId;
|
||||
}
|
||||
return checksum != null && checksum == other.checksum;
|
||||
}
|
||||
|
||||
bool get isEditable => false;
|
||||
|
||||
// Overridden in subclasses
|
||||
|
||||
@@ -395,7 +395,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final currentHeroTag = ref.watch(assetViewerProvider.select((s) => s.currentAsset?.heroTag));
|
||||
final currentAsset = ref.watch(assetViewerProvider.select((s) => s.currentAsset));
|
||||
_showingDetails = ref.watch(assetViewerProvider.select((s) => s.showingDetails));
|
||||
final stackIndex = ref.watch(assetViewerProvider.select((s) => s.stackIndex));
|
||||
final isPlayingMotionVideo = ref.watch(isPlayingMotionVideoProvider);
|
||||
@@ -414,7 +414,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
|
||||
displayAsset = stackChildren.elementAt(stackIndex);
|
||||
}
|
||||
|
||||
final isCurrent = currentHeroTag == displayAsset.heroTag;
|
||||
final isCurrent = currentAsset != null && currentAsset.isSameAsset(displayAsset);
|
||||
|
||||
final viewportWidth = MediaQuery.widthOf(context);
|
||||
final viewportHeight = MediaQuery.heightOf(context);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../../unit/factories/local_asset_factory.dart';
|
||||
import '../../unit/factories/remote_asset_factory.dart';
|
||||
|
||||
void main() {
|
||||
group('BaseAsset.isSameAsset', () {
|
||||
test('search/folder copy (localId null) matches the merged DB copy (localId set)', () {
|
||||
// #29472: search and folder assets arrive with localId null, then the viewer
|
||||
// watches the DB copy which fills localId. heroTag embeds localId, so it
|
||||
// diverges for the same asset and isCurrent used to go false.
|
||||
final searchCopy = RemoteAssetFactory.create(id: 'asset-1');
|
||||
final mergedCopy = searchCopy.copyWith(localId: 'local-1');
|
||||
|
||||
expect(searchCopy.localId, isNull);
|
||||
expect(mergedCopy.localId, 'local-1');
|
||||
expect(searchCopy.heroTag, isNot(mergedCopy.heroTag));
|
||||
|
||||
expect(searchCopy.isSameAsset(mergedCopy), isTrue);
|
||||
expect(mergedCopy.isSameAsset(searchCopy), isTrue);
|
||||
});
|
||||
|
||||
test('different remote assets are not the same', () {
|
||||
final a = RemoteAssetFactory.create(id: 'asset-1');
|
||||
final b = RemoteAssetFactory.create(id: 'asset-2');
|
||||
|
||||
expect(a.isSameAsset(b), isFalse);
|
||||
});
|
||||
|
||||
test('same checksum but different remote ids are not the same (duplicate files)', () {
|
||||
final a = RemoteAssetFactory.create(id: 'asset-1');
|
||||
final b = RemoteAssetFactory.create(id: 'asset-2').copyWith(checksum: a.checksum);
|
||||
|
||||
expect(a.checksum, b.checksum);
|
||||
expect(a.isSameAsset(b), isFalse);
|
||||
});
|
||||
|
||||
test('falls back to checksum when only one side has an id (local-only vs remote-only)', () {
|
||||
final remoteOnly = RemoteAssetFactory.create(id: 'asset-1');
|
||||
final localOnly = LocalAssetFactory.create(id: 'local-1').copyWith(checksum: remoteOnly.checksum);
|
||||
|
||||
expect(remoteOnly.isSameAsset(localOnly), isTrue);
|
||||
expect(localOnly.isSameAsset(remoteOnly), isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user