You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			161 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Dart
		
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Dart
		
	
| import 'package:flutter/material.dart';
 | |
| 
 | |
| import 'package:flutter_linkify/flutter_linkify.dart';
 | |
| import 'package:matrix/matrix.dart';
 | |
| 
 | |
| import 'package:fluffychat/config/app_config.dart';
 | |
| import 'package:fluffychat/pages/image_viewer/image_viewer.dart';
 | |
| import 'package:fluffychat/utils/file_description.dart';
 | |
| import 'package:fluffychat/utils/url_launcher.dart';
 | |
| import 'package:fluffychat/widgets/mxc_image.dart';
 | |
| import '../../../widgets/blur_hash.dart';
 | |
| 
 | |
| class ImageBubble extends StatelessWidget {
 | |
|   final Event event;
 | |
|   final bool tapToView;
 | |
|   final BoxFit fit;
 | |
|   final Color? backgroundColor;
 | |
|   final Color? textColor;
 | |
|   final Color? linkColor;
 | |
|   final bool thumbnailOnly;
 | |
|   final bool animated;
 | |
|   final double width;
 | |
|   final double height;
 | |
|   final void Function()? onTap;
 | |
|   final BorderRadius? borderRadius;
 | |
|   final Timeline? timeline;
 | |
| 
 | |
|   const ImageBubble(
 | |
|     this.event, {
 | |
|     this.tapToView = true,
 | |
|     this.backgroundColor,
 | |
|     this.fit = BoxFit.contain,
 | |
|     this.thumbnailOnly = true,
 | |
|     this.width = 400,
 | |
|     this.height = 300,
 | |
|     this.animated = false,
 | |
|     this.onTap,
 | |
|     this.borderRadius,
 | |
|     this.timeline,
 | |
|     this.textColor,
 | |
|     this.linkColor,
 | |
|     super.key,
 | |
|   });
 | |
| 
 | |
|   Widget _buildPlaceholder(BuildContext context) {
 | |
|     final String blurHashString =
 | |
|         event.infoMap['xyz.amorgan.blurhash'] is String
 | |
|             ? event.infoMap['xyz.amorgan.blurhash']
 | |
|             : 'LEHV6nWB2yk8pyo0adR*.7kCMdnj';
 | |
|     return SizedBox(
 | |
|       width: width,
 | |
|       height: height,
 | |
|       child: BlurHash(
 | |
|         blurhash: blurHashString,
 | |
|         width: width,
 | |
|         height: height,
 | |
|         fit: fit,
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   void _onTap(BuildContext context) {
 | |
|     if (onTap != null) {
 | |
|       onTap!();
 | |
|       return;
 | |
|     }
 | |
|     if (!tapToView) return;
 | |
|     showDialog(
 | |
|       context: context,
 | |
|       builder: (_) => ImageViewer(
 | |
|         event,
 | |
|         timeline: timeline,
 | |
|         outerContext: context,
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     final theme = Theme.of(context);
 | |
| 
 | |
|     var borderRadius =
 | |
|         this.borderRadius ?? BorderRadius.circular(AppConfig.borderRadius);
 | |
| 
 | |
|     final fileDescription = event.fileDescription;
 | |
|     final textColor = this.textColor;
 | |
| 
 | |
|     if (fileDescription != null) {
 | |
|       borderRadius = borderRadius.copyWith(
 | |
|         bottomLeft: Radius.zero,
 | |
|         bottomRight: Radius.zero,
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return Column(
 | |
|       mainAxisSize: MainAxisSize.min,
 | |
|       spacing: 8,
 | |
|       children: [
 | |
|         Material(
 | |
|           color: Colors.transparent,
 | |
|           clipBehavior: Clip.hardEdge,
 | |
|           shape: RoundedRectangleBorder(
 | |
|             borderRadius: borderRadius,
 | |
|             side: BorderSide(
 | |
|               color: event.messageType == MessageTypes.Sticker
 | |
|                   ? Colors.transparent
 | |
|                   : theme.dividerColor,
 | |
|             ),
 | |
|           ),
 | |
|           child: InkWell(
 | |
|             onTap: () => _onTap(context),
 | |
|             borderRadius: borderRadius,
 | |
|             child: Hero(
 | |
|               tag: event.eventId,
 | |
|               child: MxcImage(
 | |
|                 event: event,
 | |
|                 width: width,
 | |
|                 height: height,
 | |
|                 fit: fit,
 | |
|                 animated: animated,
 | |
|                 isThumbnail: thumbnailOnly,
 | |
|                 placeholder: event.messageType == MessageTypes.Sticker
 | |
|                     ? null
 | |
|                     : _buildPlaceholder,
 | |
|               ),
 | |
|             ),
 | |
|           ),
 | |
|         ),
 | |
|         if (fileDescription != null && textColor != null)
 | |
|           SizedBox(
 | |
|             width: width,
 | |
|             child: Padding(
 | |
|               padding: const EdgeInsets.symmetric(
 | |
|                 horizontal: 16,
 | |
|                 vertical: 8,
 | |
|               ),
 | |
|               child: Linkify(
 | |
|                 text: fileDescription,
 | |
|                 textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
 | |
|                 style: TextStyle(
 | |
|                   color: textColor,
 | |
|                   fontSize:
 | |
|                       AppConfig.fontSizeFactor * AppConfig.messageFontSize,
 | |
|                 ),
 | |
|                 options: const LinkifyOptions(humanize: false),
 | |
|                 linkStyle: TextStyle(
 | |
|                   color: linkColor,
 | |
|                   fontSize:
 | |
|                       AppConfig.fontSizeFactor * AppConfig.messageFontSize,
 | |
|                   decoration: TextDecoration.underline,
 | |
|                   decorationColor: linkColor,
 | |
|                 ),
 | |
|                 onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
 | |
|               ),
 | |
|             ),
 | |
|           ),
 | |
|       ],
 | |
|     );
 | |
|   }
 | |
| }
 |