Compare commits

...

5 Commits

4 changed files with 84 additions and 59 deletions
@@ -4,6 +4,7 @@ enum Setting<T> {
tilesPerRow<int>(StoreKey.tilesPerRow, 4), tilesPerRow<int>(StoreKey.tilesPerRow, 4),
groupAssetsBy<int>(StoreKey.groupAssetsBy, 0), groupAssetsBy<int>(StoreKey.groupAssetsBy, 0),
showStorageIndicator<bool>(StoreKey.storageIndicator, true), showStorageIndicator<bool>(StoreKey.storageIndicator, true),
loadPreview<bool>(StoreKey.loadPreview, true),
loadOriginal<bool>(StoreKey.loadOriginal, false), loadOriginal<bool>(StoreKey.loadOriginal, false),
loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, false), loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, false),
autoPlayVideo<bool>(StoreKey.autoPlayVideo, true), autoPlayVideo<bool>(StoreKey.autoPlayVideo, true),
@@ -45,7 +45,6 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
completer.operation.valueOrCancellation().whenComplete(() { completer.operation.valueOrCancellation().whenComplete(() {
cachedStream.removeListener(listener); cachedStream.removeListener(listener);
cachedOperation = null;
}); });
cachedOperation = completer.operation; cachedOperation = completer.operation;
return null; return null;
@@ -106,18 +105,33 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
} }
} }
Stream<ImageInfo> initialImageStream() async* { Stream<ImageInfo> initialImageStream({required bool isFinal}) async* {
final cachedOperation = this.cachedOperation; final cachedOperation = this.cachedOperation;
if (isCancelled) {
return;
}
if (cachedOperation == null) { if (cachedOperation == null) {
// image resolved synchronously
isFinished = isFinal;
return; return;
} }
try { try {
final cachedImage = await cachedOperation.valueOrCancellation(); final cachedImage = await cachedOperation.valueOrCancellation();
if (cachedImage != null && !isCancelled) { if (isCancelled || cachedImage == null) {
yield cachedImage; return;
} }
isFinished = isFinal;
yield cachedImage;
} catch (e, stack) { } catch (e, stack) {
if (isCancelled) {
return;
}
if (isFinal) {
isFinished = true;
PaintingBinding.instance.imageCache.evict(this);
rethrow;
}
_log.severe('Error loading initial image', e, stack); _log.severe('Error loading initial image', e, stack);
} finally { } finally {
this.cachedOperation = null; this.cachedOperation = null;
@@ -1,8 +1,8 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/setting.model.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/domain/services/setting.service.dart';
import 'package:immich_mobile/infrastructure/loaders/image_request.dart'; import 'package:immich_mobile/infrastructure/loaders/image_request.dart';
import 'package:immich_mobile/presentation/widgets/images/animated_image_stream_completer.dart'; import 'package:immich_mobile/presentation/widgets/images/animated_image_stream_completer.dart';
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
@@ -97,51 +97,55 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
} }
Stream<ImageInfo> _codec(LocalFullImageProvider key, ImageDecoderCallback decode) async* { Stream<ImageInfo> _codec(LocalFullImageProvider key, ImageDecoderCallback decode) async* {
yield* initialImageStream(); final loadOriginal = AppSetting.get(Setting.loadOriginal);
final loadPreview = AppSetting.get(Setting.loadPreview);
yield* initialImageStream(isFinal: !loadOriginal && !loadPreview);
if (isCancelled) { if (isCancelled) {
return; return;
} }
final loadOriginal = Store.get(StoreKey.loadOriginal, false); if (loadPreview) {
final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio; final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio;
var request = this.request = LocalImageRequest( final previewRequest = request = LocalImageRequest(
localId: key.id, localId: key.id,
size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio), size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio),
assetType: key.assetType, assetType: key.assetType,
); );
yield* loadRequest(request, decode, isFinal: !loadOriginal); yield* loadRequest(previewRequest, decode, isFinal: !loadOriginal);
if (isCancelled) {
return;
}
}
if (!loadOriginal) { if (!loadOriginal) {
return; return;
} }
if (isCancelled) { final originalRequest = request = LocalImageRequest(localId: key.id, assetType: key.assetType, size: Size.zero);
return; yield* loadRequest(originalRequest, decode, isFinal: true);
}
request = this.request = LocalImageRequest(localId: key.id, assetType: key.assetType, size: Size.zero);
yield* loadRequest(request, decode, isFinal: true);
} }
Stream<Object> _animatedCodec(LocalFullImageProvider key, ImageDecoderCallback decode) async* { Stream<Object> _animatedCodec(LocalFullImageProvider key, ImageDecoderCallback decode) async* {
yield* initialImageStream(); yield* initialImageStream(isFinal: false);
if (isCancelled) { if (isCancelled) {
return; return;
} }
final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio; if (AppSetting.get(Setting.loadPreview)) {
final previewRequest = request = LocalImageRequest( final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio;
localId: key.id, final previewRequest = request = LocalImageRequest(
size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio), localId: key.id,
assetType: key.assetType, size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio),
); assetType: key.assetType,
yield* loadRequest(previewRequest, decode, isFinal: false); );
yield* loadRequest(previewRequest, decode, isFinal: false);
if (isCancelled) { if (isCancelled) {
return; return;
}
} }
// always try original for animated, since previews don't support animation // always try original for animated, since previews don't support animation
@@ -107,31 +107,35 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
} }
Stream<ImageInfo> _codec(RemoteFullImageProvider key, ImageDecoderCallback decode) async* { Stream<ImageInfo> _codec(RemoteFullImageProvider key, ImageDecoderCallback decode) async* {
yield* initialImageStream(); final isImage = assetType == AssetType.image;
final loadOriginal = isImage && AppSetting.get(Setting.loadOriginal);
final loadPreview = isImage && AppSetting.get(Setting.loadPreview);
yield* initialImageStream(isFinal: !loadOriginal && !loadPreview);
if (isCancelled) { if (isCancelled) {
return; return;
} }
final previewRequest = request = RemoteImageRequest( if (loadPreview) {
uri: getThumbnailUrlForRemoteId( final previewRequest = request = RemoteImageRequest(
key.assetId, uri: getThumbnailUrlForRemoteId(
type: AssetMediaSize.preview, key.assetId,
thumbhash: key.thumbhash, type: AssetMediaSize.preview,
edited: key.edited, thumbhash: key.thumbhash,
), edited: key.edited,
); ),
final loadOriginal = assetType == AssetType.image && AppSetting.get(Setting.loadOriginal); );
yield* loadRequest(previewRequest, decode, isFinal: !loadOriginal); yield* loadRequest(previewRequest, decode, isFinal: !loadOriginal);
if (isCancelled) {
return;
}
}
if (!loadOriginal) { if (!loadOriginal) {
return; return;
} }
if (isCancelled) {
return;
}
final originalRequest = request = RemoteImageRequest( final originalRequest = request = RemoteImageRequest(
uri: getOriginalUrlForRemoteId(key.assetId, edited: key.edited), uri: getOriginalUrlForRemoteId(key.assetId, edited: key.edited),
); );
@@ -139,24 +143,26 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
} }
Stream<Object> _animatedCodec(RemoteFullImageProvider key, ImageDecoderCallback decode) async* { Stream<Object> _animatedCodec(RemoteFullImageProvider key, ImageDecoderCallback decode) async* {
yield* initialImageStream(); yield* initialImageStream(isFinal: false);
if (isCancelled) { if (isCancelled) {
return; return;
} }
final previewRequest = request = RemoteImageRequest( if (AppSetting.get(Setting.loadPreview)) {
uri: getThumbnailUrlForRemoteId( final previewRequest = request = RemoteImageRequest(
key.assetId, uri: getThumbnailUrlForRemoteId(
type: AssetMediaSize.preview, key.assetId,
thumbhash: key.thumbhash, type: AssetMediaSize.preview,
edited: key.edited, thumbhash: key.thumbhash,
), edited: key.edited,
); ),
yield* loadRequest(previewRequest, decode, isFinal: false); );
yield* loadRequest(previewRequest, decode, isFinal: false);
if (isCancelled) { if (isCancelled) {
return; return;
}
} }
// always try original for animated, since previews don't support animation // always try original for animated, since previews don't support animation