Compare commits

..

1 Commits

Author SHA1 Message Date
Santo Shakil 96b195ff8e fix(mobile): send a full datetime from the android memories widget 2026-07-07 14:33:58 +06:00
4 changed files with 5 additions and 60 deletions
@@ -14,6 +14,7 @@ import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import java.time.LocalDate
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
class ImmichAPI(cfg: ServerConfig) {
@@ -88,7 +89,8 @@ class ImmichAPI(cfg: ServerConfig) {
}
suspend fun fetchMemory(date: LocalDate): List<MemoryResult> = withContext(Dispatchers.IO) {
val iso8601 = date.format(DateTimeFormatter.ISO_LOCAL_DATE)
// server matches memories by the UTC day, so send noon UTC of the local day to land on the right day in every timezone
val iso8601 = date.atTime(12, 0).atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
val url = buildRequestURL("/memories", listOf("for" to iso8601))
val connection = (url.openConnection() as HttpURLConnection).apply {
requestMethod = "GET"
@@ -79,17 +79,6 @@ 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 currentAsset = ref.watch(assetViewerProvider.select((s) => s.currentAsset));
final currentHeroTag = ref.watch(assetViewerProvider.select((s) => s.currentAsset?.heroTag));
_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 = currentAsset != null && currentAsset.isSameAsset(displayAsset);
final isCurrent = currentHeroTag == displayAsset.heroTag;
final viewportWidth = MediaQuery.widthOf(context);
final viewportHeight = MediaQuery.heightOf(context);
@@ -1,46 +0,0 @@
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);
});
});
}