فهرست منبع

mobile: show thumbhash on scroll

shalong-tanwen 1 سال پیش
والد
کامیت
ce2ecbea40
2فایلهای تغییر یافته به همراه61 افزوده شده و 60 حذف شده
  1. 59 60
      mobile/lib/modules/home/ui/asset_grid/immich_asset_grid_view.dart
  2. 2 0
      mobile/lib/shared/ui/immich_image.dart

+ 59 - 60
mobile/lib/modules/home/ui/asset_grid/immich_asset_grid_view.dart

@@ -4,6 +4,7 @@ import 'dart:math';
 import 'package:collection/collection.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter_thumbhash/flutter_thumbhash.dart';
 import 'package:immich_mobile/modules/asset_viewer/providers/scroll_notifier.provider.dart';
 import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_image.dart';
 import 'package:immich_mobile/shared/models/asset.dart';
@@ -120,33 +121,55 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
         assets.firstWhereOrNull((e) => !_selectedAssets.contains(e)) == null;
   }
 
-  Widget _buildThumbnailOrPlaceholder(Asset asset, int index) {
-    return ThumbnailImage(
-      asset: asset,
-      index: index,
-      loadAsset: widget.renderList.loadAsset,
-      totalAssets: widget.renderList.totalAssets,
-      multiselectEnabled: widget.selectionActive,
-      isSelected: widget.selectionActive && _selectedAssets.contains(asset),
-      onSelect: () => _selectAssets([asset]),
-      onDeselect: widget.canDeselect ||
-              widget.preselectedAssets == null ||
-              !widget.preselectedAssets!.contains(asset)
-          ? () => _deselectAssets([asset])
-          : null,
-      useGrayBoxPlaceholder: true,
-      showStorageIndicator: widget.showStorageIndicator,
-      heroOffset: widget.heroOffset,
-      showStack: widget.showStack,
+  Widget _getPlaceholder(Asset asset) {
+    if (asset.thumbhash != null) {
+      return FittedBox(
+        fit: BoxFit.fill,
+        child: Image(
+          image: ThumbHash.fromIntList(asset.thumbhash!).toImage(),
+        ),
+      );
+    }
+    return Container(
+      color: Colors.grey,
     );
   }
 
+  Widget _buildThumbnailOrPlaceholder(
+    Asset asset,
+    int index,
+    bool isScrolling,
+  ) {
+    return isScrolling
+        ? _getPlaceholder(asset)
+        : ThumbnailImage(
+            asset: asset,
+            index: index,
+            loadAsset: widget.renderList.loadAsset,
+            totalAssets: widget.renderList.totalAssets,
+            multiselectEnabled: widget.selectionActive,
+            isSelected:
+                widget.selectionActive && _selectedAssets.contains(asset),
+            onSelect: () => _selectAssets([asset]),
+            onDeselect: widget.canDeselect ||
+                    widget.preselectedAssets == null ||
+                    !widget.preselectedAssets!.contains(asset)
+                ? () => _deselectAssets([asset])
+                : null,
+            useGrayBoxPlaceholder: true,
+            showStorageIndicator: widget.showStorageIndicator,
+            heroOffset: widget.heroOffset,
+            showStack: widget.showStack,
+          );
+  }
+
   Widget _buildAssetRow(
     Key key,
     BuildContext context,
     List<Asset> assets,
     int absoluteOffset,
     double width,
+    bool isScrolling,
   ) {
     // Default: All assets have the same width
     final widthDistribution = List.filled(assets.length, 1.0);
@@ -185,7 +208,11 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
             bottom: widget.margin,
             right: last ? 0.0 : widget.margin,
           ),
-          child: _buildThumbnailOrPlaceholder(asset, absoluteOffset + index),
+          child: _buildThumbnailOrPlaceholder(
+            asset,
+            absoluteOffset + index,
+            isScrolling,
+          ),
         );
       }).toList(),
     );
@@ -224,25 +251,6 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
     );
   }
 
-  Widget _buildPlaceHolderRow(Key key, int num, double width, double height) {
-    return Row(
-      key: key,
-      children: [
-        for (int i = 0; i < num; i++)
-          Container(
-            key: ValueKey(i),
-            width: width,
-            height: height,
-            margin: EdgeInsets.only(
-              bottom: widget.margin,
-              right: i + 1 == num ? 0.0 : widget.margin,
-            ),
-            color: Colors.grey,
-          ),
-      ],
-    );
-  }
-
   Widget _buildSection(
     BuildContext context,
     RenderAssetGridElement section,
@@ -254,9 +262,8 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
             widget.margin * (widget.assetsPerRow - 1) / widget.assetsPerRow;
         final rows =
             (section.count + widget.assetsPerRow - 1) ~/ widget.assetsPerRow;
-        final List<Asset> assetsToRender = scrolling
-            ? []
-            : widget.renderList.loadAssets(section.offset, section.count);
+        final List<Asset> assetsToRender =
+            widget.renderList.loadAssets(section.offset, section.count);
         return Column(
           key: ValueKey(section.offset),
           crossAxisAlignment: CrossAxisAlignment.start,
@@ -274,25 +281,17 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
                         .loadAssets(section.offset, section.totalCount),
               ),
             for (int i = 0; i < rows; i++)
-              scrolling
-                  ? _buildPlaceHolderRow(
-                      ValueKey(i),
-                      i + 1 == rows
-                          ? section.count - i * widget.assetsPerRow
-                          : widget.assetsPerRow,
-                      width,
-                      width,
-                    )
-                  : _buildAssetRow(
-                      ValueKey(i),
-                      context,
-                      assetsToRender.nestedSlice(
-                        i * widget.assetsPerRow,
-                        min((i + 1) * widget.assetsPerRow, section.count),
-                      ),
-                      section.offset + i * widget.assetsPerRow,
-                      width,
-                    ),
+              _buildAssetRow(
+                ValueKey(i),
+                context,
+                assetsToRender.nestedSlice(
+                  i * widget.assetsPerRow,
+                  min((i + 1) * widget.assetsPerRow, section.count),
+                ),
+                section.offset + i * widget.assetsPerRow,
+                width,
+                scrolling,
+              ),
           ],
         );
       },

+ 2 - 0
mobile/lib/shared/ui/immich_image.dart

@@ -123,6 +123,8 @@ class ImmichImage extends StatelessWidget {
         cacheKey: getThumbnailCacheKey(asset, type: type),
       ),
       fit: fit,
+      duration: const Duration(milliseconds: 500),
+      syncDuration: const Duration(milliseconds: 500),
       placeholder: placeholderWidget,
       errorBuilder: (context, error) {
         if (error is HttpExceptionWithStatus &&