diff --git a/lib/src/attachment_actions.dart b/lib/src/attachment_actions.dart deleted file mode 100644 index f101ef53..00000000 --- a/lib/src/attachment_actions.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -class AttachmentActions extends StatelessWidget { - final Attachment attachment; - final Message message; - - const AttachmentActions({ - Key key, - this.attachment, - this.message, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final streamChannel = StreamChannel.of(context); - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: attachment.actions?.map((action) { - if (action.style == 'primary') { - return FlatButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Text('${action.text}'), - color: action.style == 'primary' - ? StreamChatTheme.of(context).accentColor - : null, - textColor: Colors.white, - onPressed: () { - streamChannel.channel.sendAction(message, { - action.name: action.value, - }); - }, - ); - } - return OutlineButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Text('${action.text}'), - color: StreamChatTheme.of(context).accentColor, - onPressed: () { - streamChannel.channel.sendAction(message, { - action.name: action.value, - }); - }, - ); - })?.toList(), - ); - } -} diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 62de980b..89beb4b1 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -1,10 +1,9 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/attachment_actions.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; -import 'attachment_title.dart'; import 'full_screen_image.dart'; class GiphyAttachment extends StatelessWidget { @@ -31,13 +30,260 @@ class GiphyAttachment extends StatelessWidget { ); } + return attachment.actions != null + ? _buildSendingAttachment(context) + : _buildSentAttachment(context); + } + + Widget _buildSendingAttachment(context) { + final streamChannel = StreamChannel.of(context); + return Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - GestureDetector( + children: [ + Card( + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ), + ), + ), + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + top: 8.0, + bottom: 4.0, + ), + child: Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 16.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + ), + ), + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + child: IconButton( + icon: Icon( + StreamIcons.left, + size: 24.0, + ), + splashRadius: 24, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + Expanded( + child: Center( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, + ), + ), + ), + ), + Card( + child: IconButton( + icon: Icon( + StreamIcons.right, + size: 24.0, + ), + splashRadius: 24, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + ], + ), + ), + ), + SizedBox( + height: 4.0, + ), + Container( + color: Colors.black.withOpacity(0.2), + width: double.infinity, + height: 0.5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'cancel', + }); + }, + child: Text( + 'Cancel', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5)), + ), + ), + ), + Container( + width: 0.5, + color: Colors.black.withOpacity(0.2), + height: 50.0, + ), + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'send', + }); + }, + child: Text( + 'Send', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ], + ), + ), + SizedBox( + height: 4.0, + ), + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + StreamIcons.eye, + color: Colors.black.withOpacity(0.5), + size: 16.0, + ), + SizedBox( + width: 8.0, + ), + Text( + 'Only visible to you', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 12.0, + ), + ), + ], + ), + ), + ), + ], + ); + } + + Widget _buildSentAttachment(context) { + return Container( + child: Column( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), + ), + ), + clipBehavior: Clip.antiAlias, + child: GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) { return FullScreenImage( @@ -69,25 +315,34 @@ class GiphyAttachment extends StatelessWidget { fit: BoxFit.cover, ), ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Material( - color: messageTheme.messageBackgroundColor, - child: AttachmentTitle( - messageTheme: messageTheme, - attachment: attachment, - ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Row( + children: [ + Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 15.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + ], + mainAxisAlignment: MainAxisAlignment.start, ), - ), - if (attachment.actions != null) - AttachmentActions( - attachment: attachment, - message: message, - ), - ], + ) + ], + ), ); } } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 7bdbfd5d..9c9cf67f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -335,7 +335,7 @@ class MessageInputState extends State { setState(() { _commandEnabled = true; }); - _commandsOverlay.remove(); + _commandsOverlay?.remove(); _commandsOverlay = null; } else { _commandsOverlay = _buildCommandsOverlayEntry(); @@ -344,6 +344,7 @@ class MessageInputState extends State { } if (textEditingController.selection.isCollapsed && + s.isNotEmpty && (s[textEditingController.selection.start - 1] == '@' || textEditingController.text .substring( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e65da576..ad574fc8 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -183,7 +183,9 @@ class MessageWidget extends StatefulWidget { 'giphy': (context, message, attachment) { return GiphyAttachment( attachment: attachment, - messageTheme: messageTheme, + messageTheme: messageTheme.copyWith( + messageBackgroundColor: Colors.white, + ), message: message, size: Size( MediaQuery.of(context).size.width * 0.8, @@ -213,6 +215,11 @@ class _MessageWidgetState extends State { var leftPadding = widget.showUserAvatar != DisplayWidget.gone ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 : 6.0; + + final isGiphy = + widget.message.attachments?.any((element) => element.type == 'giphy') == + true; + return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -287,8 +294,9 @@ class _MessageWidgetState extends State { children: [ ..._parseAttachments(context), if (widget.message.text - .trim() - .isNotEmpty) + .trim() + .isNotEmpty && + !isGiphy) _buildTextBubble(context), ], ), @@ -551,12 +559,14 @@ class _MessageWidgetState extends State { widget.message, attachment, ); - return wrapAttachmentWidget(context, attachmentWidget); + return wrapAttachmentWidget(context, attachmentWidget, + attachment: attachment); })?.toList() ?? []; } - Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget) { + Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget, + {Attachment attachment}) { return Padding( padding: EdgeInsets.only( bottom: 4, @@ -565,7 +575,9 @@ class _MessageWidgetState extends State { onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), child: Material( - color: _getBackgroundColor(), + color: attachment?.type == 'giphy' + ? Colors.white + : _getBackgroundColor(), clipBehavior: Clip.hardEdge, shape: widget.attachmentShape ?? widget.shape ??