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:
Jonathan Rainville 2022-12-08 16:01:08 -05:00
parent 59a05243af
commit 194e3048bc
17 changed files with 126 additions and 28 deletions

View File

@ -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*(

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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.} =

View File

@ -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)

View File

@ -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

View File

@ -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}"

View File

@ -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])

View File

@ -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

View File

@ -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
}
}
}

View File

@ -210,19 +210,19 @@ QtObject {
function requestMoreMessages() {
if(!messageModule)
return
return messageModule.requestMoreMessages();
return messageModule.requestMoreMessages()
}
function fillGaps(messageId) {
if(!messageModule)
if(!messageModule)
return
return messageModule.fillGaps(messageId);
return messageModule.fillGaps(messageId)
}
function leaveChat() {
if(!messageModule)
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)
}
}

View File

@ -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

View File

@ -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 &&

View File

@ -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"
}