feat: Determine if a message was sent
This commit is contained in:
parent
7eb44366da
commit
64452e71b9
|
@ -1,6 +1,7 @@
|
|||
import NimQml, eventemitter, chronicles, tables
|
||||
import ../../status/chat as chat_model
|
||||
import ../../status/mailservers as mailserver_model
|
||||
import ../../status/messages as messages_model
|
||||
import ../../signals/types
|
||||
import ../../status/libstatus/types as status_types
|
||||
import ../../status/libstatus/wallet as status_wallet
|
||||
|
@ -27,45 +28,8 @@ proc delete*(self: ChatController) =
|
|||
delete self.variant
|
||||
delete self.view
|
||||
|
||||
proc handleChatEvents(self: ChatController) =
|
||||
# Display already saved messages
|
||||
self.status.events.on("messagesLoaded") do(e:Args):
|
||||
self.view.pushMessages(MsgsLoadedArgs(e).messages)
|
||||
|
||||
self.status.events.on("contactUpdate") do(e: Args):
|
||||
var evArgs = ContactUpdateArgs(e)
|
||||
self.view.updateUsernames(evArgs.contacts)
|
||||
|
||||
self.status.events.on("chatUpdate") do(e: Args):
|
||||
var evArgs = ChatUpdateArgs(e)
|
||||
self.view.updateUsernames(evArgs.contacts)
|
||||
self.view.updateChats(evArgs.chats)
|
||||
self.view.pushMessages(evArgs.messages)
|
||||
|
||||
self.status.events.on("chatHistoryCleared") do(e: Args):
|
||||
var args = ChannelArgs(e)
|
||||
self.view.clearMessages(args.chat.id)
|
||||
|
||||
self.status.events.on("channelJoined") do(e: Args):
|
||||
var channel = ChannelArgs(e)
|
||||
discard self.view.chats.addChatItemToList(channel.chat)
|
||||
self.status.chat.chatMessages(channel.chat.id)
|
||||
self.view.setActiveChannel(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(ChatIdArg(e).chatId)
|
||||
|
||||
proc handleMailserverEvents(self: ChatController) =
|
||||
self.status.events.on("mailserverTopics") do(e: Args):
|
||||
self.status.mailservers.addTopics(TopicArgs(e).topics)
|
||||
if(self.status.mailservers.isSelectedMailserverAvailable):
|
||||
self.status.mailservers.requestMessages()
|
||||
|
||||
self.status.events.on("mailserverAvailable") do(e:Args):
|
||||
self.status.mailservers.requestMessages()
|
||||
include event_handling
|
||||
include signal_handling
|
||||
|
||||
proc init*(self: ChatController) =
|
||||
self.handleMailserverEvents()
|
||||
|
@ -83,16 +47,10 @@ proc init*(self: ChatController) =
|
|||
self.view.addRecentStickerToList(sticker)
|
||||
self.status.chat.addStickerToRecent(sticker)
|
||||
|
||||
proc handleMessage(self: ChatController, data: MessageSignal) =
|
||||
self.status.chat.update(data.chats, data.messages)
|
||||
|
||||
proc handleDiscoverySummary(self: ChatController, data: DiscoverySummarySignal) =
|
||||
## Handle mailserver peers being added and removed
|
||||
self.status.mailservers.peerSummaryChange(data.enodes)
|
||||
|
||||
method onSignal(self: ChatController, data: Signal) =
|
||||
case data.signalType:
|
||||
of SignalType.Message: handleMessage(self, MessageSignal(data))
|
||||
of SignalType.DiscoverySummary: handleDiscoverySummary(self, DiscoverySummarySignal(data))
|
||||
of SignalType.EnvelopeSent: handleEnvelopeSent(self, EnvelopeSentSignal(data))
|
||||
else:
|
||||
warn "Unhandled signal received", signalType = data.signalType
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
proc handleChatEvents(self: ChatController) =
|
||||
# Display already saved messages
|
||||
self.status.events.on("messagesLoaded") do(e:Args):
|
||||
self.view.pushMessages(MsgsLoadedArgs(e).messages)
|
||||
|
||||
self.status.events.on("contactUpdate") do(e: Args):
|
||||
var evArgs = ContactUpdateArgs(e)
|
||||
self.view.updateUsernames(evArgs.contacts)
|
||||
|
||||
self.status.events.on("chatUpdate") do(e: Args):
|
||||
var evArgs = ChatUpdateArgs(e)
|
||||
self.view.updateUsernames(evArgs.contacts)
|
||||
self.view.updateChats(evArgs.chats)
|
||||
self.view.pushMessages(evArgs.messages)
|
||||
|
||||
self.status.events.on("chatHistoryCleared") do(e: Args):
|
||||
var args = ChannelArgs(e)
|
||||
self.view.clearMessages(args.chat.id)
|
||||
|
||||
self.status.events.on("channelJoined") do(e: Args):
|
||||
var channel = ChannelArgs(e)
|
||||
discard self.view.chats.addChatItemToList(channel.chat)
|
||||
self.status.chat.chatMessages(channel.chat.id)
|
||||
self.view.setActiveChannel(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(ChatIdArg(e).chatId)
|
||||
|
||||
self.status.events.on("sendingMessage") do(e:Args):
|
||||
var msg = MessageArgs(e)
|
||||
self.status.messages.trackMessage(msg.id, msg.channel)
|
||||
|
||||
self.status.events.on("messageSent") do(e:Args):
|
||||
var msg = MessageSentArgs(e)
|
||||
self.view.markMessageAsSent(msg.chatId, msg.id)
|
||||
|
||||
proc handleMailserverEvents(self: ChatController) =
|
||||
self.status.events.on("mailserverTopics") do(e: Args):
|
||||
self.status.mailservers.addTopics(TopicArgs(e).topics)
|
||||
if(self.status.mailservers.isSelectedMailserverAvailable):
|
||||
self.status.mailservers.requestMessages()
|
||||
|
||||
self.status.events.on("mailserverAvailable") do(e:Args):
|
||||
self.status.mailservers.requestMessages()
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
proc handleMessage(self: ChatController, data: MessageSignal) =
|
||||
self.status.chat.update(data.chats, data.messages)
|
||||
|
||||
proc handleDiscoverySummary(self: ChatController, data: DiscoverySummarySignal) =
|
||||
## Handle mailserver peers being added and removed
|
||||
self.status.mailservers.peerSummaryChange(data.enodes)
|
||||
|
||||
proc handleEnvelopeSent(self: ChatController, data: EnvelopeSentSignal) =
|
||||
self.status.messages.updateStatus(data.messageIds)
|
|
@ -147,6 +147,9 @@ QtObject:
|
|||
for k in self.messageList.keys:
|
||||
self.messageList[k].updateUsernames(contacts)
|
||||
|
||||
proc markMessageAsSent*(self:ChatsView, chat: string, messageId: string) =
|
||||
self.messageList[chat].markMessageAsSent(messageId)
|
||||
|
||||
proc getMessageList(self: ChatsView): QVariant {.slot.} =
|
||||
self.upsertChannel(self.activeChannel.id)
|
||||
return newQVariant(self.messageList[self.activeChannel.id])
|
||||
|
@ -160,7 +163,7 @@ QtObject:
|
|||
self.messagePushed()
|
||||
|
||||
proc sendMessage*(self: ChatsView, message: string) {.slot.} =
|
||||
discard self.status.chat.sendMessage(self.activeChannel.id, message)
|
||||
self.status.chat.sendMessage(self.activeChannel.id, message)
|
||||
|
||||
proc addRecentStickerToList*(self: ChatsView, sticker: Sticker) =
|
||||
self.stickers[RECENT_STICKERS].addStickerToList(sticker)
|
||||
|
|
|
@ -21,6 +21,7 @@ type
|
|||
ChatId = UserRole + 10
|
||||
SectionIdentifier = UserRole + 11
|
||||
Id = UserRole + 12
|
||||
OutgoingStatus = UserRole + 13
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
@ -71,6 +72,7 @@ QtObject:
|
|||
of ChatMessageRoles.ChatId: result = newQVariant(message.chatId)
|
||||
of ChatMessageRoles.SectionIdentifier: result = newQVariant(sectionIdentifier(message))
|
||||
of ChatMessageRoles.Id: result = newQVariant(message.id)
|
||||
of ChatMessageRoles.OutgoingStatus: result = newQVariant(message.outgoingStatus)
|
||||
|
||||
method roleNames(self: ChatMessageList): Table[int, string] =
|
||||
{
|
||||
|
@ -85,7 +87,8 @@ QtObject:
|
|||
ChatMessageRoles.FromAuthor.int:"fromAuthor",
|
||||
ChatMessageRoles.ChatId.int:"chatId",
|
||||
ChatMessageRoles.SectionIdentifier.int: "sectionIdentifier",
|
||||
ChatMessageRoles.Id.int: "messageId"
|
||||
ChatMessageRoles.Id.int: "messageId",
|
||||
ChatMessageRoles.OutgoingStatus.int: "outgoingStatus"
|
||||
}.toTable
|
||||
|
||||
proc add*(self: ChatMessageList, message: Message) =
|
||||
|
@ -104,6 +107,15 @@ QtObject:
|
|||
self.messages = @[]
|
||||
self.endResetModel()
|
||||
|
||||
proc markMessageAsSent*(self: ChatMessageList, messageId: string)=
|
||||
let topLeft = self.createIndex(0, 0, nil)
|
||||
let bottomRight = self.createIndex(self.messages.len, 0, nil)
|
||||
for m in self.messages.mitems:
|
||||
if m.id == messageId:
|
||||
m.outgoingStatus = "sent"
|
||||
self.dataChanged(topLeft, bottomRight, @[ChatMessageRoles.OutgoingStatus.int])
|
||||
|
||||
|
||||
proc updateUsernames*(self: ChatMessageList, contacts: seq[Profile]) =
|
||||
let topLeft = self.createIndex(0, 0, nil)
|
||||
let bottomRight = self.createIndex(self.messages.len, 0, nil)
|
||||
|
|
|
@ -107,6 +107,7 @@ proc mainProc() =
|
|||
signalController.addSubscriber(SignalType.Message, chat)
|
||||
signalController.addSubscriber(SignalType.Message, profile)
|
||||
signalController.addSubscriber(SignalType.DiscoverySummary, chat)
|
||||
signalController.addSubscriber(SignalType.EnvelopeSent, chat)
|
||||
signalController.addSubscriber(SignalType.NodeLogin, login)
|
||||
signalController.addSubscriber(SignalType.NodeLogin, onboarding)
|
||||
signalController.addSubscriber(SignalType.NodeStopped, login)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import NimQml, tables, json, chronicles, strutils, json_serialization
|
||||
import ../status/libstatus/types as status_types
|
||||
import types, messages, discovery, whisperFilter
|
||||
import types, messages, discovery, whisperFilter, envelopes
|
||||
|
||||
logScope:
|
||||
topics = "signals"
|
||||
|
@ -57,6 +57,8 @@ QtObject:
|
|||
case signalType:
|
||||
of SignalType.Message:
|
||||
signal = messages.fromEvent(jsonSignal)
|
||||
of SignalType.EnvelopeSent:
|
||||
signal = envelopes.fromEvent(jsonSignal)
|
||||
of SignalType.WhisperFilterAdded:
|
||||
signal = whisperFilter.fromEvent(jsonSignal)
|
||||
of SignalType.Wallet:
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import json
|
||||
import types
|
||||
|
||||
proc fromEvent*(jsonSignal: JsonNode): Signal =
|
||||
var signal:EnvelopeSentSignal = EnvelopeSentSignal()
|
||||
if jsonSignal["event"].kind != JNull and jsonSignal["event"].hasKey("ids") and jsonSignal["event"]["ids"].kind != JNull:
|
||||
for messageId in jsonSignal["event"]["ids"]:
|
||||
signal.messageIds.add(messageId.getStr)
|
||||
result = signal
|
||||
|
|
@ -140,7 +140,8 @@ proc toMessage*(jsonMsg: JsonNode): Message =
|
|||
text: jsonMsg{"text"}.getStr,
|
||||
timestamp: $jsonMsg{"timestamp"}.getInt,
|
||||
whisperTimestamp: $jsonMsg{"whisperTimestamp"}.getInt,
|
||||
isCurrentUser: $jsonMsg{"outgoingStatus"}.getStr == "sending",
|
||||
outgoingStatus: $jsonMsg{"outgoingStatus"}.getStr,
|
||||
isCurrentUser: $jsonMsg{"outgoingStatus"}.getStr == "sending" or $jsonMsg{"outgoingStatus"}.getStr == "sent",
|
||||
stickerHash: "",
|
||||
parsedText: @[]
|
||||
)
|
||||
|
|
|
@ -17,6 +17,9 @@ type NodeSignal* = ref object of Signal
|
|||
type WalletSignal* = ref object of Signal
|
||||
content*: string
|
||||
|
||||
type EnvelopeSentSignal* = ref object of Signal
|
||||
messageIds*: seq[string]
|
||||
|
||||
# Override this method
|
||||
method onSignal*(self: SignalSubscriber, data: Signal) {.base.} =
|
||||
error "onSignal must be overriden in controller. Signal is unhandled"
|
||||
|
|
|
@ -5,6 +5,7 @@ import libstatus/types
|
|||
import profile/profile
|
||||
import chat/[chat, message]
|
||||
import ../signals/messages
|
||||
import ../signals/types as signal_types
|
||||
import ens
|
||||
import eth/common/eth_types
|
||||
|
||||
|
@ -35,6 +36,10 @@ type
|
|||
channels*: Table[string, Chat]
|
||||
msgCursor*: Table[string, string]
|
||||
recentStickers*: seq[Sticker]
|
||||
|
||||
MessageArgs* = ref object of Args
|
||||
id*: string
|
||||
channel*: string
|
||||
|
||||
include chat/utils
|
||||
|
||||
|
@ -148,10 +153,11 @@ proc clearHistory*(self: ChatModel, chatId: string) =
|
|||
proc setActiveChannel*(self: ChatModel, chatId: string) =
|
||||
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))
|
||||
|
||||
proc sendMessage*(self: ChatModel, chatId: string, msg: string): string =
|
||||
var sentMessage = status_chat.sendChatMessage(chatId, msg)
|
||||
self.emitUpdate(sentMessage)
|
||||
sentMessage
|
||||
proc sendMessage*(self: ChatModel, chatId: string, msg: string) =
|
||||
var response = status_chat.sendChatMessage(chatId, msg)
|
||||
var (chats, messages) = self.processChatUpdate(parseJson(response))
|
||||
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
|
||||
self.events.emit("sendingMessage", MessageArgs(id: messages[0].id, channel: messages[0].chatId))
|
||||
|
||||
proc addStickerToRecent*(self: ChatModel, sticker: Sticker, save: bool = false) =
|
||||
self.recentStickers.insert(sticker, 0)
|
||||
|
@ -164,7 +170,9 @@ proc addStickerToRecent*(self: ChatModel, sticker: Sticker, save: bool = false)
|
|||
proc sendSticker*(self: ChatModel, chatId: string, sticker: Sticker) =
|
||||
var response = status_chat.sendStickerMessage(chatId, sticker)
|
||||
self.addStickerToRecent(sticker, save = true)
|
||||
self.emitUpdate(response)
|
||||
var (chats, messages) = self.processChatUpdate(parseJson(response))
|
||||
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
|
||||
self.events.emit("sendingMessage", MessageArgs(id: messages[0].id, channel: messages[0].chatId))
|
||||
|
||||
proc chatMessages*(self: ChatModel, chatId: string, initialLoad:bool = true) =
|
||||
if not self.msgCursor.hasKey(chatId):
|
||||
|
|
|
@ -41,6 +41,7 @@ type Message* = object
|
|||
whisperTimestamp*: string
|
||||
isCurrentUser*: bool
|
||||
stickerHash*: string
|
||||
outgoingStatus*: string
|
||||
|
||||
proc `$`*(self: Message): string =
|
||||
result = fmt"Message(id:{self.id}, chatId:{self.chatId}, clock:{self.clock}, from:{self.fromAuthor}, type:{self.contentType})"
|
||||
|
|
|
@ -124,3 +124,7 @@ proc kickGroupMember*(chatId: string, pubKey: string): string =
|
|||
|
||||
proc makeAdmin*(chatId: string, pubKey: string): string =
|
||||
callPrivateRPC("addAdminsToGroupChat".prefix, %* [nil, chatId, [pubKey]])
|
||||
|
||||
proc updateOutgoingMessageStatus*(messageId: string, status: string): string =
|
||||
result = callPrivateRPC("updateMessageOutgoingStatus".prefix, %* [messageId, status])
|
||||
# TODO: handle errors
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import tables, sets, eventemitter
|
||||
import libstatus/chat
|
||||
|
||||
type
|
||||
MessageDetails = object
|
||||
status: string
|
||||
chatId: string
|
||||
|
||||
MessagesModel* = ref object
|
||||
events*: EventEmitter
|
||||
messages*: Table[string, MessageDetails]
|
||||
confirmations*: HashSet[string]
|
||||
|
||||
MessageSentArgs* = ref object of Args
|
||||
id*: string
|
||||
chatId*: string
|
||||
|
||||
proc newMessagesModel*(events: EventEmitter): MessagesModel =
|
||||
result = MessagesModel()
|
||||
result.events = events
|
||||
result.messages = initTable[string, MessageDetails]()
|
||||
result.confirmations = initHashSet[string]()
|
||||
|
||||
proc delete*(self: MessagesModel) =
|
||||
discard
|
||||
|
||||
# For each message sent we call trackMessage to register the message id,
|
||||
# and wait until an EnvelopeSent signals is emitted for that message. However
|
||||
# due to communication being async, it's possible that the signal arrives
|
||||
# first, hence why we check if there's a confirmation (an envelope.sent)
|
||||
# inside trackMessage to emit the "messageSent" event
|
||||
|
||||
proc trackMessage*(self: MessagesModel, id: string, chatId: string) =
|
||||
self.messages[id] = MessageDetails(status: "sending", chatId: chatId)
|
||||
if self.confirmations.contains(id):
|
||||
self.confirmations.excl(id)
|
||||
self.messages[id].status = "sent"
|
||||
discard updateOutgoingMessageStatus(id, "sent")
|
||||
self.events.emit("messageSent", MessageSentArgs(id: id, chatId: chatId))
|
||||
|
||||
proc updateStatus*(self: MessagesModel, messageIds: seq[string]) =
|
||||
for messageId in messageIds:
|
||||
if self.messages.hasKey(messageId):
|
||||
self.messages[messageId].status = "sent"
|
||||
discard updateOutgoingMessageStatus(messageId, "sent")
|
||||
self.events.emit("messageSent", MessageSentArgs(id: messageId, chatId: self.messages[messageId].chatId))
|
||||
else:
|
||||
self.confirmations.incl(messageId)
|
|
@ -9,12 +9,14 @@ import accounts as accounts
|
|||
import wallet as wallet
|
||||
import node as node
|
||||
import mailservers as mailservers
|
||||
import messages as messages
|
||||
import contacts as contacts
|
||||
import profile
|
||||
|
||||
type Status* = ref object
|
||||
events*: EventEmitter
|
||||
chat*: ChatModel
|
||||
messages*: MessagesModel
|
||||
mailservers*: MailserverModel
|
||||
accounts*: AccountModel
|
||||
wallet*: WalletModel
|
||||
|
@ -31,6 +33,7 @@ proc newStatusInstance*(): Status =
|
|||
result.wallet.initEvents()
|
||||
result.node = node.newNodeModel()
|
||||
result.mailservers = mailservers.newMailserverModel(result.events)
|
||||
result.messages = messages.newMessagesModel(result.events)
|
||||
result.profile = profile.newProfileModel()
|
||||
result.contacts = contacts.newContactModel(result.events)
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ ScrollView {
|
|||
timestamp: model.timestamp
|
||||
sticker: model.sticker
|
||||
contentType: model.contentType
|
||||
outgoingStatus: model.outgoingStatus
|
||||
authorCurrentMsg: msgDelegate.ListView.section
|
||||
authorPrevMsg: msgDelegate.ListView.previousSection
|
||||
profileClick: profilePopup.openPopup.bind(profilePopup)
|
||||
|
|
|
@ -18,6 +18,7 @@ Item {
|
|||
property string sticker: "Qme8vJtyrEHxABcSVGPF95PtozDgUyfr1xGjePmFdZgk9v"
|
||||
property int contentType: 1 // constants don't work in default props
|
||||
property string chatId: "chatId"
|
||||
property string outgoingStatus: ""
|
||||
|
||||
property string authorCurrentMsg: "authorCurrentMsg"
|
||||
property string authorPrevMsg: "authorPrevMsg"
|
||||
|
@ -328,6 +329,39 @@ Item {
|
|||
// Probably only want to show this when clicking?
|
||||
visible: true
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: sentMessage
|
||||
color: Theme.darkGrey
|
||||
text: qsTr("Sent")
|
||||
anchors.top: contentType === Constants.stickerType ? stickerId.bottom : chatText.bottom
|
||||
anchors.bottomMargin: Theme.padding
|
||||
anchors.right: chatTime.left
|
||||
anchors.rightMargin: Theme.padding
|
||||
font.pixelSize: 10
|
||||
readOnly: true
|
||||
visible: isCurrentUser && outgoingStatus == "sent"
|
||||
}
|
||||
|
||||
SVGImage {
|
||||
id: sendingImg
|
||||
visible: isCurrentUser && outgoingStatus == "sending"
|
||||
anchors.top: chatText.top
|
||||
anchors.right: chatText.left
|
||||
anchors.rightMargin: 15
|
||||
source: "../../../img/settings.svg"
|
||||
width: 15
|
||||
height: 15
|
||||
fillMode: Image.Stretch
|
||||
RotationAnimator {
|
||||
target: sendingImg;
|
||||
from: 0;
|
||||
to: 360;
|
||||
duration: 1200
|
||||
running: true
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue