Przeglądaj źródła

fix(mobile): stack count reset when navigating to library (#4647)

Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
shenlong 1 rok temu
rodzic
commit
b49b10141e

+ 1 - 1
cli/src/api/open-api/api.ts

@@ -771,7 +771,7 @@ export interface AssetResponseDto {
      * @type {number}
      * @memberof AssetResponseDto
      */
-    'stackCount': number;
+    'stackCount': number | null;
     /**
      * 
      * @type {string}

+ 1 - 1
mobile/lib/modules/asset_viewer/views/gallery_viewer.dart

@@ -83,7 +83,7 @@ class GalleryViewerPage extends HookConsumerWidget {
         navStack.length > 2 &&
         navStack.elementAt(navStack.length - 2).name == TrashRoute.name;
     final stackIndex = useState(-1);
-    final stack = showStack && currentAsset.stackCount > 0
+    final stack = showStack && currentAsset.stackChildrenCount > 0
         ? ref.watch(assetStackStateProvider(currentAsset))
         : <Asset>[];
     final stackElements = showStack ? [currentAsset, ...stack] : <Asset>[];

+ 4 - 4
mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart

@@ -104,16 +104,16 @@ class ThumbnailImage extends StatelessWidget {
         right: 5,
         child: Row(
           children: [
-            if (asset.stackCount > 1)
+            if (asset.stackChildrenCount > 1)
               Text(
-                "${asset.stackCount}",
+                "${asset.stackChildrenCount}",
                 style: const TextStyle(
                   color: Colors.white,
                   fontSize: 10,
                   fontWeight: FontWeight.bold,
                 ),
               ),
-            if (asset.stackCount > 1)
+            if (asset.stackChildrenCount > 1)
               const SizedBox(
                 width: 3,
               ),
@@ -233,7 +233,7 @@ class ThumbnailImage extends StatelessWidget {
               ),
             ),
           if (!asset.isImage) buildVideoIcon(),
-          if (asset.isImage && asset.stackCount > 0) buildStackIcon(),
+          if (asset.isImage && asset.stackChildrenCount > 0) buildStackIcon(),
         ],
       ),
     );

+ 11 - 3
mobile/lib/shared/models/asset.dart

@@ -153,7 +153,10 @@ class Asset {
 
   String? stackParentId;
 
-  int stackCount;
+  @ignore
+  int get stackChildrenCount => stackCount ?? 0;
+
+  int? stackCount;
 
   /// `true` if this [Asset] is present on the device
   @ignore
@@ -253,7 +256,11 @@ class Asset {
         isFavorite != a.isFavorite ||
         isArchived != a.isArchived ||
         isTrashed != a.isTrashed ||
-        stackCount != a.stackCount;
+        // no local stack count or different count from remote
+        ((stackCount == null && a.stackCount != null) ||
+            (stackCount != null &&
+                a.stackCount != null &&
+                stackCount != a.stackCount));
   }
 
   /// Returns a new [Asset] with values from this and merged & updated with [a]
@@ -269,6 +276,7 @@ class Asset {
           width: a.width ?? width,
           height: a.height ?? height,
           exifInfo: a.exifInfo?.copyWith(id: id) ?? exifInfo,
+          stackCount: a.stackCount ?? stackCount,
         );
       } else if (isRemote) {
         return _copyWith(
@@ -299,7 +307,7 @@ class Asset {
           height: a.height,
           livePhotoVideoId: a.livePhotoVideoId,
           stackParentId: a.stackParentId,
-          stackCount: a.stackCount,
+          stackCount: a.stackCount ?? stackCount,
           // isFavorite + isArchived are not set by device-only assets
           isFavorite: a.isFavorite,
           isArchived: a.isArchived,

+ 24 - 8
mobile/lib/shared/models/asset.g.dart

@@ -250,7 +250,7 @@ Asset _assetDeserialize(
     localId: reader.readStringOrNull(offsets[10]),
     ownerId: reader.readLong(offsets[11]),
     remoteId: reader.readStringOrNull(offsets[12]),
-    stackCount: reader.readLong(offsets[13]),
+    stackCount: reader.readLongOrNull(offsets[13]),
     stackParentId: reader.readStringOrNull(offsets[14]),
     type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[15])] ??
         AssetType.other,
@@ -294,7 +294,7 @@ P _assetDeserializeProp<P>(
     case 12:
       return (reader.readStringOrNull(offset)) as P;
     case 13:
-      return (reader.readLong(offset)) as P;
+      return (reader.readLongOrNull(offset)) as P;
     case 14:
       return (reader.readStringOrNull(offset)) as P;
     case 15:
@@ -1825,8 +1825,24 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
     });
   }
 
+  QueryBuilder<Asset, Asset, QAfterFilterCondition> stackCountIsNull() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(const FilterCondition.isNull(
+        property: r'stackCount',
+      ));
+    });
+  }
+
+  QueryBuilder<Asset, Asset, QAfterFilterCondition> stackCountIsNotNull() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(const FilterCondition.isNotNull(
+        property: r'stackCount',
+      ));
+    });
+  }
+
   QueryBuilder<Asset, Asset, QAfterFilterCondition> stackCountEqualTo(
-      int value) {
+      int? value) {
     return QueryBuilder.apply(this, (query) {
       return query.addFilterCondition(FilterCondition.equalTo(
         property: r'stackCount',
@@ -1836,7 +1852,7 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
   }
 
   QueryBuilder<Asset, Asset, QAfterFilterCondition> stackCountGreaterThan(
-    int value, {
+    int? value, {
     bool include = false,
   }) {
     return QueryBuilder.apply(this, (query) {
@@ -1849,7 +1865,7 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
   }
 
   QueryBuilder<Asset, Asset, QAfterFilterCondition> stackCountLessThan(
-    int value, {
+    int? value, {
     bool include = false,
   }) {
     return QueryBuilder.apply(this, (query) {
@@ -1862,8 +1878,8 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
   }
 
   QueryBuilder<Asset, Asset, QAfterFilterCondition> stackCountBetween(
-    int lower,
-    int upper, {
+    int? lower,
+    int? upper, {
     bool includeLower = true,
     bool includeUpper = true,
   }) {
@@ -2854,7 +2870,7 @@ extension AssetQueryProperty on QueryBuilder<Asset, Asset, QQueryProperty> {
     });
   }
 
-  QueryBuilder<Asset, int, QQueryOperations> stackCountProperty() {
+  QueryBuilder<Asset, int?, QQueryOperations> stackCountProperty() {
     return QueryBuilder.apply(this, (query) {
       return query.addPropertyName(r'stackCount');
     });

+ 7 - 3
mobile/openapi/lib/model/asset_response_dto.dart

@@ -118,7 +118,7 @@ class AssetResponseDto {
 
   List<AssetResponseDto> stack;
 
-  int stackCount;
+  int? stackCount;
 
   String? stackParentId;
 
@@ -194,7 +194,7 @@ class AssetResponseDto {
     (resized.hashCode) +
     (smartInfo == null ? 0 : smartInfo!.hashCode) +
     (stack.hashCode) +
-    (stackCount.hashCode) +
+    (stackCount == null ? 0 : stackCount!.hashCode) +
     (stackParentId == null ? 0 : stackParentId!.hashCode) +
     (tags.hashCode) +
     (thumbhash == null ? 0 : thumbhash!.hashCode) +
@@ -248,7 +248,11 @@ class AssetResponseDto {
     //  json[r'smartInfo'] = null;
     }
       json[r'stack'] = this.stack;
+    if (this.stackCount != null) {
       json[r'stackCount'] = this.stackCount;
+    } else {
+    //  json[r'stackCount'] = null;
+    }
     if (this.stackParentId != null) {
       json[r'stackParentId'] = this.stackParentId;
     } else {
@@ -299,7 +303,7 @@ class AssetResponseDto {
         resized: mapValueOfType<bool>(json, r'resized')!,
         smartInfo: SmartInfoResponseDto.fromJson(json[r'smartInfo']),
         stack: AssetResponseDto.listFromJson(json[r'stack']),
-        stackCount: mapValueOfType<int>(json, r'stackCount')!,
+        stackCount: mapValueOfType<int>(json, r'stackCount'),
         stackParentId: mapValueOfType<String>(json, r'stackParentId'),
         tags: TagResponseDto.listFromJson(json[r'tags']),
         thumbhash: mapValueOfType<String>(json, r'thumbhash'),

+ 1 - 0
server/immich-openapi-specs.json

@@ -6009,6 +6009,7 @@
             "type": "array"
           },
           "stackCount": {
+            "nullable": true,
             "type": "integer"
           },
           "stackParentId": {

+ 2 - 2
server/src/domain/asset/response-dto/asset-response.dto.ts

@@ -45,7 +45,7 @@ export class AssetResponseDto extends SanitizedAssetResponseDto {
   stackParentId?: string | null;
   stack?: AssetResponseDto[];
   @ApiProperty({ type: 'integer' })
-  stackCount!: number;
+  stackCount!: number | null;
 }
 
 export type AssetMapOptions = {
@@ -102,7 +102,7 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As
     checksum: entity.checksum.toString('base64'),
     stackParentId: entity.stackParentId,
     stack: withStack ? entity.stack?.map((a) => mapAsset(a, { stripMetadata })) ?? undefined : undefined,
-    stackCount: entity.stack?.length ?? 0,
+    stackCount: entity.stack?.length ?? null,
     isExternal: entity.isExternal,
     isOffline: entity.isOffline,
     isReadOnly: entity.isReadOnly,

+ 1 - 1
web/src/api/open-api/api.ts

@@ -771,7 +771,7 @@ export interface AssetResponseDto {
      * @type {number}
      * @memberof AssetResponseDto
      */
-    'stackCount': number;
+    'stackCount': number | null;
     /**
      * 
      * @type {string}