Use section identifiers as a way to identify if messages have been sent by the current user (no need to modify the model with `repeatMessageInfo`)

This commit is contained in:
Richard Ramos 2020-06-05 18:20:45 -04:00 committed by Iuri Matias
parent 4fe6d9b767
commit 9d75f6f552
7 changed files with 68 additions and 45 deletions

View File

@ -31,15 +31,14 @@ proc delete*(self: ChatController) =
proc handleChatEvents(self: ChatController) = proc handleChatEvents(self: ChatController) =
# Display already saved messages # Display already saved messages
self.status.events.on("messagesLoaded") do(e:Args): self.status.events.on("messagesLoaded") do(e:Args):
for message in MsgsLoadedArgs(e).messages: self.view.pushMessages(MsgsLoadedArgs(e).messages)
self.view.pushMessage(message.chatId, message.toChatMessage())
self.status.events.on("messageSent") do(e: Args): self.status.events.on("messageSent") do(e: Args):
var sentMessage = MsgArgs(e) var sentMessage = MsgArgs(e)
var chatMessage = sentMessage.payload.toChatMessage() var chatMessage = sentMessage.payload.toChatMessage()
chatMessage.message = sentMessage.message chatMessage.message = sentMessage.message
chatMessage.isCurrentUser = true chatMessage.isCurrentUser = true
self.view.pushMessage(sentMessage.chatId, chatMessage) self.view.pushMessage(chatMessage)
self.status.events.on("channelJoined") do(e: Args): self.status.events.on("channelJoined") do(e: Args):
var channelMessage = ChannelArgs(e) var channelMessage = ChannelArgs(e)
@ -69,13 +68,10 @@ proc init*(self: ChatController) =
self.status.mailservers.init() self.status.mailservers.init()
self.status.chat.init() self.status.chat.init()
proc handleMessage(self: ChatController, data: MessageSignal) = proc handleMessage(self: ChatController, data: MessageSignal) =
for c in data.chats: for c in data.chats:
self.view.updateChat(c.toChatItem()) self.view.updateChat(c.toChatItem())
self.view.pushMessages(data.messages)
for message in data.messages:
self.view.pushMessage(message.localChatId, message.toChatMessage())
proc handleDiscoverySummary(self: ChatController, data: DiscoverySummarySignal) = proc handleDiscoverySummary(self: ChatController, data: DiscoverySummarySignal) =
## Handle mailserver peers being added and removed ## Handle mailserver peers being added and removed

View File

@ -50,6 +50,7 @@ QtObject:
let selectedChannel = self.chats.getChannel(index) let selectedChannel = self.chats.getChannel(index)
if self.activeChannel.id == selectedChannel.id: return if self.activeChannel.id == selectedChannel.id: return
self.activeChannel.setChatItem(selectedChannel) self.activeChannel.setChatItem(selectedChannel)
self.status.chat.setActiveChannel(selectedChannel.id)
self.activeChannelChanged() self.activeChannelChanged()
proc getActiveChannelIdx(self: ChatsView): QVariant {.slot.} = proc getActiveChannelIdx(self: ChatsView): QVariant {.slot.} =
@ -77,9 +78,14 @@ QtObject:
if not self.messageList.hasKey(channel): if not self.messageList.hasKey(channel):
self.messageList[channel] = newChatMessageList() self.messageList[channel] = newChatMessageList()
proc pushMessage*(self:ChatsView, channel: string, message: ChatMessage) = proc pushMessage*(self:ChatsView, message: ChatMessage) =
self.upsertChannel(channel) self.upsertChannel(message.chatId)
self.messageList[channel].add(message) self.messageList[message.chatId].add(message)
proc pushMessages*(self:ChatsView, messages: seq[Message]) =
for msg in messages:
self.upsertChannel(msg.chatId)
self.messageList[msg.chatId].add(msg.toChatMessage())
proc getMessageList(self: ChatsView): QVariant {.slot.} = proc getMessageList(self: ChatsView): QVariant {.slot.} =
self.upsertChannel(self.activeChannel.id) self.upsertChannel(self.activeChannel.id)

View File

@ -8,11 +8,10 @@ type
Timestamp = UserRole + 3 Timestamp = UserRole + 3
Identicon = UserRole + 4 Identicon = UserRole + 4
IsCurrentUser = UserRole + 5 IsCurrentUser = UserRole + 5
RepeatMessageInfo = UserRole + 6 ContentType = UserRole + 6
ContentType = UserRole + 7 Sticker = UserRole + 7
Sticker = UserRole + 8 FromAuthor = UserRole + 8
FromAuthor = UserRole + 9 Clock = UserRole + 9
Clock = UserRole + 10
QtObject: QtObject:
type type
ChatMessageList* = ref object of QAbstractListModel ChatMessageList* = ref object of QAbstractListModel
@ -41,7 +40,6 @@ QtObject:
if index.row < 0 or index.row >= self.messages.len: if index.row < 0 or index.row >= self.messages.len:
return return
let message = self.messages[index.row] let message = self.messages[index.row]
let repeatMessageInfo = (index.row == 0) or message.fromAuthor != self.messages[index.row - 1].fromAuthor
let chatMessageRole = role.ChatMessageRoles let chatMessageRole = role.ChatMessageRoles
case chatMessageRole: case chatMessageRole:
of ChatMessageRoles.UserName: result = newQVariant(message.userName) of ChatMessageRoles.UserName: result = newQVariant(message.userName)
@ -50,7 +48,6 @@ QtObject:
of ChatMessageRoles.Clock: result = newQVariant($message.clock) of ChatMessageRoles.Clock: result = newQVariant($message.clock)
of ChatMessageRoles.Identicon: result = newQVariant(message.identicon) of ChatMessageRoles.Identicon: result = newQVariant(message.identicon)
of ChatMessageRoles.IsCurrentUser: result = newQVariant(message.isCurrentUser) of ChatMessageRoles.IsCurrentUser: result = newQVariant(message.isCurrentUser)
of ChatMessageRoles.RepeatMessageInfo: result = newQVariant(repeatMessageInfo)
of ChatMessageRoles.ContentType: result = newQVariant(message.contentType) of ChatMessageRoles.ContentType: result = newQVariant(message.contentType)
of ChatMessageRoles.Sticker: result = newQVariant(message.sticker) of ChatMessageRoles.Sticker: result = newQVariant(message.sticker)
of ChatMessageRoles.FromAuthor: result = newQVariant(message.fromAuthor) of ChatMessageRoles.FromAuthor: result = newQVariant(message.fromAuthor)
@ -63,7 +60,6 @@ QtObject:
ChatMessageRoles.Clock.int:"clock", ChatMessageRoles.Clock.int:"clock",
ChatMessageRoles.Identicon.int:"identicon", ChatMessageRoles.Identicon.int:"identicon",
ChatMessageRoles.IsCurrentUser.int:"isCurrentUser", ChatMessageRoles.IsCurrentUser.int:"isCurrentUser",
ChatMessageRoles.RepeatMessageInfo.int:"repeatMessageInfo",
ChatMessageRoles.ContentType.int:"contentType", ChatMessageRoles.ContentType.int:"contentType",
ChatMessageRoles.Sticker.int:"sticker", ChatMessageRoles.Sticker.int:"sticker",
ChatMessageRoles.FromAuthor.int:"fromAuthor" ChatMessageRoles.FromAuthor.int:"fromAuthor"
@ -73,3 +69,10 @@ QtObject:
self.beginInsertRows(newQModelIndex(), self.messages.len, self.messages.len) self.beginInsertRows(newQModelIndex(), self.messages.len, self.messages.len)
self.messages.add(message) self.messages.add(message)
self.endInsertRows() self.endInsertRows()
proc add*(self: ChatMessageList, messages: seq[ChatMessage]) =
self.beginInsertRows(newQModelIndex(), self.messages.len, self.messages.len)
for message in messages:
self.messages.add(message)
self.endInsertRows()

