fix(messages): fix Resend btn not working and add Sending visual state
Fixes #7643 This adds the backend to resend. It then hooks the button to it. This also adds a visual state for when we are sending. This gives a good indication that a message was sent.
This commit is contained in:
parent
59a05243af
commit
194e3048bc
|
@ -97,7 +97,8 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch
|
|||
message.mentionedUsersPks,
|
||||
contactDetails.details.trustStatus,
|
||||
contactDetails.details.ensVerified,
|
||||
message.discordMessage
|
||||
message.discordMessage,
|
||||
resendError = ""
|
||||
))
|
||||
|
||||
method convertToItems*(
|
||||
|
|
|
@ -289,3 +289,6 @@ proc leaveChat*(self: Controller) =
|
|||
method checkEditedMessageForMentions*(self: Controller, chatId: string,
|
||||
editedMessage: MessageDto, oldMentions: seq[string]) =
|
||||
self.messageService.checkEditedMessageForMentions(chatId, editedMessage, oldMentions)
|
||||
|
||||
method resendChatMessage*(self: Controller, messageId: string): string =
|
||||
return self.messageService.resendChatMessage(messageId)
|
||||
|
|
|
@ -148,3 +148,6 @@ method getMessageById*(self: AccessInterface, messageId: string): message_item.I
|
|||
|
||||
method onMailserverSynced*(self: AccessInterface, syncedFrom: int64) =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method resendChatMessage*(self: AccessInterface, messageId: string): string =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
|
|
@ -99,7 +99,8 @@ proc createFetchMoreMessagesItem(self: Module): Item =
|
|||
mentionedUsersPks = @[],
|
||||
senderTrustStatus = TrustStatus.Unknown,
|
||||
senderEnsVerified = false,
|
||||
DiscordMessage()
|
||||
DiscordMessage(),
|
||||
resendError = ""
|
||||
)
|
||||
|
||||
proc createChatIdentifierItem(self: Module): Item =
|
||||
|
@ -140,7 +141,8 @@ proc createChatIdentifierItem(self: Module): Item =
|
|||
mentionedUsersPks = @[],
|
||||
senderTrustStatus = TrustStatus.Unknown,
|
||||
senderEnsVerified = false,
|
||||
DiscordMessage()
|
||||
DiscordMessage(),
|
||||
resendError = ""
|
||||
)
|
||||
|
||||
proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module): bool =
|
||||
|
@ -220,7 +222,8 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
|
|||
m.mentionedUsersPks(),
|
||||
sender.details.trustStatus,
|
||||
sender.details.ensVerified,
|
||||
m.discordMessage
|
||||
m.discordMessage,
|
||||
resendError = ""
|
||||
)
|
||||
|
||||
for r in reactions:
|
||||
|
@ -319,7 +322,8 @@ method messageAdded*(self: Module, message: MessageDto) =
|
|||
message.mentionedUsersPks,
|
||||
sender.details.trustStatus,
|
||||
sender.details.ensVerified,
|
||||
message.discordMessage
|
||||
message.discordMessage,
|
||||
resendError = ""
|
||||
)
|
||||
|
||||
self.view.model().insertItemBasedOnClock(item)
|
||||
|
@ -593,7 +597,8 @@ method getMessageById*(self: Module, messageId: string): message_item.Item =
|
|||
m.mentionedUsersPks(),
|
||||
sender.details.trustStatus,
|
||||
sender.details.ensVerified,
|
||||
m.discordMessage
|
||||
m.discordMessage,
|
||||
resendError = ""
|
||||
)
|
||||
return item
|
||||
return nil
|
||||
|
@ -602,3 +607,6 @@ method onMailserverSynced*(self: Module, syncedFrom: int64) =
|
|||
let chatDto = self.controller.getChatDetails()
|
||||
if (not chatDto.hasMoreMessagesToRequest(syncedFrom)):
|
||||
self.view.model().removeItem(FETCH_MORE_MESSAGES_MESSAGE_ID)
|
||||
|
||||
method resendChatMessage*(self: Module, messageId: string): string =
|
||||
return self.controller.resendChatMessage(messageId)
|
||||
|
|
|
@ -183,3 +183,11 @@ QtObject:
|
|||
|
||||
proc jumpToMessage*(self: View, messageId: string) {.slot.} =
|
||||
self.delegate.scrollToMessage(messageId)
|
||||
|
||||
proc resendMessage*(self: View, messageId: string) {.slot.} =
|
||||
let error = self.delegate.resendChatMessage(messageId)
|
||||
if (error != ""):
|
||||
self.model.itemFailedResending(messageId, error)
|
||||
return
|
||||
self.model.itemSending(messageId)
|
||||
|
||||
|
|
|
@ -197,7 +197,8 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy:
|
|||
m.mentionedUsersPks,
|
||||
contactDetails.details.trustStatus,
|
||||
contactDetails.details.ensVerified,
|
||||
m.discordMessage
|
||||
m.discordMessage,
|
||||
resendError = ""
|
||||
)
|
||||
item.pinned = true
|
||||
item.pinnedBy = actionInitiatedBy
|
||||
|
|
|
@ -42,6 +42,7 @@ type
|
|||
senderTrustStatus: TrustStatus
|
||||
senderEnsVerified: bool
|
||||
messageAttachments: seq[string]
|
||||
resendError: string
|
||||
|
||||
proc initItem*(
|
||||
id,
|
||||
|
@ -70,7 +71,8 @@ proc initItem*(
|
|||
mentionedUsersPks: seq[string],
|
||||
senderTrustStatus: TrustStatus,
|
||||
senderEnsVerified: bool,
|
||||
discordMessage: DiscordMessage
|
||||
discordMessage: DiscordMessage,
|
||||
resendError: string
|
||||
): Item =
|
||||
result = Item()
|
||||
result.id = id
|
||||
|
@ -106,6 +108,7 @@ proc initItem*(
|
|||
result.senderTrustStatus = senderTrustStatus
|
||||
result.senderEnsVerified = senderEnsVerified
|
||||
result.messageAttachments = @[]
|
||||
result.resendError = resendError
|
||||
|
||||
if ContentType.DiscordMessage == contentType:
|
||||
if result.messageText == "":
|
||||
|
@ -137,6 +140,7 @@ proc `$`*(self: Item): string =
|
|||
senderIsAdded: {$self.senderIsAdded},
|
||||
seen: {$self.seen},
|
||||
outgoingStatus:{$self.outgoingStatus},
|
||||
resendError:{$self.resendError},
|
||||
messageText:{self.messageText},
|
||||
messageContainsMentions:{self.messageContainsMentions},
|
||||
timestamp:{$self.timestamp},
|
||||
|
@ -212,6 +216,12 @@ proc outgoingStatus*(self: Item): string {.inline.} =
|
|||
proc `outgoingStatus=`*(self: Item, value: string) {.inline.} =
|
||||
self.outgoingStatus = value
|
||||
|
||||
proc resendError*(self: Item): string {.inline.} =
|
||||
self.resendError
|
||||
|
||||
proc `resendError=`*(self: Item, value: string) {.inline.} =
|
||||
self.resendError = value
|
||||
|
||||
proc messageText*(self: Item): string {.inline.} =
|
||||
self.messageText
|
||||
|
||||
|
@ -328,7 +338,8 @@ proc toJsonNode*(self: Item): JsonNode =
|
|||
"isEdited": self.isEdited,
|
||||
"links": self.links,
|
||||
"mentionedUsersPks": self.mentionedUsersPks,
|
||||
"senderEnsVerified": self.senderEnsVerified
|
||||
"senderEnsVerified": self.senderEnsVerified,
|
||||
"resendError": self.resendError
|
||||
}
|
||||
|
||||
proc editMode*(self: Item): bool {.inline.} =
|
||||
|
|
|
@ -42,6 +42,7 @@ type
|
|||
SenderTrustStatus
|
||||
SenderEnsVerified
|
||||
MessageAttachments
|
||||
ResendError
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
@ -98,6 +99,7 @@ QtObject:
|
|||
ModelRole.SenderIsAdded.int:"senderIsAdded",
|
||||
ModelRole.Seen.int:"seen",
|
||||
ModelRole.OutgoingStatus.int:"outgoingStatus",
|
||||
ModelRole.ResendError.int:"resendError",
|
||||
ModelRole.MessageText.int:"messageText",
|
||||
ModelRole.MessageImage.int:"messageImage",
|
||||
ModelRole.MessageContainsMentions.int:"messageContainsMentions",
|
||||
|
@ -166,6 +168,8 @@ QtObject:
|
|||
result = newQVariant(item.seen)
|
||||
of ModelRole.OutgoingStatus:
|
||||
result = newQVariant(item.outgoingStatus)
|
||||
of ModelRole.ResendError:
|
||||
result = newQVariant(item.resendError)
|
||||
of ModelRole.MessageText:
|
||||
result = newQVariant(item.messageText)
|
||||
of ModelRole.MessageImage:
|
||||
|
@ -375,6 +379,9 @@ QtObject:
|
|||
let index = self.createIndex(ind, 0, nil)
|
||||
self.dataChanged(index, index, @[ModelRole.OutgoingStatus.int])
|
||||
|
||||
proc itemSending*(self: Model, messageId: string) =
|
||||
self.setOutgoingStatus(messageId, PARSED_TEXT_OUTGOING_STATUS_SENDING)
|
||||
|
||||
proc itemSent*(self: Model, messageId: string) =
|
||||
self.setOutgoingStatus(messageId, PARSED_TEXT_OUTGOING_STATUS_SENT)
|
||||
|
||||
|
@ -384,6 +391,14 @@ QtObject:
|
|||
proc itemExpired*(self: Model, messageId: string) =
|
||||
self.setOutgoingStatus(messageId, PARSED_TEXT_OUTGOING_STATUS_EXPIRED)
|
||||
|
||||
proc itemFailedResending*(self: Model, messageId: string, error: string) =
|
||||
let ind = self.findIndexForMessageId(messageId)
|
||||
if(ind == -1):
|
||||
return
|
||||
self.items[ind].resendError = error
|
||||
let index = self.createIndex(ind, 0, nil)
|
||||
self.dataChanged(index, index, @[ModelRole.ResendError.int])
|
||||
|
||||
proc addReaction*(self: Model, messageId: string, emojiId: EmojiId, didIReactWithThisEmoji: bool,
|
||||
userPublicKey: string, userDisplayName: string, reactionId: string) =
|
||||
let ind = self.findIndexForMessageId(messageId)
|
||||
|
|
|
@ -21,6 +21,7 @@ const PARSED_TEXT_OUTGOING_STATUS_SENDING* = "sending"
|
|||
const PARSED_TEXT_OUTGOING_STATUS_SENT* = "sent"
|
||||
const PARSED_TEXT_OUTGOING_STATUS_DELIVERED* = "delivered"
|
||||
const PARSED_TEXT_OUTGOING_STATUS_EXPIRED* = "expired"
|
||||
const PARSED_TEXT_OUTGOING_STATUS_FAILED_RESENDING* = "failedResending"
|
||||
|
||||
type ParsedText* = object
|
||||
`type`*: string
|
||||
|
|
|
@ -793,3 +793,16 @@ proc checkEditedMessageForMentions*(self: Service, chatId: string, editedMessage
|
|||
if not oldMentions.contains(myPubKey) and editedMessage.mentionedUsersPks().contains(myPubKey):
|
||||
let data = MessageEditedArgs(chatId: chatId, message: editedMessage)
|
||||
self.events.emit(SIGNAL_MENTIONED_IN_EDITED_MESSAGE, data)
|
||||
|
||||
proc resendChatMessage*(self: Service, messageId: string): string =
|
||||
try:
|
||||
let response = status_go.resendChatMessage(messageId)
|
||||
|
||||
if response.error != nil:
|
||||
let error = Json.decode($response.error, RpcError)
|
||||
raise newException(RpcException, "Error resending chat message: " & error.message)
|
||||
|
||||
return
|
||||
except Exception as e:
|
||||
error "error: ", procName="resendChatMessage", errName = e.name, errDesription = e.msg
|
||||
return fmt"{e.name}: {e.msg}"
|
|
@ -64,3 +64,6 @@ proc deleteMessageAndSend*(messageID: string): RpcResponse[JsonNode] {.raises: [
|
|||
|
||||
proc editMessage*(messageId: string, contentType: int, msg: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
result = callPrivateRPC("editMessage".prefix, %* [{"id": messageId, "text": msg, "content-type": contentType}])
|
||||
|
||||
proc resendChatMessage*(messageId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
result = callPrivateRPC("reSendChatMessage".prefix, %* [messageId])
|
||||
|
|
|
@ -58,6 +58,8 @@ Control {
|
|||
property bool isPinned: false
|
||||
property string pinnedBy: ""
|
||||
property bool hasExpired: false
|
||||
property bool isSending: false
|
||||
property string resendError: ""
|
||||
property double timestamp: 0
|
||||
property var reactionsModel: []
|
||||
property bool hasLinks
|
||||
|
@ -275,7 +277,9 @@ Control {
|
|||
amISender: root.messageDetails.amISender
|
||||
messageOriginInfo: root.messageDetails.messageOriginInfo
|
||||
resendText: root.resendText
|
||||
showResendButton: root.hasExpired && root.messageDetails.amISender
|
||||
showResendButton: root.hasExpired && root.messageDetails.amISender && !editMode
|
||||
showSendingLoader: root.isSending && root.messageDetails.amISender && !editMode
|
||||
resendError: root.messageDetails.amISender && !editMode ? root.resendError : ""
|
||||
onClicked: root.senderNameClicked(sender, mouse)
|
||||
onResendClicked: root.resendClicked()
|
||||
visible: root.showHeader && !editMode
|
||||
|
@ -372,17 +376,6 @@ Control {
|
|||
onEditCancelled: root.editCancelled()
|
||||
onEditCompleted: root.editCompleted(newMsgText)
|
||||
}
|
||||
StatusBaseText {
|
||||
color: Theme.palette.dangerColor1
|
||||
text: root.resendText
|
||||
font.pixelSize: 12
|
||||
visible: root.hasExpired && root.messageDetails.amISender && !root.timestamp && !editMode
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: root.resendClicked()
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
active: root.reactionsModel.count > 0
|
||||
visible: active
|
||||
|
|
|
@ -22,6 +22,8 @@ Item {
|
|||
property string tertiaryDetail: sender.id
|
||||
property string resendText: ""
|
||||
property bool showResendButton: false
|
||||
property bool showSendingLoader: false
|
||||
property string resendError: ""
|
||||
property bool isContact: sender.isContact
|
||||
property int trustIndicator: sender.trustIndicator
|
||||
property bool amISender: false
|
||||
|
@ -120,5 +122,19 @@ Item {
|
|||
onClicked: root.resendClicked()
|
||||
}
|
||||
}
|
||||
StatusBaseText {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
text: qsTr("Failed to resend: %1").arg(resendError) // TODO replace this with the required design
|
||||
visible: resendError && !!timestampText.text
|
||||
}
|
||||
StatusBaseText {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
text: qsTr("Sending...") // TODO replace this with the required design
|
||||
visible: showSendingLoader && !!timestampText.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,19 +210,19 @@ QtObject {
|
|||
function requestMoreMessages() {
|
||||
if(!messageModule)
|
||||
return
|
||||
return messageModule.requestMoreMessages();
|
||||
return messageModule.requestMoreMessages()
|
||||
}
|
||||
|
||||
function fillGaps(messageId) {
|
||||
if(!messageModule)
|
||||
return
|
||||
return messageModule.fillGaps(messageId);
|
||||
return messageModule.fillGaps(messageId)
|
||||
}
|
||||
|
||||
function leaveChat() {
|
||||
if(!messageModule)
|
||||
return
|
||||
messageModule.leaveChat();
|
||||
messageModule.leaveChat()
|
||||
}
|
||||
|
||||
property bool playAnimation: {
|
||||
|
@ -243,4 +243,10 @@ QtObject {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
function resendMessage(messageId) {
|
||||
if(!messageModule)
|
||||
return
|
||||
messageModule.resendMessage(messageId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -293,6 +293,7 @@ Item {
|
|||
messageImage: model.messageImage
|
||||
messageTimestamp: model.timestamp
|
||||
messageOutgoingStatus: model.outgoingStatus
|
||||
resendError: model.resendError
|
||||
messageContentType: model.contentType
|
||||
pinnedMessage: model.pinned
|
||||
messagePinnedBy: model.pinnedBy
|
||||
|
|
|
@ -52,6 +52,7 @@ Loader {
|
|||
property string messageImage: ""
|
||||
property double messageTimestamp: 0 // We use double, because QML's int is too small
|
||||
property string messageOutgoingStatus: ""
|
||||
property string resendError: ""
|
||||
property int messageContentType: Constants.messageContentType.messageType
|
||||
property bool pinnedMessage: false
|
||||
property string messagePinnedBy: ""
|
||||
|
@ -90,7 +91,7 @@ Loader {
|
|||
property double prevMsgTimestamp: prevMessageAsJsonObj ? prevMessageAsJsonObj.timestamp : 0
|
||||
property double nextMsgTimestamp: nextMessageAsJsonObj ? nextMessageAsJsonObj.timestamp : 0
|
||||
|
||||
property bool shouldRepeatHeader: ((messageTimestamp - prevMsgTimestamp) / 60 / 1000) > Constants.repeatHeaderInterval
|
||||
property bool shouldRepeatHeader: ((messageTimestamp - prevMsgTimestamp) / 60 / 1000) > Constants.repeatHeaderInterval || isExpired
|
||||
|
||||
property bool hasMention: false
|
||||
|
||||
|
@ -108,7 +109,8 @@ Loader {
|
|||
property bool isMessage: isEmoji || isImage || isSticker || isText || isAudio
|
||||
|| messageContentType === Constants.messageContentType.communityInviteType || messageContentType === Constants.messageContentType.transactionType
|
||||
|
||||
readonly property bool isExpired: (messageOutgoingStatus === "sending" && (Math.floor(messageTimestamp) + 180000) < Date.now()) || messageOutgoingStatus === "expired"
|
||||
readonly property bool isExpired: (messageOutgoingStatus === Constants.sending && (Math.floor(messageTimestamp) + 180000) < Date.now()) || messageOutgoingStatus === Constants.expired
|
||||
readonly property bool isSending: messageOutgoingStatus === Constants.sending && !isExpired
|
||||
property int statusAgeEpoch: 0
|
||||
|
||||
signal imageClicked(var image)
|
||||
|
@ -468,6 +470,8 @@ Loader {
|
|||
isPinned: root.pinnedMessage
|
||||
pinnedBy: root.pinnedMessage && !root.isDiscordMessage ? Utils.getContactDetailsAsJson(root.messagePinnedBy, false).displayName : ""
|
||||
hasExpired: root.isExpired
|
||||
isSending: root.isSending
|
||||
resendError: root.resendError
|
||||
reactionsModel: root.reactionsModel
|
||||
|
||||
showHeader: root.senderId !== root.authorPrevMsg ||
|
||||
|
@ -577,6 +581,10 @@ Loader {
|
|||
root.openStickerPackPopup(root.stickerPack);
|
||||
}
|
||||
|
||||
onResendClicked: {
|
||||
root.messageStore.resendMessage(root.messageId)
|
||||
}
|
||||
|
||||
mouseArea {
|
||||
acceptedButtons: root.activityCenterMessage ? Qt.LeftButton : Qt.RightButton
|
||||
enabled: !root.isChatBlocked &&
|
||||
|
|
|
@ -729,4 +729,11 @@ QtObject {
|
|||
readonly property QtObject walletSection: QtObject {
|
||||
readonly property string cancelledMessage: "cancelled"
|
||||
}
|
||||
|
||||
// Message outgoing status
|
||||
readonly property string sending: "sending"
|
||||
readonly property string sent: "sent"
|
||||
readonly property string delivered: "delivered"
|
||||
readonly property string expired: "expired"
|
||||
readonly property string failedResending: "failedResending"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue