feat: show last message and unread message count
This commit is contained in:
parent
ac5c6389d3
commit
2eee8c7a2d
|
@ -0,0 +1,18 @@
|
||||||
|
type ChatItem* = ref object
|
||||||
|
name*: string
|
||||||
|
lastMessage*: string
|
||||||
|
timestamp*: int64
|
||||||
|
unviewedMessagesCount*: int
|
||||||
|
|
||||||
|
proc newChatItem*(): ChatItem =
|
||||||
|
new(result)
|
||||||
|
result.name = ""
|
||||||
|
result.lastMessage = ""
|
||||||
|
result.timestamp = 0
|
||||||
|
result.unviewedMessagesCount = 0
|
||||||
|
|
||||||
|
proc findByName*(self: seq[ChatItem], name: string): int =
|
||||||
|
result = -1
|
||||||
|
for item in self:
|
||||||
|
inc result
|
||||||
|
if(item.name == name): break
|
|
@ -2,9 +2,10 @@ import NimQml
|
||||||
import json, eventemitter
|
import json, eventemitter
|
||||||
import ../../status/chat as status_chat
|
import ../../status/chat as status_chat
|
||||||
import view
|
import view
|
||||||
|
import chatItem
|
||||||
import messages
|
import messages
|
||||||
import ../signals/types
|
import ../signals/types
|
||||||
import ../../models/chat
|
import ../../models/chat as chat_model
|
||||||
|
|
||||||
type ChatController* = ref object of SignalSubscriber
|
type ChatController* = ref object of SignalSubscriber
|
||||||
view*: ChatsView
|
view*: ChatsView
|
||||||
|
@ -40,9 +41,18 @@ proc load*(self: ChatController, chatId: string) =
|
||||||
discard self.view.joinChat(chatId)
|
discard self.view.joinChat(chatId)
|
||||||
self.view.setActiveChannelByIndex(0)
|
self.view.setActiveChannelByIndex(0)
|
||||||
|
|
||||||
proc onSignal(self: ChatController, data: Signal) =
|
method onSignal(self: ChatController, data: Signal) =
|
||||||
var chatSignal = cast[ChatSignal](data)
|
var messageSignal = cast[MessageSignal](data)
|
||||||
for message in chatSignal.messages:
|
|
||||||
|
for c in messageSignal.chats:
|
||||||
|
let channel = newChatitem()
|
||||||
|
channel.name = c.name
|
||||||
|
channel.lastMessage = c.lastMessage.text
|
||||||
|
channel.timestamp = c.timestamp
|
||||||
|
channel.unviewedMessagesCount = c.unviewedMessagesCount
|
||||||
|
self.view.updateChat(channel)
|
||||||
|
|
||||||
|
for message in messageSignal.messages:
|
||||||
let chatMessage = newChatMessage()
|
let chatMessage = newChatMessage()
|
||||||
chatMessage.userName = message.alias
|
chatMessage.userName = message.alias
|
||||||
chatMessage.message = message.text
|
chatMessage.message = message.text
|
||||||
|
|
|
@ -2,17 +2,21 @@ import NimQml
|
||||||
import Tables
|
import Tables
|
||||||
import messages
|
import messages
|
||||||
import messageList
|
import messageList
|
||||||
|
import chatItem
|
||||||
import ../../models/chat
|
import ../../models/chat
|
||||||
|
|
||||||
type
|
type
|
||||||
RoleNames {.pure.} = enum
|
RoleNames {.pure.} = enum
|
||||||
Name = UserRole + 1,
|
Name = UserRole + 1,
|
||||||
|
LastMessage = UserRole + 2
|
||||||
|
Timestamp = UserRole + 3
|
||||||
|
UnreadMessages = UserRole + 4
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
ChatsView* = ref object of QAbstractListModel
|
ChatsView* = ref object of QAbstractListModel
|
||||||
model: ChatModel
|
model: ChatModel
|
||||||
names*: seq[string]
|
chats: seq[ChatItem]
|
||||||
callResult: string
|
callResult: string
|
||||||
messageList: Table[string, ChatMessageList]
|
messageList: Table[string, ChatMessageList]
|
||||||
activeChannel: string
|
activeChannel: string
|
||||||
|
@ -24,7 +28,7 @@ QtObject:
|
||||||
proc newChatsView*(model: ChatModel): ChatsView =
|
proc newChatsView*(model: ChatModel): ChatsView =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.model = model
|
result.model = model
|
||||||
result.names = @[]
|
result.chats = @[]
|
||||||
result.activeChannel = ""
|
result.activeChannel = ""
|
||||||
result.messageList = initTable[string, ChatMessageList]()
|
result.messageList = initTable[string, ChatMessageList]()
|
||||||
result.setup()
|
result.setup()
|
||||||
|
@ -33,17 +37,29 @@ QtObject:
|
||||||
if not self.messageList.hasKey(channel):
|
if not self.messageList.hasKey(channel):
|
||||||
self.messageList[channel] = newChatMessageList()
|
self.messageList[channel] = newChatMessageList()
|
||||||
|
|
||||||
method rowCount(self: ChatsView, index: QModelIndex = nil): int = self.names.len
|
method rowCount(self: ChatsView, index: QModelIndex = nil): int = self.chats.len
|
||||||
|
|
||||||
method data(self: ChatsView, index: QModelIndex, role: int): QVariant =
|
method data(self: ChatsView, index: QModelIndex, role: int): QVariant =
|
||||||
if not index.isValid:
|
if not index.isValid:
|
||||||
return
|
return
|
||||||
if index.row < 0 or index.row >= self.names.len:
|
if index.row < 0 or index.row >= self.chats.len:
|
||||||
return
|
return
|
||||||
return newQVariant(self.names[index.row])
|
|
||||||
|
let chatItem = self.chats[index.row]
|
||||||
|
let chatItemRole = role.RoleNames
|
||||||
|
case chatItemRole:
|
||||||
|
of RoleNames.Name: result = newQVariant(chatItem.name)
|
||||||
|
of RoleNames.Timestamp: result = newQVariant($chatItem.timestamp)
|
||||||
|
of RoleNames.LastMessage: result = newQVariant(chatItem.lastMessage)
|
||||||
|
of RoleNames.UnreadMessages: result = newQVariant(chatItem.unviewedMessagesCount)
|
||||||
|
|
||||||
method roleNames(self: ChatsView): Table[int, string] =
|
method roleNames(self: ChatsView): Table[int, string] =
|
||||||
{ RoleNames.Name.int:"name"}.toTable
|
{
|
||||||
|
RoleNames.Name.int:"name",
|
||||||
|
RoleNames.Timestamp.int:"timestamp",
|
||||||
|
RoleNames.LastMessage.int: "lastMessage",
|
||||||
|
RoleNames.UnreadMessages.int: "unviewedMessagesCount"
|
||||||
|
}.toTable
|
||||||
|
|
||||||
proc onSend*(self: ChatsView, inputJSON: string) {.slot.} =
|
proc onSend*(self: ChatsView, inputJSON: string) {.slot.} =
|
||||||
discard self.model.sendMessage(self.activeChannel, inputJSON)
|
discard self.model.sendMessage(self.activeChannel, inputJSON)
|
||||||
|
@ -57,8 +73,8 @@ QtObject:
|
||||||
proc activeChannelChanged*(self: ChatsView) {.signal.}
|
proc activeChannelChanged*(self: ChatsView) {.signal.}
|
||||||
|
|
||||||
proc setActiveChannelByIndex*(self: ChatsView, index: int) {.slot.} =
|
proc setActiveChannelByIndex*(self: ChatsView, index: int) {.slot.} =
|
||||||
if self.activeChannel == self.names[index]: return
|
if self.activeChannel == self.chats[index].name: return
|
||||||
self.activeChannel = self.names[index]
|
self.activeChannel = self.chats[index].name
|
||||||
self.activeChannelChanged()
|
self.activeChannelChanged()
|
||||||
|
|
||||||
QtProperty[string] activeChannel:
|
QtProperty[string] activeChannel:
|
||||||
|
@ -80,18 +96,27 @@ QtObject:
|
||||||
|
|
||||||
proc addToList(self: ChatsView, channel: string): int =
|
proc addToList(self: ChatsView, channel: string): int =
|
||||||
if(self.activeChannel == ""): self.setActiveChannel(channel)
|
if(self.activeChannel == ""): self.setActiveChannel(channel)
|
||||||
|
var chatItem = newChatItem()
|
||||||
self.beginInsertRows(newQModelIndex(), self.names.len, self.names.len)
|
chatItem.name = channel
|
||||||
self.names.add(channel)
|
|
||||||
self.upsertChannel(channel)
|
self.upsertChannel(channel)
|
||||||
|
self.beginInsertRows(newQModelIndex(), self.chats.len, self.chats.len)
|
||||||
|
self.chats.add(chatItem)
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
|
||||||
result = self.names.len - 1
|
result = self.chats.len - 1
|
||||||
|
|
||||||
proc joinChat*(self: ChatsView, channel: string): int {.slot.} =
|
proc joinChat*(self: ChatsView, channel: string): int {.slot.} =
|
||||||
self.setActiveChannel(channel)
|
self.setActiveChannel(channel)
|
||||||
if self.model.hasChannel(channel):
|
if self.model.hasChannel(channel):
|
||||||
result = self.names.find(channel)
|
result = self.chats.findByName(channel)
|
||||||
else:
|
else:
|
||||||
self.model.join(channel)
|
self.model.join(channel)
|
||||||
result = self.addToList(channel)
|
result = self.addToList(channel)
|
||||||
|
|
||||||
|
proc updateChat*(self: ChatsView, chat: ChatItem) =
|
||||||
|
var idx = self.chats.findByName(chat.name)
|
||||||
|
if idx > -1:
|
||||||
|
self.chats[idx] = chat
|
||||||
|
var x = self.createIndex(idx,0,nil)
|
||||||
|
var y = self.createIndex(idx,0,nil)
|
||||||
|
self.dataChanged(x, y, @[RoleNames.Timestamp.int, RoleNames.LastMessage.int, RoleNames.UnreadMessages.int])
|
||||||
|
|
|
@ -1,13 +1,40 @@
|
||||||
import json
|
import json
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
proc toMessage(jsonMsg: JsonNode): Message
|
||||||
|
proc toChat(jsonChat: JsonNode): Chat
|
||||||
|
|
||||||
proc fromEvent*(event: JsonNode): Signal =
|
proc fromEvent*(event: JsonNode): Signal =
|
||||||
var signal:ChatSignal = ChatSignal()
|
var signal:MessageSignal = MessageSignal()
|
||||||
signal.messages = @[]
|
signal.messages = @[]
|
||||||
|
|
||||||
if event["event"]{"messages"} != nil:
|
if event["event"]{"messages"} != nil:
|
||||||
for jsonMsg in event["event"]["messages"]:
|
for jsonMsg in event["event"]["messages"]:
|
||||||
let msg = Message(
|
signal.messages.add(jsonMsg.toMessage)
|
||||||
|
|
||||||
|
if event["event"]{"chats"} != nil:
|
||||||
|
for jsonChat in event["event"]["chats"]:
|
||||||
|
signal.chats.add(jsonChat.toChat)
|
||||||
|
|
||||||
|
result = signal
|
||||||
|
|
||||||
|
proc toChat(jsonChat: JsonNode): Chat =
|
||||||
|
result = Chat(
|
||||||
|
id: jsonChat{"id"}.getStr,
|
||||||
|
name: jsonChat{"name"}.getStr,
|
||||||
|
color: jsonChat{"color"}.getStr,
|
||||||
|
active: jsonChat{"active"}.getBool,
|
||||||
|
chatType: ChatType(jsonChat{"chatType"}.getInt),
|
||||||
|
timestamp: jsonChat{"timestamp"}.getBiggestInt,
|
||||||
|
lastClockValue: jsonChat{"lastClockValue"}.getBiggestInt,
|
||||||
|
deletedAtClockValue: jsonChat{"deletedAtClockValue"}.getBiggestInt,
|
||||||
|
unviewedMessagesCount: jsonChat{"unviewedMessagesCount"}.getInt,
|
||||||
|
lastMessage: jsonChat{"lastMessage"}.toMessage
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
proc toMessage(jsonMsg: JsonNode): Message =
|
||||||
|
result = Message(
|
||||||
alias: jsonMsg{"alias"}.getStr,
|
alias: jsonMsg{"alias"}.getStr,
|
||||||
chatId: jsonMsg{"chatId"}.getStr,
|
chatId: jsonMsg{"chatId"}.getStr,
|
||||||
clock: $jsonMsg{"clock"}.getInt,
|
clock: $jsonMsg{"clock"}.getInt,
|
||||||
|
@ -28,6 +55,3 @@ proc fromEvent*(event: JsonNode): Signal =
|
||||||
whisperTimestamp: $jsonMsg{"whisperTimestamp"}.getInt,
|
whisperTimestamp: $jsonMsg{"whisperTimestamp"}.getInt,
|
||||||
isCurrentUser: false # TODO: this must compare the fromAuthor against current user because the messages received from the mailserver will arrive as signals too, and those include the current user messages
|
isCurrentUser: false # TODO: this must compare the fromAuthor against current user because the messages received from the mailserver will arrive as signals too, and those include the current user messages
|
||||||
)
|
)
|
||||||
signal.messages.add(msg)
|
|
||||||
|
|
||||||
result = signal
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import chronicles
|
||||||
|
|
||||||
type SignalSubscriber* = ref object of RootObj
|
type SignalSubscriber* = ref object of RootObj
|
||||||
|
|
||||||
type Signal* = ref object of RootObj
|
type Signal* = ref object of RootObj
|
||||||
|
@ -30,10 +32,32 @@ type Message* = object
|
||||||
whisperTimestamp*: string
|
whisperTimestamp*: string
|
||||||
isCurrentUser*: bool
|
isCurrentUser*: bool
|
||||||
|
|
||||||
|
|
||||||
type ChatSignal* = ref object of Signal
|
|
||||||
messages*: seq[Message]
|
|
||||||
|
|
||||||
# Override this method
|
# Override this method
|
||||||
method onSignal*(self: SignalSubscriber, data: Signal) {.base.} =
|
method onSignal*(self: SignalSubscriber, data: Signal) {.base.} =
|
||||||
echo "Received a signal" # TODO: log signal received
|
discard
|
||||||
|
# TODO: log signal received
|
||||||
|
|
||||||
|
type ChatType* = enum
|
||||||
|
ChatTypeOneToOne = 1,
|
||||||
|
ChatTypePublic = 2,
|
||||||
|
ChatTypePrivateGroupChat = 3
|
||||||
|
|
||||||
|
type Chat* = object
|
||||||
|
id*: string # ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one is the hex encoded public key and for group chats is a random uuid appended with the hex encoded pk of the creator of the chat
|
||||||
|
name*: string
|
||||||
|
color*: string
|
||||||
|
active*: bool # indicates whether the chat has been soft deleted
|
||||||
|
chatType*: ChatType
|
||||||
|
timestamp*: int64 # indicates the last time this chat has received/sent a message
|
||||||
|
lastClockValue*: int64 # indicates the last clock value to be used when sending messages
|
||||||
|
deletedAtClockValue*: int64 # indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
|
||||||
|
unviewedMessagesCount*: int
|
||||||
|
lastMessage*: Message
|
||||||
|
# Group chat fields
|
||||||
|
# members ?
|
||||||
|
# membershipUpdateEvents # ?
|
||||||
|
|
||||||
|
|
||||||
|
type MessageSignal* = ref object of Signal
|
||||||
|
messages*: seq[Message]
|
||||||
|
chats*: seq[Chat]
|
|
@ -75,7 +75,6 @@ proc mainProc() =
|
||||||
|
|
||||||
appState.subscribe(proc () =
|
appState.subscribe(proc () =
|
||||||
for channel in appState.channels:
|
for channel in appState.channels:
|
||||||
echo channel.name
|
|
||||||
chat.load(channel.name)
|
chat.load(channel.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ SplitView {
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
id: lastChatMessage
|
id: lastChatMessage
|
||||||
text: "Chatting blah blah..."
|
text: lastMessage || qsTr("No messages")
|
||||||
anchors.right: contactNumberChatsCircle.left
|
anchors.right: contactNumberChatsCircle.left
|
||||||
anchors.rightMargin: Theme.smallPadding
|
anchors.rightMargin: Theme.smallPadding
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
@ -194,7 +194,7 @@ SplitView {
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
id: contactTime
|
id: contactTime
|
||||||
text: "12:22 AM"
|
text: timestamp
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: Theme.padding
|
anchors.rightMargin: Theme.padding
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -212,9 +212,10 @@ SplitView {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: Theme.padding
|
anchors.rightMargin: Theme.padding
|
||||||
color: Theme.blue
|
color: Theme.blue
|
||||||
|
visible: unviewedMessagesCount > 0
|
||||||
Text {
|
Text {
|
||||||
id: contactNumberChats
|
id: contactNumberChats
|
||||||
text: qsTr("1")
|
text: unviewedMessagesCount
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: "white"
|
color: "white"
|
||||||
|
|
Loading…
Reference in New Issue