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
2 changed files with 113 additions and 5 deletions
|
@ -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…
Reference in a new issue