From c0e6e7f37ad4f40b6d8edd88d5a8c8f19e6e4931 Mon Sep 17 00:00:00 2001 From: --global Date: Tue, 7 May 2024 18:29:45 +0700 Subject: [PATCH] TW-1650: fix memory overuse in avatar --- lib/pages/chat/events/image_bubble.dart | 46 ++++++++++---------- lib/pages/chat/events/image_builder_web.dart | 13 ++++-- lib/widgets/avatar/avatar.dart | 29 +++++++----- lib/widgets/mxc_image.dart | 22 +++++++--- 4 files changed, 67 insertions(+), 43 deletions(-) diff --git a/lib/pages/chat/events/image_bubble.dart b/lib/pages/chat/events/image_bubble.dart index 7a72c45415..fb1e21b9e3 100644 --- a/lib/pages/chat/events/image_bubble.dart +++ b/lib/pages/chat/events/image_bubble.dart @@ -67,26 +67,28 @@ class ImageBubble extends StatelessWidget { borderRadius: rounded ? MessageContentStyle.borderRadiusBubble : BorderRadius.zero, - child: Stack( - alignment: Alignment.center, - children: [ - SizedBox( - width: bubbleWidth, - height: bubbleHeight, - child: const BlurHash(hash: MessageContentStyle.defaultBlurHash), - ), - PlatformInfos.isWeb && - event.isEventEncrypted(isThumbnail: thumbnailOnly) - ? ImageBuilderWeb( - event: event, - isThumbnail: thumbnailOnly, - width: width, - height: height, - onTapPreview: onTapPreview, - onTapSelectMode: onTapSelectMode, - fit: fit, - ) - : MxcImage( + child: (PlatformInfos.isWeb && + !event.isEventEncrypted(isThumbnail: thumbnailOnly)) + ? UnencryptedImageBuilderWeb( + event: event, + isThumbnail: thumbnailOnly, + width: width, + height: height, + onTapPreview: onTapPreview, + onTapSelectMode: onTapSelectMode, + fit: fit, + ) + : Stack( + alignment: Alignment.center, + children: [ + SizedBox( + width: bubbleWidth, + height: bubbleHeight, + child: const BlurHash( + hash: MessageContentStyle.defaultBlurHash, + ), + ), + MxcImage( event: event, width: width, height: height, @@ -107,8 +109,8 @@ class ImageBubble extends StatelessWidget { cacheMap: thumbnailCacheMap, noResize: noResizeThumbnail, ), - ], - ), + ], + ), ), ); } diff --git a/lib/pages/chat/events/image_builder_web.dart b/lib/pages/chat/events/image_builder_web.dart index 1a8a587c20..882ac0058a 100644 --- a/lib/pages/chat/events/image_builder_web.dart +++ b/lib/pages/chat/events/image_builder_web.dart @@ -10,7 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_blurhash/flutter_blurhash.dart'; import 'package:matrix/matrix.dart'; -class ImageBuilderWeb extends StatelessWidget { +class UnencryptedImageBuilderWeb extends StatelessWidget { final Event event; final bool isThumbnail; @@ -27,10 +27,10 @@ class ImageBuilderWeb extends StatelessWidget { final void Function()? onTapSelectMode; - const ImageBuilderWeb({ + const UnencryptedImageBuilderWeb({ super.key, required this.event, - this.isThumbnail = false, + this.isThumbnail = true, this.width = 256, this.height = 300, this.fit = BoxFit.cover, @@ -131,6 +131,13 @@ class UnencryptedImageWidget extends StatelessWidget { fit: fit, width: width, height: height, + cacheWidth: (width * MediaQuery.of(context).devicePixelRatio).toInt(), + filterQuality: FilterQuality.none, + errorBuilder: (context, error, stackTrace) { + return BlurHash( + hash: event.blurHash ?? MessageContentStyle.defaultBlurHash, + ); + }, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) { return child; diff --git a/lib/widgets/avatar/avatar.dart b/lib/widgets/avatar/avatar.dart index f3e0b677bd..8c6e2dd46a 100644 --- a/lib/widgets/avatar/avatar.dart +++ b/lib/widgets/avatar/avatar.dart @@ -32,7 +32,6 @@ class Avatar extends StatelessWidget { @override Widget build(BuildContext context) { - final fallbackLetters = name?.getShortcutNameForAvatar() ?? '@'; return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(size / 2), @@ -44,23 +43,29 @@ class Avatar extends StatelessWidget { fit: BoxFit.cover, width: size, height: size, + cacheWidth: (size * MediaQuery.of(context).devicePixelRatio).toInt(), cacheKey: mxContent.toString(), - placeholder: (context) => RoundAvatar( - size: size, - text: fallbackLetters, - boxShadows: boxShadows, - textStyle: TextStyle( - fontSize: fontSize, - color: textColor ?? AvatarStyle.defaultTextColor(_havePicture), - fontFamily: AvatarStyle.fontFamily, - fontWeight: AvatarStyle.fontWeight, - ), - ), + placeholder: (context) => _fallbackAvatar(), ), ), ); } + Widget _fallbackAvatar() { + final fallbackLetters = name?.getShortcutNameForAvatar() ?? '@'; + return RoundAvatar( + size: size, + text: fallbackLetters, + boxShadows: boxShadows, + textStyle: TextStyle( + fontSize: fontSize, + color: textColor ?? AvatarStyle.defaultTextColor(_havePicture), + fontFamily: AvatarStyle.fontFamily, + fontWeight: AvatarStyle.fontWeight, + ), + ); + } + bool get _havePicture { return mxContent == null || mxContent.toString().isEmpty || diff --git a/lib/widgets/mxc_image.dart b/lib/widgets/mxc_image.dart index c0ede95b7a..aae43264fc 100644 --- a/lib/widgets/mxc_image.dart +++ b/lib/widgets/mxc_image.dart @@ -43,6 +43,8 @@ class MxcImage extends StatefulWidget { final VoidCallback? closeRightColumn; + final int? cacheWidth; + const MxcImage({ this.uri, this.event, @@ -65,6 +67,7 @@ class MxcImage extends StatefulWidget { this.cacheMap, this.noResize = false, this.closeRightColumn, + this.cacheWidth, Key? key, }) : super(key: key); @@ -303,6 +306,7 @@ class _MxcImageState extends State { height: widget.height, fit: widget.fit, needResize: needResize, + cacheWidth: widget.cacheWidth, imageErrorWidgetBuilder: (context, __, ___) { _isCached = false; _imageData = null; @@ -322,6 +326,7 @@ class _ImageWidget extends StatelessWidget { final bool needResize; final BoxFit? fit; final ImageErrorWidgetBuilder imageErrorWidgetBuilder; + final int? cacheWidth; const _ImageWidget({ this.filePath, @@ -331,6 +336,7 @@ class _ImageWidget extends StatelessWidget { required this.needResize, this.fit, required this.imageErrorWidgetBuilder, + this.cacheWidth, }); @override @@ -341,9 +347,11 @@ class _ImageWidget extends StatelessWidget { File(filePath!), width: width, height: height, - cacheWidth: (width != null && needResize) - ? (width! * devicePixelRatio).toInt() - : null, + cacheWidth: cacheWidth != null + ? cacheWidth! + : (width != null && needResize) + ? (width! * devicePixelRatio).toInt() + : null, cacheHeight: (height != null && needResize) ? (height! * devicePixelRatio).toInt() : null, @@ -356,9 +364,11 @@ class _ImageWidget extends StatelessWidget { data!, width: width, height: height, - cacheWidth: (width != null && needResize) - ? (width! * devicePixelRatio).toInt() - : null, + cacheWidth: cacheWidth != null + ? cacheWidth! + : (width != null && needResize) + ? (width! * devicePixelRatio).toInt() + : null, cacheHeight: (height != null && needResize) ? (height! * devicePixelRatio).toInt() : null,