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 SwiftUI 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 it, the SDK shows an alert with the Send Anyway, Edit Message and Delete Message actions. This is controlled by the bouncedMessagesAlertActionsEnabled flag of MessageListConfig, which is true by default.
The alert is added by the BouncedMessageActionsModifier. To provide your own UI, implement makeBouncedMessageActionsModifier in your custom Styles. The ChatChannelViewModel exposes the bounced message and the actions that can be performed on it:
struct CustomBouncedMessageActionsModifier: ViewModifier {
@ObservedObject var viewModel: ChatChannelViewModel
func body(content: Content) -> some View {
content
.alert(isPresented: $viewModel.bouncedActionsViewShown) {
Alert(
title: Text("Message not sent"),
message: Text("This message goes against our community guidelines."),
primaryButton: .default(Text("Edit Message")) {
if let message = viewModel.bouncedMessage {
viewModel.editMessage(message)
}
},
secondaryButton: .destructive(Text("Delete Message")) {
if let message = viewModel.bouncedMessage {
viewModel.deleteMessage(message)
}
}
)
}
}
}
final class CustomStyles: Styles {
var composerPlacement: ComposerPlacement = .docked
func makeBouncedMessageActionsModifier(viewModel: ChatChannelViewModel) -> some ViewModifier {
CustomBouncedMessageActionsModifier(viewModel: viewModel)
}
func makeComposerInputViewModifier(options: ComposerInputModifierOptions) -> some ViewModifier {
RegularInputViewModifier()
}
func makeComposerButtonViewModifier(options: ComposerButtonModifierOptions) -> some ViewModifier {
RegularButtonViewModifier()
}
func makeSuggestionsContainerModifier(options: SuggestionsContainerModifierOptions) -> some ViewModifier {
SuggestionsRegularContainerModifier()
}
}
class CustomViewFactory: ViewFactory {
@Injected(\.chatClient) public var chatClient
public var styles = CustomStyles()
}If you set bouncedMessagesAlertActionsEnabled to false, long pressing a bounced message opens the regular message actions overlay instead. In this case, the actions are provided by supportedMessageActions, as described in the next section, and you can check options.message.isBounced to return different actions for bounced messages.
Flag Action
The message actions are provided by the supportedMessageActions closure of MessageListConfig. The default flag action has the MessageActionId.flag identifier, so you can remove it or replace it with your own action:
let utils = Utils(
messageListConfig: MessageListConfig(
supportedMessageActions: { options in
var actions = MessageAction.defaultActions(for: options)
guard let index = actions.firstIndex(where: { $0.id == MessageActionId.flag }) else {
return actions
}
let chatClient = InjectedValues[\.chatClient]
let messageController = chatClient.messageController(
cid: options.channel.cid,
messageId: options.message.id
)
actions[index] = MessageAction(
id: MessageActionId.flag,
title: "Report",
iconName: "exclamationmark.bubble",
action: {
messageController.flag(reason: "inappropriate") { error in
if let error {
options.onError(error)
} else {
options.onFinish(MessageActionInfo(message: options.message, identifier: "flag"))
}
}
},
confirmationPopup: ConfirmationPopup(
title: "Report message?",
message: "Our moderators will review this message.",
buttonTitle: "Report"
),
isDestructive: true
)
return actions
}
)
)
let streamChat = StreamChat(chatClient: chatClient, utils: utils)To hide the flag action, filter it out instead: MessageAction.defaultActions(for: options).filter { $0.id != MessageActionId.flag }.
For more details, see View Customizations and Message Reactions.
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.alert.title |
Are you sure? |
message.moderation.alert.message |
Consider how your comment might... |
message.moderation.alert.resend |
Send Anyway |
message.moderation.alert.edit |
Edit Message |
message.moderation.alert.delete |
Delete Message |
message.bounce.title |
Message was bounced |
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.