sendMessage method
Send a message to this channel.
If skipPush is true the message will not send a push notification.
Waits for a _messageAttachmentsUploadCompleter to complete
before actually sending the message.
Implementation
Future<SendMessageResponse> sendMessage(
Message message, {
bool skipPush = false,
bool skipEnrichUrl = false,
}) async {
_checkInitialized();
// Clean up stale error messages before sending a new message.
state!.cleanUpStaleErrorMessages();
// Cancelling previous completer in case it's called again in the process
// Eg. Updating the message while the previous call is in progress.
_messageAttachmentsUploadCompleter
.remove(message.id)
?.completeError(const StreamChatError('Message cancelled'));
final quotedMessage = state!.messages.firstWhereOrNull(
(m) => m.id == message.quotedMessageId,
);
// ignore: parameter_assignments
message = message.copyWith(
localCreatedAt: DateTime.now(),
user: _client.state.currentUser,
quotedMessage: quotedMessage,
state: MessageState.sending,
attachments: message.attachments.map(
(it) {
if (it.uploadState.isSuccess) return it;
return it.copyWith(uploadState: const UploadState.preparing());
},
).toList(),
);
state!.updateMessage(message);
try {
if (message.attachments.any((it) => !it.uploadState.isSuccess)) {
final attachmentsUploadCompleter = Completer<Message>();
_messageAttachmentsUploadCompleter[message.id] =
attachmentsUploadCompleter;
_uploadAttachments(
message.id,
message.attachments.map((it) => it.id),
);
// ignore: parameter_assignments
message = await attachmentsUploadCompleter.future;
}
// Validate the final message before sending it to the server.
if (MessageRules.canUpload(message) != true) {
client.logger.warning('Message is not valid for sending, removing it');
// Remove the message from state as it is invalid.
state!.deleteMessage(message, hardDelete: true);
throw const StreamChatError('Message is not valid for sending');
}
// Wait for the previous sendMessage call to finish. Otherwise, the order
// of messages will not be maintained.
final response = await _sendMessageLock.synchronized(
() => _client.sendMessage(
message,
id!,
type,
skipPush: skipPush,
skipEnrichUrl: skipEnrichUrl,
),
);
final sentMessage = response.message.syncWith(message).copyWith(
// Update the message state to sent.
state: MessageState.sent,
);
state!.updateMessage(sentMessage);
return response;
} catch (e) {
if (e is StreamChatNetworkError && e.isRetriable) {
state!._retryQueue.add([
message.copyWith(
// Update the message state to failed.
state: MessageState.sendingFailed,
),
]);
}
rethrow;
}
}