From 3a44117628a93a0f244f2ed69dd91b1a3c51e14f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 14 Jun 2021 17:20:52 +0200 Subject: [PATCH] let users use custom reaction builders --- packages/stream_chat_flutter/CHANGELOG.md | 1 + .../lib/src/message_actions_modal.dart | 12 +++- .../lib/src/message_reactions_modal.dart | 12 +++- .../lib/src/reaction_bubble.dart | 15 +++-- .../lib/src/reaction_icon.dart | 10 +++- .../lib/src/reaction_picker.dart | 10 ++-- .../lib/src/stream_chat_theme.dart | 54 +++++++++++++++-- .../lib/src/stream_svg_icon.dart | 60 +++++++++++++++++++ 8 files changed, 148 insertions(+), 26 deletions(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 509ac26a..39247b13 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -5,6 +5,7 @@ - Performance improvements - Added pinMessage ui support - Added `MessageListView.threadSeparatorBuilder` property + ## 2.0.0-nullsafety.4 - Minor fixes and improvements diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 13900c21..f763585b 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -148,6 +148,10 @@ class _MessageActionsModalState extends State { final streamChatThemeData = StreamChatTheme.of(context); + final numberOfReactions = streamChatThemeData.reactionIcons.length; + final shiftFactor = + numberOfReactions < 5 ? (5 - numberOfReactions) * 0.1 : 0.0; + final child = Center( child: SingleChildScrollView( child: Padding( @@ -162,8 +166,12 @@ class _MessageActionsModalState extends State { Align( alignment: Alignment( user?.id == widget.message.user?.id - ? (divFactor >= 1.0 ? -0.2 : (1.2 - divFactor)) - : (divFactor >= 1.0 ? 0.2 : -(1.2 - divFactor)), + ? (divFactor >= 1.0 + ? -0.2 - shiftFactor + : (1.2 - divFactor)) + : (divFactor >= 1.0 + ? 0.2 + shiftFactor + : -(1.2 - divFactor)), 0), child: ReactionPicker( message: widget.message, diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index e9369e99..842fe79d 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -80,6 +80,10 @@ class MessageReactionsModal extends StatelessWidget { final hasFileAttachment = message.attachments.any((it) => it.type == 'file') == true; + final numberOfReactions = StreamChatTheme.of(context).reactionIcons.length; + final shiftFactor = + numberOfReactions < 5 ? (5 - numberOfReactions) * 0.1 : 0.0; + final child = Center( child: SingleChildScrollView( child: Padding( @@ -93,8 +97,12 @@ class MessageReactionsModal extends StatelessWidget { Align( alignment: Alignment( user!.id == message.user!.id - ? (divFactor >= 1.0 ? -0.2 : (1.2 - divFactor)) - : (divFactor >= 1.0 ? 0.2 : -(1.2 - divFactor)), + ? (divFactor >= 1.0 + ? -0.2 - shiftFactor + : (1.2 - divFactor)) + : (divFactor >= 1.0 + ? 0.2 + shiftFactor + : -(1.2 - divFactor)), 0), child: ReactionPicker( message: message, diff --git a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart index ce75445b..a3b2052f 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Creates reaction bubble widget for displaying over messages @@ -130,13 +129,13 @@ class ReactionBubble extends StatelessWidget { horizontal: 4, ), child: reactionIcon != null - ? StreamSvgIcon( - assetName: reactionIcon.assetName, - width: 16, - height: 16, - color: (!highlightOwnReactions || reaction.user?.id == userId) - ? chatThemeData.colorTheme.accentBlue - : chatThemeData.colorTheme.black.withOpacity(.5), + ? ConstrainedBox( + constraints: BoxConstraints.tight(const Size.square(16)), + child: reactionIcon.builder( + context, + !highlightOwnReactions || reaction.user?.id == userId, + 16, + ), ) : Icon( Icons.help_outline_rounded, diff --git a/packages/stream_chat_flutter/lib/src/reaction_icon.dart b/packages/stream_chat_flutter/lib/src/reaction_icon.dart index 4466e154..e675128b 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_icon.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_icon.dart @@ -1,14 +1,20 @@ +import 'package:flutter/material.dart'; + /// Reaction icon data class ReactionIcon { /// Constructor for creating [ReactionIcon] ReactionIcon({ required this.type, - required this.assetName, + required this.builder, }); /// Type of reaction final String type; /// Asset to display for reaction - final String assetName; + final Widget Function( + BuildContext, + bool highlighted, + double size, + ) builder; } diff --git a/packages/stream_chat_flutter/lib/src/reaction_picker.dart b/packages/stream_chat_flutter/lib/src/reaction_picker.dart index 2e47b933..5101cbb7 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_picker.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_picker.dart @@ -1,7 +1,6 @@ import 'package:ezanimation/ezanimation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/extension.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/reaction_picker.png) @@ -69,11 +68,10 @@ class _ReactionPickerState extends State -1; final index = reactionIcons.indexOf(reactionIcon); - final child = StreamSvgIcon( - assetName: reactionIcon.assetName, - color: ownReactionIndex != -1 - ? chatThemeData.colorTheme.accentBlue - : Theme.of(context).iconTheme.color!.withOpacity(.5), + final child = reactionIcon.builder( + context, + ownReactionIndex != -1, + 24, ); return ConstrainedBox( diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 25c2ca32..981d8131 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -217,10 +217,11 @@ class StreamChatThemeData { TextTheme textTheme, ) { final accentColor = colorTheme.accentBlue; + final iconTheme = IconThemeData(color: colorTheme.black.withOpacity(.5)); return StreamChatThemeData.raw( textTheme: textTheme, colorTheme: colorTheme, - primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), + primaryIconTheme: iconTheme, defaultChannelImage: (context, channel) => const SizedBox(), defaultUserImage: (context, user) => Center( child: CachedNetworkImage( @@ -342,29 +343,70 @@ class StreamChatThemeData { reactionIcons: [ ReactionIcon( type: 'love', - assetName: 'Icon_love_reaction.svg', + builder: (context, highlighted, size) => StreamSvgIcon.loveReaction( + color: highlighted + ? colorTheme.accentBlue + : iconTheme.color!.withOpacity(.5), + size: size, + ), ), ReactionIcon( type: 'like', - assetName: 'Icon_thumbs_up_reaction.svg', + builder: (context, highlighted, size) => + StreamSvgIcon.thumbsUpReaction( + color: highlighted + ? colorTheme.accentBlue + : iconTheme.color!.withOpacity(.5), + size: size, + ), ), ReactionIcon( type: 'sad', - assetName: 'Icon_thumbs_down_reaction.svg', + builder: (context, highlighted, size) => + StreamSvgIcon.thumbsDownReaction( + color: highlighted + ? colorTheme.accentBlue + : iconTheme.color!.withOpacity(.5), + size: size, + ), ), ReactionIcon( type: 'haha', - assetName: 'Icon_LOL_reaction.svg', + builder: (context, highlighted, size) => StreamSvgIcon.lolReaction( + color: highlighted + ? colorTheme.accentBlue + : iconTheme.color!.withOpacity(.5), + size: size, + ), ), ReactionIcon( type: 'wow', - assetName: 'Icon_wut_reaction.svg', + builder: (context, highlighted, size) => StreamSvgIcon.wutReaction( + color: highlighted + ? colorTheme.accentBlue + : iconTheme.color!.withOpacity(.5), + size: size, + ), ), ], ); } } +class ReactionTheme { + final double singleSize; + final double size; + final Color ownReactionColor; + final Color otherReactionColor; + + const ReactionTheme({ + required this.singleSize, + required this.size, + required this.ownReactionColor, + required this.otherReactionColor, + }); +} + /// Class for holding text theme class TextTheme { /// Initialise light text theme diff --git a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart index ae344a89..fb5017e1 100644 --- a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart +++ b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart @@ -49,6 +49,66 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); + /// [StreamSvgIcon] type + factory StreamSvgIcon.loveReaction({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_love_reaction.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.thumbsUpReaction({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_thumbs_up_reaction.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.thumbsDownReaction({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_thumbs_down_reaction.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.lolReaction({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_LOL_reaction.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.wutReaction({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_wut_reaction.svg', + color: color, + width: size, + height: size, + ); + /// [StreamSvgIcon] type factory StreamSvgIcon.smile({ double? size,