diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim index ceb7ef80e7..944ae45c7c 100644 --- a/src/app/modules/main/activity_center/module.nim +++ b/src/app/modules/main/activity_center/module.nim @@ -89,7 +89,8 @@ method convertToItems*[T]( ContentType(n.message.contentType), n.message.messageType, self.controller.decodeContentHash(n.message.sticker.hash), - n.message.sticker.pack + n.message.sticker.pack, + n.message.links, )) return notification_item.initItem( diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller.nim b/src/app/modules/main/chat_section/chat_content/messages/controller.nim index 43fe00bc9c..ccdcc1b18b 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/controller.nim @@ -136,6 +136,10 @@ method init*(self: Controller) = self.events.on(SignalType.HistoryRequestFailed.event) do(e:Args): self.delegate.setLoadingHistoryMessagesInProgress(false) + self.events.on(SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED) do(e: Args): + let args = LinkPreviewDataArgs(e) + self.delegate.onPreviewDataLoaded(args.response) + method getMySectionId*(self: Controller): string = return self.sectionId @@ -190,3 +194,6 @@ method decodeContentHash*(self: Controller, hash: string): string = method editMessage*(self: Controller, messageId: string, updatedMsg: string) = self.messageService.editMessage(messageId, updatedMsg) + +method getLinkPreviewData*(self: Controller, link: string, uuid: string): string = + self.messageService.asyncGetLinkPreviewData(link, uuid) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim b/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim index d904e21982..2ec2472175 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim @@ -63,9 +63,11 @@ method getMessageDetails*(self: AccessInterface, messageId: string): method deleteMessage*(self: AccessInterface, messageId: string) {.base.} = raise newException(ValueError, "No implementation available") - method decodeContentHash*(self: AccessInterface, hash: string): string {.base.} = raise newException(ValueError, "No implementation available") method editMessage*(self: AccessInterface, messageId: string, updatedMsg: string) {.base.} = raise newException(ValueError, "No implementation available") + +method getLinkPreviewData*(self: AccessInterface, link: string, uuid: string): string {.base.} = + raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/chat_content/messages/module.nim b/src/app/modules/main/chat_section/chat_content/messages/module.nim index 8194db5ddf..b807ef3260 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/module.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/module.nim @@ -90,7 +90,8 @@ proc createChatIdentifierItem(self: Module): Item = ContentType.ChatIdentifier, messageType = -1, sticker = "", - stickerPack = -1 + stickerPack = -1, + @[], ) method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto], @@ -120,7 +121,8 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se m.contentType.ContentType, m.messageType, sticker = self.controller.decodeContentHash(m.sticker.hash), - m.sticker.pack + m.sticker.pack, + m.links, ) for r in reactions: @@ -177,7 +179,8 @@ method messageAdded*(self: Module, message: MessageDto) = message.contentType.ContentType, message.messageType, sticker = self.controller.decodeContentHash(message.sticker.hash), - message.sticker.pack + message.sticker.pack, + message.links ) self.view.model().insertItemBasedOnTimestamp(item) @@ -308,3 +311,9 @@ method updateChatIdentifier*(self: Module) = method setLoadingHistoryMessagesInProgress*(self: Module, isLoading: bool) = self.view.setLoadingHistoryMessagesInProgress(isLoading) + +method getLinkPreviewData*(self: Module, link: string, uuid: string): string = + return self.controller.getLinkPreviewData(link, uuid) + +method onPreviewDataLoaded*(self: Module, previewData: string) = + self.view.onPreviewDataLoaded(previewData) diff --git a/src/app/modules/main/chat_section/chat_content/messages/private_interfaces/module_view_delegate_interface.nim b/src/app/modules/main/chat_section/chat_content/messages/private_interfaces/module_view_delegate_interface.nim index a81d16ba62..747bdb353e 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/private_interfaces/module_view_delegate_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/private_interfaces/module_view_delegate_interface.nim @@ -33,3 +33,9 @@ method editMessage*(self: AccessInterface, messageId: string, updatedMsg: string method onHistoryCleared*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") + +method getLinkPreviewData*(self: AccessInterface, link: string, uuid: string): string {.base.} = + raise newException(ValueError, "No implementation available") + +method onPreviewDataLoaded*(self: AccessInterface, previewData: string) {.base.} = + raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/messages/view.nim b/src/app/modules/main/chat_section/chat_content/messages/view.nim index 8c5da66412..dc322b8cd4 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/view.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/view.nim @@ -123,3 +123,11 @@ QtObject: proc editMessage*(self: View, messageId: string, updatedMsg: string) {.slot.} = self.delegate.editMessage(messageId, updatedMsg) + + proc getLinkPreviewData*(self: View, link: string, uuid: string): string {.slot.} = + return self.delegate.getLinkPreviewData(link, uuid) + + proc linkPreviewDataWasReceived*(self: View, previewData: string) {.signal.} + + proc onPreviewDataLoaded*(self: View, previewData: string) {.slot.} = + self.linkPreviewDataWasReceived(previewData) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 45896879cc..0a17c7bc49 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -151,7 +151,8 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy: m.contentType.ContentType, m.messageType, self.controller.decodeContentHash(m.sticker.hash), - m.sticker.pack + m.sticker.pack, + m.links, ) item.pinned = true item.pinnedBy = actionInitiatedBy diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim index ee24d447dd..6dcd0b7ae3 100644 --- a/src/app/modules/shared_models/message_item.nim +++ b/src/app/modules/shared_models/message_item.nim @@ -31,6 +31,7 @@ type pinnedBy: string editMode: bool isEdited: bool + links: seq[string] proc initItem*( id, @@ -50,7 +51,8 @@ proc initItem*( contentType: ContentType, messageType: int, sticker: string, - stickerPack: int + stickerPack: int, + links: seq[string], ): Item = result = Item() result.id = id @@ -75,6 +77,7 @@ proc initItem*( result.stickerPack = stickerPack result.editMode = false result.isEdited = false + result.links = links proc `$`*(self: Item): string = result = fmt"""Item( @@ -97,6 +100,7 @@ proc `$`*(self: Item): string = messageReactions: [{$self.reactionsModel}], editMode:{$self.editMode}, isEdited:{$self.isEdited} + links:{$self.links} )""" proc id*(self: Item): string {.inline.} = @@ -199,6 +203,9 @@ proc addReaction*(self: Item, emojiId: EmojiId, didIReactWithThisEmoji: bool, us proc removeReaction*(self: Item, emojiId: EmojiId, reactionId: string, didIRemoveThisReaction: bool) = self.reactionsModel.removeReaction(emojiId, reactionId, didIRemoveThisReaction) +proc links*(self: Item): seq[string] {.inline.} = + self.links + proc toJsonNode*(self: Item): JsonNode = result = %* { "id": self.id, @@ -224,7 +231,8 @@ proc toJsonNode*(self: Item): JsonNode = "pinned": self.pinned, "pinnedBy": self.pinnedBy, "editMode": self.editMode, - "isEdited": self.isEdited + "isEdited": self.isEdited, + "links": self.links } proc editMode*(self: Item): bool {.inline.} = diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim index 247eea30fe..a43f698ac5 100644 --- a/src/app/modules/shared_models/message_model.nim +++ b/src/app/modules/shared_models/message_model.nim @@ -30,6 +30,7 @@ type Reactions EditMode IsEdited + Links QtObject: type @@ -89,7 +90,8 @@ QtObject: ModelRole.PinnedBy.int:"pinnedBy", ModelRole.Reactions.int:"reactions", ModelRole.EditMode.int: "editMode", - ModelRole.IsEdited.int: "isEdited" + ModelRole.IsEdited.int: "isEdited", + ModelRole.Links.int: "links", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -153,6 +155,8 @@ QtObject: result = newQVariant(item.editMode) of ModelRole.IsEdited: result = newQVariant(item.isEdited) + of ModelRole.Links: + result = newQVariant(item.links.join(" ")) proc findIndexForMessageId(self: Model, messageId: string): int = for i in 0 ..< self.items.len: diff --git a/src/app_service/service/message/async_tasks.nim b/src/app_service/service/message/async_tasks.nim index 784c312570..a6ec11662d 100644 --- a/src/app_service/service/message/async_tasks.nim +++ b/src/app_service/service/message/async_tasks.nim @@ -1,6 +1,9 @@ include ../../common/json_utils include ../../../app/core/tasks/common +import status/statusgo_backend_new/chat as status_go_chat + + ################################################# # Async load messages ################################################# @@ -141,4 +144,33 @@ const asyncMarkCertainMessagesReadTask: Task = proc(argEncoded: string) {.gcsafe "error": error } arg.finish(responseJson) -################################################# \ No newline at end of file +################################################# + +################################################# +# Async GetLinkPreviewData +################################################# + +type + AsyncGetLinkPreviewDataTaskArg = ref object of QObjectTaskArg + link: string + uuid: string + +const asyncGetLinkPreviewDataTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncGetLinkPreviewDataTaskArg](argEncoded) + + var success = true + var result: JsonNode = %* {} + try: + let response = status_go_chat.getLinkPreviewData(arg.link) + result = response.result + except: + success = false + + let responseJson = %*{ + "link": arg.link, + "uuid": arg.uuid, + "success": success, + "result": result, + } + + arg.finish(responseJson) \ No newline at end of file diff --git a/src/app_service/service/message/service.nim b/src/app_service/service/message/service.nim index b00faf4ac1..6b904c95b2 100644 --- a/src/app_service/service/message/service.nim +++ b/src/app_service/service/message/service.nim @@ -35,6 +35,7 @@ const SIGNAL_MESSAGE_REACTION_REMOVED* = "messageReactionRemoved" const SIGNAL_MESSAGE_REACTION_FROM_OTHERS* = "messageReactionFromOthers" const SIGNAL_MESSAGE_DELETION* = "messageDeleted" const SIGNAL_MESSAGE_EDITED* = "messageEdited" +const SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED* = "messageLinkPreviewDataLoaded" include async_tasks @@ -77,6 +78,9 @@ type chatId*: string message*: MessageDto + LinkPreviewDataArgs* = ref object of Args + response*: string + QtObject: type Service* = ref object of QObject events: EventEmitter @@ -530,6 +534,19 @@ QtObject: proc getNumOfPinnedMessages*(self: Service, chatId: string): int = return self.numOfPinnedMessagesPerChat[chatId] + proc onAsyncGetLinkPreviewData*(self: Service, response: string) {.slot.} = + self.events.emit(SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED, LinkPreviewDataArgs(response: response)) + + proc asyncGetLinkPreviewData*(self: Service, link: string, uuid: string) = + let arg = AsyncGetLinkPreviewDataTaskArg( + tptr: cast[ByteAddress](asyncGetLinkPreviewDataTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncGetLinkPreviewData", + link: link, + uuid: uuid + ) + self.threadpool.start(arg) + # See render-inline in status-react/src/status_im/ui/screens/chat/message/message.cljs proc renderInline(self: Service, parsedTextChild: ParsedTextChild): string = let value = escape_html(parsedTextChild.literal) @@ -635,4 +652,4 @@ proc editMessage*(self: Service, messageId: string, updatedMsg: string) = self.events.emit(SIGNAL_MESSAGE_EDITED, data) except Exception as e: - error "error: ", methodName="editMessage", errName = e.name, errDesription = e.msg + error "error: ", methodName="editMessage", errName = e.name, errDesription = e.msg \ No newline at end of file diff --git a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml index 59b0798d8b..a7ac038ddd 100644 --- a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml @@ -129,6 +129,7 @@ ModalPopup { pinnedMessage: model.pinned messagePinnedBy: model.pinnedBy reactionsModel: model.reactions + linkUrls: model.links // This is possible since we have all data loaded before we load qml. // When we fetch messages to fulfill a gap we have to set them at once. diff --git a/ui/app/AppLayouts/Chat/stores/MessageStore.qml b/ui/app/AppLayouts/Chat/stores/MessageStore.qml index d4aba5983f..881577ef81 100644 --- a/ui/app/AppLayouts/Chat/stores/MessageStore.qml +++ b/ui/app/AppLayouts/Chat/stores/MessageStore.qml @@ -187,4 +187,11 @@ QtObject { return msg } + + + function getLinkPreviewData(url, uuid) { + if(!messageModule) + return + return messageModule.getLinkPreviewData(url, uuid) + } } diff --git a/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml b/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml index 2c79ef29aa..9da44063ec 100644 --- a/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml +++ b/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml @@ -122,6 +122,7 @@ Item { amISender: model.message.amISender messageImage: model.message.messageImage messageTimestamp: model.timestamp + linkUrls: model.links //timestamp: model.message.timestamp messageOutgoingStatus: model.message.outgoingStatus messageContentType: model.message.contentType diff --git a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml index 4805628de1..440c18a3ab 100644 --- a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml @@ -340,6 +340,7 @@ Item { stickerPack: model.stickerPack editModeOn: model.editMode isEdited: model.isEdited + linkUrls: model.links // This is possible since we have all data loaded before we load qml. // When we fetch messages to fulfill a gap we have to set them at once. diff --git a/ui/imports/shared/views/chat/CompactMessageView.qml b/ui/imports/shared/views/chat/CompactMessageView.qml index 00fcc48f55..da3013bf69 100644 --- a/ui/imports/shared/views/chat/CompactMessageView.qml +++ b/ui/imports/shared/views/chat/CompactMessageView.qml @@ -52,6 +52,7 @@ Item { } } property bool editModeOn: false + property string linkUrls: "" signal openStickerPackPopup(string stickerPackId) signal addEmoji(bool isProfileClick, bool isSticker, bool isImage , var image, bool emojiOnly, bool hideEmojiPicker) @@ -468,8 +469,6 @@ Item { visible: !editModeOn ChatTextView { id: chatText - // Not Refactored Yet -// store: rootStore readonly property int leftPadding: chatImage.anchors.leftMargin + chatImage.width + chatHorizontalPadding visible: { const urls = linkUrls.split(" ") @@ -586,10 +585,9 @@ Item { sourceComponent: Component { LinksMessageView { - // Not Refactored Yet -// store: rootStore - linkUrls: linkUrls + linkUrls: root.linkUrls container: root.container + messageStore: root.messageStore isCurrentUser: isCurrentUser } } diff --git a/ui/imports/shared/views/chat/LinksMessageView.qml b/ui/imports/shared/views/chat/LinksMessageView.qml index fcdffc2f4b..70702f9b10 100644 --- a/ui/imports/shared/views/chat/LinksMessageView.qml +++ b/ui/imports/shared/views/chat/LinksMessageView.qml @@ -9,14 +9,14 @@ import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 import shared.status 1.0 -import shared.stores 1.0 import shared.panels 1.0 +import shared.stores 1.0 import shared.panels.chat 1.0 import shared.controls.chat 1.0 Column { id: root - property var store + property var messageStore property var container property string linkUrls: "" property bool isCurrentUser: false @@ -66,42 +66,37 @@ Column { } } - // Not Refactored Yet -// Connections { -// id: linkFetchConnections -// enabled: false -// target: root.store.chatsModelInst -// onLinkPreviewDataWasReceived: { -// let response -// try { -// response = JSON.parse(previewData) + Connections { + id: linkFetchConnections + enabled: false + target: root.messageStore.messageModule + onLinkPreviewDataWasReceived: { + let response + try { + response = JSON.parse(previewData) + } catch (e) { + console.error(previewData, e) + return + } + if (response.uuid !== linkMessageLoader.uuid) return + linkFetchConnections.enabled = false -// } catch (e) { -// console.error(previewData, e) -// return -// } + if (!response.success) { + console.error("could not get preview data") + return undefined + } + linkData = response.result -// if (response.uuid !== linkMessageLoader.uuid) return - -// linkFetchConnections.enabled = false - -// if (!response.success) { -// console.error(response.result.error) -// return undefined -// } - -// linkData = response.result - -// if (linkData.contentType.startsWith("image/")) { -// return linkMessageLoader.sourceComponent = unfurledImageComponent -// } -// if (linkData.site && linkData.title) { -// linkData.address = link -// return linkMessageLoader.sourceComponent = unfurledLinkComponent -// } -// } -// } + if (linkData.contentType.startsWith("image/")) { + return linkMessageLoader.sourceComponent = unfurledImageComponent + } + if (linkData.site && linkData.title) { + linkData.address = link + return linkMessageLoader.sourceComponent = unfurledLinkComponent + } + } + } // Not Refactored Yet // Connections { @@ -185,9 +180,8 @@ Column { } linkFetchConnections.enabled = true - // Not Refactored Yet - return "" -// return root.store.chatsModelInst.getLinkPreviewData(link, linkMessageLoader.uuid) + + root.messageStore.getLinkPreviewData(link, linkMessageLoader.uuid) } // setting the height to 0 allows the "enable link" dialog to // disappear correctly when RootStore.neverAskAboutUnfurlingAgain @@ -226,7 +220,7 @@ Column { Component { id: invitationBubble InvitationBubbleView { - store: root.store + // store: root.store communityId: linkData.communityId isLink: true anchors.left: parent.left diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index 18a93609af..433722573c 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -37,6 +37,7 @@ Column { property bool pinnedMessage: false property string messagePinnedBy: "" property var reactionsModel: [] + property string linkUrls: "" property int prevMessageIndex: -1 property var prevMessageAsJsonObj @@ -101,7 +102,6 @@ Column { property string emojiReactions: "" property bool timeout: false property bool hasMention: false - property string linkUrls: "" property bool placeholderMessage: false property bool activityCenterMessage: false property bool read: true @@ -353,6 +353,7 @@ Column { isCurrentUser: root.amISender isHovered: root.isHovered editModeOn: root.editModeOn + linkUrls: root.linkUrls onAddEmoji: { root.clickMessage(isProfileClick, isSticker, isImage , image, emojiOnly, hideEmojiPicker)