refactor: Remove ChatItem object

This commit is contained in:
Richard Ramos 2020-06-09 17:20:42 -04:00 committed by Iuri Matias
parent 152dd102dd
commit 39c494f9d5
11 changed files with 126 additions and 112 deletions

View File

@ -42,15 +42,14 @@ proc handleChatEvents(self: ChatController) =
self.status.events.on("channelJoined") do(e: Args):
var channel = ChannelArgs(e)
let chatItem = newChatItem(id = channel.channel, name = channel.name, chatType = channel.chatTypeInt)
discard self.view.chats.addChatItemToList(chatItem)
self.status.chat.chatMessages(channel.channel)
discard self.view.chats.addChatItemToList(channel.chat)
self.status.chat.chatMessages(channel.chat.id)
self.status.events.on("channelLeft") do(e: Args):
discard self.view.chats.removeChatItemFromList(self.view.activeChannel.chatItem.id)
self.status.events.on("activeChannelChanged") do(e: Args):
self.view.setActiveChannel(ChannelArgs(e).channel)
self.view.setActiveChannel(ChatIdArg(e).chatId)
proc handleMailserverEvents(self: ChatController) =
self.status.events.on("mailserverTopics") do(e: Args):
@ -69,8 +68,9 @@ proc init*(self: ChatController) =
self.status.chat.init()
proc handleMessage(self: ChatController, data: MessageSignal) =
for c in data.chats:
self.view.updateChat(c.toChatItem())
for chat in data.chats:
var c = chat
self.view.updateChat(c)
self.view.pushMessages(data.messages)
proc handleDiscoverySummary(self: ChatController, data: DiscoverySummarySignal) =

View File

@ -103,7 +103,7 @@ QtObject:
read = getMessageList
notify = activeChannelChanged
proc pushChatItem*(self: ChatsView, chatItem: ChatItem) =
proc pushChatItem*(self: ChatsView, chatItem: var Chat) =
discard self.chats.addChatItemToList(chatItem)
self.messagePushed()
@ -123,5 +123,5 @@ QtObject:
proc leaveActiveChat*(self: ChatsView) {.slot.} =
self.status.chat.leave(self.activeChannel.id)
proc updateChat*(self: ChatsView, chat: ChatItem) =
proc updateChat*(self: ChatsView, chat: var Chat) =
self.chats.updateChat(chat)

View File

@ -1,8 +1,6 @@
import NimQml, Tables
import random
import ../../../status/chat
const channelColors* = ["#fa6565", "#7cda00", "#887af9", "#51d0f0", "#FE8F59", "#d37ef4"]
import ../../../signals/types
type
ChannelsRoles {.pure.} = enum
@ -17,7 +15,7 @@ type
QtObject:
type
ChannelsList* = ref object of QAbstractListModel
chats*: seq[ChatItem]
chats*: seq[Chat]
proc setup(self: ChannelsList) = self.QAbstractListModel.setup
@ -41,7 +39,7 @@ QtObject:
case chatItemRole:
of ChannelsRoles.Name: result = newQVariant(chatItem.name)
of ChannelsRoles.Timestamp: result = newQVariant($chatItem.timestamp)
of ChannelsRoles.LastMessage: result = newQVariant(chatItem.lastMessage)
of ChannelsRoles.LastMessage: result = newQVariant(chatItem.lastMessage.text)
of ChannelsRoles.UnreadMessages: result = newQVariant(chatItem.unviewedMessagesCount)
of ChannelsRoles.Identicon: result = newQVariant(chatItem.identicon)
of ChannelsRoles.ChatType: result = newQVariant(chatItem.chatType.int)
@ -58,10 +56,7 @@ QtObject:
ChannelsRoles.Color.int: "color"
}.toTable
proc addChatItemToList*(self: ChannelsList, channel: ChatItem): int =
if channel.color == "":
randomize()
channel.color = channelColors[rand(channelColors.len - 1)]
proc addChatItemToList*(self: ChannelsList, channel: var Chat): int =
self.beginInsertRows(newQModelIndex(), 0, 0)
self.chats.insert(channel, 0)
self.endInsertRows()
@ -75,9 +70,9 @@ QtObject:
result = self.chats.len
proc getChannel*(self: ChannelsList, index: int): ChatItem = self.chats[index]
proc getChannel*(self: ChannelsList, index: int): Chat = self.chats[index]
proc upsertChannel(self: ChannelsList, channel: ChatItem): int =
proc upsertChannel(self: ChannelsList, channel: var Chat): int =
let idx = self.chats.findById(channel.id)
if idx == -1:
result = self.addChatItemToList(channel)
@ -88,9 +83,9 @@ QtObject:
for chat in self.chats:
if chat.name == name:
return chat.color
return channelColors[0]
return "#fa6565" # TODO determine if it is possible to have a chat without color
proc updateChat*(self: ChannelsList, channel: ChatItem) =
proc updateChat*(self: ChannelsList, channel: var Chat) =
let idx = self.upsertChannel(channel)
let topLeft = self.createIndex(0, 0, nil)
let bottomRight = self.createIndex(self.chats.len, 0, nil)
@ -102,8 +97,10 @@ QtObject:
self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int])
proc clearUnreadMessagesCount*(self: ChannelsList, channel: ChatItem) =
proc clearUnreadMessagesCount*(self: ChannelsList, channel: var Chat) =
let idx = self.chats.findById(channel.id)
if idx == -1: return
let topLeft = self.createIndex(0, 0, nil)
let bottomRight = self.createIndex(self.chats.len, 0, nil)
channel.unviewedMessagesCount = 0

