Merge pull request #474 from GetStream/feat/customReaction

feat: let users use custom reaction builders
This commit is contained in:
Salvatore Giordano
2021-06-14 17:50:35 +02:00
committed by GitHub
8 changed files with 147 additions and 26 deletions
@@ -5,6 +5,7 @@
- Performance improvements
- Added pinMessage ui support
- Added `MessageListView.threadSeparatorBuilder` property
## 2.0.0-nullsafety.4
- Minor fixes and improvements
@@ -148,6 +148,10 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
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<MessageActionsModal> {
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,
@@ -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,
@@ -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,
@@ -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;
}
@@ -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<ReactionPicker>
-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(
@@ -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,23 +343,63 @@ class StreamChatThemeData {
reactionIcons: [
ReactionIcon(
type: 'love',
assetName: 'Icon_love_reaction.svg',
builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context);
return StreamSvgIcon.loveReaction(
color: highlighted
? theme.colorTheme.accentBlue
: theme.primaryIconTheme.color!.withOpacity(.5),
size: size,
);
},
),
ReactionIcon(
type: 'like',
assetName: 'Icon_thumbs_up_reaction.svg',
builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context);
return StreamSvgIcon.thumbsUpReaction(
color: highlighted
? theme.colorTheme.accentBlue
: theme.primaryIconTheme.color!.withOpacity(.5),
size: size,
);
},
),
ReactionIcon(
type: 'sad',
assetName: 'Icon_thumbs_down_reaction.svg',
builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context);
return StreamSvgIcon.thumbsDownReaction(
color: highlighted
? theme.colorTheme.accentBlue
: theme.primaryIconTheme.color!.withOpacity(.5),
size: size,
);
},
),
ReactionIcon(
type: 'haha',
assetName: 'Icon_LOL_reaction.svg',
builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context);
return StreamSvgIcon.lolReaction(
color: highlighted
? theme.colorTheme.accentBlue
: theme.primaryIconTheme.color!.withOpacity(.5),
size: size,
);
},
),
ReactionIcon(
type: 'wow',
assetName: 'Icon_wut_reaction.svg',
builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context);
return StreamSvgIcon.wutReaction(
color: highlighted
? theme.colorTheme.accentBlue
: theme.primaryIconTheme.color!.withOpacity(.5),
size: size,
);
},
),
],
);
@@ -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,