Skip to content

Commit ae6d342

Browse files
authoredDec 23, 2022
Merge pull request #1416 from GetStream/geweald-sendingIndicator-bottomRow
2 parents 7adbc18 + 5638e0c commit ae6d342

File tree

4 files changed

+269
-95
lines changed

4 files changed

+269
-95
lines changed
 

‎packages/stream_chat_flutter/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
## Upcomming
22

3+
✅ Added
4+
- Added a new `bottomRowBuilderWithDefaultWidget` parameter to `StreamMessageWidget` which contains a third parameter (default `BottomRow` widget with `copyWith` method available) to allow easier customization.
5+
36
🔄 Changed
47

58
- Updated `lottie` dependency to `^2.0.0`
69
- Updated `desktop_drop` dependency to `^0.4.0`
710
- Updated `connectivity_plus` dependency to `^3.0.2`
811
- Updated `dart_vlc` dependency to `^0.4.0`
912
- Updated `file_picker` dependency to `^5.2.4`
13+
- Deprecated `StreamMessageWidget.bottomRowBuilder` in favor of `StreamMessageWidget.bottomRowBuilderWithDefaultWidget`.
14+
- Deprecated `StreamMessageWidget.deletedBottomRowBuilder` in favor of `StreamMessageWidget.bottomRowBuilderWithDefaultWidget`.
15+
- Deprecated `StreamMessageWidget.usernameBuilder` in favor of `StreamMessageWidget.bottomRowBuilderWithDefaultWidget`.
1016

