From 755dd511edfc77c0640a5abef837e38c3bceedc6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 10 Nov 2020 19:32:46 +0530 Subject: [PATCH 1/7] feat: Added url attachments --- lib/src/message_widget.dart | 194 ++++++++++++++++++++++++++++++------ 1 file changed, 165 insertions(+), 29 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 476217f3..0affe079 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'dart:ui'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:emojis/emoji.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -343,6 +344,83 @@ class _MessageWidgetState extends State { ); } + Widget _buildUrlAttachment() { + var urlAttachment = widget.message.attachments + .firstWhere((element) => element.ogScrapeUrl != null); + + var host = Uri.parse(urlAttachment.ogScrapeUrl).host; + var splitList = host.split('.'); + var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; + var hostDisplayName = + _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); + + return Column( + children: [ + SizedBox( + height: 16.0, + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Positioned( + left: 0.0, + bottom: 0.0, + child: Container( + child: Padding( + padding: + const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: + BorderRadius.only(topRight: Radius.circular(16.0)), + color: Color(0xFFE9F2FF), + ), + ), + ), + ], + ), + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + ), + Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), + ), + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), + ), + ], + ); + } + Padding _buildBottomRow(double leftPadding) { return Padding( padding: EdgeInsets.only( @@ -525,7 +603,8 @@ class _MessageWidgetState extends State { List _parseAttachments(BuildContext context) { final images = widget.message.attachments - ?.where((element) => element.type == 'image') + ?.where((element) => + element.type == 'image' && element.ogScrapeUrl == null) ?.toList() ?? []; @@ -548,7 +627,9 @@ class _MessageWidgetState extends State { ]; } - return widget.message.attachments?.map((attachment) { + return widget.message.attachments + ?.where((element) => element.ogScrapeUrl == null) + ?.map((attachment) { final attachmentBuilder = widget.attachmentBuilders[attachment.type]; if (attachmentBuilder == null) { @@ -757,28 +838,35 @@ class _MessageWidgetState extends State { Widget child = Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget(context), - widget.textBuilder != null - ? widget.textBuilder(context, widget.message) - : MessageText( - onLinkTap: widget.onLinkTap, - message: widget.message, - onMentionTap: widget.onMentionTap, - messageTheme: isOnlyEmoji - ? widget.messageTheme.copyWith( - messageText: - widget.messageTheme.messageText.copyWith( - fontSize: 40, - )) - : widget.messageTheme, - ), - ], - ), + child: Column( + children: [ + Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget(context), + widget.textBuilder != null + ? widget.textBuilder(context, widget.message) + : MessageText( + onLinkTap: widget.onLinkTap, + message: widget.message, + onMentionTap: widget.onMentionTap, + messageTheme: isOnlyEmoji + ? widget.messageTheme.copyWith( + messageText: + widget.messageTheme.messageText.copyWith( + fontSize: 40, + )) + : widget.messageTheme, + ), + ], + ), + ), + if (widget.message.attachments + .any((element) => element.ogScrapeUrl != null)) + _buildUrlAttachment(), + ], ), ); @@ -796,11 +884,18 @@ class _MessageWidgetState extends State { } Color _getBackgroundColor() { - return (widget.message.status == MessageSendingStatus.FAILED || - widget.message.status == MessageSendingStatus.FAILED_UPDATE || - widget.message.status == MessageSendingStatus.FAILED_DELETE) - ? Color(0xffd0021B).withOpacity(.1) - : widget.messageTheme.messageBackgroundColor; + if ((widget.message.status == MessageSendingStatus.FAILED || + widget.message.status == MessageSendingStatus.FAILED_UPDATE || + widget.message.status == MessageSendingStatus.FAILED_DELETE)) { + return Color(0xffd0021B).withOpacity(.1); + } + + if (widget.message.attachments + .any((element) => element.ogScrapeUrl != null)) { + return Color(0xFFE9F2FF); + } + + return widget.messageTheme.messageBackgroundColor; } void retryMessage(BuildContext context) { @@ -825,4 +920,45 @@ class _MessageWidgetState extends State { return; } } + + String _getWebsiteName(String hostName) { + switch (hostName) { + case 'reddit': + return 'Reddit'; + case 'youtube': + return 'Youtube'; + case 'wikipedia': + return 'Wikipedia'; + case 'twitter': + return 'Twitter'; + case 'facebook': + return 'Facebook'; + case 'amazon': + return 'Amazon'; + case 'yelp': + return 'Yelp'; + case 'imdb': + return 'IMDB'; + case 'pinterest': + return 'Pinterest'; + case 'tripadvisor': + return 'TripAdvisor'; + case 'instagram': + return 'Instagram'; + case 'walmart': + return 'Walmart'; + case 'craigslist': + return 'Craigslist'; + case 'ebay': + return 'eBay'; + case 'linkedin': + return 'LinkedIn'; + case 'google': + return 'Google'; + case 'apple': + return 'Apple'; + default: + return null; + } + } } From 477673aa28eb65ee51bf221b71513cdfb62bc888 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 10 Nov 2020 19:38:05 +0530 Subject: [PATCH 2/7] fix: Fix case when image is null --- lib/src/message_widget.dart | 58 +++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 0affe079..4291e00e 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -356,42 +356,44 @@ class _MessageWidgetState extends State { return Column( children: [ + if (urlAttachment.imageUrl != null) SizedBox( height: 16.0, ), - Container( - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - clipBehavior: Clip.antiAlias, - children: [ - CachedNetworkImage(imageUrl: urlAttachment.imageUrl), - Positioned( - left: 0.0, - bottom: 0.0, - child: Container( - child: Padding( - padding: - const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), + if (urlAttachment.imageUrl != null) + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Positioned( + left: 0.0, + bottom: 0.0, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, left: 8.0, right: 8.0), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), ), ), - ), - decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topRight: Radius.circular(16.0)), - color: Color(0xFFE9F2FF), + decoration: BoxDecoration( + borderRadius: + BorderRadius.only(topRight: Radius.circular(16.0)), + color: Color(0xFFE9F2FF), + ), ), ), - ), - ], + ], + ), + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), ), - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), - ), Padding( padding: widget.textPadding, child: Column( From f87fa8ae8fd361c71e6e0cdfa468de8e19f1c16a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:12:48 +0100 Subject: [PATCH 3/7] add inkwell --- lib/src/message_widget.dart | 135 +++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 57 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 4291e00e..1f3a12dd 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -16,6 +16,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; import 'message_text.dart'; +import 'utils.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); @@ -354,69 +355,89 @@ class _MessageWidgetState extends State { var hostDisplayName = _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); - return Column( + return Stack( children: [ - if (urlAttachment.imageUrl != null) - SizedBox( - height: 16.0, - ), - if (urlAttachment.imageUrl != null) - Container( - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - clipBehavior: Clip.antiAlias, - children: [ - CachedNetworkImage(imageUrl: urlAttachment.imageUrl), - Positioned( - left: 0.0, - bottom: 0.0, - child: Container( - child: Padding( - padding: const EdgeInsets.only( - top: 8.0, left: 8.0, right: 8.0), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), + Column( + children: [ + if (urlAttachment.imageUrl != null) + SizedBox( + height: 16.0, + ), + if (urlAttachment.imageUrl != null) + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Positioned( + left: 0.0, + bottom: 0.0, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 8.0, + right: 8.0, + ), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + ), + color: Color(0xFFE9F2FF), ), ), ), - decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topRight: Radius.circular(16.0)), - color: Color(0xFFE9F2FF), + ], + ), + clipBehavior: Clip.antiAlias, + decoration: + BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + ), + Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), ), - ), - ), - ], + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), + ), + ], + ), + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => launchURL( + context, + urlAttachment.ogScrapeUrl, + ), ), - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), - ), - Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (urlAttachment.title != null) - Text( - urlAttachment.title, - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), - ), - if (urlAttachment.text != null) - Text( - urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, - ), - ), - ], ), ), ], From 24c44520e610eef8af2f2b5c985368248639307d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:16:40 +0100 Subject: [PATCH 4/7] fix alignment --- lib/src/message_widget.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1f3a12dd..d1be132d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -862,6 +862,7 @@ class _MessageWidgetState extends State { transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: widget.textPadding, From 2d125ea83692dbb65a80047c748cacb2494a8c09 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:25:25 +0100 Subject: [PATCH 5/7] use hostname if not null --- lib/src/message_widget.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index d1be132d..55d08424 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -352,8 +352,9 @@ class _MessageWidgetState extends State { var host = Uri.parse(urlAttachment.ogScrapeUrl).host; var splitList = host.split('.'); var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; - var hostDisplayName = - _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); + var hostDisplayName = urlAttachment.authorName?.capitalize() ?? + _getWebsiteName(hostName.toLowerCase()) ?? + hostName.capitalize(); return Stack( children: [ From a91f1c500044e0c07bb225fa3247f0f47458fb47 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:28:10 +0100 Subject: [PATCH 6/7] fix image alignent --- lib/src/message_widget.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 55d08424..6f81f149 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -359,6 +359,7 @@ class _MessageWidgetState extends State { return Stack( children: [ Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (urlAttachment.imageUrl != null) SizedBox( @@ -370,7 +371,11 @@ class _MessageWidgetState extends State { child: Stack( clipBehavior: Clip.antiAlias, children: [ - CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Center( + child: CachedNetworkImage( + imageUrl: urlAttachment.imageUrl, + ), + ), Positioned( left: 0.0, bottom: 0.0, From 49f792bceb273a15d467ba53a51b2e4f7bd38dc0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 11 Nov 2020 17:23:51 +0530 Subject: [PATCH 7/7] rfac, fix: Separated URL attachment to widget, fixed clipping --- lib/src/message_widget.dart | 96 ++----------------------------- lib/src/url_attachment.dart | 110 ++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 91 deletions(-) create mode 100644 lib/src/url_attachment.dart diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 6f81f149..a41bc97f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -12,6 +12,7 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; +import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; @@ -356,97 +357,10 @@ class _MessageWidgetState extends State { _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); - return Stack( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (urlAttachment.imageUrl != null) - SizedBox( - height: 16.0, - ), - if (urlAttachment.imageUrl != null) - Container( - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - clipBehavior: Clip.antiAlias, - children: [ - Center( - child: CachedNetworkImage( - imageUrl: urlAttachment.imageUrl, - ), - ), - Positioned( - left: 0.0, - bottom: 0.0, - child: Container( - child: Padding( - padding: const EdgeInsets.only( - top: 8.0, - left: 8.0, - right: 8.0, - ), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), - ), - ), - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - ), - color: Color(0xFFE9F2FF), - ), - ), - ), - ], - ), - clipBehavior: Clip.antiAlias, - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(8.0)), - ), - Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (urlAttachment.title != null) - Text( - urlAttachment.title, - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), - ), - if (urlAttachment.text != null) - Text( - urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, - ), - ), - ], - ), - ), - ], - ), - Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => launchURL( - context, - urlAttachment.ogScrapeUrl, - ), - ), - ), - ), - ], + return UrlAttachment( + urlAttachment: urlAttachment, + hostDisplayName: hostDisplayName, + textPadding: widget.textPadding, ); } diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart new file mode 100644 index 00000000..4b296a6a --- /dev/null +++ b/lib/src/url_attachment.dart @@ -0,0 +1,110 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class UrlAttachment extends StatelessWidget { + Attachment urlAttachment; + String hostDisplayName; + EdgeInsets textPadding; + + UrlAttachment({ + @required this.urlAttachment, + @required this.hostDisplayName, + @required this.textPadding, + }); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (urlAttachment.imageUrl != null) + SizedBox( + height: 16.0, + ), + if (urlAttachment.imageUrl != null) + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + children: [ + Center( + child: CachedNetworkImage( + imageUrl: urlAttachment.imageUrl, + ), + ), + Positioned( + left: 0.0, + bottom: -1, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 8.0, + right: 8.0, + ), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + ), + color: Color(0xFFE9F2FF), + ), + ), + ), + ], + ), + decoration: + BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + ), + Padding( + padding: textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), + ), + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), + ), + ], + ), + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => launchURL( + context, + urlAttachment.ogScrapeUrl, + ), + ), + ), + ), + ], + ); + } +}