View File

@ -1,10 +1,11 @@
import NimQml
import std/wrapnils
import ../../../status/chat
import ../../../signals/types
QtObject:
type ChatItemView* = ref object of QObject
chatItem*: ChatItem
chatItem*: Chat
proc setup(self: ChatItemView) =
self.QObject.setup
@ -15,9 +16,10 @@ QtObject:
proc newChatItemView*(): ChatItemView =
new(result, delete)
result = ChatItemView()
result.chatItem = nil
result.setup
proc setChatItem*(self: ChatItemView, chatItem: ChatItem) =
proc setChatItem*(self: ChatItemView, chatItem: Chat) =
self.chatItem = chatItem
proc id*(self: ChatItemView): string {.slot.} = result = ?.self.chatItem.id
@ -30,6 +32,11 @@ QtObject:
QtProperty[string] name:
read = name
proc color*(self: ChatItemView): string {.slot.} = result = ?.self.chatItem.color
QtProperty[string] color:
read = color
proc identicon*(self: ChatItemView): string {.slot.} = result = ?.self.chatItem.identicon
QtProperty[string] identicon:

View File

@ -1,7 +1,10 @@
import json
import types
import ../status/libstatus/accounts as status_accounts
import random
proc toMessage*(jsonMsg: JsonNode): Message
proc toChat*(jsonChat: JsonNode): Chat
proc fromEvent*(event: JsonNode): Signal =
@ -18,10 +21,41 @@ proc fromEvent*(event: JsonNode): Signal =
result = signal
proc toChatMember*(jsonMember: JsonNode): ChatMember =
result = ChatMember(
admin: jsonMember["admin"].getBool,
id: jsonMember["id"].getStr,
joined: jsonMember["joined"].getBool
)
const channelColors* = ["#fa6565", "#7cda00", "#887af9", "#51d0f0", "#FE8F59", "#d37ef4"]
proc newChat*(id: string, chatType: ChatType): Chat =
randomize()
result = Chat(
id: id,
color: channelColors[rand(channelColors.len - 1)],
active: true,
chatType: chatType,
timestamp: 0,
lastClockValue: 0,
deletedAtClockValue: 0,
unviewedMessagesCount: 0
)
if chatType == ChatType.OneToOne:
result.identicon = generateIdenticon(id)
result.name = generateAlias(id)
else:
result.name = id
proc toChat*(jsonChat: JsonNode): Chat =
result = Chat(
id: jsonChat{"id"}.getStr,
name: jsonChat{"name"}.getStr,
identicon: "",
color: jsonChat{"color"}.getStr,
active: jsonChat{"active"}.getBool,
chatType: ChatType(jsonChat{"chatType"}.getInt),
@ -30,8 +64,21 @@ proc toChat*(jsonChat: JsonNode): Chat =
deletedAtClockValue: jsonChat{"deletedAtClockValue"}.getBiggestInt,
unviewedMessagesCount: jsonChat{"unviewedMessagesCount"}.getInt,
)
if jsonChat["lastMessage"].kind != JNull:
result.lastMessage = jsonChat{"lastMessage"}.toMessage
if result.chatType == ChatType.OneToOne:
result.name = result.lastMessage.alias
result.identicon = result.lastMessage.identicon
else:
if result.chatType == ChatType.OneToOne:
result.identicon = generateIdenticon(result.id)
result.name = generateAlias(result.id)
if jsonChat["members"].kind != JNull:
result.members = @[]
for jsonMember in jsonChat["members"]:
result.members.add(jsonMember.toChatMember)
proc toMessage*(jsonMsg: JsonNode): Message =
result = Message(
@ -56,5 +103,8 @@ proc toMessage*(jsonMsg: JsonNode): Message =
isCurrentUser: $jsonMsg{"outgoingStatus"}.getStr == "sending",
stickerHash: ""
)
if result.contentType == 2:
result.stickerHash = jsonMsg["sticker"]["hash"].getStr

