mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:29:32 -05:00 
			
		
		
		
	feat(mobile): Precaches next image in memories (#3365)
* Precaches images in memories * Fixes jumps and precaches images * refactors to move precacheAsset over to ImmichImage to keep logic in same place --------- Co-authored-by: Alex Tran <Alex.Tran@conductix.com>
This commit is contained in:
		
							parent
							
								
									ace755f264
								
							
						
					
					
						commit
						7f35583c2c
					
				@ -5,7 +5,10 @@ import 'package:flutter_hooks/flutter_hooks.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/memories/models/memory.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/memories/ui/memory_card.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/models/asset.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_image.dart';
 | 
			
		||||
import 'package:intl/intl.dart';
 | 
			
		||||
import 'package:openapi/api.dart' as api;
 | 
			
		||||
 | 
			
		||||
class MemoryPage extends HookConsumerWidget {
 | 
			
		||||
  final List<Memory> memories;
 | 
			
		||||
@ -37,11 +40,16 @@ class MemoryPage extends HookConsumerWidget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toNextAsset(int currentAssetIndex) {
 | 
			
		||||
      (currentAssetIndex + 1 < currentMemory.value.assets.length)
 | 
			
		||||
          ? memoryAssetPageController.jumpToPage(
 | 
			
		||||
              (currentAssetIndex + 1),
 | 
			
		||||
            )
 | 
			
		||||
          : toNextMemory();
 | 
			
		||||
      if (currentAssetIndex + 1 < currentMemory.value.assets.length) {
 | 
			
		||||
        // Go to the next asset
 | 
			
		||||
        memoryAssetPageController.nextPage(
 | 
			
		||||
          curve: Curves.easeInOut,
 | 
			
		||||
          duration: const Duration(milliseconds: 500),
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        // Go to the next memory since we are at the end of our assets
 | 
			
		||||
        toNextMemory();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateProgressText() {
 | 
			
		||||
@ -49,9 +57,67 @@ class MemoryPage extends HookConsumerWidget {
 | 
			
		||||
          "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Downloads and caches the image for the asset at this [currentMemory]'s index
 | 
			
		||||
    precacheAsset(int index) async {
 | 
			
		||||
      // Guard index out of range
 | 
			
		||||
      if (index < 0) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      late Asset asset;
 | 
			
		||||
      if (index < currentMemory.value.assets.length) {
 | 
			
		||||
        // Uses the next asset in this current memory
 | 
			
		||||
        asset = currentMemory.value.assets[index];
 | 
			
		||||
      } else {
 | 
			
		||||
        // Precache the first asset in the next memory if available
 | 
			
		||||
        final currentMemoryIndex = memories.indexOf(currentMemory.value);
 | 
			
		||||
 | 
			
		||||
        // Guard no memory found
 | 
			
		||||
        if (currentMemoryIndex == -1) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final nextMemoryIndex = currentMemoryIndex + 1;
 | 
			
		||||
        // Guard no next memory
 | 
			
		||||
        if (nextMemoryIndex >= memories.length) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get the first asset from the next memory
 | 
			
		||||
        asset = memories[nextMemoryIndex].assets.first;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Gets the thumbnail url and precaches it
 | 
			
		||||
      final precaches = <Future<dynamic>>[];
 | 
			
		||||
 | 
			
		||||
      precaches.add(
 | 
			
		||||
        ImmichImage.precacheAsset(
 | 
			
		||||
          asset,
 | 
			
		||||
          context,
 | 
			
		||||
          type: api.ThumbnailFormat.WEBP,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      precaches.add(
 | 
			
		||||
        ImmichImage.precacheAsset(
 | 
			
		||||
          asset,
 | 
			
		||||
          context,
 | 
			
		||||
          type: api.ThumbnailFormat.JPEG,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      await Future.wait(precaches);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Precache the next page right away if we are on the first page
 | 
			
		||||
    if (currentAssetPage.value == 0) {
 | 
			
		||||
      Future.delayed(const Duration(milliseconds: 200))
 | 
			
		||||
          .then((_) => precacheAsset(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onAssetChanged(int otherIndex) {
 | 
			
		||||
      HapticFeedback.selectionClick();
 | 
			
		||||
      currentAssetPage.value = otherIndex;
 | 
			
		||||
      precacheAsset(otherIndex + 1);
 | 
			
		||||
      updateProgressText();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -147,4 +147,46 @@ class ImmichImage extends StatelessWidget {
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Precaches this asset for instant load the next time it is shown
 | 
			
		||||
  static Future<void> precacheAsset(
 | 
			
		||||
    Asset asset,
 | 
			
		||||
    BuildContext context, {
 | 
			
		||||
    type = api.ThumbnailFormat.WEBP,
 | 
			
		||||
  }) {
 | 
			
		||||
    final authToken = 'Bearer ${Store.get(StoreKey.accessToken)}';
 | 
			
		||||
 | 
			
		||||
    if (type == api.ThumbnailFormat.WEBP) {
 | 
			
		||||
      final thumbnailUrl = getThumbnailUrl(asset);
 | 
			
		||||
      final thumbnailCacheKey = getThumbnailCacheKey(asset);
 | 
			
		||||
      final thumbnailProvider = CachedNetworkImageProvider(
 | 
			
		||||
        thumbnailUrl,
 | 
			
		||||
        cacheKey: thumbnailCacheKey,
 | 
			
		||||
        headers: {"Authorization": authToken},
 | 
			
		||||
      );
 | 
			
		||||
      return precacheImage(thumbnailProvider, context);
 | 
			
		||||
    }
 | 
			
		||||
    // Precache the local image
 | 
			
		||||
    if (!asset.isRemote &&
 | 
			
		||||
        (asset.isLocal || !Store.get(StoreKey.preferRemoteImage, false))) {
 | 
			
		||||
      final provider = AssetEntityImageProvider(
 | 
			
		||||
        asset.local!,
 | 
			
		||||
        isOriginal: false,
 | 
			
		||||
        thumbnailSize: const ThumbnailSize.square(250), // like server thumbs
 | 
			
		||||
      );
 | 
			
		||||
      return precacheImage(provider, context);
 | 
			
		||||
    } else {
 | 
			
		||||
      // Precache the remote image since we are not using local images
 | 
			
		||||
      final url = getThumbnailUrl(asset, type: api.ThumbnailFormat.JPEG);
 | 
			
		||||
      final cacheKey =
 | 
			
		||||
          getThumbnailCacheKey(asset, type: api.ThumbnailFormat.JPEG);
 | 
			
		||||
      final provider = CachedNetworkImageProvider(
 | 
			
		||||
        url,
 | 
			
		||||
        cacheKey: cacheKey,
 | 
			
		||||
        headers: {"Authorization": authToken},
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      return precacheImage(provider, context);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user