refactor(@desktop/chat-messages): load more messages

- load more messages on scroll up for chat/channel added
- sending messages improved in terms of adding new messages to
appropriate position
- scroll to message added on the qml side
- qml connected to the sending message success/failed signals
This commit is contained in:
Sale Djenic 2021-12-22 13:00:44 +01:00 committed by Sale Djenic
parent 0eb40287fa
commit 16a33f8fa7
14 changed files with 348 additions and 174 deletions

View File

@ -56,7 +56,13 @@ method init*(self: Controller) =
let args = MessageSendingSuccess(e)
if(self.chatId != args.chat.id):
return
self.delegate.newMessagesLoaded(@[args.message], @[], @[])
self.delegate.onSendingMessageSuccess(args.message)
self.events.on(SIGNAL_SENDING_FAILED) do(e:Args):
let args = ChatArgs(e)
if(self.chatId != args.chatId):
return
self.delegate.onSendingMessageError()
self.events.on(SIGNAL_MESSAGE_PINNED) do(e:Args):
let args = MessagePinUnpinArgs(e)
@ -100,6 +106,9 @@ method getOneToOneChatNameAndImage*(self: Controller): tuple[name: string, image
method belongsToCommunity*(self: Controller): bool =
return self.belongsToCommunity
method loadMoreMessages*(self: Controller) =
self.messageService.asyncLoadMoreMessagesForChat(self.chatId)
method addReaction*(self: Controller, messageId: string, emojiId: int) =
self.messageService.addReaction(self.chatId, messageId, emojiId)

View File

@ -31,6 +31,9 @@ method getOneToOneChatNameAndImage*(self: AccessInterface): tuple[name: string,
method belongsToCommunity*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method loadMoreMessages*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method addReaction*(self: AccessInterface, messageId: string, emojiId: int) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -81,44 +81,73 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
pinnedMessages: seq[PinnedMessageDto]) =
var viewItems: seq[Item]
for m in messages:
let sender = self.controller.getContactById(m.`from`)
let senderDisplayName = sender.userNameOrAlias()
let amISender = m.`from` == singletonInstance.userProfile.getPubKey()
var senderIcon = sender.identicon
var isSenderIconIdenticon = sender.identicon.len > 0
if(sender.image.thumbnail.len > 0):
senderIcon = sender.image.thumbnail
isSenderIconIdenticon = false
if(messages.len > 0):
for m in messages:
let sender = self.controller.getContactById(m.`from`)
let senderDisplayName = sender.userNameOrAlias()
let amISender = m.`from` == singletonInstance.userProfile.getPubKey()
var senderIcon = sender.identicon
var isSenderIconIdenticon = sender.identicon.len > 0
if(sender.image.thumbnail.len > 0):
senderIcon = sender.image.thumbnail
isSenderIconIdenticon = false
var item = initItem(m.id, m.responseTo, m.`from`, senderDisplayName, sender.localNickname, senderIcon,
isSenderIconIdenticon, amISender, m.outgoingStatus, m.text, m.image, m.seen, m.timestamp, m.contentType.ContentType,
m.messageType)
var item = initItem(m.id, m.responseTo, m.`from`, senderDisplayName, sender.localNickname, senderIcon,
isSenderIconIdenticon, amISender, m.outgoingStatus, m.text, m.image, m.seen, m.timestamp, m.contentType.ContentType,
m.messageType)
for r in reactions:
if(r.messageId == m.id):
var emojiIdAsEnum: EmojiId
if(message_reaction_item.toEmojiIdAsEnum(r.emojiId, emojiIdAsEnum)):
let userWhoAddedThisReaction = self.controller.getContactById(r.`from`)
let didIReactWithThisEmoji = userWhoAddedThisReaction.id == singletonInstance.userProfile.getPubKey()
item.addReaction(emojiIdAsEnum, didIReactWithThisEmoji, userWhoAddedThisReaction.id,
userWhoAddedThisReaction.userNameOrAlias(), r.id)
else:
error "wrong emoji id found when loading messages"
for r in reactions:
if(r.messageId == m.id):
var emojiIdAsEnum: EmojiId
if(message_reaction_item.toEmojiIdAsEnum(r.emojiId, emojiIdAsEnum)):
let userWhoAddedThisReaction = self.controller.getContactById(r.`from`)
let didIReactWithThisEmoji = userWhoAddedThisReaction.id == singletonInstance.userProfile.getPubKey()
item.addReaction(emojiIdAsEnum, didIReactWithThisEmoji, userWhoAddedThisReaction.id,
userWhoAddedThisReaction.userNameOrAlias(), r.id)
else:
error "wrong emoji id found when loading messages"
for p in pinnedMessages:
if(p.message.id == m.id):
item.pinned = true
for p in pinnedMessages:
if(p.message.id == m.id):
item.pinned = true
# messages are sorted from the most recent to the least recent one
viewItems.add(item)
# messages are sorted from the most recent to the least recent one
viewItems.add(item)
# ChatIdentifier message will be always the first message (the oldest one)
viewItems.add(self.createChatIdentifierItem())
# Delete the old ChatIdentifier message first
self.view.model().removeItem(CHAT_IDENTIFIER_MESSAGE_ID)
# Add new loaded messages
self.view.model().prependItems(viewItems)
# ChatIdentifier message will be always the first message (the oldest one)
viewItems.add(self.createChatIdentifierItem())
# Delete the old ChatIdentifier message first
self.view.model().removeItem(CHAT_IDENTIFIER_MESSAGE_ID)
# Add new loaded messages
self.view.model().appendItems(viewItems)
if(not self.view.getInitialMessagesLoaded()):
self.view.initialMessagesAreLoaded()
self.view.setLoadingHistoryMessagesInProgress(false)
method onSendingMessageSuccess*(self: Module, message: MessageDto) =
let sender = self.controller.getContactById(message.`from`)
let senderDisplayName = sender.userNameOrAlias()
let amISender = message.`from` == singletonInstance.userProfile.getPubKey()
var senderIcon = sender.identicon
var isSenderIconIdenticon = sender.identicon.len > 0
if(sender.image.thumbnail.len > 0):
senderIcon = sender.image.thumbnail
isSenderIconIdenticon = false
var item = initItem(message.id, message.responseTo, message.`from`, senderDisplayName, sender.localNickname,
senderIcon, isSenderIconIdenticon, amISender, message.outgoingStatus, message.text, message.image, message.seen,
message.timestamp, message.contentType.ContentType, message.messageType)
self.view.model().prependItem(item)
self.view.emitSendingMessageSuccessSignal()
method onSendingMessageError*(self: Module) =
self.view.emitSendingMessageErrorSignal()
method loadMoreMessages*(self: Module) =
self.controller.loadMoreMessages()
method toggleReaction*(self: Module, messageId: string, emojiId: int) =
var emojiIdAsEnum: EmojiId

View File

@ -11,4 +11,10 @@ method onReactionRemoved*(self: AccessInterface, messageId: string, emojiId: int
raise newException(ValueError, "No implementation available")
method onPinUnpinMessage*(self: AccessInterface, messageId: string, pin: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method onSendingMessageSuccess*(self: AccessInterface, message: MessageDto) {.base.} =
raise newException(ValueError, "No implementation available")
method onSendingMessageError*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,6 +1,9 @@
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method loadMoreMessages*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method toggleReaction*(self: AccessInterface, messageId: string, emojiId: int) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -8,6 +8,8 @@ QtObject:
delegate: io_interface.AccessInterface
model: Model
modelVariant: QVariant
initialMessagesLoaded: bool
loadingHistoryMessagesInProgress: bool
proc delete*(self: View) =
self.model.delete
@ -20,6 +22,8 @@ QtObject:
result.delegate = delegate
result.model = newModel()
result.modelVariant = newQVariant(result.model)
result.initialMessagesLoaded = false
result.loadingHistoryMessagesInProgress = false
proc load*(self: View) =
self.delegate.viewDidLoad()
@ -29,7 +33,6 @@ QtObject:
proc getModel(self: View): QVariant {.slot.} =
return self.modelVariant
QtProperty[QVariant] model:
read = getModel
@ -64,4 +67,42 @@ QtObject:
return self.delegate.amIChatAdmin()
proc getNumberOfPinnedMessages*(self: View): int {.slot.} =
return self.delegate.getNumberOfPinnedMessages()
return self.delegate.getNumberOfPinnedMessages()
proc initialMessagesLoadedChanged*(self: View) {.signal.}
proc getInitialMessagesLoaded*(self: View): bool {.slot.} =
return self.initialMessagesLoaded
QtProperty[bool] initialMessagesLoaded:
read = getInitialMessagesLoaded
notify = initialMessagesLoadedChanged
proc initialMessagesAreLoaded*(self: View) = # this is not a slot
if (self.initialMessagesLoaded):
return
self.initialMessagesLoaded = true
self.initialMessagesLoadedChanged()
proc loadingHistoryMessagesInProgressChanged*(self: View) {.signal.}
proc getLoadingHistoryMessagesInProgress*(self: View): bool {.slot.} =
return self.loadingHistoryMessagesInProgress
QtProperty[bool] loadingHistoryMessagesInProgress:
read = getLoadingHistoryMessagesInProgress
notify = loadingHistoryMessagesInProgressChanged
proc setLoadingHistoryMessagesInProgress*(self: View, value: bool) = # this is not a slot
if (value == self.loadingHistoryMessagesInProgress):
return
self.loadingHistoryMessagesInProgress = value
self.loadingHistoryMessagesInProgressChanged()
proc loadMoreMessages*(self: View) {.slot.} =
self.setLoadingHistoryMessagesInProgress(true)
self.delegate.loadMoreMessages()
proc messageSuccessfullySent*(self: View) {.signal.}
proc emitSendingMessageSuccessSignal*(self: View) =
self.messageSuccessfullySent()
proc sendingMessageFailed*(self: View) {.signal.}
proc emitSendingMessageErrorSignal*(self: View) =
self.sendingMessageFailed()

View File

@ -173,6 +173,8 @@ method newPinnedMessagesLoaded*(self: Module, pinnedMessages: seq[PinnedMessageD
viewItems = item & viewItems # messages are sorted from the most recent to the least recent one
if(viewItems.len == 0):
return
self.view.pinnedModel().prependItems(viewItems)
method unpinMessage*(self: Module, messageId: string) =

View File

@ -1,4 +1,4 @@
import Tables, json, strformat
import json, strformat
import ../../../app_service/common/types
export types.ContentType

View File

@ -158,6 +158,20 @@ QtObject:
self.endInsertRows()
self.countChanged()
proc appendItems*(self: Model, items: seq[Item]) =
if(items.len == 0):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
let first = self.items.len
let last = first + items.len - 1
self.beginInsertRows(parentModelIndex, first, last)
self.items.add(items)
self.endInsertRows()
self.countChanged()
proc appendItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
@ -167,6 +181,15 @@ QtObject:
self.endInsertRows()
self.countChanged()
proc prependItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, 0, 0)
self.items.insert(item, 0)
self.endInsertRows()
self.countChanged()
proc removeItem*(self: Model, messageId: string) =
let ind = self.findIndexForMessageId(messageId)
if(ind == -1):

View File

@ -111,8 +111,8 @@ QtObject:
proc processMessageUpdateAfterSend*(self: Service, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto]) =
result = self.parseChatResponse(response)
var (chats, messages) = result
if chats.len == 0 and messages.len == 0:
self.events.emit(SIGNAL_SENDING_FAILED, Args())
if chats.len == 0 or messages.len == 0:
error "no chats or messages in the parsed response"
return
# This fixes issue#3490
@ -251,7 +251,9 @@ QtObject:
preferredUsername,
communityId)
discard self.processMessageUpdateAfterSend(response)
let (chats, messages) = self.processMessageUpdateAfterSend(response)
if chats.len == 0 or messages.len == 0:
self.events.emit(SIGNAL_SENDING_FAILED, ChatArgs(chatId: chatId))
except Exception as e:
error "Error sending message", msg = e.msg

View File

@ -14,34 +14,37 @@ type
const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncFetchChatMessagesTaskArg](argEncoded)
var responseJson = %*{
"chatId": arg.chatId
}
# handle messages
var messagesArr: JsonNode
var messagesCursor: string
let msgsResponse = status_go.fetchMessages(arg.chatId, arg.msgCursor, arg.limit)
discard msgsResponse.result.getProp("cursor", messagesCursor)
discard msgsResponse.result.getProp("messages", messagesArr)
if(arg.msgCursor != CURSOR_VALUE_IGNORE):
var messagesArr: JsonNode
var messagesCursor: JsonNode
let msgsResponse = status_go.fetchMessages(arg.chatId, arg.msgCursor, arg.limit)
discard msgsResponse.result.getProp("cursor", messagesCursor)
discard msgsResponse.result.getProp("messages", messagesArr)
responseJson["messages"] = messagesArr
responseJson["messagesCursor"] = messagesCursor
# handle pinned messages
var pinnedMsgArr: JsonNode
var pinnedMsgCursor: string
let pinnedMsgsResponse = status_go.fetchPinnedMessages(arg.chatId, arg.pinnedMsgCursor, arg.limit)
discard pinnedMsgsResponse.result.getProp("cursor", pinnedMsgCursor)
discard pinnedMsgsResponse.result.getProp("pinnedMessages", pinnedMsgArr)
if(arg.pinnedMsgCursor != CURSOR_VALUE_IGNORE):
var pinnedMsgArr: JsonNode
var pinnedMsgCursor: JsonNode
let pinnedMsgsResponse = status_go.fetchPinnedMessages(arg.chatId, arg.pinnedMsgCursor, arg.limit)
discard pinnedMsgsResponse.result.getProp("cursor", pinnedMsgCursor)
discard pinnedMsgsResponse.result.getProp("pinnedMessages", pinnedMsgArr)
responseJson["pinnedMessages"] = pinnedMsgArr
responseJson["pinnedMessagesCursor"] = pinnedMsgCursor
# handle reactions
var reactionsArr: JsonNode
# messages and reactions are using the same cursor
let rResponse = status_go.fetchReactions(arg.chatId, arg.msgCursor, arg.limit)
reactionsArr = rResponse.result
let responseJson = %*{
"chatId": arg.chatId,
"messages": messagesArr,
"messagesCursor": messagesCursor,
"pinnedMessages": pinnedMsgArr,
"pinnedMessagesCursor": pinnedMsgCursor,
"reactions": reactionsArr
}
if(arg.msgCursor != CURSOR_VALUE_IGNORE):
# messages and reactions are using the same cursor
var reactionsArr: JsonNode
let rResponse = status_go.fetchReactions(arg.chatId, arg.msgCursor, arg.limit)
reactionsArr = rResponse.result
responseJson["pinnedMessages"] = reactionsArr
arg.finish(responseJson)

View File

@ -13,12 +13,11 @@ export message_dto
export pinned_msg_dto
export reaction_dto
include async_tasks
logScope:
topics = "messages-service"
const MESSAGES_PER_PAGE = 20
const CURSOR_VALUE_IGNORE = "ignore"
# Signals which may be emitted by this service:
const SIGNAL_MESSAGES_LOADED* = "new-messagesLoaded" #Once we are done with refactoring we should remove "new-" from all signals
@ -29,6 +28,8 @@ const SIGNAL_MESSAGES_MARKED_AS_READ* = "new-messagesMarkedAsRead"
const SIGNAL_MESSAGE_REACTION_ADDED* = "new-messageReactionAdded"
const SIGNAL_MESSAGE_REACTION_REMOVED* = "new-messageReactionRemoved"
include async_tasks
type
SearchMessagesLoadedArgs* = ref object of Args
messages*: seq[MessageDto]
@ -59,7 +60,9 @@ QtObject:
events: EventEmitter
threadpool: ThreadPool
msgCursor: Table[string, string]
lastUsedMsgCursor: Table[string, string]
pinnedMsgCursor: Table[string, string]
lastUsedPinnedMsgCursor: Table[string, string]
numOfPinnedMessagesPerChat: Table[string, int] # [chat_id, num_of_pinned_messages]
proc delete*(self: Service) =
@ -71,7 +74,9 @@ QtObject:
result.events = events
result.threadpool = threadpool
result.msgCursor = initTable[string, string]()
result.lastUsedMsgCursor = initTable[string, string]()
result.pinnedMsgCursor = initTable[string, string]()
result.lastUsedPinnedMsgCursor = initTable[string, string]()
proc initialMessagesFetched(self: Service, chatId: string): bool =
return self.msgCursor.hasKey(chatId)
@ -99,11 +104,18 @@ QtObject:
var chatId: string
discard responseObj.getProp("chatId", chatId)
# this is important case we don't want to fetch the same messages multiple times.
self.lastUsedMsgCursor[chatId] = self.msgCursor[chatId]
self.lastUsedPinnedMsgCursor[chatId] = self.pinnedMsgCursor[chatId]
# handling messages
var msgCursor: string
if(responseObj.getProp("messagesCursor", msgCursor)):
self.msgCursor[chatId] = msgCursor
if(msgCursor.len > 0):
self.msgCursor[chatId] = msgCursor
else:
self.msgCursor[chatId] = self.lastUsedMsgCursor[chatId]
var messagesArr: JsonNode
var messages: seq[MessageDto]
@ -113,7 +125,10 @@ QtObject:
# handling pinned messages
var pinnedMsgCursor: string
if(responseObj.getProp("pinnedMessagesCursor", pinnedMsgCursor)):
self.pinnedMsgCursor[chatId] = pinnedMsgCursor
if(pinnedMsgCursor.len > 0):
self.pinnedMsgCursor[chatId] = pinnedMsgCursor
else:
self.pinnedMsgCursor[chatId] = self.lastUsedPinnedMsgCursor[chatId]
var pinnedMsgArr: JsonNode
var pinnedMessages: seq[PinnedMessageDto]
@ -142,13 +157,27 @@ QtObject:
error "empty chat id", methodName="asyncLoadMoreMessagesForChat"
return
var msgCursor = self.getCurrentMessageCursor(chatId)
if(self.lastUsedMsgCursor.hasKey(chatId) and msgCursor == self.lastUsedMsgCursor[chatId]):
msgCursor = CURSOR_VALUE_IGNORE
var pinnedMsgCursor = self.getCurrentPinnedMessageCursor(chatId)
if(self.lastUsedPinnedMsgCursor.hasKey(chatId) and pinnedMsgCursor == self.lastUsedPinnedMsgCursor[chatId]):
pinnedMsgCursor = CURSOR_VALUE_IGNORE
if(msgCursor == CURSOR_VALUE_IGNORE and pinnedMsgCursor == CURSOR_VALUE_IGNORE):
# it's important to emit signal in case we are not fetching messages, so we can update the view appropriatelly.
let data = MessagesLoadedArgs(chatId: chatId)
self.events.emit(SIGNAL_MESSAGES_LOADED, data)
return
let arg = AsyncFetchChatMessagesTaskArg(
tptr: cast[ByteAddress](asyncFetchChatMessagesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncLoadMoreMessagesForChat",
chatId: chatId,
msgCursor: self.getCurrentMessageCursor(chatId),
pinnedMsgCursor: self.getCurrentPinnedMessageCursor(chatId),
msgCursor: msgCursor,
pinnedMsgCursor: pinnedMsgCursor,
limit: MESSAGES_PER_PAGE
)

View File

@ -5,6 +5,16 @@ QtObject {
id: root
property var messageModule
property var messagesModel: messageModule.model
function loadMoreMessages () {
if(!messageModule)
return
if(!messageModule.initialMessagesLoaded || messageModule.loadingHistoryMessagesInProgress)
return
messageModule.loadMoreMessages()
}
function getMessageByIdAsJson (id) {
if(!messageModule)

View File

@ -36,9 +36,33 @@ Item {
property int countOnStartUp: 0
signal openStickerPackPopup(string stickerPackId)
Item {
id: loadingMessagesIndicator
visible: messageStore.messageModule.loadingHistoryMessagesInProgress
anchors.top: parent.top
anchors.left: parent.left
height: visible? 20 : 0
width: parent.width
Loader {
active: messageStore.messageModule.loadingHistoryMessagesInProgress
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
sourceComponent: Component {
LoadingAnimation {
width: 18
height: 18
}
}
}
}
ListView {
id: chatLogView
anchors.fill: parent
anchors.top: loadingMessagesIndicator.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
boundsBehavior: Flickable.StopAtBounds
clip: true
@ -92,9 +116,9 @@ Item {
// }
// }
// ScrollBar.vertical: ScrollBar {
// visible: chatLogView.visibleArea.heightRatio < 1
// }
ScrollBar.vertical: ScrollBar {
visible: chatLogView.visibleArea.heightRatio < 1
}
// Connections {
// id: contentHeightConnection
@ -112,80 +136,79 @@ Item {
id: timer
}
// Button {
// readonly property int buttonPadding: 5
Button {
readonly property int buttonPadding: 5
// id: scrollDownButton
// visible: false
// height: 32
// width: nbMessages.width + arrowImage.width + 2 * Style.current.halfPadding + (nbMessages.visible ? scrollDownButton.buttonPadding : 0)
// anchors.bottom: parent.bottom
// anchors.right: parent.right
// anchors.rightMargin: Style.current.padding
// background: Rectangle {
// color: Style.current.buttonSecondaryColor
// border.width: 0
// radius: 16
// }
// onClicked: {
// newMessages = 0
// scrollDownButton.visible = false
// chatLogView.scrollToBottom(true)
// }
id: scrollDownButton
visible: false
height: 32
width: nbMessages.width + arrowImage.width + 2 * Style.current.halfPadding + (nbMessages.visible ? scrollDownButton.buttonPadding : 0)
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
background: Rectangle {
color: Style.current.buttonSecondaryColor
border.width: 0
radius: 16
}
onClicked: {
newMessages = 0
scrollDownButton.visible = false
chatLogView.scrollToBottom(true)
}
// StyledText {
// id: nbMessages
// visible: newMessages > 0
// width: visible ? implicitWidth : 0
// text: newMessages
// anchors.verticalCenter: parent.verticalCenter
// anchors.left: parent.left
// color: Style.current.pillButtonTextColor
// font.pixelSize: 15
// anchors.leftMargin: Style.current.halfPadding
// }
StyledText {
id: nbMessages
visible: newMessages > 0
width: visible ? implicitWidth : 0
text: newMessages
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
color: Style.current.pillButtonTextColor
font.pixelSize: 15
anchors.leftMargin: Style.current.halfPadding
}
// SVGImage {
// id: arrowImage
// width: 24
// height: 24
// anchors.verticalCenter: parent.verticalCenter
// anchors.left: nbMessages.right
// source: Style.svg("leave_chat")
// anchors.leftMargin: nbMessages.visible ? scrollDownButton.buttonPadding : 0
// rotation: -90
SVGImage {
id: arrowImage
width: 24
height: 24
anchors.verticalCenter: parent.verticalCenter
anchors.left: nbMessages.right
source: Style.svg("leave_chat")
anchors.leftMargin: nbMessages.visible ? scrollDownButton.buttonPadding : 0
rotation: -90
// ColorOverlay {
// anchors.fill: parent
// source: parent
// color: Style.current.pillButtonTextColor
// }
// }
ColorOverlay {
anchors.fill: parent
source: parent
color: Style.current.pillButtonTextColor
}
}
// MouseArea {
// cursorShape: Qt.PointingHandCursor
// anchors.fill: parent
// onPressed: mouse.accepted = false
// }
// }
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onPressed: mouse.accepted = false
}
}
function scrollToBottom(force, caller) {
// Not Refactored Yet
// if (!force && !chatLogView.atYEnd) {
// // User has scrolled up, we don't want to scroll back
// return false
// }
// if (caller && caller !== chatLogView.itemAtIndex(chatLogView.count - 1)) {
// // If we have a caller, only accept its request if it's the last message
// return false
// }
// // Call this twice and with a timer since the first scroll to bottom might have happened before some stuff loads
// // meaning that the scroll will not actually be at the bottom on switch
// // Add a small delay because images, even though they say they say they are loaed, they aren't shown yet
// Qt.callLater(chatLogView.positionViewAtBeginning)
// timer.setTimeout(function() {
// Qt.callLater(chatLogView.positionViewAtBeginning)
// }, 100);
if (!force && !chatLogView.atYEnd) {
// User has scrolled up, we don't want to scroll back
return false
}
if (caller && caller !== chatLogView.itemAtIndex(chatLogView.count - 1)) {
// If we have a caller, only accept its request if it's the last message
return false
}
// Call this twice and with a timer since the first scroll to bottom might have happened before some stuff loads
// meaning that the scroll will not actually be at the bottom on switch
// Add a small delay because images, even though they say they say they are loaed, they aren't shown yet
Qt.callLater(chatLogView.positionViewAtBeginning)
timer.setTimeout(function() {
Qt.callLater(chatLogView.positionViewAtBeginning)
}, 100);
return true
}
@ -198,24 +221,24 @@ Item {
// }
// }
// Connections {
// Not Refactored Yet
// target: root.store.chatsModelInst.messageView
Connections {
target: messageStore.messageModule
// onSendingMessageSuccess: {
// chatLogView.scrollToBottom(true)
// }
onMessageSuccessfullySent: {
chatLogView.scrollToBottom(true)
}
// onSendingMessageFailed: {
// sendingMsgFailedPopup.open();
// }
onSendingMessageFailed: {
sendingMsgFailedPopup.open();
}
// Not Refactored Yet
// onNewMessagePushed: {
// if (!chatLogView.scrollToBottom()) {
// newMessages++
// }
// }
// }
}
// Connections {
// Not Refactored Yet
@ -274,24 +297,15 @@ Item {
// }
// }
// Not Refactored Yet
// property var loadMsgs : Backpressure.oneInTime(chatLogView, 500, function() {
// if(!messages.initialMessagesLoaded || messages.loadingHistoryMessages)
// return
onContentYChanged: {
scrollDownButton.visible = contentHeight - (scrollY + height) > 400
let loadMore = scrollDownButton.visible && scrollY < 500
if(loadMore){
messageStore.loadMoreMessages()
}
}
// root.store.chatsModelInst.messageView.loadMoreMessages(chatId);
// });
// onContentYChanged: {
// scrollDownButton.visible = (contentHeight - (scrollY + height) > 400)
// if(scrollDownButton.visible && scrollY < 500){
// loadMsgs();
// }
// }
model: messageStore.messageModule.model
section.property: "sectionIdentifier"
section.criteria: ViewSection.FullString
model: messageStore.messagesModel
// Not Refactored Yet
//Component.onCompleted: scrollToBottom(true)
@ -330,11 +344,11 @@ Item {
}
}
// MessageDialog {
// id: sendingMsgFailedPopup
// standardButtons: StandardButton.Ok
// //% "Failed to send message."
// text: qsTrId("failed-to-send-message-")
// icon: StandardIcon.Critical
// }
MessageDialog {
id: sendingMsgFailedPopup
standardButtons: StandardButton.Ok
//% "Failed to send message."
text: qsTrId("failed-to-send-message-")
icon: StandardIcon.Critical
}
}