View File

@ -55,10 +55,16 @@ type ChatType* = enum
proc isOneToOne*(self: ChatType): bool = self == ChatType.OneToOne
type Chat* = object
type ChatMember* = object
admin*: bool
id*: string
joined*: bool
type Chat* = ref 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
identicon*: 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
@ -66,8 +72,7 @@ type Chat* = object
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 ?
members*: seq[ChatMember]
# membershipUpdateEvents # ?
type MessageSignal* = ref object of Signal
@ -87,3 +92,15 @@ type WhisperFilterSignal* = ref object of Signal
type DiscoverySummarySignal* = ref object of Signal
enodes*: seq[string]
proc findById*(self: seq[Chat], id: string): int =
result = -1
var idx = -1
for item in self:
inc idx
if(item.id == id):
result = idx
break

View File

@ -3,12 +3,12 @@ import sequtils
import libstatus/chat as status_chat
import chronicles
import ../signals/types
import chat/chat_item
import ../signals/messages
import chat/chat_message
import tables
export chat_item
export chat_message
export Chat
type
MsgArgs* = ref object of Args
@ -16,10 +16,11 @@ type
chatId*: string
payload*: JsonNode
ChatIdArg* = ref object of Args
chatId*: string
ChannelArgs* = ref object of Args
channel*: string
name*: string
chatTypeInt*: ChatType
chat*: Chat
ChatArgs* = ref object of Args
chats*: seq[Chat]
@ -32,14 +33,14 @@ type
ChatModel* = ref object
events*: EventEmitter
channels*: HashSet[string]
channels*: Table[string, Chat]
filters*: Table[string, string]
msgCursor*: Table[string, string]
proc newChatModel*(events: EventEmitter): ChatModel =
result = ChatModel()
result.events = events
result.channels = initHashSet[string]()
result.channels = initTable[string, Chat]()
result.filters = initTable[string, string]()
result.msgCursor = initTable[string, string]()
@ -47,15 +48,17 @@ proc delete*(self: ChatModel) =
discard
proc hasChannel*(self: ChatModel, chatId: string): bool =
result = self.channels.contains(chatId)
self.channels.hasKey(chatId)
proc getActiveChannel*(self: ChatModel): string =
if (self.channels.len == 0): "" else: self.channels.toSeq[self.channels.len - 1]
if (self.channels.len == 0): "" else: toSeq(self.channels.values)[self.channels.len - 1].id
proc join*(self: ChatModel, chatId: string, chatType: ChatType) =
if self.hasChannel(chatId): return
self.channels.incl chatId
status_chat.saveChat(chatId, chatType.isOneToOne)
var chat = newChat(chatId, ChatType(chatType))
self.channels[chat.id] = chat
status_chat.saveChat(chatId, chatType.isOneToOne, true, chat.color)
let filterResult = status_chat.loadFilters(@[status_chat.buildFilter(chatId = chatId, oneToOne = chatType.isOneToOne)])
var topics:seq[string] = @[]
@ -70,8 +73,8 @@ proc join*(self: ChatModel, chatId: string, chatType: ChatType) =
else:
self.events.emit("mailserverTopics", TopicArgs(topics: topics));
self.events.emit("channelJoined", ChannelArgs(channel: chatId, chatTypeInt: chatType, name: chatId))
self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel()))
self.events.emit("channelJoined", ChannelArgs(chat: chat))
self.events.emit("activeChannelChanged", ChatIdArg(chatId: self.getActiveChannel()))
proc init*(self: ChatModel) =
let chatList = status_chat.loadChats()
@ -80,8 +83,8 @@ proc init*(self: ChatModel) =
for chat in chatList:
if self.hasChannel(chat.id): continue
filters.add status_chat.buildFilter(chatId = chat.id, oneToOne = chat.chatType.isOneToOne)
self.channels.incl chat.id
self.events.emit("channelJoined", ChannelArgs(channel: chat.id, chatTypeInt: chat.chatType, name: chat.name))
self.channels[chat.id] = chat
self.events.emit("channelJoined", ChannelArgs(chat: chat))
if filters.len == 0: return
@ -105,14 +108,14 @@ proc leave*(self: ChatModel, chatId: string) =
status_chat.deactivateChat(chatId)
# TODO: REMOVE MAILSERVER TOPIC
# TODO: REMOVE HISTORY
self.filters.del(chatId)
self.channels.excl(chatId)
self.events.emit("channelLeft", ChannelArgs(channel: chatId))
self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel()))
self.channels.del(chatId)
self.events.emit("channelLeft", ChatIdArg(chatId: chatId))
self.events.emit("activeChannelChanged", ChatIdArg(chatId: self.getActiveChannel()))
proc setActiveChannel*(self: ChatModel, chatId: string) =
self.events.emit("activeChannelChanged", ChannelArgs(channel: chatId))
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))
proc sendMessage*(self: ChatModel, chatId: string, msg: string): string =
var sentMessage = status_chat.sendChatMessage(chatId, msg)

