feat: introduce "fetch more messages" button to request old messages
Closes #149
This commit is contained in:
parent
464a2018d4
commit
1481f2648f
|
@ -78,7 +78,7 @@ proc handleMailserverEvents(self: ChatController) =
|
|||
|
||||
self.status.events.on("mailserverAvailable") do(e:Args):
|
||||
let mailserverTopics = self.status.mailservers.getMailserverTopics()
|
||||
var fromValue: int64 = times.toUnix(times.getTime()) - 86400
|
||||
var fromValue = times.toUnix(times.getTime()) - 86400 # today - 24 hours
|
||||
|
||||
if mailserverTopics.len > 0:
|
||||
fromValue = min(mailserverTopics.map(topic => topic.lastRequest))
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import NimQml, Tables, json, sequtils, chronicles, times, re, sugar, strutils, os, strformat
|
||||
import ../../status/status
|
||||
import ../../status/mailservers
|
||||
import ../../status/libstatus/accounts/constants
|
||||
import ../../status/libstatus/mailservers as status_mailservers
|
||||
import ../../status/accounts as status_accounts
|
||||
import ../../status/chat as status_chat
|
||||
import ../../status/messages as status_messages
|
||||
|
@ -35,6 +37,7 @@ QtObject:
|
|||
channelOpenTime*: Table[string, int64]
|
||||
connected: bool
|
||||
unreadMessageCnt: int
|
||||
oldestMessageTimestamp: int64
|
||||
|
||||
proc setup(self: ChatsView) = self.QAbstractListModel.setup
|
||||
|
||||
|
@ -62,6 +65,27 @@ QtObject:
|
|||
result.pubKey = ""
|
||||
result.setup()
|
||||
|
||||
proc oldestMessageTimestampChanged*(self: ChatsView) {.signal.}
|
||||
|
||||
proc getOldestMessageTimestamp*(self: ChatsView): QVariant {.slot.} =
|
||||
newQVariant($self.oldestMessageTimestamp)
|
||||
|
||||
QtProperty[QVariant] oldestMsgTimestamp:
|
||||
read = getOldestMessageTimestamp
|
||||
notify = oldestMessageTimestampChanged
|
||||
|
||||
proc setLastMessageTimestamp(self: ChatsView, force = false) =
|
||||
if self.status.chat.lastMessageTimestamps.hasKey(self.activeChannel.id):
|
||||
if force or self.status.chat.lastMessageTimestamps[self.activeChannel.id] <= self.oldestMessageTimestamp:
|
||||
self.oldestMessageTimestamp = self.status.chat.lastMessageTimestamps[self.activeChannel.id]
|
||||
else:
|
||||
let topics = self.status.mailservers.getMailserverTopicsByChatId(self.activeChannel.id)
|
||||
if topics.len > 0:
|
||||
self.oldestMessageTimestamp = topics[0].lastRequest
|
||||
else:
|
||||
self.oldestMessageTimestamp = times.toUnix(times.getTime())
|
||||
self.oldestMessageTimestampChanged()
|
||||
|
||||
proc addStickerPackToList*(self: ChatsView, stickerPack: StickerPack, isInstalled, isBought: bool) =
|
||||
self.stickerPacks.addStickerPackToList(stickerPack, newStickerList(stickerPack.stickers), isInstalled, isBought)
|
||||
|
||||
|
@ -206,6 +230,7 @@ QtObject:
|
|||
self.status.chat.setActiveChannel(selectedChannel.id)
|
||||
discard self.status.chat.markAllChannelMessagesRead(selectedChannel.id)
|
||||
self.currentSuggestions.setNewData(self.status.contacts.getContacts())
|
||||
self.setLastMessageTimestamp(true)
|
||||
self.activeChannelChanged()
|
||||
|
||||
proc getActiveChannelIdx(self: ChatsView): QVariant {.slot.} =
|
||||
|
@ -237,6 +262,7 @@ QtObject:
|
|||
self.activeChannel.setChatItem(self.chats.getChannel(self.chats.chats.findIndexById(channel)))
|
||||
discard self.status.chat.markAllChannelMessagesRead(self.activeChannel.id)
|
||||
self.currentSuggestions.setNewData(self.status.contacts.getContacts())
|
||||
self.setLastMessageTimestamp(true)
|
||||
self.activeChannelChanged()
|
||||
|
||||
proc getActiveChannel*(self: ChatsView): QVariant {.slot.} =
|
||||
|
@ -373,6 +399,8 @@ QtObject:
|
|||
trace "Loading more messages", chaId = self.activeChannel.id
|
||||
self.status.chat.chatMessages(self.activeChannel.id, false)
|
||||
self.status.chat.chatReactions(self.activeChannel.id, false)
|
||||
if self.status.chat.msgCursor[self.activeChannel.id] == "":
|
||||
self.setLastMessageTimestamp()
|
||||
self.messagesLoaded();
|
||||
|
||||
proc loadMoreMessagesWithIndex*(self: ChatsView, channelIndex: int) {.slot.} =
|
||||
|
@ -382,6 +410,16 @@ QtObject:
|
|||
trace "Loading more messages", chaId = selectedChannel.id
|
||||
self.status.chat.chatMessages(selectedChannel.id, false)
|
||||
self.status.chat.chatReactions(selectedChannel.id, false)
|
||||
self.setLastMessageTimestamp()
|
||||
self.messagesLoaded();
|
||||
|
||||
proc requestMoreMessages*(self: ChatsView) {.slot.} =
|
||||
let topics = self.status.mailservers.getMailserverTopicsByChatId(self.activeChannel.id).map(topic => topic.topic)
|
||||
let currentOldestMessageTimestamp = self.oldestMessageTimestamp
|
||||
self.oldestMessageTimestamp = self.oldestMessageTimestamp - 86400
|
||||
|
||||
self.status.mailservers.requestMessages(topics, self.oldestMessageTimestamp, currentOldestMessageTimestamp, true)
|
||||
self.oldestMessageTimestampChanged()
|
||||
self.messagesLoaded();
|
||||
|
||||
proc leaveChatByIndex*(self: ChatsView, channelIndex: int) {.slot.} =
|
||||
|
|
|
@ -52,6 +52,10 @@ QtObject:
|
|||
|
||||
include message_format
|
||||
|
||||
proc fetchMoreMessagesButton(self: ChatMessageList): Message =
|
||||
result = Message()
|
||||
result.contentType = ContentType.FetchMoreMessagesButton;
|
||||
|
||||
proc chatIdentifier(self: ChatMessageList, chatId:string): Message =
|
||||
result = Message()
|
||||
result.contentType = ContentType.ChatIdentifier;
|
||||
|
@ -59,7 +63,7 @@ QtObject:
|
|||
|
||||
proc newChatMessageList*(chatId: string, status: Status): ChatMessageList =
|
||||
new(result, delete)
|
||||
result.messages = @[result.chatIdentifier(chatId)]
|
||||
result.messages = @[result.chatIdentifier(chatId), result.fetchMoreMessagesButton()]
|
||||
result.messageIndex = initTable[string, int]()
|
||||
result.timedoutMessages = initHashSet[string]()
|
||||
result.status = status
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import eventemitter, json, strutils, sequtils, tables, chronicles, sugar
|
||||
import eventemitter, json, strutils, sequtils, tables, chronicles, sugar, times
|
||||
import libstatus/contracts as status_contracts
|
||||
import libstatus/chat as status_chat
|
||||
import libstatus/mailservers as status_mailservers
|
||||
|
@ -51,6 +51,7 @@ type
|
|||
availableStickerPacks*: Table[int, StickerPack]
|
||||
installedStickerPacks*: Table[int, StickerPack]
|
||||
purchasedStickerPacks*: seq[int]
|
||||
lastMessageTimestamps*: Table[string, int64]
|
||||
|
||||
MessageArgs* = ref object of Args
|
||||
id*: string
|
||||
|
@ -69,6 +70,7 @@ proc newChatModel*(events: EventEmitter): ChatModel =
|
|||
result.availableStickerPacks = initTable[int, StickerPack]()
|
||||
result.installedStickerPacks = initTable[int, StickerPack]()
|
||||
result.purchasedStickerPacks = @[]
|
||||
result.lastMessageTimestamps = initTable[string, int64]()
|
||||
|
||||
|
||||
proc delete*(self: ChatModel) =
|
||||
|
@ -79,6 +81,15 @@ proc update*(self: ChatModel, chats: seq[Chat], messages: seq[Message], emojiRea
|
|||
if chat.isActive:
|
||||
self.channels[chat.id] = chat
|
||||
|
||||
for message in messages:
|
||||
let chatId = message.chatId
|
||||
let ts = times.convert(Milliseconds, Seconds, message.whisperTimestamp.parseInt())
|
||||
if not self.lastMessageTimestamps.hasKey(chatId):
|
||||
self.lastMessageTimestamps[chatId] = ts
|
||||
else:
|
||||
if self.lastMessageTimestamps[chatId] > ts:
|
||||
self.lastMessageTimestamps[chatId] = ts
|
||||
|
||||
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[], emojiReactions: emojiReactions))
|
||||
|
||||
proc hasChannel*(self: ChatModel, chatId: string): bool =
|
||||
|
@ -293,6 +304,12 @@ proc chatMessages*(self: ChatModel, chatId: string, initialLoad:bool = true) =
|
|||
|
||||
let messageTuple = status_chat.chatMessages(chatId, self.msgCursor[chatId])
|
||||
self.msgCursor[chatId] = messageTuple[0];
|
||||
|
||||
if messageTuple[1].len > 0:
|
||||
let lastMsgIndex = messageTuple[1].len - 1
|
||||
let ts = times.convert(Milliseconds, Seconds, messageTuple[1][lastMsgIndex].whisperTimestamp.parseInt())
|
||||
self.lastMessageTimestamps[chatId] = ts
|
||||
|
||||
self.events.emit("messagesLoaded", MsgsLoadedArgs(messages: messageTuple[1]))
|
||||
|
||||
proc chatReactions*(self: ChatModel, chatId: string, initialLoad:bool = true) =
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import strformat
|
||||
|
||||
type ContentType* {.pure.} = enum
|
||||
FetchMoreMessagesButton = -2
|
||||
ChatIdentifier = -1,
|
||||
Unknown = 0,
|
||||
Message = 1,
|
||||
|
|
|
@ -63,10 +63,13 @@ proc update*(peer: string) =
|
|||
proc delete*(peer: string) =
|
||||
discard callPrivateRPC("mailservers_deleteMailserver", %* [peer])
|
||||
|
||||
proc requestMessages*(topics: seq[string], symKeyID: string, peer: string, numberOfMessages: int, fromTimestamp: int64 = 0) =
|
||||
var fromValue = (times.toUnix(times.getTime()) - 86400)
|
||||
proc requestMessages*(topics: seq[string], symKeyID: string, peer: string, numberOfMessages: int, fromTimestamp: int64 = 0, toTimestamp: int64 = 0, force: bool = false) =
|
||||
var toValue = times.toUnix(times.getTime())
|
||||
var fromValue = toValue - 86400
|
||||
if fromTimestamp != 0:
|
||||
fromValue = fromTimestamp
|
||||
if toTimestamp != 0:
|
||||
toValue = toTimestamp
|
||||
|
||||
echo callPrivateRPC("requestMessages".prefix, %* [
|
||||
{
|
||||
|
@ -76,7 +79,9 @@ proc requestMessages*(topics: seq[string], symKeyID: string, peer: string, numbe
|
|||
"timeout": 30,
|
||||
"limit": numberOfMessages,
|
||||
"cursor": nil,
|
||||
"from": fromValue
|
||||
"from": fromValue,
|
||||
"to": toValue,
|
||||
"force": force
|
||||
}
|
||||
])
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import algorithm, json, random, math, os, tables, sets, chronicles, eventemitter, sequtils, locks
|
||||
import algorithm, json, random, math, os, tables, sets, chronicles, eventemitter, sequtils, locks, sugar
|
||||
import libstatus/core as status_core
|
||||
import libstatus/chat as status_chat
|
||||
import libstatus/mailservers as status_mailservers
|
||||
|
@ -128,10 +128,10 @@ proc peerSummaryChange*(self: MailserverModel, peers: seq[string]) =
|
|||
self.nodes[peer] = MailserverStatus.Connected
|
||||
self.events.emit("peerConnected", MailserverArg(peer: peer))
|
||||
|
||||
proc requestMessages*(self: MailserverModel, topics: seq[string], fromValue: int64 = 0) =
|
||||
proc requestMessages*(self: MailserverModel, topics: seq[string], fromValue: int64 = 0, toValue: int64 = 0, force: bool = false) =
|
||||
debug "Requesting messages from", mailserver=self.selectedMailserver
|
||||
let generatedSymKey = status_chat.generateSymKeyFromPassword()
|
||||
status_mailservers.requestMessages(topics, generatedSymKey, self.selectedMailserver, 1000, fromValue)
|
||||
status_mailservers.requestMessages(topics, generatedSymKey, self.selectedMailserver, 1000, fromValue, toValue, force)
|
||||
|
||||
proc getMailserverTopics*(self: MailserverModel): seq[MailserverTopic] =
|
||||
let response = status_mailservers.getMailserverTopics()
|
||||
|
@ -147,6 +147,10 @@ proc getMailserverTopics*(self: MailserverModel): seq[MailserverTopic] =
|
|||
lastRequest: topic["last-request"].getInt
|
||||
))
|
||||
|
||||
proc getMailserverTopicsByChatId*(self: MailserverModel, chatId: string): seq[MailServerTopic] =
|
||||
result = self.getMailserverTopics()
|
||||
.filter(topic => topic.chatIds.contains(chatId))
|
||||
|
||||
proc addMailserverTopic*(self: MailserverModel, topic: MailserverTopic) =
|
||||
discard status_mailservers.addMailserverTopic(topic)
|
||||
|
||||
|
|
|
@ -75,6 +75,8 @@ Item {
|
|||
switch(contentType) {
|
||||
case Constants.chatIdentifier:
|
||||
return channelIdentifierComponent
|
||||
case Constants.fetchMoreMessagesButton:
|
||||
return fetchMoreMessagesButtonComponent
|
||||
case Constants.systemMessagePrivateGroupType:
|
||||
return privateGroupHeaderComponent
|
||||
default:
|
||||
|
@ -83,6 +85,50 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fetchMoreMessagesButtonComponent
|
||||
Item {
|
||||
id: wrapper
|
||||
height: wrapper.visible ? fetchMoreButton.height + fetchDate.height + 3 + Style.current.smallPadding*2 : 0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Separator {
|
||||
id: sep1
|
||||
}
|
||||
StyledText {
|
||||
id: fetchMoreButton
|
||||
font.weight: Font.Medium
|
||||
font.pixelSize: 15
|
||||
color: Style.current.blue
|
||||
text: qsTr("↓ Fetch more messages")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: sep1.bottom
|
||||
anchors.topMargin: Style.current.smallPadding
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
chatsModel.requestMoreMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
id: fetchDate
|
||||
anchors.top: fetchMoreButton.bottom
|
||||
anchors.topMargin: 3
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: Style.current.darkGrey
|
||||
text: qsTr("before %1").arg(new Date(chatsModel.oldestMsgTimestamp*1000).toDateString())
|
||||
}
|
||||
Separator {
|
||||
anchors.top: fetchDate.bottom
|
||||
anchors.topMargin: Style.current.smallPadding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: channelIdentifierComponent
|
||||
ChannelIdentifier {
|
||||
|
|
|
@ -7,6 +7,7 @@ QtObject {
|
|||
readonly property int chatTypePublic: 2
|
||||
readonly property int chatTypePrivateGroupChat: 3
|
||||
|
||||
readonly property int fetchMoreMessagesButton: -2
|
||||
readonly property int chatIdentifier: -1
|
||||
readonly property int unknownContentType: 0
|
||||
readonly property int messageType: 1
|
||||
|
|
Loading…
Reference in New Issue