View File

@ -108,6 +108,9 @@ proc leave*(self: ChatModel, chatId: string) =
self.events.emit("channelLeft", ChannelArgs(channel: chatId)) self.events.emit("channelLeft", ChannelArgs(channel: chatId))
self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel())) self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel()))
proc setActiveChannel*(self: ChatModel, chatId: string) =
self.events.emit("activeChannelChanged", ChannelArgs(channel: chatId))
proc sendMessage*(self: ChatModel, chatId: string, msg: string): string = proc sendMessage*(self: ChatModel, chatId: string, msg: string): string =
var sentMessage = status_chat.sendChatMessage(chatId, msg) var sentMessage = status_chat.sendChatMessage(chatId, msg)
var parsedMessage = parseJson(sentMessage)["result"]["chats"][0]["lastMessage"] var parsedMessage = parseJson(sentMessage)["result"]["chats"][0]["lastMessage"]

View File

@ -12,6 +12,7 @@ type ChatMessage* = ref object
isCurrentUser*: bool isCurrentUser*: bool
contentType*: int contentType*: int
sticker*: string sticker*: string
chatId*: string
proc delete*(self: ChatMessage) = proc delete*(self: ChatMessage) =
discard discard
@ -27,9 +28,11 @@ proc newChatMessage*(): ChatMessage =
result.isCurrentUser = false result.isCurrentUser = false
result.contentType = 1 result.contentType = 1
result.sticker = "" result.sticker = ""
result.chatId = ""
proc toChatMessage*(payload: JsonNode): ChatMessage = proc toChatMessage*(payload: JsonNode): ChatMessage =
result = ChatMessage( result = ChatMessage(
chatId: payload["chatId"].str,
userName: payload["alias"].str, userName: payload["alias"].str,
message: payload["text"].str, message: payload["text"].str,
timestamp: $payload["timestamp"], timestamp: $payload["timestamp"],
@ -42,6 +45,7 @@ proc toChatMessage*(payload: JsonNode): ChatMessage =
proc toChatMessage*(message: Message): ChatMessage = proc toChatMessage*(message: Message): ChatMessage =
result = ChatMessage( result = ChatMessage(
chatId: message.chatId,
userName: message.alias, userName: message.alias,
clock: message.clock, clock: message.clock,
fromAuthor: message.fromAuthor, fromAuthor: message.fromAuthor,

View File

@ -22,10 +22,6 @@ ScrollView {
ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
function scrollToBottom(goToBottom) {
chatLogView.positionViewAtEnd();
}
ListView { ListView {
anchors.fill: parent anchors.fill: parent
spacing: 4 spacing: 4
@ -33,26 +29,26 @@ ScrollView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
onCountChanged: { onCountChanged: {
scrollToBottom(); if (!this.atYEnd) {
// User has scrolled up, we don't want to scroll back
return
}
Qt.callLater( chatLogView.positionViewAtEnd )
} }
model: messageListDelegate model: messageListDelegate
section.property: "userName"
section.criteria: ViewSection.FullString
} }
DelegateModel { DelegateModel {
id: messageListDelegate id: messageListDelegate
model: messageList property var lessThan: [
delegate: Message { function(left, right) { return left.clock < right.clock }
userName: model.userName ]
message: model.message
identicon: model.identicon
isCurrentUser: model.isCurrentUser
repeatMessageInfo: model.repeatMessageInfo
timestamp: model.timestamp
sticker: model.sticker
contentType: model.contentType
}
property var lessThan: function(left, right) { return left.clock < right.clock } property int sortOrder: 0
onSortOrderChanged: items.setGroups(0, items.count, "unsorted")
function insertPosition(lessThan, item) { function insertPosition(lessThan, item) {
var lower = 0 var lower = 0
@ -73,23 +69,37 @@ ScrollView {
while (unsortedItems.count > 0) { while (unsortedItems.count > 0) {
var item = unsortedItems.get(0) var item = unsortedItems.get(0)
var index = insertPosition(lessThan, item) var index = insertPosition(lessThan, item)
item.groups = "items" item.groups = "items"
items.move(item.itemsIndex, index) items.move(item.itemsIndex, index)
} }
} }
items.includeByDefault: false items.includeByDefault: false
groups: DelegateModelGroup { groups: DelegateModelGroup {
id: unsortedItems id: unsortedItems
name: "unsorted" name: "unsorted"
includeByDefault: true includeByDefault: true
onChanged: { onChanged: {
messageListDelegate.sort(messageListDelegate.lessThan) if (messageListDelegate.sortOrder == messageListDelegate.lessThan.length)
scrollToBottom(); setGroups(0, count, "items")
else {
messageListDelegate.sort(messageListDelegate.lessThan[messageListDelegate.sortOrder])
}
} }
} }
model: messageList
delegate: Message {
id: msgDelegate
userName: model.userName
message: model.message
identicon: model.identicon
isCurrentUser: model.isCurrentUser
timestamp: model.timestamp
sticker: model.sticker
contentType: model.contentType
authorCurrentMsg: msgDelegate.ListView.section
authorPrevMsg: msgDelegate.ListView.previousSection
}
} }
} }

View File

@ -12,14 +12,15 @@ Item {
property string message: "That's right. We're friends... Of justice, that is." property string message: "That's right. We're friends... Of justice, that is."
property string identicon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" property string identicon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="
property bool isCurrentUser: false property bool isCurrentUser: false
property bool repeatMessageInfo: true
property int timestamp: 1234567 property int timestamp: 1234567
property string sticker: "Qme8vJtyrEHxABcSVGPF95PtozDgUyfr1xGjePmFdZgk9v" property string sticker: "Qme8vJtyrEHxABcSVGPF95PtozDgUyfr1xGjePmFdZgk9v"
property int contentType: 1 // constants don't work in default props property int contentType: 1 // constants don't work in default props
width: parent.width property string authorCurrentMsg: "authorCurrentMsg"
height: contentType == Constants.stickerType ? stickerId.height : (isCurrentUser || (!isCurrentUser && !repeatMessageInfo) ? chatBox.height : 24 + chatBox.height) property string authorPrevMsg: "authorPrevMsg"
width: parent.width
height: contentType == Constants.stickerType ? stickerId.height + 50 : (isCurrentUser || (!isCurrentUser && authorCurrentMsg == authorPrevMsg) ? chatBox.height : 24 + chatBox.height)
ProfilePopup { ProfilePopup {
id: profilePopup id: profilePopup
} }
@ -34,7 +35,7 @@ Item {
anchors.top: parent.top anchors.top: parent.top
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
source: identicon source: identicon
visible: repeatMessageInfo && !isCurrentUser visible: authorCurrentMsg != authorPrevMsg && !isCurrentUser
MouseArea { MouseArea {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -57,7 +58,7 @@ Item {
readOnly: true readOnly: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
selectByMouse: true selectByMouse: true
visible: repeatMessageInfo && !isCurrentUser visible: authorCurrentMsg != authorPrevMsg && !isCurrentUser
} }
Rectangle { Rectangle {
@ -74,7 +75,7 @@ Item {
anchors.leftMargin: !isCurrentUser ? 8 : 0 anchors.leftMargin: !isCurrentUser ? 8 : 0
anchors.right: !isCurrentUser ? undefined : parent.right anchors.right: !isCurrentUser ? undefined : parent.right
anchors.rightMargin: !isCurrentUser ? 0 : Theme.padding anchors.rightMargin: !isCurrentUser ? 0 : Theme.padding
anchors.top: repeatMessageInfo && !isCurrentUser ? chatImage.top : parent.top anchors.top: authorCurrentMsg != authorPrevMsg && !isCurrentUser ? chatImage.top : parent.top
anchors.topMargin: 0 anchors.topMargin: 0
// Thi`s rectangle's only job is to mask the corner to make it less rounded... yep // Thi`s rectangle's only job is to mask the corner to make it less rounded... yep