fix: Only `scrollToMessage` when it's available in the database (#11784)

* rename `fetchMessageByMessageId` to `getMessageByMessageId`
* move reply clicking logic to `StatusMessageReply`
* make message found animation faster
* `asyncGetMessageById`
This commit is contained in:
Igor Sirotin 2023-08-07 23:52:04 +03:00 committed by GitHub
parent 9d78e23b68
commit 34dba08b7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 127 additions and 32 deletions

View File

@ -202,9 +202,8 @@ proc belongsToCommunity*(self: Controller): bool =
proc unpinMessage*(self: Controller, messageId: string) =
self.messageService.pinUnpinMessage(self.chatId, messageId, false)
proc getMessageById*(self: Controller, messageId: string):
tuple[message: MessageDto, error: string] =
return self.messageService.fetchMessageByMessageId(self.chatId, messageId)
proc getMessageById*(self: Controller, messageId: string): GetMessageResult =
return self.messageService.getMessageByMessageId(messageId)
proc isUsersListAvailable*(self: Controller): bool =
return self.isUsersListAvailable

View File

@ -1,4 +1,4 @@
import chronicles
import chronicles, uuids
import io_interface
import json
@ -226,6 +226,10 @@ proc init*(self: Controller) =
return
self.delegate.onFirstUnseenMessageLoaded(args.messageId)
self.events.on(SIGNAL_GET_MESSAGE_FINISHED) do(e: Args):
let args = GetMessageResult(e)
self.delegate.onGetMessageById(args.requestId, args.messageId, args.message, args.error)
proc getMySectionId*(self: Controller): string =
return self.sectionId
@ -320,3 +324,6 @@ proc leaveChat*(self: Controller) =
proc resendChatMessage*(self: Controller, messageId: string): string =
return self.messageService.resendChatMessage(messageId)
proc asyncGetMessageById*(self: Controller, messageId: string): UUID =
return self.messageService.asyncGetMessageById(messageId)

View File

@ -1,4 +1,4 @@
import NimQml
import NimQml, uuids
import ../../../../../../app_service/service/message/dto/[message, reaction, pinned_message]
import ../../../../../../app_service/service/community/dto/community
@ -179,3 +179,6 @@ method isFirstUnseenMessageInitialized*(self: AccessInterface): bool {.base.} =
method reevaluateViewLoadingState*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onGetMessageById*(self: AccessInterface, requestId: UUID, messageId: string, message: MessageDto, error: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,4 +1,4 @@
import NimQml, chronicles, sequtils
import NimQml, chronicles, sequtils, uuids
import io_interface
import ../io_interface as delegate_interface
import view, controller
@ -41,6 +41,7 @@ type
moduleLoaded: bool
initialMessagesLoaded: bool
firstUnseenMessageState: FirstUnseenMessageState
getMessageRequestId: UUID
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, sectionId: string, chatId: string,
belongsToCommunity: bool, contactService: contact_service.Service, communityService: community_service.Service,
@ -661,13 +662,25 @@ proc switchToMessage*(self: Module, messageId: string) =
self.controller.setSearchedMessageId(messageId)
method scrollToMessage*(self: Module, messageId: string) =
if(messageId == ""):
if messageId == "":
return
if(self.view.getMessageSearchOngoing()):
if self.view.getMessageSearchOngoing():
return
self.getMessageRequestId = self.controller.asyncGetMessageById(messageId)
self.view.setMessageSearchOngoing(true)
method onGetMessageById*(self: Module, requestId: UUID, messageId: string, message: MessageDto, errorMessage: string) =
if self.getMessageRequestId != requestId:
return
if errorMessage != "":
error "attempted to scroll to a not fetched message", errorMessage, messageId, chatId = self.controller.getMyChatId()
self.view.setMessageSearchOngoing(false)
return
self.controller.setSearchedMessageId(messageId)
self.checkIfMessageLoadedAndScrollToItIfItIs()
self.reevaluateViewLoadingState()

View File

@ -248,8 +248,10 @@ method onUnpinMessage*(self: Module, messageId: string) =
method onPinMessage*(self: Module, messageId: string, actionInitiatedBy: string) =
var item: pinned_msg_item.Item
let (message, err) = self.controller.getMessageById(messageId)
if(err.len > 0 or not self.buildPinnedMessageItem(message, actionInitiatedBy, item)):
let response = self.controller.getMessageById(messageId)
if response.error.len > 0:
return
if not self.buildPinnedMessageItem(response.message, actionInitiatedBy, item):
return
self.view.pinnedModel().insertItemBasedOnClock(item)

View File

@ -1,4 +1,4 @@
import std/uri
import std/uri, uuids
include ../../common/json_utils
include ../../../app/core/tasks/common
@ -312,3 +312,35 @@ const asyncUnfurlUrlsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
"requestedUrls": %*arg.urls
}
arg.finish(output)
#################################################
# Async get message by id
#################################################
type
AsyncGetMessageByMessageIdTaskArg = ref object of QObjectTaskArg
requestId*: string
messageId*: string
const asyncGetMessageByMessageIdTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetMessageByMessageIdTaskArg](argEncoded)
try:
let response = status_go.getMessageByMessageId(arg.messageId)
let output = %*{
"error": (if response.error != nil: response.error.message else: ""),
"message": response.result,
"requestId": arg.requestId,
"messageId": arg.messageId,
}
arg.finish(output)
except Exception as e:
error "asyncGetMessageByMessageIdTask failed", message = e.msg
let output = %*{
"error": e.msg,
"message": "",
"requestId": arg.requestId,
"messageId": arg.messageId,
}
arg.finish(output)

