Compare commits

..

1 Commits

Author SHA1 Message Date
Santo Shakil b6c63df1c9 fix(mobile): refresh person thumbnail when the featured photo changes 2026-06-27 14:55:15 +06:00
23 changed files with 75 additions and 33 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
[
{
"label": "v3.0.0-rc.4",
"url": "https://docs.v3.0.0-rc.4.archive.immich.app"
"label": "v3.0.0-rc.3",
"url": "https://docs.v3.0.0-rc.3.archive.immich.app"
},
{
"label": "v2.7.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"description": "",
"main": "index.js",
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "immich-ml"
version = "3.0.0rc4"
version = "3.0.0rc3"
description = ""
authors = [{ name = "Hau Tran", email = "alex.tran1502@gmail.com" }]
requires-python = ">=3.11,<4.0"
+1 -1
View File
@@ -974,7 +974,7 @@ wheels = [
[[package]]
name = "immich-ml"
version = "3.0.0rc4"
version = "3.0.0rc3"
source = { editable = "." }
dependencies = [
{ name = "aiocache" },
+4 -4
View File
@@ -22,8 +22,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 3052,
"android.injected.version.name" => "3.0.0-rc.4",
"android.injected.version.code" => 3051,
"android.injected.version.name" => "3.0.0-rc.3",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab', track: 'beta')
@@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 3052,
"android.injected.version.name" => "3.0.0-rc.4",
"android.injected.version.code" => 3051,
"android.injected.version.name" => "3.0.0-rc.3",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
@@ -180,7 +180,11 @@ class _PeopleCollectionCard extends ConsumerWidget {
mainAxisSpacing: 8,
physics: const NeverScrollableScrollPhysics(),
children: people.take(4).map((person) {
return CircleAvatar(backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(person.id)));
return CircleAvatar(
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(person.id, updatedAt: person.updatedAt),
),
);
}).toList(),
);
},
@@ -94,7 +94,9 @@ class _DriftPeopleCollectionPageState extends ConsumerState<DriftPeopleCollectio
child: CircleAvatar(
key: ValueKey(person.id),
maxRadius: isTablet ? 100 / 2 : 96 / 2,
backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(person.id)),
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(person.id, updatedAt: person.updatedAt),
),
),
),
),
@@ -49,21 +49,14 @@ class BaseActionButton extends ConsumerWidget {
if (menuItem) {
final iconColor = this.iconColor;
final onPressed = this.onPressed;
return MenuItemButton(
closeOnActivate: false,
style: MenuItemButton.styleFrom(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
leadingIcon: Icon(iconData, color: iconColor, size: 20),
onPressed: onPressed == null
? null
: () {
onPressed();
MenuController.maybeOf(context)?.close();
},
onPressed: onPressed,
child: Text(label, style: TextStyle(fontSize: 15, color: iconColor)),
);
}
@@ -121,7 +121,9 @@ class _Avatar extends StatelessWidget {
elevation: 3,
child: CircleAvatar(
maxRadius: imageSize / 2,
backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(person.id)),
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(person.id, updatedAt: person.updatedAt),
),
),
),
),
@@ -32,5 +32,6 @@ class PersonApiRepository extends ApiRepository {
isHidden: dto.isHidden,
name: dto.name,
thumbnailPath: dto.thumbnailPath,
updatedAt: dto.updatedAt.orElse(null),
);
}
+3 -2
View File
@@ -20,6 +20,7 @@ String getPlaybackUrlForRemoteId(final String id) {
return '${Store.get(StoreKey.serverEndpoint)}/assets/$id/video/playback?';
}
String getFaceThumbnailUrl(final String personId) {
return '${Store.get(StoreKey.serverEndpoint)}/people/$personId/thumbnail';
String getFaceThumbnailUrl(final String personId, {DateTime? updatedAt}) {
final url = '${Store.get(StoreKey.serverEndpoint)}/people/$personId/thumbnail';
return updatedAt != null ? '$url?c=${updatedAt.millisecondsSinceEpoch}' : url;
}
@@ -230,7 +230,9 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> with S
elevation: 3,
child: CircleAvatar(
maxRadius: 84 / 2,
backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(widget.person.id)),
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(widget.person.id, updatedAt: widget.person.updatedAt),
),
),
),
),
@@ -80,7 +80,9 @@ class PeoplePicker extends HookConsumerWidget {
child: CircleAvatar(
key: ValueKey(person.id),
maxRadius: imageSize / 2,
backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(person.id)),
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(person.id, updatedAt: person.updatedAt),
),
),
),
),
+1 -1
View File
@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 3.0.0-rc.4
- API version: 3.0.0-rc.3
- Generator version: 7.22.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
+1 -1
View File
@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none'
version: 3.0.0-rc.4+3052
version: 3.0.0-rc.3+3051
environment:
sdk: '>=3.12.0 <4.0.0'
@@ -0,0 +1,35 @@
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
void main() {
const endpoint = 'http://localhost:3000';
setUpAll(() async {
final db = Drift(DatabaseConnection(NativeDatabase.memory(), closeStreamsSynchronously: true));
await StoreService.init(storeRepository: DriftStoreRepository(db), listenUpdates: false);
await StoreService.I.put(StoreKey.serverEndpoint, endpoint);
});
group('getFaceThumbnailUrl', () {
test('omits the cache buster when updatedAt is null', () {
expect(getFaceThumbnailUrl('person-1'), '$endpoint/people/person-1/thumbnail');
});
test('appends the updatedAt cache buster so a changed featured photo busts the cache (#27434)', () {
final url = getFaceThumbnailUrl('person-1', updatedAt: DateTime.fromMillisecondsSinceEpoch(1717000000000));
expect(url, '$endpoint/people/person-1/thumbnail?c=1717000000000');
});
test('a newer updatedAt yields a different url so the image cache key changes', () {
final before = getFaceThumbnailUrl('person-1', updatedAt: DateTime.fromMillisecondsSinceEpoch(1));
final after = getFaceThumbnailUrl('person-1', updatedAt: DateTime.fromMillisecondsSinceEpoch(2));
expect(before, isNot(after));
});
});
}
+1 -1
View File
@@ -16206,7 +16206,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"contact": {}
},
"tags": [
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "immich-monorepo",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"description": "Monorepo for Immich",
"type": "module",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"description": "Command Line Interface (CLI) for Immich",
"repository": {
"type": "git",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@immich/sdk",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"description": "Auto-generated TypeScript SDK for the Immich API",
"repository": {
"type": "git",
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* Immich
* 3.0.0-rc.4
* 3.0.0-rc.3
* DO NOT MODIFY - This file has been generated using oazapfts.
* See https://www.npmjs.com/package/oazapfts
*/
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "immich",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"description": "",
"author": "",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "immich-web",
"version": "3.0.0-rc.4",
"version": "3.0.0-rc.3",
"license": "GNU Affero General Public License version 3",
"type": "module",
"scripts": {