diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 0f056dde..8520e8ec 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -232,6 +232,7 @@ class MessageReactionsModal extends StatelessWidget { flipTail: !reverse, borderColor: messageTheme.reactionsBorderColor, backgroundColor: messageTheme.reactionsBackgroundColor, + maskColor: messageTheme.reactionsMaskColor, highlightOwnReactions: false, ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 2157aa32..3a718471 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -447,6 +447,9 @@ class _MessageWidgetState extends State { StreamChatTheme.of(context) .colorTheme .white, + StreamChatTheme.of(context) + .colorTheme + .white, ), ), ), @@ -694,6 +697,7 @@ class _MessageWidgetState extends State { flipTail: widget.reverse, backgroundColor: widget.messageTheme.reactionsBackgroundColor, borderColor: widget.messageTheme.reactionsBorderColor, + maskColor: widget.messageTheme.reactionsMaskColor, reactions: reactionsList, ), ) diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 9eee9997..61cca62e 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -12,6 +12,7 @@ class ReactionBubble extends StatelessWidget { @required this.reactions, @required this.borderColor, @required this.backgroundColor, + @required this.maskColor, this.reverse = false, this.flipTail = false, this.highlightOwnReactions = true, @@ -20,6 +21,7 @@ class ReactionBubble extends StatelessWidget { final List reactions; final Color borderColor; final Color backgroundColor; + final Color maskColor; final bool reverse; final bool flipTail; final bool highlightOwnReactions; @@ -38,51 +40,58 @@ class ReactionBubble extends StatelessWidget { Transform.translate( offset: Offset(reverse ? offset : -offset, 0), child: Container( - padding: EdgeInsets.symmetric( - vertical: 4, - horizontal: totalReactions > 1 ? 4 : 0, - ), + padding: const EdgeInsets.all(2), decoration: BoxDecoration( - border: Border.all( - color: borderColor, - ), - color: backgroundColor, + color: maskColor, borderRadius: BorderRadius.all(Radius.circular(14)), ), - child: LayoutBuilder( - builder: (context, constraints) { - return Flex( - direction: Axis.horizontal, - mainAxisSize: MainAxisSize.min, - children: [ - if (constraints.maxWidth < double.infinity) - ...reactions - .take((constraints.maxWidth) ~/ 22) - .map((reaction) { - return _buildReaction( - reactionIcons, - reaction, - context, - ); - }).toList(), - if (constraints.maxWidth == double.infinity) - ...reactions.map((reaction) { - return _buildReaction( - reactionIcons, - reaction, - context, - ); - }).toList(), - ], - ); - }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 4, + horizontal: totalReactions > 1 ? 4 : 0, + ), + decoration: BoxDecoration( + border: Border.all( + color: borderColor, + ), + color: backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(14)), + ), + child: LayoutBuilder( + builder: (context, constraints) { + return Flex( + direction: Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + if (constraints.maxWidth < double.infinity) + ...reactions + .take((constraints.maxWidth) ~/ 22) + .map((reaction) { + return _buildReaction( + reactionIcons, + reaction, + context, + ); + }).toList(), + if (constraints.maxWidth == double.infinity) + ...reactions.map((reaction) { + return _buildReaction( + reactionIcons, + reaction, + context, + ); + }).toList(), + ], + ); + }, + ), ), ), ), Positioned( - bottom: 0, - left: reverse ? null : 11, - right: !reverse ? null : 11, + bottom: 2, + left: reverse ? null : 13, + right: !reverse ? null : 13, child: _buildReactionsTail(context), ), ], @@ -136,6 +145,7 @@ class ReactionBubble extends StatelessWidget { painter: ReactionBubblePainter( backgroundColor, borderColor, + maskColor, ), ); return Transform( @@ -149,14 +159,20 @@ class ReactionBubble extends StatelessWidget { class ReactionBubblePainter extends CustomPainter { final Color color; final Color borderColor; + final Color maskColor; ReactionBubblePainter( this.color, this.borderColor, + this.maskColor, ); @override void paint(Canvas canvas, Size size) { + _drawOvalMask(size, canvas); + + _drawMask(size, canvas); + _drawOval(size, canvas); _drawOvalBorder(size, canvas); @@ -166,6 +182,21 @@ class ReactionBubblePainter extends CustomPainter { _drawBorder(size, canvas); } + void _drawOvalMask(Size size, Canvas canvas) { + final paint = Paint() + ..color = maskColor + ..style = PaintingStyle.fill; + + final path = Path(); + path.addOval( + Rect.fromCircle( + center: Offset(4, 3), + radius: 4, + ), + ); + canvas.drawPath(path, paint); + } + void _drawOvalBorder(Size size, Canvas canvas) { final paint = Paint() ..color = borderColor @@ -236,6 +267,27 @@ class ReactionBubblePainter extends CustomPainter { canvas.drawPath(path, paint); } + void _drawMask(Size size, Canvas canvas) { + final paint = Paint() + ..color = maskColor + ..strokeWidth = 1 + ..style = PaintingStyle.fill; + + final dy = -2.2; + final startAngle = 1.1; + final sweepAngle = 1.2; + final path = Path(); + path.addArc( + Rect.fromCircle( + center: Offset(1, dy), + radius: 6, + ), + -pi * startAngle, + -pi / sweepAngle, + ); + canvas.drawPath(path, paint); + } + @override bool shouldRepaint(CustomPainter oldDelegate) { return true; diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index c6d2d72f..70845ba9 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -234,6 +234,7 @@ class StreamChatThemeData { messageBackgroundColor: colorTheme.greyGainsboro, reactionsBackgroundColor: colorTheme.white, reactionsBorderColor: colorTheme.greyWhisper, + reactionsMaskColor: colorTheme.whiteSnow, messageBorderColor: colorTheme.greyGainsboro, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), @@ -249,6 +250,7 @@ class StreamChatThemeData { otherMessageTheme: MessageTheme( reactionsBackgroundColor: colorTheme.greyGainsboro, reactionsBorderColor: colorTheme.white, + reactionsMaskColor: colorTheme.whiteSnow, messageText: textTheme.body, createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), replies: textTheme.footnoteBold.copyWith(color: accentColor), @@ -710,6 +712,7 @@ class MessageTheme { final Color messageBorderColor; final Color reactionsBackgroundColor; final Color reactionsBorderColor; + final Color reactionsMaskColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -721,6 +724,7 @@ class MessageTheme { this.messageBorderColor, this.reactionsBackgroundColor, this.reactionsBorderColor, + this.reactionsMaskColor, this.avatarTheme, this.createdAt, }); @@ -736,6 +740,7 @@ class MessageTheme { AvatarTheme avatarTheme, Color reactionsBackgroundColor, Color reactionsBorderColor, + Color reactionsMaskColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -750,6 +755,7 @@ class MessageTheme { reactionsBackgroundColor: reactionsBackgroundColor ?? this.reactionsBackgroundColor, reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, + reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, ); MessageTheme merge(MessageTheme other) { @@ -767,6 +773,7 @@ class MessageTheme { avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, reactionsBackgroundColor: other.reactionsBackgroundColor, reactionsBorderColor: other.reactionsBorderColor, + reactionsMaskColor: other.reactionsMaskColor, ); } }