From a4deb4b7a95c4c7413521677e74491fd30902c93 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Mon, 18 May 2020 16:08:40 -0400 Subject: [PATCH] Display chat messages --- src/app/chat/chatMessageList.nim | 63 ++++++++++++++++++++++ src/app/chat/chatMessages.nim | 90 ++++++++++++++++++++++++++++++++ src/app/chat/chatView.nim | 13 +++++ ui/app/AppLayouts/ChatLayout.qml | 54 +------------------ 4 files changed, 168 insertions(+), 52 deletions(-) create mode 100644 src/app/chat/chatMessageList.nim create mode 100644 src/app/chat/chatMessages.nim diff --git a/src/app/chat/chatMessageList.nim b/src/app/chat/chatMessageList.nim new file mode 100644 index 0000000000..fa70038308 --- /dev/null +++ b/src/app/chat/chatMessageList.nim @@ -0,0 +1,63 @@ +import NimQml, chatMessages, Tables +import ../signals/types + +type + ChatMessageRoles {.pure.} = enum + UserName = UserRole + 1, + Message = UserRole + 2, + Timestamp = UserRole + 3 + IsCurrentUser = UserRole + 4 + +QtObject: + type + ChatMessageList* = ref object of QAbstractListModel + messages*: seq[ChatMessage] + + proc delete(self: ChatMessageList) = + self.QAbstractListModel.delete + for message in self.messages: + message.delete + self.messages = @[] + + proc setup(self: ChatMessageList) = + self.QAbstractListModel.setup + + proc newChatMessageList*(): ChatMessageList = + new(result, delete) + result.messages = @[] + result.setup + + method rowCount(self: ChatMessageList, index: QModelIndex = nil): int = + return self.messages.len + + method data(self: ChatMessageList, index: QModelIndex, role: int): QVariant = + if not index.isValid: + return + if index.row < 0 or index.row >= self.messages.len: + return + let message = self.messages[index.row] + let chatMessageRole = role.ChatMessageRoles + case chatMessageRole: + of ChatMessageRoles.UserName: result = newQVariant(message.userName) + of ChatMessageRoles.Message: result = newQVariant(message.message) + of ChatMessageRoles.Timestamp: result = newQVariant(message.timestamp) + of ChatMessageRoles.IsCurrentUser: result = newQVariant(message.isCurrentUser) + + method roleNames(self: ChatMessageList): Table[int, string] = + { + ChatMessageRoles.UserName.int:"userName", + ChatMessageRoles.Message.int:"message", + ChatMessageRoles.Timestamp.int:"timestamp", + ChatMessageRoles.IsCurrentUser.int:"isCurrentUser" + }.toTable + + proc add*(self: ChatMessageList, message: Message) = + let chatMessage = newChatMessage() + chatMessage.userName = message.alias + chatMessage.message = message.text + chatMessage.timestamp = message.timestamp #TODO convert to date/time? + chatMessage.isCurrentUser = false #TODO: Determine who originated the message + + self.beginInsertRows(newQModelIndex(), self.messages.len, self.messages.len) + self.messages.add(chatMessage) + self.endInsertRows() diff --git a/src/app/chat/chatMessages.nim b/src/app/chat/chatMessages.nim new file mode 100644 index 0000000000..9828a10802 --- /dev/null +++ b/src/app/chat/chatMessages.nim @@ -0,0 +1,90 @@ +import NimQml + +QtObject: + type ChatMessage* = ref object of QObject + userName: string + message: string + timestamp: string + isCurrentUser: bool + + proc delete*(self: ChatMessage) = + self.QObject.delete + + proc setup(self: ChatMessage) = + self.QObject.setup + + proc newChatMessage*(): ChatMessage = + new(result) + result.userName = "" + result.message = "" + result.timestamp = "0" + result.isCurrentUser = false + result.setup + + proc userName*(self: ChatMessage): string {.slot.} = + result = self.userName + + proc userNameChanged*(self: ChatMessage, userName: string) {.signal.} + + proc setUserName(self: ChatMessage, userName: string) {.slot.} = + if self.userName == userName: return + self.userName = userName + self.userNameChanged(userName) + + proc `userName=`*(self: ChatMessage, userName: string) = self.setUserName(userName) + + QtProperty[string] userName: + read = userName + write = setUserName + notify = userNameChanged + + proc message*(self: ChatMessage): string {.slot.} = + result = self.message + + proc messageChanged*(self: ChatMessage, message: string) {.signal.} + + proc setMessage(self: ChatMessage, message: string) {.slot.} = + if self.message == message: return + self.message = message + self.messageChanged(message) + + proc `message=`*(self: ChatMessage, message: string) = self.setMessage(message) + + QtProperty[string] message: + read = message + write = setMessage + notify = messageChanged + + proc timestamp*(self: ChatMessage): string {.slot.} = + result = self.timestamp + + proc timestampChanged*(self: ChatMessage, timestamp: string) {.signal.} + + proc setTimestamp(self: ChatMessage, timestamp: string) {.slot.} = + if self.timestamp == timestamp: return + self.timestamp = timestamp + self.timestampChanged(timestamp) + + proc `timestamp=`*(self: ChatMessage, timestamp: string) = self.setTimestamp(timestamp) + + QtProperty[string] timestamp: + read = timestamp + write = setTimestamp + notify = timestampChanged + + proc isCurrentUser*(self: ChatMessage): bool {.slot.} = + result = self.isCurrentUser + + proc isCurrentUserChanged*(self: ChatMessage, isCurrentUser: bool) {.signal.} + + proc setIsCurrentUser(self: ChatMessage, isCurrentUser: bool) {.slot.} = + if self.isCurrentUser == isCurrentUser: return + self.isCurrentUser = isCurrentUser + self.isCurrentUserChanged(isCurrentUser) + + proc `isCurrentUser=`*(self: ChatMessage, isCurrentUser: bool) = self.setIsCurrentUser(isCurrentUser) + + QtProperty[bool] isCurrentUser: + read = isCurrentUser + write = setIsCurrentUser + notify = isCurrentUserChanged diff --git a/src/app/chat/chatView.nim b/src/app/chat/chatView.nim index 348c047f69..8349dddd9d 100644 --- a/src/app/chat/chatView.nim +++ b/src/app/chat/chatView.nim @@ -1,5 +1,7 @@ import NimQml import Tables +import chatMessageList +import ../signals/types # import core as chat type @@ -11,6 +13,7 @@ QtObject: ChatsView* = ref object of QAbstractListModel names*: seq[string] callResult: string + messageList: ChatMessageList sendMessage: proc (msg: string): string proc delete(self: ChatsView) = @@ -23,6 +26,7 @@ QtObject: new(result, delete) result.sendMessage = sendMessage result.names = @[] + result.messageList = newChatMessageList() result.setup proc addNameTolist*(self: ChatsView, chatId: string) {.slot.} = @@ -69,3 +73,12 @@ QtObject: proc onMessage*(self: ChatsView, message: string) {.slot.} = self.setCallResult(message) echo "Received message: ", message + + proc pushMessage*(self:ChatsView, message: Message) = + self.messageList.add(message) + + proc getMessageList(self: ChatsView): QVariant {.slot.} = + return newQVariant(self.messageList) + + QtProperty[QVariant] messageList: + read = getMessageList \ No newline at end of file diff --git a/ui/app/AppLayouts/ChatLayout.qml b/ui/app/AppLayouts/ChatLayout.qml index 5758216bfc..1ffeae15ec 100644 --- a/ui/app/AppLayouts/ChatLayout.qml +++ b/ui/app/AppLayouts/ChatLayout.qml @@ -263,7 +263,7 @@ SplitView { TextEdit { id: chatName - text: username + text: userName anchors.top: parent.top anchors.topMargin: 22 anchors.left: !isCurrentUser ? chatImage.right : undefined @@ -316,59 +316,9 @@ SplitView { ListView { id: chatLogView anchors.fill: parent -// model: chatLogModel + model: chatsModel.messageList Layout.fillWidth: true Layout.fillHeight: true - model: ListModel { - ListElement { - username: "You" - message: "First Message - I’m generally against putting too many rules on social interaction because it makes interaction anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:30 AM" - isCurrentUser: true - } - ListElement { - username: qsTr("Slushy Welltodo Woodborer") - message: "Lorem ipsum ion anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:31 AM" - isCurrentUser: false - } - ListElement { - username: "You" - message: "I’m generally against putting too many rules on social interaction because it makes interaction anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:32 AM" - isCurrentUser: true - } - ListElement { - username: qsTr("Slushy Welltodo Woodborer") - message: "Lorem ipsum ionanything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:33 AM" - isCurrentUser: false - } - ListElement { - username: "You" - message: "I’m generally against putting too many rules on social interaction because it makes interaction anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:34 AM" - isCurrentUser: true - } - ListElement { - username: qsTr("Slushy Welltodo Woodborer") - message: "Lorem ipsum ion anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:35 AM" - isCurrentUser: false - } - ListElement { - username: "You" - message: "I’m generally against putting too many rules on social interaction because it makes interaction anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:36 AM" - isCurrentUser: true - } - ListElement { - username: qsTr("Slushy Welltodo Woodborer") - message: "Last Message - Lorem ipsum ion anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue." - timestamp: "7:36 AM" - isCurrentUser: false - } - } delegate: chatLogViewDelegate onCountChanged: { chatLogView.positionViewAtEnd()