From 02a3642894f3d24d06276c83b255d026bae2982c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 11:02:46 +0200 Subject: [PATCH] add image group --- lib/src/group_image.dart | 12 +--- lib/src/image_attachment.dart | 6 +- lib/src/image_group.dart | 99 ++++++++++++++++++++++++++ lib/src/message_widget.dart | 130 +++++++++++++++++++++------------- 4 files changed, 183 insertions(+), 64 deletions(-) create mode 100644 lib/src/image_group.dart diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 91bdf7b0..2385007d 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -17,16 +17,6 @@ class GroupImage extends StatelessWidget { @override Widget build(BuildContext context) { - final secondRow = images - .skip(2) - .map((url) => Flexible( - child: CachedNetworkImage( - imageUrl: url, - fit: BoxFit.cover, - ), - )) - .toList(); - return GestureDetector( onTap: onTap, child: ClipRRect( @@ -81,7 +71,7 @@ class GroupImage extends StatelessWidget { )) .toList(), ), - ) + ), ], ), ), diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index a4bd1a0f..e05f401b 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -17,8 +17,8 @@ class ImageAttachment extends StatelessWidget { Key key, @required this.attachment, @required this.message, + @required this.size, this.messageTheme, - this.size, }) : super(key: key); @override @@ -30,8 +30,8 @@ class ImageAttachment extends StatelessWidget { attachment: attachment, ); } - return SizedBox.fromSize( - size: size, + return ConstrainedBox( + constraints: BoxConstraints.loose(size), child: Stack( children: [ Column( diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart new file mode 100644 index 00000000..70acca23 --- /dev/null +++ b/lib/src/image_group.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/message_widget.dart'; + +class ImageGroup extends StatelessWidget { + const ImageGroup({ + Key key, + @required this.imageBuilder, + @required this.images, + @required this.message, + this.size, + }) : super(key: key); + + final AttachmentBuilder imageBuilder; + final List images; + final Message message; + final Size size; + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: BoxConstraints.loose(size), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + FittedBox( + fit: BoxFit.cover, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + imageBuilder( + context, + message, + images[0], + ), + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: imageBuilder( + context, + message, + images[1], + ), + ), + ], + ), + ), + if (images.length >= 3) + Padding( + padding: const EdgeInsets.only(top: 2.0), + child: FittedBox( + fit: BoxFit.cover, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + imageBuilder( + context, + message, + images[2], + ), + if (images.length >= 4) + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Stack( + children: [ + imageBuilder( + context, + message, + images[3], + ), + if (images.length > 4) + Positioned.fill( + child: Material( + color: Colors.black38, + child: InkWell( + onTap: () {}, + child: Center( + child: Text( + '${images.length - 4} +', + style: TextStyle( + color: Colors.white, + fontSize: 28, + ), + ), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 3103d079..09d9dc13 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -8,6 +8,7 @@ import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'image_group.dart'; import 'message_actions_bottom_sheet.dart'; import 'message_text.dart'; @@ -272,6 +273,7 @@ class _MessageWidgetState extends State { : Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ ..._parseAttachments(context), if (widget.message.text @@ -523,6 +525,30 @@ class _MessageWidgetState extends State { } List _parseAttachments(BuildContext context) { + final images = widget.message.attachments + .where((element) => element.type == 'image') + .toList(); + + if (images.length > 1) { + final imageBuilder = widget.attachmentBuilders['image']; + return [ + wrapAttachmentWidget( + context, + Material( + color: widget.messageTheme.messageBackgroundColor, + child: ImageGroup( + size: Size.fromWidth( + MediaQuery.of(context).size.width * 0.8, + ), + imageBuilder: imageBuilder, + images: images, + message: widget.message, + ), + ), + ), + ]; + } + return widget.message.attachments?.map((attachment) { final attachmentBuilder = widget.attachmentBuilders[attachment.type]; @@ -530,61 +556,65 @@ class _MessageWidgetState extends State { return SizedBox(); } - return Padding( - padding: EdgeInsets.only( - bottom: 4, - ), - child: GestureDetector( - onTap: () => retryMessage(context), - onLongPress: () => onLongPress(context), - child: Material( - color: _getBackgroundColor(), - clipBehavior: Clip.hardEdge, - shape: widget.attachmentShape ?? - widget.shape ?? - ContinuousRectangleBorder( - side: widget.attachmentBorderSide ?? - widget.borderSide ?? - BorderSide( - color: - Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ), - borderRadius: widget.attachmentBorderRadiusGeometry ?? - widget.borderRadiusGeometry ?? - BorderRadius.zero, + final attachmentWidget = attachmentBuilder( + context, + widget.message, + attachment, + ); + return wrapAttachmentWidget(context, attachmentWidget); + })?.toList() ?? + []; + } + + Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget) { + return Padding( + padding: EdgeInsets.only( + bottom: 4, + ), + child: GestureDetector( + onTap: () => retryMessage(context), + onLongPress: () => onLongPress(context), + child: Material( + color: _getBackgroundColor(), + clipBehavior: Clip.hardEdge, + shape: widget.attachmentShape ?? + widget.shape ?? + ContinuousRectangleBorder( + side: widget.attachmentBorderSide ?? + widget.borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), ), - child: Padding( - padding: widget.attachmentPadding, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget( - context, - padding: const EdgeInsets.all(8.0), - ), - attachmentBuilder( - context, - widget.message, - attachment, - ), - ], - ), + borderRadius: widget.attachmentBorderRadiusGeometry ?? + widget.borderRadiusGeometry ?? + BorderRadius.zero, + ), + child: Padding( + padding: widget.attachmentPadding, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget( + context, + padding: const EdgeInsets.all(8.0), ), - ), + attachmentWidget, + ], ), ), ), - ); - })?.toList() ?? - []; + ), + ), + ), + ); } void onLongPress(BuildContext context) {