View File

@ -1,58 +0,0 @@
import ../../signals/types
import ../libstatus/accounts as status_accounts
type ChatItem* = ref object
id*: string
name*: string
chatType*: ChatType
lastMessage*: string
timestamp*: int64
unviewedMessagesCount*: int
color*: string
identicon*: string
proc newChatItem*(id: string, name: string, chatType: ChatType, lastMessage: string = "", timestamp: int64 = 0, unviewedMessagesCount: int = 0, color: string = "", identicon: string = ""): ChatItem =
new(result)
result.id = id
result.name = case chatType
of ChatType.Public: name
of ChatType.OneToOne: generateAlias(id)
of ChatType.PrivateGroupChat: name
of ChatType.Unknown: "Unknown: " & id
result.chatType = chatType
result.lastMessage = lastMessage
result.timestamp = timestamp
result.unviewedMessagesCount = unviewedMessagesCount
result.color = color
result.identicon = if identicon == "" and chatType == ChatType.OneToOne:
generateIdenticon(id)
else:
identicon
proc findById*(self: seq[ChatItem], id: string): int =
result = -1
var idx = -1
for item in self:
inc idx
if(item.id == id):
result = idx
break
proc chatName(chat: Chat): string =
case chat.chatType
of ChatType.OneToOne: result = chat.lastMessage.alias
of ChatType.Public: result = chat.name
of ChatType.PrivateGroupChat: result = chat.name
of ChatType.Unknown: result = "Unknown"
proc toChatItem*(chat: Chat): ChatItem =
result = ChatItem(
id: chat.id,
name: chatName(chat),
color: chat.color,
chatType: chat.chatType,
lastMessage: chat.lastMessage.text,
timestamp: chat.timestamp,
identicon: chat.lastMessage.identicon,
unviewedMessagesCount: chat.unviewedMessagesCount
)

View File

@ -32,17 +32,16 @@ proc removeFilters*(chatId: string, filterId: string) =
}]
])
proc saveChat*(chatId: string, oneToOne: bool = false, active: bool = true) =
proc saveChat*(chatId: string, oneToOne: bool = false, active: bool = true, color: string = "#51d0f0") =
discard callPrivateRPC("saveChat".prefix, %* [
{
"lastClockValue": 0, # TODO:
"color": "#51d0f0", # TODO:
"color": color,
"name": chatId,
"lastMessage": nil, # TODO:
"active": active,
"id": chatId,
"unviewedMessagesCount": 0, # TODO:
# TODO use constants for those too or use the Date
"chatType": if oneToOne: 1 else: 2, # TODO: use constants
"timestamp": 1588940692659 # TODO:
}

View File

@ -51,11 +51,10 @@ Item {
border.width: chatsModel.activeChannel.chatType == Constants.chatTypeOneToOne ? 2 : 0
border.color: Theme.grey
color: {
const color = chatsModel.getChannelColor(chatId)
if (chatsModel.activeChannel.chatType == Constants.chatTypeOneToOne || !color) {
if (chatsModel.activeChannel.chatType == Constants.chatTypeOneToOne) {
return Theme.transparent
}
return color
return chatsModel.activeChannel.color
}
Image {

View File

@ -20,7 +20,7 @@ Rectangle {
ChannelIcon {
id: channelIcon
channelName: chatsModel.activeChannel.id
channelName: chatsModel.activeChannel.name
channelType: chatsModel.activeChannel.chatType
channelIdenticon: chatsModel.activeChannel.identicon
}