Message Moderation
Stream Chat can moderate messages before they are delivered (bounce) and lets users report messages to moderators (flag). This page shows how to customize the UIKit components for moderated messages. For how moderated messages are represented in the SDK, see the Moderation guide.
Bounced Messages
A bounced message is displayed with an error indicator next to it. When the user long presses the message or taps the indicator, ChatMessageListVC calls showActions(forDebouncedMessage:), which presents an alert with the Send Anyway, Edit Message and Delete Message actions.
To change the actions, or to replace the alert with your own UI, subclass ChatMessageListVC and override messageActions(forDebouncedMessage:) or showActions(forDebouncedMessage:):
class CustomChatMessageListVC: ChatMessageListVC {
// Change the list of actions, e.g. do not allow sending a bounced message anyway.
override func messageActions(forDebouncedMessage message: ChatMessage) -> [ChatMessageActionItem] {
super.messageActions(forDebouncedMessage: message)
.filter { !($0 is ResendActionItem) }
}
// Or replace the default alert completely.
override func showActions(forDebouncedMessage message: ChatMessage) {
let actions = messageActions(forDebouncedMessage: message)
let alert = UIAlertController(
title: "Message not sent",
message: "This message goes against our community guidelines.",
preferredStyle: .alert
)
actions.forEach { item in
alert.addAction(UIAlertAction(
title: item.title,
style: item.isDestructive ? .destructive : .default,
handler: { _ in item.action(item) }
))
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert, animated: true)
}
}
Components.default.messageListVC = CustomChatMessageListVC.selfThe error indicator is a ChatMessageErrorIndicator. You can change its icon with Appearance.default.images.messageListErrorIndicator, or provide your own subclass:
class CustomErrorIndicator: ChatMessageErrorIndicator {
override func setUpAppearance() {
super.setUpAppearance()
setImage(UIImage(systemName: "exclamationmark.shield.fill"), for: .normal)
tintColor = .systemOrange
}
}
Components.default.messageErrorIndicator = CustomErrorIndicator.selfThe error indicator is also used for messages that failed to be sent for other reasons, for example because of a network error.
Flag Action
The flag action is created by ChatMessageActionsVC.flagActionItem(). It shows a confirmation alert and then calls flag() on the message controller. To change the title, the behaviour, or to flag the message with a reason, subclass ChatMessageActionsVC and override flagActionItem():
class CustomChatMessageActionsVC: ChatMessageActionsVC {
override func flagActionItem() -> ChatMessageActionItem {
FlagActionItem(
title: "Report",
action: { [weak self] _ in
guard let self else { return }
self.alertsRouter.showMessageFlagConfirmationAlert { confirmed in
guard confirmed else { return }
self.messageController.flag(reason: "inappropriate") { _ in
self.delegate?.chatMessageActionsVCDidFinish(self)
}
}
},
appearance: appearance
)
}
}
Components.default.messageActionsVC = CustomChatMessageActionsVC.selfThe icon of the default flag action can be changed with Appearance.default.images.messageActionFlag.
To hide the flag action, override messageActions and filter it out:
class CustomChatMessageActionsVC: ChatMessageActionsVC {
override var messageActions: [ChatMessageActionItem] {
super.messageActions.filter { !($0 is FlagActionItem) }
}
}To customize the confirmation alert, subclass AlertsRouter and override showMessageFlagConfirmationAlert(confirmed:):
class CustomAlertsRouter: AlertsRouter {
override func showMessageFlagConfirmationAlert(confirmed: @escaping (Bool) -> Void) {
let alert = UIAlertController(
title: "Report message?",
message: "Our moderators will review this message.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in confirmed(false) })
alert.addAction(UIAlertAction(title: "Report", style: .destructive) { _ in confirmed(true) })
rootViewController.present(alert, animated: true)
}
}
Components.default.alertsRouter = CustomAlertsRouter.selfFor more details about replacing components, see Custom Components and Customize Message Actions.
Changing the Texts
If you only need to change the texts, override the following keys in your app's Localizable.strings:
| Key | Default value |
|---|---|
message.moderation.title |
Are you sure? |
message.moderation.message |
Consider how your comment might... |
message.moderation.resend |
Send Anyway |
message.moderation.edit |
Edit Message |
message.moderation.delete |
Delete Message |
message.actions.flag |
Flag Message |
message.actions.flag.confirmation-title |
Flag Message |
message.actions.flag.confirmation-message |
Do you want to send a copy of... |
See the localization guide for more details.