editChatMessage method
- ChatMessage message, {
- ChatMessageTextInput? text,
- ChatMessageAttachmentsInput? attachments,
- ChatMessageRepliesInput? repliesTo,
override
Edits the specified ChatMessage posted by the authenticated MyUser.
Implementation
@override
Future<void> editChatMessage(
ChatMessage message, {
model.ChatMessageTextInput? text,
model.ChatMessageAttachmentsInput? attachments,
model.ChatMessageRepliesInput? repliesTo,
}) async {
Log.debug(
'editChatMessage($message, text: ${text?.changed}, attachments: ${attachments?.changed}, repliesTo: ${repliesTo?.changed})',
'$runtimeType',
);
final Rx<ChatItem>? item = chats[message.chatId]?.messages.firstWhereOrNull(
(e) => e.value.id == message.id,
);
ChatMessageText? previousText;
List<Attachment>? previousAttachments;
List<ChatItemQuote>? previousReplies;
if (item?.value is ChatMessage) {
previousText = (item?.value as ChatMessage).text;
previousAttachments = (item?.value as ChatMessage).attachments;
previousReplies = (item?.value as ChatMessage).repliesTo;
item?.update((c) {
(c as ChatMessage).text = text != null ? text.changed : previousText;
c.attachments = attachments?.changed ?? previousAttachments!;
c.repliesTo =
repliesTo?.changed
.map(
(e) =>
c.repliesTo.firstWhereOrNull((a) => a.original?.id == e),
)
.nonNulls
.toList() ??
previousReplies!;
});
}
// Don't upload the [Attachment]s and don't proceed with `editChatMessage`
// if the message's status is [SendingStatus.error].
if (message.status.value == SendingStatus.error) {
return;
}
final List<Future>? uploads = attachments?.changed
.map((e) {
if (e is LocalAttachment) {
return e.upload.value?.future.then(
(a) {
final index = attachments.changed.indexOf(e);
// If `Attachment` returned is `null`, then it was canceled.
if (a == null) {
attachments.changed.removeAt(index);
} else {
attachments.changed[index] = a;
}
item?.update((_) {});
},
onError: (_) {
// No-op, as failed upload attempts are handled below.
},
);
}
})
.nonNulls
.toList();
await Future.wait(uploads ?? []);
try {
if (attachments?.changed.whereType<LocalAttachment>().isNotEmpty ==
true) {
throw const ConnectionException(
EditChatMessageException(EditChatMessageErrorCode.unknownAttachment),
);
}
final bool hasText =
(text?.changed ?? message.text)?.val.isNotEmpty == true;
final bool hasAttachments =
(attachments?.changed ?? message.attachments).isNotEmpty;
final bool hasReplies =
(repliesTo?.changed ?? message.repliesTo).isNotEmpty;
// If after editing the message contains no content, then delete it.
if (!hasText && !hasAttachments && !hasReplies) {
return await deleteChatMessage(message);
}
await Backoff.run(
() async {
await _graphQlProvider.editChatMessage(
message.id,
text: text == null
? null
: ChatMessageTextInput(kw$new: text.changed?.nullIfEmpty),
attachments: attachments == null
? null
: ChatMessageAttachmentsInput(
kw$new: attachments.changed.map((e) => e.id).toList(),
),
repliesTo: repliesTo == null
? null
: ChatMessageRepliesInput(kw$new: repliesTo.changed),
);
},
retryIf: (e) => e.isNetworkRelated,
retries: 10,
);
} on EditChatMessageException catch (e) {
switch (e.code) {
case EditChatMessageErrorCode.uneditable:
case EditChatMessageErrorCode.blocked:
case EditChatMessageErrorCode.unknownAttachment:
case EditChatMessageErrorCode.artemisUnknown:
case EditChatMessageErrorCode.wrongAttachmentsCount:
case EditChatMessageErrorCode.unknownReplyingChatItem:
case EditChatMessageErrorCode.wrongReplyingChatItemsCount:
rethrow;
case EditChatMessageErrorCode.unknownChatItem:
chats[message.chatId]?.remove(message.id);
break;
case EditChatMessageErrorCode.notAuthor:
case EditChatMessageErrorCode.noTextAndNoAttachment:
// No-op.
break;
}
} catch (_) {
if (item?.value is ChatMessage) {
item?.update((c) {
(c as ChatMessage).text = previousText;
c.attachments = previousAttachments ?? [];
c.repliesTo = previousReplies ?? [];
});
}
rethrow;
}
}