refactor(mobile): Uses blurhash for memory card instead of blurred thumbnail (#7469)

* Uses blurhash for memory card instead of blurred thumbnail

New blurred backdrop widget

Comments

* Fixes video placeholder image placement

* unused import
This commit is contained in:
martyfuhry 2024-02-27 13:38:14 -05:00 committed by GitHub
parent 908104299d
commit b15eec7ca7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 37 deletions

View File

@ -40,7 +40,7 @@ class VideoViewerPage extends HookWidget {
controlsSafeAreaMinimum: const EdgeInsets.only( controlsSafeAreaMinimum: const EdgeInsets.only(
bottom: 100, bottom: 100,
), ),
placeholder: placeholder, placeholder: SizedBox.expand(child: placeholder),
showControls: showControls && !isMotionVideo, showControls: showControls && !isMotionVideo,
hideControlsTimer: hideControlsTimer, hideControlsTimer: hideControlsTimer,
customControls: const VideoPlayerControls(), customControls: const VideoPlayerControls(),
@ -58,7 +58,7 @@ class VideoViewerPage extends HookWidget {
if (controller == null) { if (controller == null) {
return Stack( return Stack(
children: [ children: [
if (placeholder != null) placeholder!, if (placeholder != null) SizedBox.expand(child: placeholder!),
const DelayedLoadingIndicator( const DelayedLoadingIndicator(
fadeInDuration: Duration(milliseconds: 500), fadeInDuration: Duration(milliseconds: 500),
), ),

View File

@ -1,12 +1,12 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; 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/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/asset_viewer/views/video_viewer_page.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/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_image.dart';
import 'package:immich_mobile/shared/ui/immich_thumbnail.dart';
class MemoryCard extends StatelessWidget { class MemoryCard extends StatelessWidget {
final Asset asset; final Asset asset;
@ -22,8 +22,6 @@ class MemoryCard extends StatelessWidget {
super.key, super.key,
}); });
String get accessToken => Store.get(StoreKey.accessToken);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return Card(
@ -38,19 +36,8 @@ class MemoryCard extends StatelessWidget {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: Stack( child: Stack(
children: [ children: [
ImageFiltered( SizedBox.expand(
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30), child: _BlurredBackdrop(asset: asset),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: ImmichThumbnail.imageProvider(
asset: asset,
),
fit: BoxFit.cover,
),
),
child: Container(color: Colors.black.withOpacity(0.2)),
),
), ),
LayoutBuilder( LayoutBuilder(
builder: (context, constraints) { 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),
),
),
);
}
}
}

View File

@ -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/modules/memories/ui/memory_progress_indicator.dart';
import 'package:immich_mobile/shared/models/asset.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_image.dart';
import 'package:immich_mobile/shared/ui/immich_thumbnail.dart';
@RoutePage() @RoutePage()
class MemoryPage extends HookConsumerWidget { class MemoryPage extends HookConsumerWidget {
@ -110,24 +109,13 @@ class MemoryPage extends HookConsumerWidget {
asset = memories[nextMemoryIndex].assets.first; asset = memories[nextMemoryIndex].assets.first;
} }
// Gets the thumbnail url and precaches it // Precache the asset
final precaches = <Future<dynamic>>[]; await precacheImage(
ImmichImage.imageProvider(
precaches.addAll([ asset: asset,
precacheImage(
ImmichImage.imageProvider(
asset: asset,
),
context,
), ),
precacheImage( context,
ImmichThumbnail.imageProvider( );
asset: asset,
),
context,
),
]);
await Future.wait(precaches);
} }
// Precache the next page right away if we are on the first page // Precache the next page right away if we are on the first page