Merge branch 'develop' of https://github.com/GetStream/stream-chat-flutter into fix/pass_message_action_flags
This commit is contained in:
@@ -1,9 +1,20 @@
|
||||
## Upcoming
|
||||
## 4.1.0
|
||||
|
||||
✅ Added
|
||||
|
||||
- [[#1119]](https://github.com/GetStream/stream-chat-flutter/issues/1119) Added an option to disable mentions overlay in `StreamMessageInput`
|
||||
- Deprecated `disableEmojiSuggestionsOverlay` in favor of `enableEmojiSuggestionsOverlay` in `StreamMessageInput`
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
- Fixed attachment picker ui.
|
||||
- Fixed StreamChannelHeader and StreamThreadHeader subtitle alignment.
|
||||
- Fixed message widget thread indicator in reverse mode.
|
||||
- [[#1044]](https://github.com/GetStream/stream-chat-flutter/issues/1044): Refactor StreamMessageWidget bottom row to use Text.rich.
|
||||
|
||||
🔄 Changed
|
||||
|
||||
- Removed `isOwner` condition from `ChannelBottomSheet` and `StreamChannelInfoBottomSheet` for delete option tile.
|
||||
|
||||
## 4.0.1
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
|
||||
final userAsMember = members
|
||||
.firstWhere((e) => e.user?.id == _streamChatState.currentUser?.id);
|
||||
final isOwner = userAsMember.role == 'owner';
|
||||
|
||||
return Material(
|
||||
color: _streamChatThemeData.colorTheme.barsBg,
|
||||
@@ -179,9 +178,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
});
|
||||
},
|
||||
),
|
||||
if (isOwner &&
|
||||
channel.ownCapabilities
|
||||
.contains(PermissionType.deleteChannel))
|
||||
if (channel.ownCapabilities
|
||||
.contains(PermissionType.deleteChannel))
|
||||
StreamOptionListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
|
||||
@@ -100,12 +100,10 @@ class StreamChannelInfo extends StatelessWidget {
|
||||
return alternativeWidget ?? const Offstage();
|
||||
}
|
||||
|
||||
return Align(
|
||||
child: StreamTypingIndicator(
|
||||
parentId: parentId,
|
||||
style: textStyle,
|
||||
alternativeWidget: alternativeWidget,
|
||||
),
|
||||
return StreamTypingIndicator(
|
||||
parentId: parentId,
|
||||
style: textStyle,
|
||||
alternativeWidget: alternativeWidget,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -878,7 +878,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
||||
const Offstage();
|
||||
}
|
||||
|
||||
final children = <Widget>[];
|
||||
final children = <WidgetSpan>[];
|
||||
|
||||
final threadParticipants = widget.message.threadParticipants?.take(2);
|
||||
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
|
||||
@@ -909,68 +909,72 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
||||
const usernameKey = Key('username');
|
||||
|
||||
children.addAll([
|
||||
if (showUsername) _buildUsername(usernameKey),
|
||||
if (showUsername) WidgetSpan(child: _buildUsername(usernameKey)),
|
||||
if (showTimeStamp)
|
||||
Text(
|
||||
Jiffy(widget.message.createdAt.toLocal()).jm,
|
||||
style: widget.messageTheme.createdAtStyle,
|
||||
WidgetSpan(
|
||||
child: Text(
|
||||
Jiffy(widget.message.createdAt.toLocal()).jm,
|
||||
style: widget.messageTheme.createdAtStyle,
|
||||
),
|
||||
),
|
||||
if (showSendingIndicator)
|
||||
WidgetSpan(
|
||||
child: _buildSendingIndicator(),
|
||||
),
|
||||
if (showSendingIndicator) _buildSendingIndicator(),
|
||||
]);
|
||||
|
||||
final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) &&
|
||||
(showThreadReplyIndicator || showInChannel);
|
||||
|
||||
final threadIndicatorWidgets = <Widget>[
|
||||
final threadIndicatorWidgets = <WidgetSpan>[
|
||||
if (showThreadTail)
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: context.textScaleFactor *
|
||||
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||
),
|
||||
child: CustomPaint(
|
||||
size: const Size(16, 32) * context.textScaleFactor,
|
||||
painter: _ThreadReplyPainter(
|
||||
context: context,
|
||||
color: widget.messageTheme.messageBorderColor,
|
||||
reverse: widget.reverse,
|
||||
WidgetSpan(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: context.textScaleFactor *
|
||||
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||
),
|
||||
child: CustomPaint(
|
||||
size: const Size(16, 32) * context.textScaleFactor,
|
||||
painter: _ThreadReplyPainter(
|
||||
context: context,
|
||||
color: widget.messageTheme.messageBorderColor,
|
||||
reverse: widget.reverse,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showInChannel || showThreadReplyIndicator) ...[
|
||||
if (showThreadParticipants)
|
||||
SizedBox.fromSize(
|
||||
size: Size((threadParticipants!.length * 8.0) + 8, 16),
|
||||
child: _buildThreadParticipantsIndicator(threadParticipants),
|
||||
WidgetSpan(
|
||||
child: SizedBox.fromSize(
|
||||
size: Size((threadParticipants!.length * 8.0) + 8, 16),
|
||||
child: _buildThreadParticipantsIndicator(threadParticipants),
|
||||
),
|
||||
),
|
||||
WidgetSpan(
|
||||
child: InkWell(
|
||||
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
||||
child: Text(msg, style: widget.messageTheme.repliesStyle),
|
||||
),
|
||||
InkWell(
|
||||
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
||||
child: Text(msg, style: widget.messageTheme.repliesStyle),
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment:
|
||||
widget.reverse ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||
children: [
|
||||
if (showThreadTail && !widget.reverse) ...threadIndicatorWidgets,
|
||||
...children.map(
|
||||
(child) {
|
||||
Widget mappedChild = SizedBox(
|
||||
height: context.textScaleFactor * 14,
|
||||
child: child,
|
||||
);
|
||||
if (child.key == usernameKey) {
|
||||
mappedChild = Flexible(child: mappedChild);
|
||||
}
|
||||
return mappedChild;
|
||||
},
|
||||
),
|
||||
if (showThreadTail && widget.reverse)
|
||||
...threadIndicatorWidgets.reversed,
|
||||
].insertBetween(const SizedBox(width: 8)),
|
||||
if (widget.reverse) {
|
||||
children.addAll(threadIndicatorWidgets.reversed);
|
||||
} else {
|
||||
children.insertAll(0, threadIndicatorWidgets);
|
||||
}
|
||||
|
||||
return Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
...children,
|
||||
].insertBetween(const WidgetSpan(child: SizedBox(width: 8))),
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: widget.reverse ? TextAlign.right : TextAlign.left,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1263,6 +1267,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
||||
);
|
||||
if (isMessageRead) {
|
||||
child = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (memberCount > 2)
|
||||
Text(
|
||||
|
||||
@@ -186,13 +186,11 @@ class StreamThreadHeader extends StatelessWidget
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
if (showTypingIndicator)
|
||||
Align(
|
||||
child: StreamTypingIndicator(
|
||||
channel: StreamChannel.of(context).channel,
|
||||
style: channelHeaderTheme.subtitleStyle,
|
||||
parentId: parent.id,
|
||||
alternativeWidget: defaultSubtitle,
|
||||
),
|
||||
StreamTypingIndicator(
|
||||
channel: StreamChannel.of(context).channel,
|
||||
style: channelHeaderTheme.subtitleStyle,
|
||||
parentId: parent.id,
|
||||
alternativeWidget: defaultSubtitle,
|
||||
)
|
||||
else
|
||||
defaultSubtitle,
|
||||
|
||||
@@ -207,8 +207,10 @@ class StreamMessageInput extends StatefulWidget {
|
||||
this.enableSafeArea,
|
||||
this.elevation,
|
||||
this.shadow,
|
||||
this.autoCorrect,
|
||||
this.disableEmojiSuggestionsOverlay,
|
||||
this.autoCorrect = true,
|
||||
this.disableEmojiSuggestionsOverlay = false,
|
||||
this.enableEmojiSuggestionsOverlay = true,
|
||||
this.enableMentionsOverlay = true,
|
||||
}) : super(key: key);
|
||||
|
||||
/// List of options for showing overlays.
|
||||
@@ -327,11 +329,20 @@ class StreamMessageInput extends StatefulWidget {
|
||||
|
||||
/// Disable autoCorrect by passing false
|
||||
/// autoCorrect is enabled by default
|
||||
final bool? autoCorrect;
|
||||
final bool autoCorrect;
|
||||
|
||||
/// Disable the default emoji suggestions
|
||||
/// Enabled by default
|
||||
final bool? disableEmojiSuggestionsOverlay;
|
||||
@Deprecated('Please use enableEmojiSuggestionsOverlay')
|
||||
final bool disableEmojiSuggestionsOverlay;
|
||||
|
||||
/// Disable the default emoji suggestions by passing `false`
|
||||
/// Enabled by default
|
||||
final bool enableEmojiSuggestionsOverlay;
|
||||
|
||||
/// Disable the mentions overlay by passing false
|
||||
/// Enabled by default
|
||||
final bool enableMentionsOverlay;
|
||||
|
||||
static bool _defaultValidator(Message message) =>
|
||||
message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
|
||||
@@ -364,11 +375,6 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
||||
bool get _isEditing =>
|
||||
_effectiveController.value.status != MessageSendingStatus.sending;
|
||||
|
||||
bool get _autoCorrect => widget.autoCorrect ?? true;
|
||||
|
||||
bool get _disableEmojiSuggestionsOverlay =>
|
||||
widget.disableEmojiSuggestionsOverlay ?? false;
|
||||
|
||||
StreamRestorableMessageInputController? _controller;
|
||||
|
||||
StreamMessageInputController get _effectiveController =>
|
||||
@@ -598,7 +604,8 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
||||
visible: _showCommandsOverlay,
|
||||
widget: _buildCommandsOverlayEntry(),
|
||||
),
|
||||
if (!_disableEmojiSuggestionsOverlay)
|
||||
if (widget.enableEmojiSuggestionsOverlay &&
|
||||
!widget.disableEmojiSuggestionsOverlay)
|
||||
OverlayOptions(
|
||||
visible: _focusNode.hasFocus &&
|
||||
_effectiveController.text.isNotEmpty &&
|
||||
@@ -611,10 +618,11 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
||||
.contains(':'),
|
||||
widget: _buildEmojiOverlay(),
|
||||
),
|
||||
OverlayOptions(
|
||||
visible: _showMentionsOverlay,
|
||||
widget: _buildMentionsOverlayEntry(),
|
||||
),
|
||||
if (widget.enableMentionsOverlay)
|
||||
OverlayOptions(
|
||||
visible: _showMentionsOverlay,
|
||||
widget: _buildMentionsOverlayEntry(),
|
||||
),
|
||||
...widget.customOverlays,
|
||||
],
|
||||
child: child,
|
||||
@@ -813,7 +821,7 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
decoration: _getInputDecoration(context),
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
autocorrect: _autoCorrect,
|
||||
autocorrect: widget.autoCorrect,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -59,10 +59,6 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
||||
|
||||
final members = channel.state?.members ?? [];
|
||||
|
||||
final isOwner = members.any(
|
||||
(it) => it.user?.id == currentUser?.id && it.role == 'owner',
|
||||
);
|
||||
|
||||
// remove current user in case it's 1-1 conversation
|
||||
if (isOneToOneChannel) {
|
||||
members.removeWhere((it) => it.user?.id == currentUser?.id);
|
||||
@@ -153,7 +149,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
||||
),
|
||||
onTap: onLeaveChannelTap,
|
||||
),
|
||||
if (isOwner)
|
||||
if (channel.ownCapabilities.contains(PermissionType.deleteChannel))
|
||||
StreamOptionListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: stream_chat_flutter
|
||||
homepage: https://github.com/GetStream/stream-chat-flutter
|
||||
description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter.
|
||||
version: 4.0.1
|
||||
version: 4.1.0
|
||||
repository: https://github.com/GetStream/stream-chat-flutter
|
||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||
|
||||
@@ -36,7 +36,7 @@ dependencies:
|
||||
rxdart: ^0.27.0
|
||||
share_plus: ^4.0.1
|
||||
shimmer: ^2.0.0
|
||||
stream_chat_flutter_core: ^4.0.1
|
||||
stream_chat_flutter_core: ^4.1.0
|
||||
substring_highlight: ^1.0.26
|
||||
url_launcher: ^6.1.0
|
||||
video_player: ^2.1.0
|
||||
|
||||
Reference in New Issue
Block a user