1117
🐞 Fixed
1218
- [[#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.

‎packages/stream_chat_flutter/lib/src/message_widget/bottom_row.dart

+64-7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class BottomRow extends StatelessWidget {
3232
this.deletedBottomRowBuilder,
3333
this.onThreadTap,
3434
this.usernameBuilder,
35+
this.sendingIndicatorBuilder,
3536
});
3637

3738
/// {@macro messageIsDeleted}
@@ -88,6 +89,61 @@ class BottomRow extends StatelessWidget {
8889
/// {@macro usernameBuilder}
8990
final Widget Function(BuildContext, Message)? usernameBuilder;
9091

92+
/// {@macro sendingIndicatorBuilder}
93+
final Widget Function(BuildContext, Message)? sendingIndicatorBuilder;
94+
95+
/// {@template copyWith}
96+
/// Creates a copy of [BottomRow] with specified attributes
97+
/// overridden.
98+
/// {@endtemplate}
99+
BottomRow copyWith({
100+
Key? key,
101+
bool? isDeleted,
102+
Message? message,
103+
bool? showThreadReplyIndicator,
104+
bool? showInChannel,
105+
bool? showTimeStamp,
106+
bool? showUsername,
107+
bool? reverse,
108+
bool? showSendingIndicator,
109+
bool? hasUrlAttachments,
110+
bool? isGiphy,
111+
bool? isOnlyEmoji,
112+
StreamMessageThemeData? messageTheme,
113+
StreamChatThemeData? streamChatTheme,
114+
bool? hasNonUrlAttachments,
115+
StreamChatState? streamChat,
116+
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
117+
void Function(Message)? onThreadTap,
118+
Widget Function(BuildContext, Message)? usernameBuilder,
119+
Widget Function(BuildContext, Message)? sendingIndicatorBuilder,
120+
}) =>
121+
BottomRow(
122+
key: key ?? this.key,
123+
isDeleted: isDeleted ?? this.isDeleted,
124+
message: message ?? this.message,
125+
showThreadReplyIndicator:
126+
showThreadReplyIndicator ?? this.showThreadReplyIndicator,
127+
showInChannel: showInChannel ?? this.showInChannel,
128+
showTimeStamp: showTimeStamp ?? this.showTimeStamp,
129+
showUsername: showUsername ?? this.showUsername,
130+
reverse: reverse ?? this.reverse,
131+
showSendingIndicator: showSendingIndicator ?? this.showSendingIndicator,
132+
hasUrlAttachments: hasUrlAttachments ?? this.hasUrlAttachments,
133+
isGiphy: isGiphy ?? this.isGiphy,
134+
isOnlyEmoji: isOnlyEmoji ?? this.isOnlyEmoji,
135+
messageTheme: messageTheme ?? this.messageTheme,
136+
streamChatTheme: streamChatTheme ?? this.streamChatTheme,
137+
hasNonUrlAttachments: hasNonUrlAttachments ?? this.hasNonUrlAttachments,
138+
streamChat: streamChat ?? this.streamChat,
139+
deletedBottomRowBuilder:
140+
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
141+
onThreadTap: onThreadTap ?? this.onThreadTap,
142+
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
143+
sendingIndicatorBuilder:
144+
sendingIndicatorBuilder ?? this.sendingIndicatorBuilder,
145+
);
146+
91147
@override
92148
Widget build(BuildContext context) {
93149
if (isDeleted) {
@@ -147,13 +203,14 @@ class BottomRow extends StatelessWidget {
147203
),
148204
if (showSendingIndicator)
149205
WidgetSpan(
150-
child: SendingIndicatorWrapper(
151-
messageTheme: messageTheme,
152-
message: message,
153-
hasNonUrlAttachments: hasNonUrlAttachments,
154-
streamChat: streamChat,
155-
streamChatTheme: streamChatTheme,
156-
),
206+
child: sendingIndicatorBuilder?.call(context, message) ??
207+
SendingIndicatorWrapper(
208+
messageTheme: messageTheme,
209+
message: message,
210+
hasNonUrlAttachments: hasNonUrlAttachments,
211+
streamChat: streamChat,
212+
streamChatTheme: streamChatTheme,
213+
),
157214
),
158215
]);
159216

‎packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart

+126-58
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:stream_chat_flutter/src/context_menu_items/context_menu_reaction
88
import 'package:stream_chat_flutter/src/context_menu_items/stream_chat_context_menu_item.dart';
99
import 'package:stream_chat_flutter/src/dialogs/dialogs.dart';
1010
import 'package:stream_chat_flutter/src/message_actions_modal/message_actions_modal.dart';
11+
import 'package:stream_chat_flutter/src/message_widget/bottom_row.dart';
1112
import 'package:stream_chat_flutter/src/message_widget/message_widget_content.dart';
1213
import 'package:stream_chat_flutter/src/message_widget/reactions/message_reactions_modal.dart';
1314
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
@@ -79,8 +80,15 @@ class StreamMessageWidget extends StatefulWidget {
7980
this.userAvatarBuilder,
8081
this.editMessageInputBuilder,
8182
this.textBuilder,
82-
this.bottomRowBuilder,
83-
this.deletedBottomRowBuilder,
83+
@Deprecated('''
84+
Use [bottomRowBuilderWithDefaultWidget] instead.
85+
Will be removed in the next major version.
86+
''') this.bottomRowBuilder,
87+
this.bottomRowBuilderWithDefaultWidget,
88+
@Deprecated('''
89+
Use [bottomRowBuilderWithDefaultWidget] instead.
90+
Will be removed in the next major version.
91+
''') this.deletedBottomRowBuilder,
8492
this.customAttachmentBuilders,
8593
this.padding,
8694
this.textPadding = const EdgeInsets.symmetric(
@@ -92,11 +100,18 @@ class StreamMessageWidget extends StatefulWidget {
92100
this.onQuotedMessageTap,
93101
this.customActions = const [],
94102
this.onAttachmentTap,
95-
this.usernameBuilder,
103+
@Deprecated('''
104+
Use [bottomRowBuilderWithDefaultWidget] instead.
105+
Will be removed in the next major version.
106+
''') this.usernameBuilder,
96107
this.imageAttachmentThumbnailSize = const Size(400, 400),
97108
this.imageAttachmentThumbnailResizeType = 'clip',
98109
this.imageAttachmentThumbnailCropType = 'center',
99-
}) : attachmentBuilders = {
110+
}) : assert(
111+
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
112+
'You can only use one of the two bottom row builders',
113+
),
114+
attachmentBuilders = {
100115
'image': (context, message, attachments) {
101116
final border = RoundedRectangleBorder(
102117
side: attachmentBorderSide ??
@@ -306,7 +321,13 @@ class StreamMessageWidget extends StatefulWidget {
306321
/// {@template bottomRowBuilder}
307322
/// Widget builder for building a bottom row below the message
308323
/// {@endtemplate}
309-
final Widget Function(BuildContext, Message)? bottomRowBuilder;
324+
final BottomRowBuilder? bottomRowBuilder;
325+
326+
/// {@template bottomRowBuilderWithDefaultWidget}
327+
/// Widget builder for building a bottom row below the message.
328+
/// Also contains the default bottom row widget.
329+
/// {@endtemplate}
330+
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
310331

311332
/// {@template deletedBottomRowBuilder}
312333
/// Widget builder for building a bottom row below a deleted message
@@ -537,9 +558,19 @@ class StreamMessageWidget extends StatefulWidget {
537558
void Function(Message)? onReplyTap,
538559
Widget Function(BuildContext, Message)? editMessageInputBuilder,
539560
Widget Function(BuildContext, Message)? textBuilder,
540-
Widget Function(BuildContext, Message)? usernameBuilder,
541-
Widget Function(BuildContext, Message)? bottomRowBuilder,
542-
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
561+
@Deprecated('''
562+
Use [bottomRowBuilderWithDefaultWidget] instead.
563+
Will be removed in the next major version.
564+
''') Widget Function(BuildContext, Message)? usernameBuilder,
565+
@Deprecated('''
566+
Use [bottomRowBuilderWithDefaultWidget] instead.
567+
Will be removed in the next major version.
568+
''') BottomRowBuilder? bottomRowBuilder,
569+
BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget,
570+
@Deprecated('''
571+
Use [bottomRowBuilderWithDefaultWidget] instead.
572+
Will be removed in the next major version.
573+
''') Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
543574
void Function(BuildContext, Message)? onMessageActions,
544575
Message? message,
545576
StreamMessageThemeData? messageTheme,
@@ -587,6 +618,29 @@ class StreamMessageWidget extends StatefulWidget {
587618
String? imageAttachmentThumbnailResizeType,
588619
String? imageAttachmentThumbnailCropType,
589620
}) {
621+
assert(
622+
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
623+
'You can only use one of the two bottom row builders',
624+
);
625+
626+
var _bottomRowBuilderWithDefaultWidget =
627+
bottomRowBuilderWithDefaultWidget ??
628+
this.bottomRowBuilderWithDefaultWidget;
629+
630+
_bottomRowBuilderWithDefaultWidget ??= (context, message, defaultWidget) {
631+
final _bottomRowBuilder = bottomRowBuilder ?? this.bottomRowBuilder;
632+
if (_bottomRowBuilder != null) {
633+
return _bottomRowBuilder(context, message);
634+
}
635+
636+
return defaultWidget.copyWith(
637+
onThreadTap: onThreadTap ?? this.onThreadTap,
638+
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
639+
deletedBottomRowBuilder:
640+
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
641+
);
642+
};
643+
590644
return StreamMessageWidget(
591645
key: key ?? this.key,
592646
onMentionTap: onMentionTap ?? this.onMentionTap,
@@ -595,10 +649,7 @@ class StreamMessageWidget extends StatefulWidget {
595649
editMessageInputBuilder:
596650
editMessageInputBuilder ?? this.editMessageInputBuilder,
597651
textBuilder: textBuilder ?? this.textBuilder,
598-
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
599-
bottomRowBuilder: bottomRowBuilder ?? this.bottomRowBuilder,
600-
deletedBottomRowBuilder:
601-
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
652+
bottomRowBuilderWithDefaultWidget: _bottomRowBuilderWithDefaultWidget,
602653
onMessageActions: onMessageActions ?? this.onMessageActions,
603654
message: message ?? this.message,
604655
messageTheme: messageTheme ?? this.messageTheme,
@@ -838,52 +889,69 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
838889
? Alignment.centerRight
839890
: Alignment.centerLeft,
840891
widthFactor: widget.widthFactor,
841-
child: MessageWidgetContent(
842-
streamChatTheme: _streamChatTheme,
843-
showUsername: showUsername,
844-
showTimeStamp: showTimeStamp,
845-
showThreadReplyIndicator: showThreadReplyIndicator,
846-
showSendingIndicator: showSendingIndicator,
847-
showInChannel: showInChannel,
848-
isGiphy: isGiphy,
849-
isOnlyEmoji: isOnlyEmoji,
850-
hasUrlAttachments: hasUrlAttachments,
851-
messageTheme: widget.messageTheme,
852-
reverse: widget.reverse,
853-
message: widget.message,
854-
hasNonUrlAttachments: hasNonUrlAttachments,
855-
shouldShowReactions: shouldShowReactions,
856-
hasQuotedMessage: hasQuotedMessage,
857-
textPadding: widget.textPadding,
858-
attachmentBuilders: widget.attachmentBuilders,
859-
attachmentPadding: widget.attachmentPadding,
860-
avatarWidth: avatarWidth,
861-
bottomRowPadding: bottomRowPadding,
862-
isFailedState: isFailedState,
863-
isPinned: isPinned,
864-
messageWidget: widget,
865-
showBottomRow: showBottomRow,
866-
showPinHighlight: widget.showPinHighlight,
867-
showReactionPickerIndicator:
868-
widget.showReactionPickerIndicator,
869-
showReactions: showReactions,
870-
showUserAvatar: widget.showUserAvatar,
871-
streamChat: _streamChat,
872-
translateUserAvatar: widget.translateUserAvatar,
873-
deletedBottomRowBuilder: widget.deletedBottomRowBuilder,
874-
onThreadTap: widget.onThreadTap,
875-
shape: widget.shape,
876-
borderSide: widget.borderSide,
877-
borderRadiusGeometry: widget.borderRadiusGeometry,
878-
textBuilder: widget.textBuilder,
879-
onLinkTap: widget.onLinkTap,
880-
onMentionTap: widget.onMentionTap,
881-
onQuotedMessageTap: widget.onQuotedMessageTap,
882-
bottomRowBuilder: widget.bottomRowBuilder,
883-
onUserAvatarTap: widget.onUserAvatarTap,
884-
userAvatarBuilder: widget.userAvatarBuilder,
885-
usernameBuilder: widget.usernameBuilder,
886-
),
892+
child: Builder(builder: (context) {
893+
var _bottomRowBuilderWithDefaultWidget =
894+
widget.bottomRowBuilderWithDefaultWidget;
895+
896+
_bottomRowBuilderWithDefaultWidget ??=
897+
(context, message, defaultWidget) {
898+
final _bottomRowBuilder = widget.bottomRowBuilder;
899+
if (_bottomRowBuilder != null) {
900+
return _bottomRowBuilder(context, message);
901+
}
902+
903+
return defaultWidget.copyWith(
904+
onThreadTap: widget.onThreadTap,
905+
usernameBuilder: widget.usernameBuilder,
906+
deletedBottomRowBuilder: widget.deletedBottomRowBuilder,
907+
);
908+
};
909+
910+
return MessageWidgetContent(
911+
streamChatTheme: _streamChatTheme,
912+
showUsername: showUsername,
913+
showTimeStamp: showTimeStamp,
914+
showThreadReplyIndicator: showThreadReplyIndicator,
915+
showSendingIndicator: showSendingIndicator,
916+
showInChannel: showInChannel,
917+
isGiphy: isGiphy,
918+
isOnlyEmoji: isOnlyEmoji,
919+
hasUrlAttachments: hasUrlAttachments,
920+
messageTheme: widget.messageTheme,
921+
reverse: widget.reverse,
922+
message: widget.message,
923+
hasNonUrlAttachments: hasNonUrlAttachments,
924+
shouldShowReactions: shouldShowReactions,
925+
hasQuotedMessage: hasQuotedMessage,
926+
textPadding: widget.textPadding,
927+
attachmentBuilders: widget.attachmentBuilders,
928+
attachmentPadding: widget.attachmentPadding,
929+
avatarWidth: avatarWidth,
930+
bottomRowPadding: bottomRowPadding,
931+
isFailedState: isFailedState,
932+
isPinned: isPinned,
933+
messageWidget: widget,
934+
showBottomRow: showBottomRow,
935+
showPinHighlight: widget.showPinHighlight,
936+
showReactionPickerIndicator:
937+
widget.showReactionPickerIndicator,
938+
showReactions: showReactions,
939+
showUserAvatar: widget.showUserAvatar,
940+
streamChat: _streamChat,
941+
translateUserAvatar: widget.translateUserAvatar,
942+
shape: widget.shape,
943+
borderSide: widget.borderSide,
944+
borderRadiusGeometry: widget.borderRadiusGeometry,
945+
textBuilder: widget.textBuilder,
946+
onLinkTap: widget.onLinkTap,
947+
onMentionTap: widget.onMentionTap,
948+
onQuotedMessageTap: widget.onQuotedMessageTap,
949+
bottomRowBuilderWithDefaultWidget:
950+
_bottomRowBuilderWithDefaultWidget,
951+
onUserAvatarTap: widget.onUserAvatarTap,
952+
userAvatarBuilder: widget.userAvatarBuilder,
953+
);
954+
}),
887955
),
888956
),
889957
),

‎packages/stream_chat_flutter/lib/src/message_widget/message_widget_content.dart

+73-30
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ import 'package:stream_chat_flutter/src/message_widget/message_widget_content_co
44
import 'package:stream_chat_flutter/src/message_widget/reactions/desktop_reactions_builder.dart';
55
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
66

7+
/// Signature for the builder function that will be called when the message
8+
/// bottom row is built. Includes the [Message].
9+
typedef BottomRowBuilder = Widget Function(BuildContext, Message);
10+
11+
/// Signature for the builder function that will be called when the message
12+
/// bottom row is built. Includes the [Message] and the default [BottomRow].
13+
typedef BottomRowBuilderWithDefaultWidget = Widget Function(
14+
BuildContext,
15+
Message,
16+
BottomRow,
17+
);
18+
719
/// {@template messageWidgetContent}
820
/// The main content of a [StreamMessageWidget].
921
///
@@ -51,12 +63,28 @@ class MessageWidgetContent extends StatelessWidget {
5163
this.onMentionTap,
5264
this.onLinkTap,
5365
this.textBuilder,
54-
this.bottomRowBuilder,
55-
this.onThreadTap,
56-
this.deletedBottomRowBuilder,
66+
@Deprecated('''
67+
Use [bottomRowBuilderWithDefaultWidget] instead.
68+
Will be removed in the next major version.
69+
''') this.bottomRowBuilder,
70+
this.bottomRowBuilderWithDefaultWidget,
71+
@Deprecated('''
72+
Use [bottomRowBuilderWithDefaultWidget] instead.
73+
Will be removed in the next major version.
74+
''') this.onThreadTap,
75+
@Deprecated('''
76+
Use [bottomRowBuilderWithDefaultWidget] instead.
77+
Will be removed in the next major version.
78+
''') this.deletedBottomRowBuilder,
5779
this.userAvatarBuilder,
58-
this.usernameBuilder,
59-
});
80+
@Deprecated('''
81+
Use [bottomRowBuilderWithDefaultWidget] instead.
82+
Will be removed in the next major version.
83+
''') this.usernameBuilder,
84+
}) : assert(
85+
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
86+
'You can only use one of the two bottom row builders',
87+
);
6088

6189
/// {@macro reverse}
6290
final bool reverse;
@@ -152,7 +180,10 @@ class MessageWidgetContent extends StatelessWidget {
152180
final double bottomRowPadding;
153181

154182
/// {@macro bottomRowBuilder}
155-
final Widget Function(BuildContext, Message)? bottomRowBuilder;
183+
final BottomRowBuilder? bottomRowBuilder;
184+
185+
/// {@macro bottomRowBuilderWithDefaultWidget}
186+
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
156187

157188
/// {@macro showInChannelIndicator}
158189
final bool showInChannel;
@@ -207,30 +238,7 @@ class MessageWidgetContent extends StatelessWidget {
207238
right: reverse ? bottomRowPadding : 0,
208239
bottom: isPinned && showPinHighlight ? 6.0 : 0.0,
209240
),
210-
child: bottomRowBuilder?.call(
211-
context,
212-
message,
213-
) ??
214-
BottomRow(
215-
message: message,
216-
reverse: reverse,
217-
messageTheme: messageTheme,
218-
hasUrlAttachments: hasUrlAttachments,
219-
isOnlyEmoji: isOnlyEmoji,
220-
isDeleted: message.isDeleted,
221-
isGiphy: isGiphy,
222-
showInChannel: showInChannel,
223-
showSendingIndicator: showSendingIndicator,
224-
showThreadReplyIndicator: showThreadReplyIndicator,
225-
showTimeStamp: showTimeStamp,
226-
showUsername: showUsername,
227-
streamChatTheme: streamChatTheme,
228-
onThreadTap: onThreadTap,
229-
deletedBottomRowBuilder: deletedBottomRowBuilder,
230-
streamChat: streamChat,
231-
hasNonUrlAttachments: hasNonUrlAttachments,
232-
usernameBuilder: usernameBuilder,
233-
),
241+
child: _buildBottomRow(context),
234242
),
235243
Padding(
236244
padding: EdgeInsets.only(
@@ -457,4 +465,39 @@ class MessageWidgetContent extends StatelessWidget {
457465
),
458466
);
459467
}
468+
469+
Widget _buildBottomRow(BuildContext context) {
470+
final defaultWidget = BottomRow(
471+
message: message,
472+
reverse: reverse,
473+
messageTheme: messageTheme,
474+
hasUrlAttachments: hasUrlAttachments,
475+
isOnlyEmoji: isOnlyEmoji,
476+
isDeleted: message.isDeleted,
477+
isGiphy: isGiphy,
478+
showInChannel: showInChannel,
479+
showSendingIndicator: showSendingIndicator,
480+
showThreadReplyIndicator: showThreadReplyIndicator,
481+
showTimeStamp: showTimeStamp,
482+
showUsername: showUsername,
483+
streamChatTheme: streamChatTheme,
484+
onThreadTap: onThreadTap,
485+
deletedBottomRowBuilder: deletedBottomRowBuilder,
486+
streamChat: streamChat,
487+
hasNonUrlAttachments: hasNonUrlAttachments,
488+
usernameBuilder: usernameBuilder,
489+
);
490+
491+
if (bottomRowBuilder != null) {
492+
return bottomRowBuilder!(context, message);
493+
} else if (bottomRowBuilderWithDefaultWidget != null) {
494+
return bottomRowBuilderWithDefaultWidget!(
495+
context,
496+
message,
497+
defaultWidget,
498+
);
499+
}
500+
501+
return defaultWidget;
502+
}
460503
}

0 commit comments

Comments
 (0)
Please sign in to comment.