Merge pull request #1416 from GetStream/geweald-sendingIndicator-bottomRow

This commit is contained in:
Sahil Kumar
2022-12-23 14:46:03 +05:30
committed by GitHub
4 changed files with 269 additions and 95 deletions
@@ -1,5 +1,8 @@
## Upcomming ## Upcomming
✅ Added
- Added a new `bottomRowBuilderWithDefaultWidget` parameter to `StreamMessageWidget` which contains a third parameter (default `BottomRow` widget with `copyWith` method available) to allow easier customization.
🔄 Changed 🔄 Changed
- Updated `lottie` dependency to `^2.0.0` - Updated `lottie` dependency to `^2.0.0`
@@ -7,6 +10,9 @@
- Updated `connectivity_plus` dependency to `^3.0.2` - Updated `connectivity_plus` dependency to `^3.0.2`
- Updated `dart_vlc` dependency to `^0.4.0` - Updated `dart_vlc` dependency to `^0.4.0`
- Updated `file_picker` dependency to `^5.2.4` - Updated `file_picker` dependency to `^5.2.4`
- Deprecated `StreamMessageWidget.bottomRowBuilder` in favor of `StreamMessageWidget.bottomRowBuilderWithDefaultWidget`.
- Deprecated `StreamMessageWidget.deletedBottomRowBuilder` in favor of `StreamMessageWidget.bottomRowBuilderWithDefaultWidget`.
- Deprecated `StreamMessageWidget.usernameBuilder` in favor of `StreamMessageWidget.bottomRowBuilderWithDefaultWidget`.
🐞 Fixed 🐞 Fixed
- [[#1379]](https://github.com/GetStream/stream-chat-flutter/issues/1379) Fixed "Issues with photo attachments on web", where the cached image attachment would not render while uploading. - [[#1379]](https://github.com/GetStream/stream-chat-flutter/issues/1379) Fixed "Issues with photo attachments on web", where the cached image attachment would not render while uploading.
@@ -32,6 +32,7 @@ class BottomRow extends StatelessWidget {
this.deletedBottomRowBuilder, this.deletedBottomRowBuilder,
this.onThreadTap, this.onThreadTap,
this.usernameBuilder, this.usernameBuilder,
this.sendingIndicatorBuilder,
}); });
/// {@macro messageIsDeleted} /// {@macro messageIsDeleted}
@@ -88,6 +89,61 @@ class BottomRow extends StatelessWidget {
/// {@macro usernameBuilder} /// {@macro usernameBuilder}
final Widget Function(BuildContext, Message)? usernameBuilder; final Widget Function(BuildContext, Message)? usernameBuilder;
/// {@macro sendingIndicatorBuilder}
final Widget Function(BuildContext, Message)? sendingIndicatorBuilder;
/// {@template copyWith}
/// Creates a copy of [BottomRow] with specified attributes
/// overridden.
/// {@endtemplate}
BottomRow copyWith({
Key? key,
bool? isDeleted,
Message? message,
bool? showThreadReplyIndicator,
bool? showInChannel,
bool? showTimeStamp,
bool? showUsername,
bool? reverse,
bool? showSendingIndicator,
bool? hasUrlAttachments,
bool? isGiphy,
bool? isOnlyEmoji,
StreamMessageThemeData? messageTheme,
StreamChatThemeData? streamChatTheme,
bool? hasNonUrlAttachments,
StreamChatState? streamChat,
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
void Function(Message)? onThreadTap,
Widget Function(BuildContext, Message)? usernameBuilder,
Widget Function(BuildContext, Message)? sendingIndicatorBuilder,
}) =>
BottomRow(
key: key ?? this.key,
isDeleted: isDeleted ?? this.isDeleted,
message: message ?? this.message,
showThreadReplyIndicator:
showThreadReplyIndicator ?? this.showThreadReplyIndicator,
showInChannel: showInChannel ?? this.showInChannel,
showTimeStamp: showTimeStamp ?? this.showTimeStamp,
showUsername: showUsername ?? this.showUsername,
reverse: reverse ?? this.reverse,
showSendingIndicator: showSendingIndicator ?? this.showSendingIndicator,
hasUrlAttachments: hasUrlAttachments ?? this.hasUrlAttachments,
isGiphy: isGiphy ?? this.isGiphy,
isOnlyEmoji: isOnlyEmoji ?? this.isOnlyEmoji,
messageTheme: messageTheme ?? this.messageTheme,
streamChatTheme: streamChatTheme ?? this.streamChatTheme,
hasNonUrlAttachments: hasNonUrlAttachments ?? this.hasNonUrlAttachments,
streamChat: streamChat ?? this.streamChat,
deletedBottomRowBuilder:
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
onThreadTap: onThreadTap ?? this.onThreadTap,
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
sendingIndicatorBuilder:
sendingIndicatorBuilder ?? this.sendingIndicatorBuilder,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (isDeleted) { if (isDeleted) {
@@ -147,13 +203,14 @@ class BottomRow extends StatelessWidget {
), ),
if (showSendingIndicator) if (showSendingIndicator)
WidgetSpan( WidgetSpan(
child: SendingIndicatorWrapper( child: sendingIndicatorBuilder?.call(context, message) ??
messageTheme: messageTheme, SendingIndicatorWrapper(
message: message, messageTheme: messageTheme,
hasNonUrlAttachments: hasNonUrlAttachments, message: message,
streamChat: streamChat, hasNonUrlAttachments: hasNonUrlAttachments,
streamChatTheme: streamChatTheme, streamChat: streamChat,
), streamChatTheme: streamChatTheme,
),
), ),
]); ]);
@@ -8,6 +8,7 @@ import 'package:stream_chat_flutter/src/context_menu_items/context_menu_reaction
import 'package:stream_chat_flutter/src/context_menu_items/stream_chat_context_menu_item.dart'; import 'package:stream_chat_flutter/src/context_menu_items/stream_chat_context_menu_item.dart';
import 'package:stream_chat_flutter/src/dialogs/dialogs.dart'; import 'package:stream_chat_flutter/src/dialogs/dialogs.dart';
import 'package:stream_chat_flutter/src/message_actions_modal/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_actions_modal/message_actions_modal.dart';
import 'package:stream_chat_flutter/src/message_widget/bottom_row.dart';
import 'package:stream_chat_flutter/src/message_widget/message_widget_content.dart'; import 'package:stream_chat_flutter/src/message_widget/message_widget_content.dart';
import 'package:stream_chat_flutter/src/message_widget/reactions/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/message_widget/reactions/message_reactions_modal.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
@@ -79,8 +80,15 @@ class StreamMessageWidget extends StatefulWidget {
this.userAvatarBuilder, this.userAvatarBuilder,
this.editMessageInputBuilder, this.editMessageInputBuilder,
this.textBuilder, this.textBuilder,
this.bottomRowBuilder, @Deprecated('''
this.deletedBottomRowBuilder, Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') this.bottomRowBuilder,
this.bottomRowBuilderWithDefaultWidget,
@Deprecated('''
Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') this.deletedBottomRowBuilder,
this.customAttachmentBuilders, this.customAttachmentBuilders,
this.padding, this.padding,
this.textPadding = const EdgeInsets.symmetric( this.textPadding = const EdgeInsets.symmetric(
@@ -92,11 +100,18 @@ class StreamMessageWidget extends StatefulWidget {
this.onQuotedMessageTap, this.onQuotedMessageTap,
this.customActions = const [], this.customActions = const [],
this.onAttachmentTap, this.onAttachmentTap,
this.usernameBuilder, @Deprecated('''
Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') this.usernameBuilder,
this.imageAttachmentThumbnailSize = const Size(400, 400), this.imageAttachmentThumbnailSize = const Size(400, 400),
this.imageAttachmentThumbnailResizeType = 'clip', this.imageAttachmentThumbnailResizeType = 'clip',
this.imageAttachmentThumbnailCropType = 'center', this.imageAttachmentThumbnailCropType = 'center',
}) : attachmentBuilders = { }) : assert(
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
'You can only use one of the two bottom row builders',
),
attachmentBuilders = {
'image': (context, message, attachments) { 'image': (context, message, attachments) {
final border = RoundedRectangleBorder( final border = RoundedRectangleBorder(
side: attachmentBorderSide ?? side: attachmentBorderSide ??
@@ -306,7 +321,13 @@ class StreamMessageWidget extends StatefulWidget {
/// {@template bottomRowBuilder} /// {@template bottomRowBuilder}
/// Widget builder for building a bottom row below the message /// Widget builder for building a bottom row below the message
/// {@endtemplate} /// {@endtemplate}
final Widget Function(BuildContext, Message)? bottomRowBuilder; final BottomRowBuilder? bottomRowBuilder;
/// {@template bottomRowBuilderWithDefaultWidget}
/// Widget builder for building a bottom row below the message.
/// Also contains the default bottom row widget.
/// {@endtemplate}
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
/// {@template deletedBottomRowBuilder} /// {@template deletedBottomRowBuilder}
/// Widget builder for building a bottom row below a deleted message /// Widget builder for building a bottom row below a deleted message
@@ -537,9 +558,19 @@ class StreamMessageWidget extends StatefulWidget {
void Function(Message)? onReplyTap, void Function(Message)? onReplyTap,
Widget Function(BuildContext, Message)? editMessageInputBuilder, Widget Function(BuildContext, Message)? editMessageInputBuilder,
Widget Function(BuildContext, Message)? textBuilder, Widget Function(BuildContext, Message)? textBuilder,
Widget Function(BuildContext, Message)? usernameBuilder, @Deprecated('''
Widget Function(BuildContext, Message)? bottomRowBuilder, Use [bottomRowBuilderWithDefaultWidget] instead.
Widget Function(BuildContext, Message)? deletedBottomRowBuilder, Will be removed in the next major version.
''') Widget Function(BuildContext, Message)? usernameBuilder,
@Deprecated('''
Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') BottomRowBuilder? bottomRowBuilder,
BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget,
@Deprecated('''
Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
void Function(BuildContext, Message)? onMessageActions, void Function(BuildContext, Message)? onMessageActions,
Message? message, Message? message,
StreamMessageThemeData? messageTheme, StreamMessageThemeData? messageTheme,
@@ -587,6 +618,29 @@ class StreamMessageWidget extends StatefulWidget {
String? imageAttachmentThumbnailResizeType, String? imageAttachmentThumbnailResizeType,
String? imageAttachmentThumbnailCropType, String? imageAttachmentThumbnailCropType,
}) { }) {
assert(
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
'You can only use one of the two bottom row builders',
);
var _bottomRowBuilderWithDefaultWidget =
bottomRowBuilderWithDefaultWidget ??
this.bottomRowBuilderWithDefaultWidget;
_bottomRowBuilderWithDefaultWidget ??= (context, message, defaultWidget) {
final _bottomRowBuilder = bottomRowBuilder ?? this.bottomRowBuilder;
if (_bottomRowBuilder != null) {
return _bottomRowBuilder(context, message);
}
return defaultWidget.copyWith(
onThreadTap: onThreadTap ?? this.onThreadTap,
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
deletedBottomRowBuilder:
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
);
};
return StreamMessageWidget( return StreamMessageWidget(
key: key ?? this.key, key: key ?? this.key,
onMentionTap: onMentionTap ?? this.onMentionTap, onMentionTap: onMentionTap ?? this.onMentionTap,
@@ -595,10 +649,7 @@ class StreamMessageWidget extends StatefulWidget {
editMessageInputBuilder: editMessageInputBuilder:
editMessageInputBuilder ?? this.editMessageInputBuilder, editMessageInputBuilder ?? this.editMessageInputBuilder,
textBuilder: textBuilder ?? this.textBuilder, textBuilder: textBuilder ?? this.textBuilder,
usernameBuilder: usernameBuilder ?? this.usernameBuilder, bottomRowBuilderWithDefaultWidget: _bottomRowBuilderWithDefaultWidget,
bottomRowBuilder: bottomRowBuilder ?? this.bottomRowBuilder,
deletedBottomRowBuilder:
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
onMessageActions: onMessageActions ?? this.onMessageActions, onMessageActions: onMessageActions ?? this.onMessageActions,
message: message ?? this.message, message: message ?? this.message,
messageTheme: messageTheme ?? this.messageTheme, messageTheme: messageTheme ?? this.messageTheme,
@@ -838,52 +889,69 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
? Alignment.centerRight ? Alignment.centerRight
: Alignment.centerLeft, : Alignment.centerLeft,
widthFactor: widget.widthFactor, widthFactor: widget.widthFactor,
child: MessageWidgetContent( child: Builder(builder: (context) {
streamChatTheme: _streamChatTheme, var _bottomRowBuilderWithDefaultWidget =
showUsername: showUsername, widget.bottomRowBuilderWithDefaultWidget;
showTimeStamp: showTimeStamp,
showThreadReplyIndicator: showThreadReplyIndicator, _bottomRowBuilderWithDefaultWidget ??=
showSendingIndicator: showSendingIndicator, (context, message, defaultWidget) {
showInChannel: showInChannel, final _bottomRowBuilder = widget.bottomRowBuilder;
isGiphy: isGiphy, if (_bottomRowBuilder != null) {
isOnlyEmoji: isOnlyEmoji, return _bottomRowBuilder(context, message);
hasUrlAttachments: hasUrlAttachments, }
messageTheme: widget.messageTheme,
reverse: widget.reverse, return defaultWidget.copyWith(
message: widget.message, onThreadTap: widget.onThreadTap,
hasNonUrlAttachments: hasNonUrlAttachments, usernameBuilder: widget.usernameBuilder,
shouldShowReactions: shouldShowReactions, deletedBottomRowBuilder: widget.deletedBottomRowBuilder,
hasQuotedMessage: hasQuotedMessage, );
textPadding: widget.textPadding, };
attachmentBuilders: widget.attachmentBuilders,
attachmentPadding: widget.attachmentPadding, return MessageWidgetContent(
avatarWidth: avatarWidth, streamChatTheme: _streamChatTheme,
bottomRowPadding: bottomRowPadding, showUsername: showUsername,
isFailedState: isFailedState, showTimeStamp: showTimeStamp,
isPinned: isPinned, showThreadReplyIndicator: showThreadReplyIndicator,
messageWidget: widget, showSendingIndicator: showSendingIndicator,
showBottomRow: showBottomRow, showInChannel: showInChannel,
showPinHighlight: widget.showPinHighlight, isGiphy: isGiphy,
showReactionPickerIndicator: isOnlyEmoji: isOnlyEmoji,
widget.showReactionPickerIndicator, hasUrlAttachments: hasUrlAttachments,
showReactions: showReactions, messageTheme: widget.messageTheme,
showUserAvatar: widget.showUserAvatar, reverse: widget.reverse,
streamChat: _streamChat, message: widget.message,
translateUserAvatar: widget.translateUserAvatar, hasNonUrlAttachments: hasNonUrlAttachments,
deletedBottomRowBuilder: widget.deletedBottomRowBuilder, shouldShowReactions: shouldShowReactions,
onThreadTap: widget.onThreadTap, hasQuotedMessage: hasQuotedMessage,
shape: widget.shape, textPadding: widget.textPadding,
borderSide: widget.borderSide, attachmentBuilders: widget.attachmentBuilders,
borderRadiusGeometry: widget.borderRadiusGeometry, attachmentPadding: widget.attachmentPadding,
textBuilder: widget.textBuilder, avatarWidth: avatarWidth,
onLinkTap: widget.onLinkTap, bottomRowPadding: bottomRowPadding,
onMentionTap: widget.onMentionTap, isFailedState: isFailedState,
onQuotedMessageTap: widget.onQuotedMessageTap, isPinned: isPinned,
bottomRowBuilder: widget.bottomRowBuilder, messageWidget: widget,
onUserAvatarTap: widget.onUserAvatarTap, showBottomRow: showBottomRow,
userAvatarBuilder: widget.userAvatarBuilder, showPinHighlight: widget.showPinHighlight,
usernameBuilder: widget.usernameBuilder, showReactionPickerIndicator:
), widget.showReactionPickerIndicator,
showReactions: showReactions,
showUserAvatar: widget.showUserAvatar,
streamChat: _streamChat,
translateUserAvatar: widget.translateUserAvatar,
shape: widget.shape,
borderSide: widget.borderSide,
borderRadiusGeometry: widget.borderRadiusGeometry,
textBuilder: widget.textBuilder,
onLinkTap: widget.onLinkTap,
onMentionTap: widget.onMentionTap,
onQuotedMessageTap: widget.onQuotedMessageTap,
bottomRowBuilderWithDefaultWidget:
_bottomRowBuilderWithDefaultWidget,
onUserAvatarTap: widget.onUserAvatarTap,
userAvatarBuilder: widget.userAvatarBuilder,
);
}),
), ),
), ),
), ),
@@ -4,6 +4,18 @@ import 'package:stream_chat_flutter/src/message_widget/message_widget_content_co
import 'package:stream_chat_flutter/src/message_widget/reactions/desktop_reactions_builder.dart'; import 'package:stream_chat_flutter/src/message_widget/reactions/desktop_reactions_builder.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Signature for the builder function that will be called when the message
/// bottom row is built. Includes the [Message].
typedef BottomRowBuilder = Widget Function(BuildContext, Message);
/// Signature for the builder function that will be called when the message
/// bottom row is built. Includes the [Message] and the default [BottomRow].
typedef BottomRowBuilderWithDefaultWidget = Widget Function(
BuildContext,
Message,
BottomRow,
);
/// {@template messageWidgetContent} /// {@template messageWidgetContent}
/// The main content of a [StreamMessageWidget]. /// The main content of a [StreamMessageWidget].
/// ///
@@ -51,12 +63,28 @@ class MessageWidgetContent extends StatelessWidget {
this.onMentionTap, this.onMentionTap,
this.onLinkTap, this.onLinkTap,
this.textBuilder, this.textBuilder,
this.bottomRowBuilder, @Deprecated('''
this.onThreadTap, Use [bottomRowBuilderWithDefaultWidget] instead.
this.deletedBottomRowBuilder, Will be removed in the next major version.
''') this.bottomRowBuilder,
this.bottomRowBuilderWithDefaultWidget,
@Deprecated('''
Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') this.onThreadTap,
@Deprecated('''
Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') this.deletedBottomRowBuilder,
this.userAvatarBuilder, this.userAvatarBuilder,
this.usernameBuilder, @Deprecated('''
}); Use [bottomRowBuilderWithDefaultWidget] instead.
Will be removed in the next major version.
''') this.usernameBuilder,
}) : assert(
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
'You can only use one of the two bottom row builders',
);
/// {@macro reverse} /// {@macro reverse}
final bool reverse; final bool reverse;
@@ -152,7 +180,10 @@ class MessageWidgetContent extends StatelessWidget {
final double bottomRowPadding; final double bottomRowPadding;
/// {@macro bottomRowBuilder} /// {@macro bottomRowBuilder}
final Widget Function(BuildContext, Message)? bottomRowBuilder; final BottomRowBuilder? bottomRowBuilder;
/// {@macro bottomRowBuilderWithDefaultWidget}
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
/// {@macro showInChannelIndicator} /// {@macro showInChannelIndicator}
final bool showInChannel; final bool showInChannel;
@@ -207,30 +238,7 @@ class MessageWidgetContent extends StatelessWidget {
right: reverse ? bottomRowPadding : 0, right: reverse ? bottomRowPadding : 0,
bottom: isPinned && showPinHighlight ? 6.0 : 0.0, bottom: isPinned && showPinHighlight ? 6.0 : 0.0,
), ),
child: bottomRowBuilder?.call( child: _buildBottomRow(context),
context,
message,
) ??
BottomRow(
message: message,
reverse: reverse,
messageTheme: messageTheme,
hasUrlAttachments: hasUrlAttachments,
isOnlyEmoji: isOnlyEmoji,
isDeleted: message.isDeleted,
isGiphy: isGiphy,
showInChannel: showInChannel,
showSendingIndicator: showSendingIndicator,
showThreadReplyIndicator: showThreadReplyIndicator,
showTimeStamp: showTimeStamp,
showUsername: showUsername,
streamChatTheme: streamChatTheme,
onThreadTap: onThreadTap,
deletedBottomRowBuilder: deletedBottomRowBuilder,
streamChat: streamChat,
hasNonUrlAttachments: hasNonUrlAttachments,
usernameBuilder: usernameBuilder,
),
), ),
Padding( Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
@@ -457,4 +465,39 @@ class MessageWidgetContent extends StatelessWidget {
), ),
); );
} }
Widget _buildBottomRow(BuildContext context) {
final defaultWidget = BottomRow(
message: message,
reverse: reverse,
messageTheme: messageTheme,
hasUrlAttachments: hasUrlAttachments,
isOnlyEmoji: isOnlyEmoji,
isDeleted: message.isDeleted,
isGiphy: isGiphy,
showInChannel: showInChannel,
showSendingIndicator: showSendingIndicator,
showThreadReplyIndicator: showThreadReplyIndicator,
showTimeStamp: showTimeStamp,
showUsername: showUsername,
streamChatTheme: streamChatTheme,
onThreadTap: onThreadTap,
deletedBottomRowBuilder: deletedBottomRowBuilder,
streamChat: streamChat,
hasNonUrlAttachments: hasNonUrlAttachments,
usernameBuilder: usernameBuilder,
);
if (bottomRowBuilder != null) {
return bottomRowBuilder!(context, message);
} else if (bottomRowBuilderWithDefaultWidget != null) {
return bottomRowBuilderWithDefaultWidget!(
context,
message,
defaultWidget,
);
}
return defaultWidget;
}
} }