diff --git a/src/app/chat/event_handling.nim b/src/app/chat/event_handling.nim index 4674558b1d..8ed107cba0 100644 --- a/src/app/chat/event_handling.nim +++ b/src/app/chat/event_handling.nim @@ -6,6 +6,7 @@ import import # status-desktop libs ../../status/chat/chat as status_chat, ./views/communities, + ../../status/libstatus/mailservers as status_mailservers, ../../status/tasks/marathon, ../../status/tasks/marathon/mailserver/worker, ../../status/libstatus/mailservers # TODO: needed for MailserverTopic type, remove? @@ -144,6 +145,7 @@ proc handleMailserverEvents(self: ChatController) = mailserverWorker.start(task) self.status.events.on("mailserverAvailable") do(e:Args): + discard status_mailservers.requestAllHistoricMessages() let task = GetMailserverTopicsTaskArg( `method`: "getMailserverTopics", vptr: cast[ByteAddress](self.view.vptr), diff --git a/src/app/chat/view.nim b/src/app/chat/view.nim index e595a2cbf3..1f0b7782d9 100644 --- a/src/app/chat/view.nim +++ b/src/app/chat/view.nim @@ -719,6 +719,12 @@ QtObject: ) mailserverWorker.start(task) + + proc fillGaps*(self: ChatsView, messageId: string) {.slot.} = + self.loadingMessages = true + self.loadingMessagesChanged(true) + discard status_mailservers.fillGaps(self.activeChannel.id, @[messageId]) + proc leaveActiveChat*(self: ChatsView) {.slot.} = self.status.chat.leave(self.activeChannel.id) let diff --git a/src/app/chat/views/message_list.nim b/src/app/chat/views/message_list.nim index 2828a473c8..cd3bd1e426 100644 --- a/src/app/chat/views/message_list.nim +++ b/src/app/chat/views/message_list.nim @@ -37,6 +37,8 @@ type CommunityId = UserRole + 27 HasMention = UserRole + 28 StickerPackId = UserRole + 29 + GapFrom = UserRole + 30 + GapTo = UserRole + 31 QtObject: type @@ -172,6 +174,8 @@ QtObject: })) of ChatMessageRoles.Alias: result = newQVariant(message.alias) of ChatMessageRoles.LocalName: result = newQVariant(message.localName) + of ChatMessageRoles.GapFrom: result = newQVariant(message.gapFrom) + of ChatMessageRoles.GapTo: result = newQVariant(message.gapTo) method roleNames(self: ChatMessageList): Table[int, string] = { @@ -202,7 +206,9 @@ QtObject: ChatMessageRoles.Alias.int:"alias", ChatMessageRoles.HasMention.int:"hasMention", ChatMessageRoles.LocalName.int:"localName", - ChatMessageRoles.StickerPackId.int:"stickerPackId" + ChatMessageRoles.StickerPackId.int:"stickerPackId", + ChatMessageRoles.GapFrom.int:"gapFrom", + ChatMessageRoles.GapTo.int:"gapTo" }.toTable proc getMessageIndex(self: ChatMessageList, messageId: string): int {.slot.} = diff --git a/src/status/chat/message.nim b/src/status/chat/message.nim index 651b1ea299..50a9e1530d 100644 --- a/src/status/chat/message.nim +++ b/src/status/chat/message.nim @@ -13,6 +13,7 @@ type ContentType* {.pure.} = enum Image = 7, Audio = 8 Community = 9 + Gap = 10 type TextItem* = object textType*: string @@ -36,6 +37,8 @@ type Message* = object localName*: string chatId*: string clock*: int + gapFrom*: int + gapTo*: int commandParameters*: CommandParameters contentType*: ContentType ensName*: string diff --git a/src/status/libstatus/mailservers.nim b/src/status/libstatus/mailservers.nim index e669d6cf63..efdd8d0c66 100644 --- a/src/status/libstatus/mailservers.nim +++ b/src/status/libstatus/mailservers.nim @@ -45,6 +45,12 @@ proc requestMessages*(topics: seq[string], symKeyID: string, peer: string, numbe } ]) +proc requestAllHistoricMessages*(): string = + return callPrivateRPC("requestAllHistoricMessages".prefix, %*[]) + +proc fillGaps*(chatId: string, messageIds: seq[string]): string = + return callPrivateRPC("fillGaps".prefix, %*[chatId, messageIds]) + proc getMailserverTopics*(): string = return callPrivateRPC("mailservers_getMailserverTopics", %*[]) diff --git a/src/status/signals/messages.nim b/src/status/signals/messages.nim index 033a228a9b..f4e9a738c8 100644 --- a/src/status/signals/messages.nim +++ b/src/status/signals/messages.nim @@ -1,4 +1,4 @@ -import json, random, strutils, sequtils, sugar, chronicles +import json, random, strutils, sequtils, sugar, chronicles, tables import json_serialization import ../libstatus/utils import ../libstatus/accounts as status_accounts @@ -283,8 +283,12 @@ proc toMessage*(jsonMsg: JsonNode, pk: string): Message = hasMention: false ) - if jsonMsg["parsedText"].kind != JNull: - for text in jsonMsg["parsedText"]: + if contentType == ContentType.Gap: + message.gapFrom = jsonMsg["gapParameters"]["from"].getInt + message.gapTo = jsonMsg["gapParameters"]["to"].getInt + + if jsonMsg.contains("parsedText") and jsonMsg{"parsedText"}.kind != JNull: + for text in jsonMsg{"parsedText"}: message.parsedText.add(text.toTextItem) message.linkUrls = concat(message.parsedText.map(t => t.children.filter(c => c.textType == "link"))) diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml index b91ddf3079..382821a555 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml @@ -335,6 +335,8 @@ ScrollView { communityId: model.communityId hasMention: model.hasMention stickerPackId: model.stickerPackId + gapFrom: model.gapFrom + gapTo: model.gapTo prevMessageIndex: { // This is used in order to have access to the previous message and determine the timestamp // we can't rely on the index because the sequence of messages is not ordered on the nim side diff --git a/ui/app/AppLayouts/Chat/ChatColumn/Message.qml b/ui/app/AppLayouts/Chat/ChatColumn/Message.qml index ab6df4b2fa..3ce0b469da 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/Message.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/Message.qml @@ -28,6 +28,8 @@ Item { property bool placeholderMessage: false property string communityId: "" property int stickerPackId: -1 + property int gapFrom: 0 + property int gapTo: 0 property string displayUserName: { if (isCurrentUser) { @@ -198,6 +200,8 @@ Item { return fetchMoreMessagesButtonComponent case Constants.systemMessagePrivateGroupType: return privateGroupHeaderComponent + case Constants.gapType: + return gapComponent default: return isStatusUpdate ? statusUpdateComponent : (appSettings.useCompactMode ? compactMessageComponent : messageComponent) @@ -210,6 +214,54 @@ Item { id: timer } + Component { + id: gapComponent + Item { + id: wrapper + height: childrenRect.height + Style.current.smallPadding * 2 + anchors.left: parent.left + anchors.right: parent.right + Separator { + id: sep1 + } + StyledText { + id: fetchMoreButton + font.weight: Font.Medium + font.pixelSize: Style.current.primaryTextFontSize + color: Style.current.blue + //% "↓ " + text: qsTr("Fetch 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.fillGaps(messageId) + root.visible = false; + root.height = 0; + } + } + } + StyledText { + id: fetchDate + anchors.top: fetchMoreButton.bottom + anchors.topMargin: 3 + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + color: Style.current.secondaryText + //% "before %1" + text: qsTr("Between %1 and %2").arg(new Date(root.gapFrom*1000)).arg(new Date(root.gapTo*1000)) + } + Separator { + anchors.top: fetchDate.bottom + anchors.topMargin: Style.current.smallPadding + } + } + } + Component { id: fetchMoreMessagesButtonComponent Item { diff --git a/ui/imports/Constants.qml b/ui/imports/Constants.qml index 4aae93e3c7..57d1a085c6 100644 --- a/ui/imports/Constants.qml +++ b/ui/imports/Constants.qml @@ -63,6 +63,7 @@ QtObject { readonly property int imageType: 7 readonly property int audioType: 8 readonly property int communityInviteType: 9 + readonly property int gapType: 10 readonly property string watchWalletType: "watch" readonly property string keyWalletType: "key"