View File

@ -1,4 +1,4 @@
import NimQml, tables, json, re, sequtils, strformat, strutils, chronicles, times, oids
import NimQml, tables, json, re, sequtils, strformat, strutils, chronicles, times, oids, uuids
import ../../../app/core/tasks/[qt, threadpool]
import ../../../app/core/signals/types
@ -60,6 +60,7 @@ const SIGNAL_ENVELOPE_EXPIRED* = "envelopeExpired"
const SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED* = "messageLinkPreviewDataLoaded"
const SIGNAL_RELOAD_MESSAGES* = "reloadMessages"
const SIGNAL_URLS_UNFURLED* = "urlsUnfurled"
const SIGNAL_GET_MESSAGE_FINISHED* = "getMessageFinished"
include async_tasks
@ -133,6 +134,12 @@ type
chatId*: string
messageId*: string
GetMessageResult* = ref object of Args
requestId*: UUID
messageId*: string
message*: MessageDto
error*: string
QtObject:
type Service* = ref object of QObject
events: EventEmitter
@ -563,19 +570,54 @@ QtObject:
except Exception as e:
error "error: ", procName="pinUnpinMessage", errName = e.name, errDesription = e.msg
proc fetchMessageByMessageId*(self: Service, chatId: string, messageId: string):
tuple[message: MessageDto, error: string] =
proc getMessageByMessageId*(self: Service, messageId: string): GetMessageResult =
try:
let msgResponse = status_go.fetchMessageByMessageId(messageId)
if(msgResponse.error.isNil):
let msgResponse = status_go.getMessageByMessageId(messageId)
if msgResponse.error.isNil:
result.message = msgResponse.result.toMessageDto()
if(result.message.id.len == 0):
if result.message.id.len == 0:
result.error = "message with id: " & messageId & " doesn't exist"
return
except Exception as e:
result.error = e.msg
error "error: ", procName="fetchMessageByMessageId", errName = e.name, errDesription = e.msg
error "error: ", procName="getMessageByMessageId", errName = e.name, errDesription = e.msg
proc onAsyncGetMessageById*(self: Service, response: string) {.slot.} =
try:
let responseObj = response.parseJson
if responseObj.kind != JObject:
raise newException(RpcException, "getMessageById response is not an json object")
var signalData = GetMessageResult(
requestId: parseUUID(responseObj["requestId"].getStr),
messageId: responseObj["messageId"].getStr,
error: responseObj["error"].getStr,
)
if signalData.error == "":
signalData.message = responseObj["message"].toMessageDto()
if signalData.message.id.len == 0:
signalData.error = "message doesn't exist"
self.events.emit(SIGNAL_GET_MESSAGE_FINISHED, signalData)
except Exception as e:
error "response processing failed", procName="asyncGetMessageByMessageId", errName = e.name, errDesription = e.msg
self.events.emit(SIGNAL_GET_MESSAGE_FINISHED, GetMessageResult( error: e.msg ))
proc asyncGetMessageById*(self: Service, messageId: string): UUID =
let requestId = genUUID()
let arg = AsyncGetMessageByMessageIdTaskArg(
tptr: cast[ByteAddress](asyncGetMessageByMessageIdTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncGetMessageById",
requestId: $requestId,
messageId: messageId,
)
self.threadpool.start(arg)
return requestId
proc finishAsyncSearchMessagesWithError*(self: Service, chatId, errorMessage: string) =
error "error: ", procName="onAsyncSearchMessages", errDescription = errorMessage

View File

@ -32,7 +32,7 @@ proc pinUnpinMessage*(chatId: string, messageId: string, pin: bool): RpcResponse
}]
result = callPrivateRPC("sendPinMessage".prefix, payload)
proc fetchMessageByMessageId*(messageId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
proc getMessageByMessageId*(messageId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [messageId]
result = callPrivateRPC("messageByMessageID".prefix, payload)

View File

@ -89,7 +89,7 @@ Control {
signal activeChanged(string messageId, bool active)
function startMessageFoundAnimation() {
messageFoundAnimation.start();
messageFoundAnimation.restart();
}
onMessageAttachmentsChanged: {
@ -133,14 +133,11 @@ Control {
SequentialAnimation {
id: messageFoundAnimation
PauseAnimation {
duration: 600
}
NumberAnimation {
target: highlightRect
property: "opacity"
to: 1.0
duration: 1500
duration: 250
}
PauseAnimation {
duration: 1000

View File

@ -12,6 +12,7 @@ QtObject {
property string messageText: ""
property string messageContent: ""
property string messageOriginInfo: ""
property bool messageDeleted: false
property var album: []
property int albumCount: 0
}

View File

@ -174,8 +174,9 @@ Item {
MouseArea {
anchors.fill: parent
enabled: !root.replyDetails.messageDeleted && root.replyDetails.sender.id
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
root.messageClicked(mouse)
}

View File

@ -115,7 +115,7 @@ MembersSelectorBase {
if (root.model.count === 0 && !hasPendingContactRequest) {
// List is empty and not a contact yet. Open the contact request popup
// If `displayName` is not undefiend and not empty,
// If `displayName` is not undefined and not empty,
// then we open the popup with given `contactData`, which probably came from URL.
if (contactData.displayName) {
// Open contact request if we have data from url

View File

@ -576,8 +576,7 @@ Loader {
}
onReplyMessageClicked: {
if (!root.quotedMessageDeleted && root.quotedMessageFrom)
root.messageStore.messageModule.jumpToMessage(root.responseToMessageWithId)
root.messageStore.messageModule.jumpToMessage(root.responseToMessageWithId)
}
onSenderNameClicked: {
@ -679,14 +678,13 @@ Loader {
}
messageText: {
if (root.quotedMessageDeleted) {
if (messageDeleted)
return qsTr("Message deleted")
}
if (!root.quotedMessageText && !root.quotedMessageFrom) {
if (!root.quotedMessageText && !root.quotedMessageFrom)
return qsTr("Unknown message. Try fetching more messages")
}
return root.quotedMessageText
}
messageDeleted: root.quotedMessageDeleted
contentType: d.convertContentType(root.quotedMessageContentType)
amISender: root.quotedMessageFrom === userProfile.pubKey
sender.id: root.quotedMessageFrom