mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat(mobile): image caching & viewer improvements (#4095)
This commit is contained in:
parent
63b6a71ebd
commit
1c02e1dadf
10 changed files with 283 additions and 212 deletions
|
|
@ -45,14 +45,9 @@ class ImmichImage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
final Asset asset = this.asset!;
|
||||
if (!asset.isRemote ||
|
||||
(asset.isLocal && !Store.get(StoreKey.preferRemoteImage, false))) {
|
||||
if (useLocal(asset)) {
|
||||
return Image(
|
||||
image: AssetEntityImageProvider(
|
||||
asset.local!,
|
||||
isOriginal: false,
|
||||
thumbnailSize: const ThumbnailSize.square(250), // like server thumbs
|
||||
),
|
||||
image: localThumbnailProvider(asset),
|
||||
width: width,
|
||||
height: height,
|
||||
fit: fit,
|
||||
|
|
@ -148,45 +143,44 @@ class ImmichImage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
static AssetEntityImageProvider localThumbnailProvider(Asset asset) =>
|
||||
AssetEntityImageProvider(
|
||||
asset.local!,
|
||||
isOriginal: false,
|
||||
thumbnailSize: const ThumbnailSize.square(250),
|
||||
);
|
||||
|
||||
static CachedNetworkImageProvider remoteThumbnailProvider(
|
||||
Asset asset,
|
||||
api.ThumbnailFormat type,
|
||||
Map<String, String> authHeader,
|
||||
) =>
|
||||
CachedNetworkImageProvider(
|
||||
getThumbnailUrl(asset, type: type),
|
||||
cacheKey: getThumbnailCacheKey(asset, type: type),
|
||||
headers: authHeader,
|
||||
);
|
||||
|
||||
/// 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);
|
||||
if (useLocal(asset)) {
|
||||
// Precache the local image
|
||||
return precacheImage(localThumbnailProvider(asset), context);
|
||||
} else {
|
||||
final authToken = 'Bearer ${Store.get(StoreKey.accessToken)}';
|
||||
// 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(
|
||||
remoteThumbnailProvider(asset, type, {"Authorization": authToken}),
|
||||
context,
|
||||
);
|
||||
|
||||
return precacheImage(provider, context);
|
||||
}
|
||||
}
|
||||
|
||||
static bool useLocal(Asset asset) =>
|
||||
!asset.isRemote ||
|
||||
asset.isLocal && !Store.get(StoreKey.preferRemoteImage, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ class PhotoView extends StatefulWidget {
|
|||
const PhotoView({
|
||||
Key? key,
|
||||
required this.imageProvider,
|
||||
required this.index,
|
||||
this.loadingBuilder,
|
||||
this.backgroundDecoration,
|
||||
this.wantKeepAlive = false,
|
||||
|
|
@ -304,6 +305,7 @@ class PhotoView extends StatefulWidget {
|
|||
imageProvider = null,
|
||||
gaplessPlayback = false,
|
||||
loadingBuilder = null,
|
||||
index = 0,
|
||||
super(key: key);
|
||||
|
||||
/// Given a [imageProvider] it resolves into an zoomable image widget using. It
|
||||
|
|
@ -419,6 +421,8 @@ class PhotoView extends StatefulWidget {
|
|||
/// Useful when you want to drag a widget without restrictions.
|
||||
final bool? enablePanAlways;
|
||||
|
||||
final int index;
|
||||
|
||||
bool get _isCustomChild {
|
||||
return child != null;
|
||||
}
|
||||
|
|
@ -571,6 +575,7 @@ class _PhotoViewState extends State<PhotoView>
|
|||
disableGestures: widget.disableGestures,
|
||||
errorBuilder: widget.errorBuilder,
|
||||
enablePanAlways: widget.enablePanAlways,
|
||||
index: widget.index,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -625,7 +630,7 @@ typedef PhotoViewImageDragStartCallback = Function(
|
|||
PhotoViewControllerValue controllerValue,
|
||||
);
|
||||
|
||||
/// A type definition for a callback when the user drags
|
||||
/// A type definition for a callback when the user drags
|
||||
typedef PhotoViewImageDragUpdateCallback = Function(
|
||||
BuildContext context,
|
||||
DragUpdateDetails details,
|
||||
|
|
@ -650,4 +655,5 @@ typedef PhotoViewImageScaleEndCallback = Function(
|
|||
typedef LoadingBuilder = Widget Function(
|
||||
BuildContext context,
|
||||
ImageChunkEvent? event,
|
||||
int index,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ class _PhotoViewGalleryState extends State<PhotoViewGallery> {
|
|||
)
|
||||
: PhotoView(
|
||||
key: ObjectKey(index),
|
||||
index: index,
|
||||
imageProvider: pageOption.imageProvider,
|
||||
loadingBuilder: widget.loadingBuilder,
|
||||
backgroundDecoration: widget.backgroundDecoration,
|
||||
|
|
@ -315,7 +316,10 @@ class _PhotoViewGalleryState extends State<PhotoViewGallery> {
|
|||
);
|
||||
}
|
||||
|
||||
PhotoViewGalleryPageOptions _buildPageOption(BuildContext context, int index) {
|
||||
PhotoViewGalleryPageOptions _buildPageOption(
|
||||
BuildContext context,
|
||||
int index,
|
||||
) {
|
||||
if (widget._isBuilder) {
|
||||
return widget.builder!(context, index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class ImageWrapper extends StatefulWidget {
|
|||
required this.disableGestures,
|
||||
required this.errorBuilder,
|
||||
required this.enablePanAlways,
|
||||
required this.index,
|
||||
}) : super(key: key);
|
||||
|
||||
final ImageProvider imageProvider;
|
||||
|
|
@ -64,6 +65,7 @@ class ImageWrapper extends StatefulWidget {
|
|||
final FilterQuality? filterQuality;
|
||||
final bool? disableGestures;
|
||||
final bool? enablePanAlways;
|
||||
final int index;
|
||||
|
||||
@override
|
||||
createState() => _ImageWrapperState();
|
||||
|
|
@ -128,6 +130,7 @@ class _ImageWrapperState extends State<ImageWrapper> {
|
|||
_lastException = null;
|
||||
_lastStack = null;
|
||||
}
|
||||
|
||||
synchronousCall ? setupCB() : setState(setupCB);
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +215,7 @@ class _ImageWrapperState extends State<ImageWrapper> {
|
|||
|
||||
Widget _buildLoading(BuildContext context) {
|
||||
if (widget.loadingBuilder != null) {
|
||||
return widget.loadingBuilder!(context, _loadingProgress);
|
||||
return widget.loadingBuilder!(context, _loadingProgress, widget.index);
|
||||
}
|
||||
|
||||
return PhotoViewDefaultLoading(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue