Merge pull request #497 from GetStream/feat/defaultMessageWidget

feat: make default message widget easier to reuse
This commit is contained in:
Salvatore Giordano
2021-06-25 15:53:23 +02:00
committed by GitHub
7 changed files with 252 additions and 295 deletions
@@ -93,6 +93,7 @@ class ChannelPage extends StatelessWidget {
BuildContext context,
MessageDetails details,
List<Message> messages,
MessageWidget _,
) {
final message = details.message;
final isCurrentUser = StreamChat.of(context).user!.id == message.user!.id;
@@ -15,6 +15,7 @@ class MessageActionsModal extends StatefulWidget {
const MessageActionsModal({
Key? key,
required this.message,
required this.messageWidget,
required this.messageTheme,
this.showReactions = true,
this.showDeleteMessage = true,
@@ -27,18 +28,15 @@ class MessageActionsModal extends StatefulWidget {
this.showThreadReplyMessage = true,
this.showFlagButton = true,
this.showPinButton = true,
this.showPinHighlight = false,
this.showUserAvatar = DisplayWidget.show,
this.editMessageInputBuilder,
this.messageShape,
this.attachmentShape,
this.reverse = false,
this.customActions = const [],
this.attachmentBorderRadiusGeometry,
this.onCopyTap,
this.textBuilder,
}) : super(key: key);
/// Widget that shows the message
final Widget messageWidget;
/// Builder for edit message
final Widget Function(BuildContext, Message)? editMessageInputBuilder;
@@ -84,30 +82,12 @@ class MessageActionsModal extends StatefulWidget {
/// Flag for showing pin action
final bool showPinButton;
/// Display Pin Highlight
final bool showPinHighlight;
/// Flag for reversing message
final bool reverse;
/// [ShapeBorder] to apply to the widget
final ShapeBorder? messageShape;
/// [ShapeBorder] to apply to attachment
final ShapeBorder? attachmentShape;
/// Enum for displaying user avatar
final DisplayWidget showUserAvatar;
/// [BorderRadius] for attachment border
final BorderRadius? attachmentBorderRadiusGeometry;
/// List of custom actions
final List<MessageAction> customActions;
/// Customize the MessageWidget textBuilder
final Widget Function(BuildContext context, Message message)? textBuilder;
@override
_MessageActionsModalState createState() => _MessageActionsModalState();
}
@@ -142,9 +122,6 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
? 1
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
final hasFileAttachment =
widget.message.attachments.any((it) => it.type == 'file') == true;
final streamChatThemeData = StreamChatTheme.of(context);
final numberOfReactions = streamChatThemeData.reactionIcons.length;
@@ -178,41 +155,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
),
const SizedBox(height: 8),
IgnorePointer(
child: MessageWidget(
key: const Key('MessageWidget'),
reverse: widget.reverse,
attachmentBorderRadiusGeometry: widget
.attachmentBorderRadiusGeometry
?.mirrorBorderIfReversed(reverse: !widget.reverse),
message: widget.message.copyWith(
text: widget.message.text!.length > 200
// ignore: lines_longer_than_80_chars
? '${widget.message.text!.substring(0, 200)}...'
: widget.message.text,
),
messageTheme: widget.messageTheme,
showReactions: false,
showUsername: false,
showReplyMessage: false,
showUserAvatar: widget.showUserAvatar,
attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2,
),
showTimestamp: false,
translateUserAvatar: false,
padding: const EdgeInsets.all(0),
textPadding: EdgeInsets.symmetric(
vertical: 8,
horizontal: widget.message.text!.isOnlyEmoji ? 0 : 16.0,
),
showReactionPickerIndicator: widget.showReactions &&
(widget.message.status == MessageSendingStatus.sent),
showSendingIndicator: false,
shape: widget.messageShape,
attachmentShape: widget.attachmentShape,
showPinHighlight: false,
textBuilder: widget.textBuilder,
),
child: widget.messageWidget,
),
const SizedBox(height: 8),
Padding(
@@ -19,16 +19,22 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:visibility_detector/visibility_detector.dart';
/// Widget builder for message
/// [defaultMessageWidget] is the default [MessageWidget] configuration
/// Use [defaultMessageWidget.copyWith] to easily customize it
typedef MessageBuilder = Widget Function(
BuildContext,
MessageDetails,
List<Message>,
MessageWidget defaultMessageWidget,
);
/// Widget builder for parent message
/// [defaultMessageWidget] is the default [MessageWidget] configuration
/// Use [defaultMessageWidget.copyWith] to easily customize it
typedef ParentMessageBuilder = Widget Function(
BuildContext,
Message?,
MessageWidget defaultMessageWidget,
);
/// Widget builder for system message
@@ -56,12 +62,12 @@ typedef ReplyTapCallback = void Function(Message);
class MessageDetails {
/// Constructor for creating [MessageDetails]
MessageDetails(
BuildContext context,
String currentUserId,
this.message,
List<Message> messages,
this.index,
) {
isMyMessage = message.user?.id == StreamChat.of(context).user?.id;
isMyMessage = message.user?.id == currentUserId;
isLastUser = index + 1 < messages.length &&
message.user?.id == messages[index + 1].user?.id;
isNextUser =
@@ -69,19 +75,19 @@ class MessageDetails {
}
/// True if the message belongs to the current user
bool? isMyMessage;
late final bool isMyMessage;
/// True if the user message is the same of the previous message
bool? isLastUser;
late final bool isLastUser;
/// True if the user message is the same of the next message
bool? isNextUser;
late final bool isNextUser;
/// The message
Message message;
final Message message;
/// The index of the message
int index;
final int index;
}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png)
@@ -545,11 +551,7 @@ class _MessageListViewState extends State<MessageListView> {
itemBuilder: (context, i) {
if (i == itemCount - 1) {
if (widget.parentMessage == null) return const Offstage();
return widget.parentMessageBuilder?.call(
context,
widget.parentMessage,
) ??
buildParentMessage(widget.parentMessage!);
return buildParentMessage(widget.parentMessage!);
}
if (i == itemCount - 2) {
@@ -576,46 +578,21 @@ class _MessageListViewState extends State<MessageListView> {
const Offstage();
}
final topMessageIndex = itemCount -
4; // 7 -> parent // 6 -> header // 5 -> loader
const bottomMessageIndex = 2; // 1 -> loader // 0 -> footer
final message = messages[i - 2];
Widget messageWidget;
if (i == topMessageIndex) {
messageWidget = _buildTopMessage(
context,
message,
messages,
streamChannel,
i,
);
} else if (i == bottomMessageIndex) {
if (i == bottomMessageIndex) {
messageWidget = _buildBottomMessage(
context,
message,
messages,
streamChannel!,
i,
i - 2,
);
} else {
if (widget.messageBuilder != null) {
messageWidget = Builder(
key: ValueKey<String>('MESSAGE-${message.id}'),
builder: (context) => widget.messageBuilder!(
context,
MessageDetails(
context,
message,
messages,
i,
),
messages),
);
} else {
messageWidget = buildMessage(message, messages, i);
}
messageWidget = buildMessage(message, messages, i - 2);
}
return messageWidget;
},
@@ -785,34 +762,6 @@ class _MessageListViewState extends State<MessageListView> {
isThreadConversation: _isThreadConversation,
);
Widget _buildTopMessage(
BuildContext context,
Message message,
List<Message> messages,
StreamChannelState? streamChannel,
int index,
) {
Widget messageWidget;
if (widget.messageBuilder != null) {
messageWidget = Builder(
key: const ValueKey<String>('TOP-MESSAGE'),
builder: (_) => widget.messageBuilder!(
context,
MessageDetails(
context,
message,
messages,
messages.length - 1,
),
messages,
),
);
} else {
messageWidget = buildMessage(message, messages, index);
}
return messageWidget;
}
Widget _buildBottomMessage(
BuildContext context,
Message message,
@@ -820,24 +769,7 @@ class _MessageListViewState extends State<MessageListView> {
StreamChannelState streamChannel,
int index,
) {
Widget messageWidget;
if (widget.messageBuilder != null) {
messageWidget = Builder(
key: ValueKey<String>('BOTTOM-MESSAGE-${message.id}'),
builder: (_) => widget.messageBuilder!(
context,
MessageDetails(
context,
message,
messages,
0,
),
messages,
),
);
} else {
messageWidget = buildMessage(message, messages, index);
}
final messageWidget = buildMessage(message, messages, index);
return VisibilityDetector(
key: ValueKey<String>('BOTTOM-MESSAGE-${message.id}'),
@@ -871,7 +803,7 @@ class _MessageListViewState extends State<MessageListView> {
final currentUserMember =
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
return MessageWidget(
final defaultMessageWidget = MessageWidget(
showReplyMessage: false,
showResendMessage: false,
showThreadReplyMessage: false,
@@ -925,6 +857,16 @@ class _MessageListViewState extends State<MessageListView> {
showPinButton: currentUserMember != null &&
widget.pinPermissions.contains(currentUserMember.role),
);
if (widget.parentMessageBuilder != null) {
return widget.parentMessageBuilder!.call(
context,
widget.parentMessage,
defaultMessageWidget,
);
}
return defaultMessageWidget;
}
Widget buildMessage(
@@ -1015,7 +957,7 @@ class _MessageListViewState extends State<MessageListView> {
final currentUserMember =
members.firstWhere((e) => e.user!.id == currentUser!.id);
Widget child = MessageWidget(
Widget messageWidget = MessageWidget(
key: ValueKey<String>('MESSAGE-${message.id}'),
message: message,
reverse: isMyMessage,
@@ -1130,6 +1072,21 @@ class _MessageListViewState extends State<MessageListView> {
showPinButton: widget.pinPermissions.contains(currentUserMember.role),
);
if (widget.messageBuilder != null) {
messageWidget = widget.messageBuilder!(
context,
MessageDetails(
userId,
message,
messages,
index,
),
messages,
messageWidget as MessageWidget,
);
}
var child = messageWidget;
if (!message.isDeleted &&
!message.isSystem &&
!message.isEphemeral &&
@@ -1,7 +1,6 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
import 'package:stream_chat_flutter/src/reaction_picker.dart';
import 'package:stream_chat_flutter/src/stream_chat.dart';
@@ -15,17 +14,16 @@ class MessageReactionsModal extends StatelessWidget {
const MessageReactionsModal({
Key? key,
required this.message,
required this.messageWidget,
required this.messageTheme,
this.showReactions = true,
this.messageShape,
this.attachmentShape,
this.reverse = false,
this.showUserAvatar = DisplayWidget.show,
this.onUserAvatarTap,
this.attachmentBorderRadiusGeometry,
this.textBuilder,
}) : super(key: key);
/// Widget that shows the message
final Widget messageWidget;
/// Message to display reactions of
final Message message;
@@ -38,24 +36,9 @@ class MessageReactionsModal extends StatelessWidget {
/// Flag to show reactions on message
final bool showReactions;
/// Enum to change user avatar config
final DisplayWidget showUserAvatar;
/// [ShapeBorder] to apply to message
final ShapeBorder? messageShape;
/// [ShapeBorder] to apply to attachment
final ShapeBorder? attachmentShape;
/// Callback when user avatar is tapped
final void Function(User)? onUserAvatarTap;
/// [BorderRadius] to apply to attachments
final BorderRadius? attachmentBorderRadiusGeometry;
/// Customize the MessageWidget textBuilder
final Widget Function(BuildContext context, Message message)? textBuilder;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
@@ -77,8 +60,6 @@ class MessageReactionsModal extends StatelessWidget {
final divFactor = message.attachments.isNotEmpty == true
? 1
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
final hasFileAttachment =
message.attachments.any((it) => it.type == 'file') == true;
final numberOfReactions = StreamChatTheme.of(context).reactionIcons.length;
final shiftFactor =
@@ -110,38 +91,7 @@ class MessageReactionsModal extends StatelessWidget {
),
const SizedBox(height: 8),
IgnorePointer(
child: MessageWidget(
key: const Key('MessageWidget'),
reverse: reverse,
message: message.copyWith(
text: message.text!.length > 200
? '${message.text!.substring(0, 200)}...'
: message.text,
),
messageTheme: messageTheme,
showReactions: false,
showUsername: false,
showUserAvatar: showUserAvatar,
showTimestamp: false,
translateUserAvatar: false,
showSendingIndicator: false,
shape: messageShape,
attachmentShape: attachmentShape,
padding: const EdgeInsets.all(0),
attachmentBorderRadiusGeometry: attachmentBorderRadiusGeometry
?.mirrorBorderIfReversed(reverse: !reverse),
attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2,
),
textPadding: EdgeInsets.symmetric(
vertical: 8,
horizontal: message.text!.isOnlyEmoji ? 0 : 16.0,
),
showReactionPickerIndicator: showReactions &&
(message.status == MessageSendingStatus.sent),
textBuilder: textBuilder,
showPinHighlight: false,
),
child: messageWidget,
),
if (message.latestReactions?.isNotEmpty == true) ...[
const SizedBox(height: 8),
@@ -397,6 +397,117 @@ class MessageWidget extends StatefulWidget {
/// Customize onTap on attachment
final void Function(Message message, Attachment attachment)? onAttachmentTap;
/// Creates a copy of [MessageWidget] with specified attributes overridden.
MessageWidget copyWith({
Key? key,
void Function(User)? onMentionTap,
void Function(Message)? onThreadTap,
void Function(Message)? onReplyTap,
Widget Function(BuildContext, Message)? editMessageInputBuilder,
Widget Function(BuildContext, Message)? textBuilder,
Widget Function(BuildContext, Message)? usernameBuilder,
void Function(BuildContext, Message)? onMessageActions,
Message? message,
MessageTheme? messageTheme,
bool? reverse,
ShapeBorder? shape,
ShapeBorder? attachmentShape,
BorderSide? borderSide,
BorderSide? attachmentBorderSide,
BorderRadiusGeometry? borderRadiusGeometry,
BorderRadiusGeometry? attachmentBorderRadiusGeometry,
EdgeInsetsGeometry? padding,
EdgeInsets? textPadding,
EdgeInsetsGeometry? attachmentPadding,
DisplayWidget? showUserAvatar,
bool? showSendingIndicator,
bool? showReactions,
bool? allRead,
bool? showThreadReplyIndicator,
bool? showInChannelIndicator,
void Function(User)? onUserAvatarTap,
void Function(String)? onLinkTap,
bool? showReactionPickerIndicator,
List<Read>? readList,
ShowMessageCallback? onShowMessage,
ValueChanged<ReturnActionType>? onReturnAction,
bool? showUsername,
bool? showTimestamp,
bool? showReplyMessage,
bool? showThreadReplyMessage,
bool? showEditMessage,
bool? showCopyMessage,
bool? showDeleteMessage,
bool? showResendMessage,
bool? showFlagButton,
bool? showPinButton,
bool? showPinHighlight,
Map<String, AttachmentBuilder>? customAttachmentBuilders,
bool? translateUserAvatar,
OnQuotedMessageTap? onQuotedMessageTap,
void Function(Message)? onMessageTap,
List<MessageAction>? customActions,
void Function(Message message, Attachment attachment)? onAttachmentTap,
}) =>
MessageWidget(
key: key ?? this.key,
onMentionTap: onMentionTap ?? this.onMentionTap,
onThreadTap: onThreadTap ?? this.onThreadTap,
onReplyTap: onReplyTap ?? this.onReplyTap,
editMessageInputBuilder:
editMessageInputBuilder ?? this.editMessageInputBuilder,
textBuilder: textBuilder ?? this.textBuilder,
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
onMessageActions: onMessageActions ?? this.onMessageActions,
message: message ?? this.message,
messageTheme: messageTheme ?? this.messageTheme,
reverse: reverse ?? this.reverse,
shape: shape ?? this.shape,
attachmentShape: attachmentShape ?? this.attachmentShape,
borderSide: borderSide ?? this.borderSide,
attachmentBorderSide: attachmentBorderSide ?? this.attachmentBorderSide,
borderRadiusGeometry: borderRadiusGeometry ?? this.borderRadiusGeometry,
attachmentBorderRadiusGeometry: attachmentBorderRadiusGeometry ??
this.attachmentBorderRadiusGeometry,
padding: padding ?? this.padding,
textPadding: textPadding ?? this.textPadding,
attachmentPadding: attachmentPadding ?? this.attachmentPadding,
showUserAvatar: showUserAvatar ?? this.showUserAvatar,
showSendingIndicator: showSendingIndicator ?? this.showSendingIndicator,
showReactions: showReactions ?? this.showReactions,
allRead: allRead ?? this.allRead,
showThreadReplyIndicator:
showThreadReplyIndicator ?? this.showThreadReplyIndicator,
showInChannelIndicator:
showInChannelIndicator ?? this.showInChannelIndicator,
onUserAvatarTap: onUserAvatarTap ?? this.onUserAvatarTap,
onLinkTap: onLinkTap ?? this.onLinkTap,
showReactionPickerIndicator:
showReactionPickerIndicator ?? this.showReactionPickerIndicator,
readList: readList ?? this.readList,
onShowMessage: onShowMessage ?? this.onShowMessage,
onReturnAction: onReturnAction ?? this.onReturnAction,
showUsername: showUsername ?? this.showUsername,
showTimestamp: showTimestamp ?? this.showTimestamp,
showReplyMessage: showReplyMessage ?? this.showReplyMessage,
showThreadReplyMessage:
showThreadReplyMessage ?? this.showThreadReplyMessage,
showEditMessage: showEditMessage ?? this.showEditMessage,
showCopyMessage: showCopyMessage ?? this.showCopyMessage,
showDeleteMessage: showDeleteMessage ?? this.showDeleteMessage,
showResendMessage: showResendMessage ?? this.showResendMessage,
showFlagButton: showFlagButton ?? this.showFlagButton,
showPinButton: showPinButton ?? this.showPinButton,
showPinHighlight: showPinHighlight ?? this.showPinHighlight,
customAttachmentBuilders:
customAttachmentBuilders ?? attachmentBuilders,
translateUserAvatar: translateUserAvatar ?? this.translateUserAvatar,
onQuotedMessageTap: onQuotedMessageTap ?? this.onQuotedMessageTap,
onMessageTap: onMessageTap ?? this.onMessageTap,
customActions: customActions ?? this.customActions,
onAttachmentTap: onAttachmentTap ?? this.onAttachmentTap,
);
@override
_MessageWidgetState createState() => _MessageWidgetState();
}
@@ -461,7 +572,7 @@ class _MessageWidgetState extends State<MessageWidget>
super.build(context);
final avatarWidth =
widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40;
final leftPadding =
final bottomRowPadding =
widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5;
return Material(
@@ -516,7 +627,8 @@ class _MessageWidgetState extends State<MessageWidget>
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (widget.showUserAvatar ==
if (!widget.reverse &&
widget.showUserAvatar ==
DisplayWidget.show &&
widget.message.user != null) ...[
_buildUserAvatar(),
@@ -642,6 +754,13 @@ class _MessageWidgetState extends State<MessageWidget>
),
),
),
if (widget.reverse &&
widget.showUserAvatar ==
DisplayWidget.show &&
widget.message.user != null) ...[
_buildUserAvatar(),
const SizedBox(width: 4),
]
],
),
if (showBottomRow)
@@ -652,7 +771,8 @@ class _MessageWidgetState extends State<MessageWidget>
if (showBottomRow)
Padding(
padding: EdgeInsets.only(
left: leftPadding,
left: !widget.reverse ? bottomRowPadding : 0,
right: widget.reverse ? bottomRowPadding : 0,
bottom:
isPinned && widget.showPinHighlight ? 6.0 : 0.0,
),
@@ -912,19 +1032,30 @@ class _MessageWidgetState extends State<MessageWidget>
builder: (context) => StreamChannel(
channel: channel,
child: MessageActionsModal(
textBuilder: widget.textBuilder,
messageWidget: widget.copyWith(
key: const Key('MessageWidget'),
message: widget.message.copyWith(
text: widget.message.text!.length > 200
? '${widget.message.text!.substring(0, 200)}...'
: widget.message.text,
),
showReactions: false,
showUsername: false,
showTimestamp: false,
translateUserAvatar: false,
showSendingIndicator: false,
padding: const EdgeInsets.all(0),
showReactionPickerIndicator: widget.showReactions &&
(widget.message.status == MessageSendingStatus.sent),
showPinHighlight: false,
showUserAvatar:
widget.message.user!.id == channel.client.state.user!.id
? DisplayWidget.gone
: DisplayWidget.show,
),
onCopyTap: (message) =>
Clipboard.setData(ClipboardData(text: message.text)),
attachmentBorderRadiusGeometry:
widget.attachmentBorderRadiusGeometry as BorderRadius?,
showUserAvatar:
widget.message.user!.id == channel.client.state.user!.id
? DisplayWidget.gone
: DisplayWidget.show,
messageTheme: widget.messageTheme,
messageShape: widget.shape ?? _getDefaultShape(context),
attachmentShape: widget.attachmentShape ??
_getDefaultAttachmentShape(context),
reverse: widget.reverse,
showDeleteMessage: widget.showDeleteMessage || isDeleteFailed,
message: widget.message,
@@ -964,18 +1095,29 @@ class _MessageWidgetState extends State<MessageWidget>
builder: (context) => StreamChannel(
channel: channel,
child: MessageReactionsModal(
textBuilder: widget.textBuilder,
attachmentBorderRadiusGeometry:
widget.attachmentBorderRadiusGeometry as BorderRadius?,
showUserAvatar:
widget.message.user!.id == channel.client.state.user!.id
? DisplayWidget.gone
: DisplayWidget.show,
messageWidget: widget.copyWith(
key: const Key('MessageWidget'),
message: widget.message.copyWith(
text: widget.message.text!.length > 200
? '${widget.message.text!.substring(0, 200)}...'
: widget.message.text,
),
showReactions: false,
showUsername: false,
showTimestamp: false,
translateUserAvatar: false,
showSendingIndicator: false,
padding: const EdgeInsets.all(0),
showReactionPickerIndicator: widget.showReactions &&
(widget.message.status == MessageSendingStatus.sent),
showPinHighlight: false,
showUserAvatar:
widget.message.user!.id == channel.client.state.user!.id
? DisplayWidget.gone
: DisplayWidget.show,
),
onUserAvatarTap: widget.onUserAvatarTap,
messageTheme: widget.messageTheme,
messageShape: widget.shape ?? _getDefaultShape(context),
attachmentShape:
widget.attachmentShape ?? _getDefaultAttachmentShape(context),
reverse: widget.reverse,
message: widget.message,
showReactions: widget.showReactions,
@@ -984,28 +1126,6 @@ class _MessageWidgetState extends State<MessageWidget>
);
}
ShapeBorder _getDefaultAttachmentShape(BuildContext context) {
final hasFiles =
widget.message.attachments.any((it) => it.type == 'file') == true;
return RoundedRectangleBorder(
side: hasFiles
? widget.attachmentBorderSide ??
BorderSide(
color: _streamChatTheme.colorTheme.greyWhisper,
)
: BorderSide.none,
borderRadius: widget.attachmentBorderRadiusGeometry ?? BorderRadius.zero,
);
}
ShapeBorder _getDefaultShape(BuildContext context) => RoundedRectangleBorder(
side: widget.borderSide ??
BorderSide(
color: _streamChatTheme.colorTheme.greyWhisper,
),
borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero,
);
Widget _parseAttachments() {
final attachmentGroups = <String, List<Attachment>>{};
@@ -38,6 +38,10 @@ void main() {
id: 'user-id',
),
),
messageWidget: const Text(
'test',
key: Key('MessageWidget'),
),
messageTheme: streamTheme.ownMessageTheme,
),
),
@@ -86,6 +90,10 @@ void main() {
),
),
messageTheme: streamTheme.ownMessageTheme,
messageWidget: const Text(
'test',
key: Key('MessageWidget'),
),
),
),
),
@@ -123,6 +131,7 @@ void main() {
client: client,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
text: 'test',
user: User(
@@ -178,6 +187,7 @@ void main() {
client: client,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
onReplyTap: (m) {
tapped = true;
},
@@ -223,6 +233,7 @@ void main() {
client: client,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
onThreadReplyTap: (m) {
tapped = true;
},
@@ -272,6 +283,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
text: 'test',
user: User(
@@ -320,6 +332,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
editMessageInputBuilder: (context, m) => const Text('test'),
message: Message(
text: 'test',
@@ -371,6 +384,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
onCopyTap: (m) => tapped = true,
message: Message(
text: 'test',
@@ -420,6 +434,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
status: MessageSendingStatus.failed,
text: 'test',
@@ -469,6 +484,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
status: MessageSendingStatus.failed_update,
text: 'test',
@@ -516,6 +532,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
id: 'testid',
text: 'test',
@@ -571,6 +588,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
id: 'testid',
text: 'test',
@@ -626,6 +644,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
id: 'testid',
text: 'test',
@@ -679,6 +698,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
id: 'testid',
text: 'test',
@@ -734,6 +754,7 @@ void main() {
channel: channel,
child: SizedBox(
child: MessageActionsModal(
messageWidget: const Text('test'),
message: Message(
id: 'testid',
text: 'test',
@@ -34,6 +34,10 @@ void main() {
client: client,
streamChatThemeData: streamTheme,
child: MessageReactionsModal(
messageWidget: const Text(
'test',
key: Key('MessageWidget'),
),
message: message,
messageTheme: streamTheme.ownMessageTheme,
),
@@ -43,28 +47,9 @@ void main() {
await tester.pump(const Duration(milliseconds: 1000));
expect(find.byType(MessageWidget), findsOneWidget);
final messageWidget =
tester.widget<MessageWidget>(find.byType(MessageWidget));
expect(messageWidget.message, message);
expect(messageWidget.messageTheme, streamTheme.ownMessageTheme);
expect(messageWidget.attachmentBorderRadiusGeometry, null);
expect(messageWidget.showUserAvatar, DisplayWidget.show);
expect(messageWidget.reverse, false);
expect(messageWidget.attachmentShape, null);
expect(messageWidget.shape, null);
expect(messageWidget.onUserAvatarTap, null);
expect(messageWidget.showReactions, false);
expect(messageWidget.showUsername, false);
expect(messageWidget.showThreadReplyIndicator, false);
expect(messageWidget.showTimestamp, false);
expect(messageWidget.translateUserAvatar, false);
expect(messageWidget.showSendingIndicator, false);
expect(find.byType(ReactionBubble), findsNothing);
//only one avatar (the message one)
expect(find.byType(UserAvatar), findsOneWidget);
expect(find.byType(UserAvatar), findsNothing);
},
);
@@ -105,14 +90,14 @@ void main() {
client: client,
streamChatThemeData: streamTheme,
child: MessageReactionsModal(
messageWidget: const Text(
'test',
key: Key('MessageWidget'),
),
message: message,
messageTheme: streamTheme.ownMessageTheme,
showUserAvatar: DisplayWidget.gone,
reverse: true,
attachmentBorderRadiusGeometry: BorderRadius.circular(1),
attachmentShape: const RoundedRectangleBorder(),
showReactions: false,
messageShape: const RoundedRectangleBorder(),
onUserAvatarTap: onUserAvatarTap,
),
),
@@ -121,27 +106,7 @@ void main() {
await tester.pump(const Duration(milliseconds: 1000));
expect(find.byType(MessageWidget), findsOneWidget);
final messageWidget =
tester.widget<MessageWidget>(find.byType(MessageWidget));
expect(messageWidget.message, message);
expect(messageWidget.messageTheme, streamTheme.ownMessageTheme);
expect(messageWidget.attachmentBorderRadiusGeometry,
BorderRadius.circular(1));
expect(messageWidget.showUserAvatar, DisplayWidget.gone);
expect(messageWidget.reverse, true);
expect(messageWidget.showReactions, false);
expect(messageWidget.attachmentShape, const RoundedRectangleBorder());
expect(messageWidget.shape, const RoundedRectangleBorder());
expect(messageWidget.showReactions, false);
expect(messageWidget.showUsername, false);
expect(messageWidget.showThreadReplyIndicator, false);
expect(messageWidget.showTimestamp, false);
expect(messageWidget.translateUserAvatar, false);
expect(messageWidget.showSendingIndicator, false);
final userAvatar = tester.widget<UserAvatar>(find.byType(UserAvatar));
expect(userAvatar.onTap, onUserAvatarTap);
expect(find.byKey(const Key('MessageWidget')), findsOneWidget);
expect(find.byType(ReactionBubble), findsOneWidget);
expect(find.byType(UserAvatar), findsOneWidget);