Files
immich/mobile-v2/lib/presentation/components/image/cache/image_loader.dart
2025-02-26 08:58:19 +05:30

55 lines
1.9 KiB
Dart

import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:immich_mobile/service_locator.dart';
import 'package:immich_mobile/utils/immich_api_client.dart';
/// An exception for the [ImageLoader] and the Immich image providers
class ImageLoadingException implements Exception {
final String message;
const ImageLoadingException(this.message);
@override
String toString() => 'ImageLoadingException: $message';
}
/// Loads the codec from the URI and sends the events to the [chunkEvents] stream
///
/// Credit to [flutter_cached_network_image](https://github.com/Baseflow/flutter_cached_network_image/blob/develop/cached_network_image/lib/src/image_provider/_image_loader.dart)
/// for this wonderful implementation of their image loader
abstract final class ImageLoader {
static Future<ui.Codec> loadImageFromCache(
String uri, {
required CacheManager cache,
required ImageDecoderCallback decode,
StreamController<ImageChunkEvent>? chunkEvents,
}) async {
final stream = cache.getFileStream(
uri,
headers: di<ImApiClient>().headers,
withProgress: chunkEvents != null,
);
await for (final result in stream) {
if (result is DownloadProgress) {
// We are downloading the file, so update the [chunkEvents]
chunkEvents?.add(
ImageChunkEvent(
cumulativeBytesLoaded: result.downloaded,
expectedTotalBytes: result.totalSize,
),
);
} else if (result is FileInfo) {
// We have the file
final buffer = await ui.ImmutableBuffer.fromFilePath(result.file.path);
return await decode(buffer);
}
}
// If we get here, the image failed to load from the cache stream
throw const ImageLoadingException('Could not load image from stream');
}
}