// Create/update a draft message in a channel
let channelId = ChannelId(type: .messaging, id: "general")
let channelController = chatClient.channelController(for: channelId)
channelController.updateDraftMessage(
text: "Hello, this is my draft message",
isSilent: false,
attachments: [imageAttachment],
mentionedUserIds: ["user-id-1", "user-id-2"],
quotedMessageId: "quoted-message-id",
extraData: ["custom_field": .string("value")]
) { _ in
print("Draft message saved: \(channelController.channel.draftMessage)")
}
// Create/update a draft message in a thread (parent message)
let messageController = chatClient.messageController(
cid: ChannelId(type: .messaging, id: "general"),
messageId: "parent-message-id"
)
messageController.updateDraftReply(
text: "This is my draft reply",
isSilent: false,
attachments: [imageAttachment],
mentionedUserIds: ["user-id-1"],
quotedMessageId: "quoted-message-id",
showReplyInChannel: true,
extraData: ["custom_field": .string("value")]
) { _ in
print("Draft message saved: \(messageController.message.draftReply)")
}
Draft Messages
Draft messages allow users to save messages as drafts for later use. This feature is useful when users want to compose a message but aren’t ready to send it yet.
Creating a draft message
It is possible to create a draft message for a channel or a thread. Only one draft per channel/thread can exist at a time, so a newly created draft overrides the existing one.
Deleting a draft message
You can delete a draft message for a channel or a thread as well.
// Delete the draft message for a channel
let channelId = ChannelId(type: .messaging, id: "general")
let channelController = chatClient.channelController(for: channelId)
channelController.deleteDraftMessage()
// Delete the draft message for a thread
let messageController = chatClient.messageController(
cid: ChannelId(type: .messaging, id: "general"),
messageId: "parent-message-id"
)
messageController.deleteDraftReply()
Loading a draft message
It is also possible to load a draft message for a channel or a thread. Although, when querying channels, each channel will contain the draft message payload, in case there is one. The same for threads (parent messages). So, for the most part this function will not be needed.
// Load the draft message for a channel
let channelId = ChannelId(type: .messaging, id: "general")
let channelController = chatClient.channelController(for: channelId)
channelController.loadDraftMessage { result in
switch result {
case .success(let draftMessage):
print("Draft message loaded: \(draftMessage)")
case .failure(let error):
print("Failed to load draft message: \(error)")
}
}
// Load the draft message for a thread
let messageController = chatClient.messageController(
cid: ChannelId(type: .messaging, id: "general"),
messageId: "parent-message-id"
)
messageController.loadDraftReply { result in
switch result {
case .success(let draftReply):
print("Draft reply loaded: \(draftReply)")
case .failure(let error):
print("Failed to load draft reply: \(error)")
}
}
Querying draft messages
The Stream Chat SDK provides a way to fetch all the draft messages for the current user. This can be useful to for the current user to manage all the drafts they have in one place.
// Load the draft messages for the current user
let currentUserController = chatClient.currentUserController()
currentUserController.loadDraftMessages { result in
switch result {
case .success:
print("Draft messages loaded: \(currentUserController.draftMessages)")
case .failure(let error):
print("Failed to load draft messages: \(error)")
}
}
// Whenever the drafts are updated, it will be notified through the currentUserController delegate
class MyView: UIView, CurrentChatUserControllerDelegate {
let controller: CurrentChatUserController
init(controller: CurrentChatUserController) {
self.controller = controller
super.init(frame: .zero)
controller.delegate = self
}
func currentUserController(
_ controller: CurrentChatUserController,
didChangeDraftMessages draftMessages: [DraftMessage]
) {
// Handle the changes
}
}
Pagination
In case the user has a lot of draft messages, you can paginate the results.
// Load the next page of draft messages
currentUserController.loadMoreDraftMessages()
// With a custom page size
currentUserController.loadMoreDraftMessages(limit: 20) { result in
switch result {
case .success:
print("Draft messages loaded: \(currentUserController.draftMessages)")
case .failure(let error):
print("Failed to load draft messages: \(error)")
}
}
Events
The following WebSocket events are available for draft messages:
draft.updated
, triggered when a draft message is updated.draft.deleted
, triggered when a draft message is deleted.
You can subscribe to these events using the Stream Chat SDK.
let chatClient = ChatClient.shared
let eventsController = chatClient.eventsController()
eventsController.delegate = self
public func eventsController(_ controller: EventsController, didReceiveEvent event: any Event) {
if let event = event as? DraftUpdatedEvent {
let threadId = event.draftMessage.threadId
let channelId = event.cid
// handle draft updated event
} else if let event = event as? DraftDeletedEvent {
let threadId = event.draftMessage.threadId
let channelId = event.cid
// handle draft deleted event
}
}