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:
parent
4fe6d9b767
commit
9d75f6f552
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,24 +69,38 @@ 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue