diff --git a/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart b/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart index 0967bf52a7..eb125f27fb 100644 --- a/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart +++ b/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart @@ -40,7 +40,7 @@ class VideoViewerPage extends HookWidget { controlsSafeAreaMinimum: const EdgeInsets.only( bottom: 100, ), - placeholder: placeholder, + placeholder: SizedBox.expand(child: placeholder), showControls: showControls && !isMotionVideo, hideControlsTimer: hideControlsTimer, customControls: const VideoPlayerControls(), @@ -58,7 +58,7 @@ class VideoViewerPage extends HookWidget { if (controller == null) { return Stack( children: [ - if (placeholder != null) placeholder!, + if (placeholder != null) SizedBox.expand(child: placeholder!), const DelayedLoadingIndicator( fadeInDuration: Duration(milliseconds: 500), ), diff --git a/mobile/lib/modules/memories/ui/memory_card.dart b/mobile/lib/modules/memories/ui/memory_card.dart index 5243e24a13..af57c272ae 100644 --- a/mobile/lib/modules/memories/ui/memory_card.dart +++ b/mobile/lib/modules/memories/ui/memory_card.dart @@ -1,12 +1,12 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/modules/asset_viewer/views/video_viewer_page.dart'; import 'package:immich_mobile/shared/models/asset.dart'; -import 'package:immich_mobile/shared/models/store.dart'; +import 'package:immich_mobile/shared/ui/hooks/blurhash_hook.dart'; import 'package:immich_mobile/shared/ui/immich_image.dart'; -import 'package:immich_mobile/shared/ui/immich_thumbnail.dart'; class MemoryCard extends StatelessWidget { final Asset asset; @@ -22,8 +22,6 @@ class MemoryCard extends StatelessWidget { super.key, }); - String get accessToken => Store.get(StoreKey.accessToken); - @override Widget build(BuildContext context) { return Card( @@ -38,19 +36,8 @@ class MemoryCard extends StatelessWidget { clipBehavior: Clip.hardEdge, child: Stack( children: [ - ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30), - child: Container( - decoration: BoxDecoration( - image: DecorationImage( - image: ImmichThumbnail.imageProvider( - asset: asset, - ), - fit: BoxFit.cover, - ), - ), - child: Container(color: Colors.black.withOpacity(0.2)), - ), + SizedBox.expand( + child: _BlurredBackdrop(asset: asset), ), LayoutBuilder( builder: (context, constraints) { @@ -113,3 +100,50 @@ class MemoryCard extends StatelessWidget { ); } } + +class _BlurredBackdrop extends HookWidget { + final Asset asset; + + const _BlurredBackdrop({required this.asset}); + + @override + Widget build(BuildContext context) { + final blurhash = useBlurHashRef(asset).value; + if (blurhash != null) { + // Use a nice cheap blur hash image decoration + return Container( + decoration: BoxDecoration( + image: DecorationImage( + image: MemoryImage( + blurhash, + ), + fit: BoxFit.cover, + ), + ), + child: Container( + color: Colors.black.withOpacity(0.2), + ), + ); + } else { + // Fall back to using a more expensive image filtered + // Since the ImmichImage is already precached, we can + // safely use that as the image provider + return ImageFiltered( + imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: ImmichImage.imageProvider( + asset: asset, + ), + fit: BoxFit.cover, + ), + ), + child: Container( + color: Colors.black.withOpacity(0.2), + ), + ), + ); + } + } +} diff --git a/mobile/lib/modules/memories/views/memory_page.dart b/mobile/lib/modules/memories/views/memory_page.dart index 4312a7ad2e..9308e812dc 100644 --- a/mobile/lib/modules/memories/views/memory_page.dart +++ b/mobile/lib/modules/memories/views/memory_page.dart @@ -10,7 +10,6 @@ import 'package:immich_mobile/modules/memories/ui/memory_epilogue.dart'; import 'package:immich_mobile/modules/memories/ui/memory_progress_indicator.dart'; import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/ui/immich_image.dart'; -import 'package:immich_mobile/shared/ui/immich_thumbnail.dart'; @RoutePage() class MemoryPage extends HookConsumerWidget { @@ -110,24 +109,13 @@ class MemoryPage extends HookConsumerWidget { asset = memories[nextMemoryIndex].assets.first; } - // Gets the thumbnail url and precaches it - final precaches = >[]; - - precaches.addAll([ - precacheImage( - ImmichImage.imageProvider( - asset: asset, - ), - context, + // Precache the asset + await precacheImage( + ImmichImage.imageProvider( + asset: asset, ), - precacheImage( - ImmichThumbnail.imageProvider( - asset: asset, - ), - context, - ), - ]); - await Future.wait(precaches); + context, + ); } // Precache the next page right away if we are on the first page