Merge pull request #1526 from GetStream/fix/qouted-message-delete
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
- [[#1355]](https://github.com/GetStream/stream-chat-flutter/issues/1355) Fixed error while hiding channel and clearing
|
- [[#1355]](https://github.com/GetStream/stream-chat-flutter/issues/1355) Fixed error while hiding channel and clearing
|
||||||
message history.
|
message history.
|
||||||
|
- [[#1525]](https://github.com/GetStream/stream-chat-flutter/issues/1525) Fixed removing message not removing quoted
|
||||||
|
message reference.
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|
||||||
|
|||||||
@@ -746,6 +746,7 @@ class Channel {
|
|||||||
state!.deleteMessage(
|
state!.deleteMessage(
|
||||||
message.copyWith(
|
message.copyWith(
|
||||||
type: 'deleted',
|
type: 'deleted',
|
||||||
|
deletedAt: message.deletedAt ?? DateTime.now(),
|
||||||
status: MessageSendingStatus.sent,
|
status: MessageSendingStatus.sent,
|
||||||
),
|
),
|
||||||
hardDelete: hardDelete,
|
hardDelete: hardDelete,
|
||||||
@@ -1928,11 +1929,9 @@ class ChannelClientState {
|
|||||||
void _listenMessageDeleted() {
|
void _listenMessageDeleted() {
|
||||||
_subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) {
|
_subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) {
|
||||||
final message = event.message!;
|
final message = event.message!;
|
||||||
if (event.hardDelete == true) {
|
final hardDelete = event.hardDelete ?? false;
|
||||||
removeMessage(message);
|
|
||||||
} else {
|
deleteMessage(message, hardDelete: hardDelete);
|
||||||
updateMessage(message);
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1957,18 +1956,35 @@ class ChannelClientState {
|
|||||||
|
|
||||||
/// Updates the [message] in the state if it exists. Adds it otherwise.
|
/// Updates the [message] in the state if it exists. Adds it otherwise.
|
||||||
void updateMessage(Message message) {
|
void updateMessage(Message message) {
|
||||||
|
// Regular messages, which are shown in channel.
|
||||||
if (message.parentId == null || message.showInChannel == true) {
|
if (message.parentId == null || message.showInChannel == true) {
|
||||||
final newMessages = [...messages];
|
var newMessages = [...messages];
|
||||||
final oldIndex = newMessages.indexWhere((m) => m.id == message.id);
|
final oldIndex = newMessages.indexWhere((m) => m.id == message.id);
|
||||||
if (oldIndex != -1) {
|
if (oldIndex != -1) {
|
||||||
Message? m;
|
var updatedMessage = message;
|
||||||
|
// Add quoted message to the message if it is not present.
|
||||||
if (message.quotedMessageId != null && message.quotedMessage == null) {
|
if (message.quotedMessageId != null && message.quotedMessage == null) {
|
||||||
final oldMessage = newMessages[oldIndex];
|
final oldMessage = newMessages[oldIndex];
|
||||||
m = message.copyWith(
|
updatedMessage = updatedMessage.copyWith(
|
||||||
quotedMessage: oldMessage.quotedMessage,
|
quotedMessage: oldMessage.quotedMessage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
newMessages[oldIndex] = m ?? message;
|
newMessages[oldIndex] = updatedMessage;
|
||||||
|
|
||||||
|
// Update quoted message reference for every message if available.
|
||||||
|
newMessages = [...newMessages].map((it) {
|
||||||
|
// Early return if the message doesn't have a quoted message.
|
||||||
|
if (it.quotedMessageId != message.id) return it;
|
||||||
|
|
||||||
|
// Setting it to null will remove the quoted message from the message
|
||||||
|
// So, we are setting the same message but with the deleted state.
|
||||||
|
return it.copyWith(
|
||||||
|
quotedMessage: updatedMessage.copyWith(
|
||||||
|
type: 'deleted',
|
||||||
|
deletedAt: updatedMessage.deletedAt ?? DateTime.now(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
} else {
|
} else {
|
||||||
newMessages.add(message);
|
newMessages.add(message);
|
||||||
}
|
}
|
||||||
@@ -1997,6 +2013,7 @@ class ChannelClientState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thread messages, which are shown in thread page.
|
||||||
if (message.parentId != null) {
|
if (message.parentId != null) {
|
||||||
updateThreadInfo(message.parentId!, [message]);
|
updateThreadInfo(message.parentId!, [message]);
|
||||||
}
|
}
|
||||||
@@ -2026,9 +2043,22 @@ class ChannelClientState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove regular message, thread message shown in channel
|
// Remove regular message, thread message shown in channel
|
||||||
final allMessages = [...messages];
|
var updatedMessages = [...messages]..removeWhere((e) => e.id == message.id);
|
||||||
|
|
||||||
|
// Remove quoted message reference from every message if available.
|
||||||
|
updatedMessages = [...updatedMessages].map((it) {
|
||||||
|
// Early return if the message doesn't have a quoted message.
|
||||||
|
if (it.quotedMessageId != message.id) return it;
|
||||||
|
|
||||||
|
// Setting it to null will remove the quoted message from the message.
|
||||||
|
return it.copyWith(
|
||||||
|
quotedMessage: null,
|
||||||
|
quotedMessageId: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
_channelState = _channelState.copyWith(
|
_channelState = _channelState.copyWith(
|
||||||
messages: allMessages..removeWhere((e) => e.id == message.id),
|
messages: updatedMessages,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
used in message edit widget.
|
used in message edit widget.
|
||||||
- [[#1523]](https://github.com/GetStream/stream-chat-flutter/issues/1523) Fixed `StreamMessageThemeData` not being
|
- [[#1523]](https://github.com/GetStream/stream-chat-flutter/issues/1523) Fixed `StreamMessageThemeData` not being
|
||||||
applied correctly.
|
applied correctly.
|
||||||
|
- [[#1525]](https://github.com/GetStream/stream-chat-flutter/issues/1525) Fixed `StreamQuotedMessageWidget` message for
|
||||||
|
deleted messages not being shown correctly.
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
this.padding = const EdgeInsets.all(8),
|
this.padding = const EdgeInsets.all(8),
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.onQuotedMessageClear,
|
this.onQuotedMessageClear,
|
||||||
this.composing = true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The message
|
/// The message
|
||||||
@@ -53,9 +52,6 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
/// Callback for clearing quoted messages.
|
/// Callback for clearing quoted messages.
|
||||||
final VoidCallback? onQuotedMessageClear;
|
final VoidCallback? onQuotedMessageClear;
|
||||||
|
|
||||||
/// True if the message is being composed
|
|
||||||
final bool composing;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final children = [
|
final children = [
|
||||||
@@ -63,11 +59,10 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
child: _QuotedMessage(
|
child: _QuotedMessage(
|
||||||
message: message,
|
message: message,
|
||||||
textLimit: textLimit,
|
textLimit: textLimit,
|
||||||
composing: composing,
|
|
||||||
onQuotedMessageClear: onQuotedMessageClear,
|
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
showBorder: showBorder,
|
showBorder: showBorder,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
|
onQuotedMessageClear: onQuotedMessageClear,
|
||||||
attachmentThumbnailBuilders: attachmentThumbnailBuilders,
|
attachmentThumbnailBuilders: attachmentThumbnailBuilders,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -104,17 +99,15 @@ class _QuotedMessage extends StatelessWidget {
|
|||||||
const _QuotedMessage({
|
const _QuotedMessage({
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.textLimit,
|
required this.textLimit,
|
||||||
required this.composing,
|
|
||||||
required this.onQuotedMessageClear,
|
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
required this.showBorder,
|
required this.showBorder,
|
||||||
required this.reverse,
|
required this.reverse,
|
||||||
|
this.onQuotedMessageClear,
|
||||||
this.attachmentThumbnailBuilders,
|
this.attachmentThumbnailBuilders,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Message message;
|
final Message message;
|
||||||
final int textLimit;
|
final int textLimit;
|
||||||
final bool composing;
|
|
||||||
final VoidCallback? onQuotedMessageClear;
|
final VoidCallback? onQuotedMessageClear;
|
||||||
final StreamMessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
final bool showBorder;
|
final bool showBorder;
|
||||||
@@ -134,6 +127,8 @@ class _QuotedMessage extends StatelessWidget {
|
|||||||
bool get _isGiphy =>
|
bool get _isGiphy =>
|
||||||
message.attachments.any((element) => element.type == 'giphy');
|
message.attachments.any((element) => element.type == 'giphy');
|
||||||
|
|
||||||
|
bool get _isDeleted => message.isDeleted || message.deletedAt != null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isOnlyEmoji = message.text!.isOnlyEmoji;
|
final isOnlyEmoji = message.text!.isOnlyEmoji;
|
||||||
@@ -144,39 +139,54 @@ class _QuotedMessage extends StatelessWidget {
|
|||||||
msg = msg.copyWith(text: '${msg.text!.substring(0, textLimit - 3)}...');
|
msg = msg.copyWith(text: '${msg.text!.substring(0, textLimit - 3)}...');
|
||||||
}
|
}
|
||||||
|
|
||||||
final children = [
|
List<Widget> children;
|
||||||
if (composing)
|
if (_isDeleted) {
|
||||||
PlatformWidgetBuilder(
|
// Show deleted message text
|
||||||
web: (context, child) => child,
|
children = [
|
||||||
desktop: (context, child) => child,
|
Text(
|
||||||
child: ClearInputItemButton(
|
context.translations.messageDeletedLabel,
|
||||||
onTap: onQuotedMessageClear,
|
style: messageTheme.messageTextStyle?.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
color: messageTheme.createdAtStyle?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_hasAttachments)
|
];
|
||||||
_ParseAttachments(
|
} else {
|
||||||
message: message,
|
// Show quoted message
|
||||||
messageTheme: messageTheme,
|
children = [
|
||||||
attachmentThumbnailBuilders: attachmentThumbnailBuilders,
|
if (onQuotedMessageClear != null)
|
||||||
),
|
PlatformWidgetBuilder(
|
||||||
if (msg.text!.isNotEmpty && !_isGiphy)
|
web: (context, child) => child,
|
||||||
Flexible(
|
desktop: (context, child) => child,
|
||||||
child: StreamMessageText(
|
child: ClearInputItemButton(
|
||||||
message: msg,
|
onTap: onQuotedMessageClear,
|
||||||
messageTheme: isOnlyEmoji && _containsText
|
),
|
||||||
? messageTheme.copyWith(
|
|
||||||
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
|
||||||
fontSize: 32,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: messageTheme.copyWith(
|
|
||||||
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
if (_hasAttachments)
|
||||||
].insertBetween(const SizedBox(width: 8));
|
_ParseAttachments(
|
||||||
|
message: message,
|
||||||
|
messageTheme: messageTheme,
|
||||||
|
attachmentThumbnailBuilders: attachmentThumbnailBuilders,
|
||||||
|
),
|
||||||
|
if (msg.text!.isNotEmpty && !_isGiphy)
|
||||||
|
Flexible(
|
||||||
|
child: StreamMessageText(
|
||||||
|
message: msg,
|
||||||
|
messageTheme: isOnlyEmoji && _containsText
|
||||||
|
? messageTheme.copyWith(
|
||||||
|
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
||||||
|
fontSize: 32,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: messageTheme.copyWith(
|
||||||
|
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].insertBetween(const SizedBox(width: 8));
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -204,7 +214,7 @@ class _QuotedMessage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color? _getBackgroundColor(BuildContext context) {
|
Color? _getBackgroundColor(BuildContext context) {
|
||||||
if (_containsLinkAttachment) {
|
if (_containsLinkAttachment && !_isDeleted) {
|
||||||
return messageTheme.urlAttachmentBackgroundColor;
|
return messageTheme.urlAttachmentBackgroundColor;
|
||||||
}
|
}
|
||||||
return messageTheme.messageBackgroundColor;
|
return messageTheme.messageBackgroundColor;
|
||||||
|
|||||||
@@ -282,9 +282,14 @@ class StreamMessageListView extends StatefulWidget {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
List<SpacingType> spacingTypes,
|
List<SpacingType> spacingTypes,
|
||||||
) {
|
) {
|
||||||
if (!spacingTypes.contains(SpacingType.defaultSpacing)) {
|
if (spacingTypes.contains(SpacingType.otherUser)) {
|
||||||
|
return const SizedBox(height: 8);
|
||||||
|
} else if (spacingTypes.contains(SpacingType.thread)) {
|
||||||
|
return const SizedBox(height: 8);
|
||||||
|
} else if (spacingTypes.contains(SpacingType.timeDiff)) {
|
||||||
return const SizedBox(height: 8);
|
return const SizedBox(height: 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return const SizedBox(height: 2);
|
return const SizedBox(height: 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,7 +649,8 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
|
|
||||||
Widget separator;
|
Widget separator;
|
||||||
|
|
||||||
final isThread = message.replyCount! > 0;
|
final isPartOfThread = message.replyCount! > 0 ||
|
||||||
|
message.showInChannel == true;
|
||||||
|
|
||||||
if (!Jiffy(message.createdAt.toLocal()).isSame(
|
if (!Jiffy(message.createdAt.toLocal()).isSame(
|
||||||
nextMessage.createdAt.toLocal(),
|
nextMessage.createdAt.toLocal(),
|
||||||
@@ -666,7 +672,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
final spacingRules = [
|
final spacingRules = [
|
||||||
if (hasTimeDiff) SpacingType.timeDiff,
|
if (hasTimeDiff) SpacingType.timeDiff,
|
||||||
if (!isNextUserSame) SpacingType.otherUser,
|
if (!isNextUserSame) SpacingType.otherUser,
|
||||||
if (isThread) SpacingType.thread,
|
if (isPartOfThread) SpacingType.thread,
|
||||||
if (isDeleted) SpacingType.deleted,
|
if (isDeleted) SpacingType.deleted,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -680,7 +686,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isThread &&
|
if (!isPartOfThread &&
|
||||||
unreadCount > 0 &&
|
unreadCount > 0 &&
|
||||||
_oldestUnreadMessage?.id == nextMessage.id) {
|
_oldestUnreadMessage?.id == nextMessage.id) {
|
||||||
final unreadMessagesSeparator =
|
final unreadMessagesSeparator =
|
||||||
|
|||||||
@@ -147,11 +147,10 @@ class BottomRow extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (isDeleted) {
|
if (isDeleted) {
|
||||||
return deletedBottomRowBuilder?.call(
|
final deletedBottomRowBuilder = this.deletedBottomRowBuilder;
|
||||||
context,
|
if (deletedBottomRowBuilder != null) {
|
||||||
message,
|
return deletedBottomRowBuilder(context, message);
|
||||||
) ??
|
}
|
||||||
const Offstage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final children = <WidgetSpan>[];
|
final children = <WidgetSpan>[];
|
||||||
|
|||||||
@@ -794,8 +794,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
showUsername ||
|
showUsername ||
|
||||||
showTimeStamp ||
|
showTimeStamp ||
|
||||||
showInChannel ||
|
showInChannel ||
|
||||||
showSendingIndicator ||
|
showSendingIndicator;
|
||||||
isDeleted;
|
|
||||||
|
|
||||||
/// {@template isPinned}
|
/// {@template isPinned}
|
||||||
/// Whether [StreamMessageWidget.message] is pinned or not.
|
/// Whether [StreamMessageWidget.message] is pinned or not.
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ class _QuotedMessageState extends State<QuotedMessage> {
|
|||||||
top: 8,
|
top: 8,
|
||||||
bottom: widget.hasNonUrlAttachments ? 8 : 0,
|
bottom: widget.hasNonUrlAttachments ? 8 : 0,
|
||||||
),
|
),
|
||||||
composing: false,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user