mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-16 08:37:12 +00:00
feature: support unfurled Status links (contact/community/channel) (#12303)
* chore: move `LinkPreviewThumbnail` to a separate file
This commit is contained in:
parent
9581e6deb6
commit
520d34240a
@ -11,6 +11,9 @@ include ../../app_service/service/accounts/utils
|
|||||||
QtObject:
|
QtObject:
|
||||||
type Utils* = ref object of QObject
|
type Utils* = ref object of QObject
|
||||||
|
|
||||||
|
proc isCompressedPubKey*(self: Utils, publicKey: string): bool
|
||||||
|
proc getDecompressedPk*(self: Utils, compressedKey: string): string
|
||||||
|
|
||||||
proc setup(self: Utils) =
|
proc setup(self: Utils) =
|
||||||
self.QObject.setup
|
self.QObject.setup
|
||||||
|
|
||||||
@ -129,13 +132,22 @@ QtObject:
|
|||||||
result = escape_html(text)
|
result = escape_html(text)
|
||||||
|
|
||||||
proc getEmojiHashAsJson*(self: Utils, publicKey: string): string {.slot.} =
|
proc getEmojiHashAsJson*(self: Utils, publicKey: string): string {.slot.} =
|
||||||
procs_from_visual_identity_service.getEmojiHashAsJson(publicKey)
|
var pk = publicKey
|
||||||
|
if self.isCompressedPubKey(publicKey):
|
||||||
|
pk = self.getDecompressedPk(publicKey)
|
||||||
|
procs_from_visual_identity_service.getEmojiHashAsJson(pk)
|
||||||
|
|
||||||
proc getColorHashAsJson*(self: Utils, publicKey: string): string {.slot.} =
|
proc getColorHashAsJson*(self: Utils, publicKey: string): string {.slot.} =
|
||||||
procs_from_visual_identity_service.getColorHashAsJson(publicKey)
|
var pk = publicKey
|
||||||
|
if self.isCompressedPubKey(publicKey):
|
||||||
|
pk = self.getDecompressedPk(publicKey)
|
||||||
|
procs_from_visual_identity_service.getColorHashAsJson(pk)
|
||||||
|
|
||||||
proc getColorId*(self: Utils, publicKey: string): int {.slot.} =
|
proc getColorId*(self: Utils, publicKey: string): int {.slot.} =
|
||||||
int(procs_from_visual_identity_service.colorIdOf(publicKey))
|
var pk = publicKey
|
||||||
|
if self.isCompressedPubKey(publicKey):
|
||||||
|
pk = self.getDecompressedPk(publicKey)
|
||||||
|
int(procs_from_visual_identity_service.colorIdOf(pk))
|
||||||
|
|
||||||
proc getCompressedPk*(self: Utils, publicKey: string): string {.slot.} =
|
proc getCompressedPk*(self: Utils, publicKey: string): string {.slot.} =
|
||||||
compressPk(publicKey)
|
compressPk(publicKey)
|
||||||
|
@ -192,8 +192,8 @@ proc getLinkPreviewEnabled*(self: Controller): bool =
|
|||||||
proc canAskToEnableLinkPreview(self: Controller): bool =
|
proc canAskToEnableLinkPreview(self: Controller): bool =
|
||||||
return self.linkPreviewPersistentSetting == LinkPreviewSetting.AlwaysAsk and self.linkPreviewCurrentMessageSetting == LinkPreviewSetting.AlwaysAsk
|
return self.linkPreviewPersistentSetting == LinkPreviewSetting.AlwaysAsk and self.linkPreviewCurrentMessageSetting == LinkPreviewSetting.AlwaysAsk
|
||||||
|
|
||||||
proc setText*(self: Controller, text: string) =
|
proc setText*(self: Controller, text: string, unfurlNewUrls: bool) =
|
||||||
if(text == ""):
|
if text == "":
|
||||||
self.resetLinkPreviews()
|
self.resetLinkPreviews()
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -204,7 +204,10 @@ proc setText*(self: Controller, text: string) =
|
|||||||
let askToEnableLinkPreview = len(newUrls) > 0 and self.canAskToEnableLinkPreview()
|
let askToEnableLinkPreview = len(newUrls) > 0 and self.canAskToEnableLinkPreview()
|
||||||
self.delegate.setAskToEnableLinkPreview(askToEnableLinkPreview)
|
self.delegate.setAskToEnableLinkPreview(askToEnableLinkPreview)
|
||||||
|
|
||||||
if self.getLinkPreviewEnabled() and len(urls) > 0:
|
if not unfurlNewUrls:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.getLinkPreviewEnabled() and len(newUrls) > 0:
|
||||||
self.messageService.asyncUnfurlUrls(newUrls)
|
self.messageService.asyncUnfurlUrls(newUrls)
|
||||||
|
|
||||||
proc linkPreviewsFromCache*(self: Controller, urls: seq[string]): Table[string, LinkPreview] =
|
proc linkPreviewsFromCache*(self: Controller, urls: seq[string]): Table[string, LinkPreview] =
|
||||||
@ -232,4 +235,4 @@ proc setLinkPreviewEnabled*(self: Controller, enabled: bool) =
|
|||||||
self.linkPreviewPersistentSetting = LinkPreviewSetting.Disabled
|
self.linkPreviewPersistentSetting = LinkPreviewSetting.Disabled
|
||||||
self.linkPreviewCurrentMessageSetting = LinkPreviewSetting.Disabled
|
self.linkPreviewCurrentMessageSetting = LinkPreviewSetting.Disabled
|
||||||
|
|
||||||
self.delegate.setAskToEnableLinkPreview(false)
|
self.delegate.setAskToEnableLinkPreview(false)
|
||||||
|
@ -96,7 +96,7 @@ method isFavorite*(self: AccessInterface, item: GifDto): bool {.base.} =
|
|||||||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method setText*(self: AccessInterface, text: string) {.base.} =
|
method setText*(self: AccessInterface, text: string, unfurlUrls: bool) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method setUrls*(self: AccessInterface, urls: seq[string]) {.base.} =
|
method setUrls*(self: AccessInterface, urls: seq[string]) {.base.} =
|
||||||
|
@ -152,8 +152,8 @@ method addToRecentsGif*(self: Module, item: GifDto) =
|
|||||||
method isFavorite*(self: Module, item: GifDto): bool =
|
method isFavorite*(self: Module, item: GifDto): bool =
|
||||||
return self.controller.isFavorite(item)
|
return self.controller.isFavorite(item)
|
||||||
|
|
||||||
method setText*(self: Module, text: string) =
|
method setText*(self: Module, text: string, unfurlUrls: bool) =
|
||||||
self.controller.setText(text)
|
self.controller.setText(text, unfurlUrls)
|
||||||
|
|
||||||
method clearLinkPreviewCache*(self: Module) {.slot.} =
|
method clearLinkPreviewCache*(self: Module) {.slot.} =
|
||||||
self.controller.clearLinkPreviewCache()
|
self.controller.clearLinkPreviewCache()
|
||||||
|
@ -51,9 +51,11 @@ QtObject:
|
|||||||
msg: string,
|
msg: string,
|
||||||
replyTo: string,
|
replyTo: string,
|
||||||
contentType: int) {.slot.} =
|
contentType: int) {.slot.} =
|
||||||
|
self.delegate.setText(msg, false)
|
||||||
self.delegate.sendChatMessage(msg, replyTo, contentType, self.linkPreviewModel.getUnfuledLinkPreviews())
|
self.delegate.sendChatMessage(msg, replyTo, contentType, self.linkPreviewModel.getUnfuledLinkPreviews())
|
||||||
|
|
||||||
proc sendImages*(self: View, imagePathsAndDataJson: string, msg: string, replyTo: string): string {.slot.} =
|
proc sendImages*(self: View, imagePathsAndDataJson: string, msg: string, replyTo: string): string {.slot.} =
|
||||||
|
self.delegate.setText(msg, false)
|
||||||
self.delegate.sendImages(imagePathsAndDataJson, msg, replyTo, self.linkPreviewModel.getUnfuledLinkPreviews())
|
self.delegate.sendImages(imagePathsAndDataJson, msg, replyTo, self.linkPreviewModel.getUnfuledLinkPreviews())
|
||||||
|
|
||||||
proc acceptAddressRequest*(self: View, messageId: string , address: string) {.slot.} =
|
proc acceptAddressRequest*(self: View, messageId: string , address: string) {.slot.} =
|
||||||
@ -212,7 +214,7 @@ QtObject:
|
|||||||
|
|
||||||
# Currently used to fetch link previews, but could be used elsewhere
|
# Currently used to fetch link previews, but could be used elsewhere
|
||||||
proc setText*(self: View, text: string) {.slot.} =
|
proc setText*(self: View, text: string) {.slot.} =
|
||||||
self.delegate.setText(text)
|
self.delegate.setText(text, true)
|
||||||
|
|
||||||
proc updateLinkPreviewsFromCache*(self: View, urls: seq[string]) =
|
proc updateLinkPreviewsFromCache*(self: View, urls: seq[string]) =
|
||||||
let linkPreviews = self.delegate.linkPreviewsFromCache(urls)
|
let linkPreviews = self.delegate.linkPreviewsFromCache(urls)
|
||||||
@ -252,4 +254,4 @@ QtObject:
|
|||||||
self.loadLinkPreviews(links)
|
self.loadLinkPreviews(links)
|
||||||
|
|
||||||
proc removeLinkPreviewData*(self: View, index: int) {.slot.} =
|
proc removeLinkPreviewData*(self: View, index: int) {.slot.} =
|
||||||
self.linkPreviewModel.removePreviewData(index)
|
self.linkPreviewModel.removePreviewData(index)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import strformat
|
import strformat
|
||||||
import ../../../app_service/service/message/dto/link_preview
|
import ../../../app_service/service/message/dto/link_preview
|
||||||
|
import ../../../app_service/service/message/dto/status_community_link_preview
|
||||||
|
import ../../../app_service/service/message/dto/status_community_channel_link_preview
|
||||||
|
|
||||||
type
|
type
|
||||||
Item* = ref object
|
Item* = ref object
|
||||||
|
@ -1,20 +1,37 @@
|
|||||||
import NimQml, strformat, tables, sequtils
|
import NimQml, strformat, tables, sequtils
|
||||||
import ./link_preview_item
|
import ./link_preview_item
|
||||||
import ../../../app_service/service/message/dto/link_preview
|
import ../../../app_service/service/message/dto/link_preview
|
||||||
|
import ../../../app_service/service/message/dto/standard_link_preview
|
||||||
|
import ../../../app_service/service/message/dto/status_link_preview
|
||||||
|
import ../../../app_service/service/message/dto/status_contact_link_preview
|
||||||
|
import ../../../app_service/service/message/dto/status_community_link_preview
|
||||||
|
import ../../../app_service/service/message/dto/status_community_channel_link_preview
|
||||||
|
|
||||||
type
|
type
|
||||||
ModelRole {.pure.} = enum
|
ModelRole {.pure.} = enum
|
||||||
Url = UserRole + 1
|
Url = UserRole + 1
|
||||||
Unfurled
|
Unfurled
|
||||||
Immutable
|
Immutable
|
||||||
Hostname
|
Empty
|
||||||
Title
|
PreviewType
|
||||||
Description
|
# Standard unfurled link (oembed, opengraph, image)
|
||||||
LinkType
|
StandardPreview
|
||||||
ThumbnailWidth
|
StandardPreviewThumbnail
|
||||||
ThumbnailHeight
|
# Status contact
|
||||||
ThumbnailUrl
|
StatusContactPreview
|
||||||
ThumbnailDataUri
|
StatusContactPreviewThumbnail
|
||||||
|
# Status community
|
||||||
|
StatusCommunityPreview
|
||||||
|
StatusCommunityPreviewIcon
|
||||||
|
StatusCommunityPreviewBanner
|
||||||
|
# Status channel
|
||||||
|
StatusCommunityChannelPreview
|
||||||
|
# NOTE: I know "CommunityChannelCommunity" doesn't sound good,
|
||||||
|
# and we could use existing `StatusCommunityPreview` role for this,
|
||||||
|
# but I decided no to mess things around. So there we have it:
|
||||||
|
StatusCommunityChannelCommunityPreview
|
||||||
|
StatusCommunityChannelCommunityPreviewIcon
|
||||||
|
StatusCommunityChannelCommunityPreviewBanner
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
@ -66,14 +83,23 @@ QtObject:
|
|||||||
ModelRole.Url.int:"url",
|
ModelRole.Url.int:"url",
|
||||||
ModelRole.Unfurled.int:"unfurled",
|
ModelRole.Unfurled.int:"unfurled",
|
||||||
ModelRole.Immutable.int:"immutable",
|
ModelRole.Immutable.int:"immutable",
|
||||||
ModelRole.Hostname.int:"hostname",
|
ModelRole.Empty.int:"empty",
|
||||||
ModelRole.Title.int:"title",
|
ModelRole.PreviewType.int:"previewType",
|
||||||
ModelRole.Description.int:"description",
|
# Standard
|
||||||
ModelRole.LinkType.int:"linkType",
|
ModelRole.StandardPreview.int:"standardPreview",
|
||||||
ModelRole.ThumbnailWidth.int:"thumbnailWidth",
|
ModelRole.StandardPreviewThumbnail.int:"standardPreviewThumbnail",
|
||||||
ModelRole.ThumbnailHeight.int:"thumbnailHeight",
|
# Contact
|
||||||
ModelRole.ThumbnailUrl.int:"thumbnailUrl",
|
ModelRole.StatusContactPreview.int:"statusContactPreview",
|
||||||
ModelRole.ThumbnailDataUri.int:"thumbnailDataUri",
|
ModelRole.StatusContactPreviewThumbnail.int:"statusContactPreviewThumbnail",
|
||||||
|
# Community
|
||||||
|
ModelRole.StatusCommunityPreview.int:"statusCommunityPreview",
|
||||||
|
ModelRole.StatusCommunityPreviewIcon.int:"statusCommunityPreviewIcon",
|
||||||
|
ModelRole.StatusCommunityPreviewBanner.int:"statusCommunityPreviewBanner",
|
||||||
|
# Channel
|
||||||
|
ModelRole.StatusCommunityChannelPreview.int:"statusCommunityChannelPreview",
|
||||||
|
ModelRole.StatusCommunityChannelCommunityPreview.int:"statusCommunityChannelCommunityPreview",
|
||||||
|
ModelRole.StatusCommunityChannelCommunityPreviewIcon.int:"statusCommunityChannelCommunityPreviewIcon",
|
||||||
|
ModelRole.StatusCommunityChannelCommunityPreviewBanner.int:"statusCommunityChannelCommunityPreviewBanner",
|
||||||
}.toTable
|
}.toTable
|
||||||
|
|
||||||
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
||||||
@ -93,22 +119,45 @@ QtObject:
|
|||||||
result = newQVariant(item.unfurled)
|
result = newQVariant(item.unfurled)
|
||||||
of ModelRole.Immutable:
|
of ModelRole.Immutable:
|
||||||
result = newQVariant(item.immutable)
|
result = newQVariant(item.immutable)
|
||||||
of ModelRole.Hostname:
|
of ModelRole.Empty:
|
||||||
result = newQVariant(item.linkPreview.hostname)
|
result = newQVariant(item.linkPreview.empty())
|
||||||
of ModelRole.Title:
|
of ModelRole.PreviewType:
|
||||||
result = newQVariant(item.linkPreview.title)
|
result = newQVariant(item.linkPreview.previewType.int)
|
||||||
of ModelRole.Description:
|
of ModelRole.StandardPreview:
|
||||||
result = newQVariant(item.linkPreview.description)
|
if item.linkPreview.standardPreview != nil:
|
||||||
of ModelRole.LinkType:
|
result = newQVariant(item.linkPreview.standardPreview)
|
||||||
result = newQVariant(item.linkPreview.linkType.int)
|
of ModelRole.StandardPreviewThumbnail:
|
||||||
of ModelRole.ThumbnailWidth:
|
if item.linkPreview.standardPreview != nil:
|
||||||
result = newQVariant(item.linkPreview.thumbnail.width)
|
result = newQVariant(item.linkPreview.standardPreview.getThumbnail())
|
||||||
of ModelRole.ThumbnailHeight:
|
of ModelRole.StatusContactPreview:
|
||||||
result = newQVariant(item.linkPreview.thumbnail.height)
|
if item.linkPreview.statusContactPreview != nil:
|
||||||
of ModelRole.ThumbnailUrl:
|
result = newQVariant(item.linkPreview.statusContactPreview)
|
||||||
result = newQVariant(item.linkPreview.thumbnail.url)
|
of ModelRole.StatusContactPreviewThumbnail:
|
||||||
of ModelRole.ThumbnailDataUri:
|
if item.linkPreview.statusContactPreview != nil:
|
||||||
result = newQVariant(item.linkPreview.thumbnail.dataUri)
|
result = newQVariant(item.linkPreview.statusContactPreview.getIcon())
|
||||||
|
of ModelRole.StatusCommunityPreview:
|
||||||
|
if item.linkPreview.statusCommunityPreview != nil:
|
||||||
|
result = newQVariant(item.linkPreview.statusCommunityPreview)
|
||||||
|
of ModelRole.StatusCommunityPreviewIcon:
|
||||||
|
if item.linkPreview.statusCommunityPreview != nil:
|
||||||
|
result = newQVariant(item.linkPreview.statusCommunityPreview.getIcon())
|
||||||
|
of ModelRole.StatusCommunityPreviewBanner:
|
||||||
|
if item.linkPreview.statusCommunityPreview != nil:
|
||||||
|
result = newQVariant(item.linkPreview.statusCommunityPreview.getBanner())
|
||||||
|
of ModelRole.StatusCommunityChannelPreview:
|
||||||
|
if item.linkPreview.statusCommunityChannelPreview != nil:
|
||||||
|
result = newQVariant(item.linkPreview.statusCommunityChannelPreview)
|
||||||
|
of ModelRole.StatusCommunityChannelCommunityPreview:
|
||||||
|
if (let community = item.linkPreview.getChannelCommunity(); community) != nil:
|
||||||
|
result = newQVariant(community)
|
||||||
|
of ModelRole.StatusCommunityChannelCommunityPreviewIcon:
|
||||||
|
if (let community = item.linkPreview.getChannelCommunity(); community) != nil:
|
||||||
|
result = newQVariant(community.getIcon())
|
||||||
|
of ModelRole.StatusCommunityChannelCommunityPreviewBanner:
|
||||||
|
if (let community = item.linkPreview.getChannelCommunity(); community) != nil:
|
||||||
|
result = newQVariant(community.getBanner())
|
||||||
|
else:
|
||||||
|
result = newQVariant()
|
||||||
|
|
||||||
proc removeItemWithIndex(self: Model, ind: int) =
|
proc removeItemWithIndex(self: Model, ind: int) =
|
||||||
if(ind < 0 or ind >= self.items.len):
|
if(ind < 0 or ind >= self.items.len):
|
||||||
@ -220,10 +269,10 @@ QtObject:
|
|||||||
proc getUnfuledLinkPreviews*(self: Model): seq[LinkPreview] =
|
proc getUnfuledLinkPreviews*(self: Model): seq[LinkPreview] =
|
||||||
result = @[]
|
result = @[]
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
if item.unfurled and item.linkPreview.hostName != "":
|
if item.unfurled and not item.linkPreview.empty():
|
||||||
result.add(item.linkPreview)
|
result.add(item.linkPreview)
|
||||||
|
|
||||||
proc getLinks*(self: Model): seq[string] =
|
proc getLinks*(self: Model): seq[string] =
|
||||||
result = @[]
|
result = @[]
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
result.add(item.linkPreview.url)
|
result.add(item.linkPreview.url)
|
||||||
|
@ -1,85 +1,128 @@
|
|||||||
import json, strformat, tables
|
import json, strformat, tables
|
||||||
|
import ./link_preview_thumbnail, ./status_link_preview, ./standard_link_preview
|
||||||
|
import ./status_contact_link_preview, ./status_community_link_preview, ./status_community_channel_link_preview
|
||||||
include ../../../common/json_utils
|
include ../../../common/json_utils
|
||||||
|
|
||||||
type
|
|
||||||
LinkType* {.pure.} = enum
|
|
||||||
Link = 0
|
|
||||||
Image
|
|
||||||
|
|
||||||
proc toLinkType*(value: int): LinkType =
|
|
||||||
try:
|
|
||||||
return LinkType(value)
|
|
||||||
except RangeDefect:
|
|
||||||
return LinkType.Link
|
|
||||||
|
|
||||||
type
|
type
|
||||||
LinkPreviewThumbnail* = object
|
PreviewType {.pure.} = enum
|
||||||
width*: int
|
NoPreview = 0
|
||||||
height*: int
|
StandardPreview
|
||||||
url*: string
|
StatusContactPreview
|
||||||
dataUri*: string
|
StatusCommunityPreview
|
||||||
|
StatusCommunityChannelPreview
|
||||||
|
|
||||||
type
|
|
||||||
LinkPreview* = ref object
|
LinkPreview* = ref object
|
||||||
url*: string
|
url*: string
|
||||||
hostname*: string
|
previewType*: PreviewType
|
||||||
title*: string
|
standardPreview*: StandardLinkPreview
|
||||||
description*: string
|
statusContactPreview*: StatusContactLinkPreview
|
||||||
thumbnail*: LinkPreviewThumbnail
|
statusCommunityPreview*: StatusCommunityLinkPreview
|
||||||
linkType*: LinkType
|
statusCommunityChannelPreview*: StatusCommunityChannelLinkPreview
|
||||||
|
|
||||||
proc delete*(self: LinkPreview) =
|
proc delete*(self: LinkPreview) =
|
||||||
discard
|
if self.standardPreview != nil:
|
||||||
|
self.standardPreview.delete
|
||||||
|
if self.statusContactPreview != nil:
|
||||||
|
self.statusContactPreview.delete
|
||||||
|
if self.statusCommunityPreview != nil:
|
||||||
|
self.statusCommunityPreview.delete
|
||||||
|
if self.statusCommunityChannelPreview != nil:
|
||||||
|
self.statusCommunityChannelPreview.delete
|
||||||
|
|
||||||
proc initLinkPreview*(url: string): LinkPreview =
|
proc initLinkPreview*(url: string): LinkPreview =
|
||||||
result = LinkPreview()
|
result = LinkPreview()
|
||||||
result.url = url
|
result.url = url
|
||||||
|
result.previewType = PreviewType.NoPreview
|
||||||
|
|
||||||
proc toLinkPreviewThumbnail*(jsonObj: JsonNode): LinkPreviewThumbnail =
|
proc toLinkPreview*(jsonObj: JsonNode, standard: bool): LinkPreview =
|
||||||
result = LinkPreviewThumbnail()
|
|
||||||
discard jsonObj.getProp("width", result.width)
|
|
||||||
discard jsonObj.getProp("height", result.height)
|
|
||||||
discard jsonObj.getProp("url", result.url)
|
|
||||||
discard jsonObj.getProp("dataUri", result.dataUri)
|
|
||||||
|
|
||||||
proc toLinkPreview*(jsonObj: JsonNode): LinkPreview =
|
|
||||||
result = LinkPreview()
|
result = LinkPreview()
|
||||||
discard jsonObj.getProp("url", result.url)
|
result.previewType = PreviewType.NoPreview
|
||||||
discard jsonObj.getProp("hostname", result.hostname)
|
|
||||||
discard jsonObj.getProp("title", result.title)
|
|
||||||
discard jsonObj.getProp("description", result.description)
|
|
||||||
discard jsonObj.getProp("hostname", result.hostname)
|
|
||||||
result.linkType = toLinkType(jsonObj["type"].getInt)
|
|
||||||
|
|
||||||
var thumbnail: JsonNode
|
if standard:
|
||||||
if jsonObj.getProp("thumbnail", thumbnail):
|
discard jsonObj.getProp("url", result.url)
|
||||||
result.thumbnail = toLinkPreviewThumbnail(thumbnail)
|
result.previewType = PreviewType.StandardPreview
|
||||||
|
result.standardPreview = toStandardLinkPreview(jsonObj)
|
||||||
proc `$`*(self: LinkPreviewThumbnail): string =
|
else:
|
||||||
result = fmt"""LinkPreviewThumbnail(
|
discard jsonObj.getProp("url", result.url)
|
||||||
width: {self.width},
|
var node: JsonNode
|
||||||
height: {self.height},
|
if jsonObj.getProp("contact", node):
|
||||||
urlLength: {self.url.len},
|
result.previewType = PreviewType.StatusContactPreview
|
||||||
dataUriLength: {self.dataUri.len}
|
result.statusContactPreview = toStatusContactLinkPreview(node)
|
||||||
)"""
|
elif jsonObj.getProp("community", node):
|
||||||
|
result.previewType = PreviewType.StatusCommunityPreview
|
||||||
|
result.statusCommunityPreview = toStatusCommunityLinkPreview(node)
|
||||||
|
elif jsonObj.getProp("channel", node):
|
||||||
|
result.previewType = PreviewType.StatusCommunityChannelPreview
|
||||||
|
result.statusCommunityChannelPreview = toStatusCommunityChannelLinkPreview(node)
|
||||||
|
|
||||||
proc `$`*(self: LinkPreview): string =
|
proc `$`*(self: LinkPreview): string =
|
||||||
|
let standardPreview = if self.standardPreview != nil: $self.standardPreview else: ""
|
||||||
|
let contactPreview = if self.statusContactPreview != nil: $self.statusContactPreview else: ""
|
||||||
|
let communityPreview = if self.statusCommunityPreview != nil: $self.statusCommunityPreview else: ""
|
||||||
|
let channelPreview = if self.statusCommunityChannelPreview != nil: $self.statusCommunityChannelPreview else: ""
|
||||||
result = fmt"""LinkPreview(
|
result = fmt"""LinkPreview(
|
||||||
type: {self.linkType},
|
|
||||||
url: {self.url},
|
url: {self.url},
|
||||||
hostname: {self.hostname},
|
previewType: {self.previewType},
|
||||||
title: {self.title},
|
standardPreview: {standardPreview},
|
||||||
description: {self.description},
|
contactPreview: {contactPreview},
|
||||||
thumbnail: {self.thumbnail}
|
communityPreview: {communityPreview},
|
||||||
|
channelPreview: {channelPreview}
|
||||||
)"""
|
)"""
|
||||||
|
|
||||||
# Custom JSON converter to force `linkType` integer instead of string
|
|
||||||
proc `%`*(self: LinkPreview): JsonNode =
|
proc `%`*(self: LinkPreview): JsonNode =
|
||||||
result = %* {
|
result = %* {
|
||||||
"type": self.linkType.int,
|
|
||||||
"url": self.url,
|
"url": self.url,
|
||||||
"hostname": self.hostname,
|
"standardPreview": %self.standardPreview,
|
||||||
"title": self.title,
|
"contactPreview": %self.statusContactPreview,
|
||||||
"description": self.description,
|
"communityPreview": %self.statusCommunityPreview,
|
||||||
"thumbnail": %self.thumbnail,
|
"channelPreview": %self.statusCommunityChannelPreview
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc empty*(self: LinkPreview): bool =
|
||||||
|
case self.previewType:
|
||||||
|
of PreviewType.StandardPreview:
|
||||||
|
return self.standardPreview == nil or self.standardPreview.empty()
|
||||||
|
of PreviewType.StatusContactPreview:
|
||||||
|
return self.statusContactPreview == nil or self.statusContactPreview.empty()
|
||||||
|
of PreviewType.StatusCommunityPreview:
|
||||||
|
return self.statusCommunityPreview == nil or self.statusCommunityPreview.empty()
|
||||||
|
of PreviewType.StatusCommunityChannelPreview:
|
||||||
|
return self.statusCommunityChannelPreview == nil or self.statusCommunityChannelPreview.empty()
|
||||||
|
else:
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc extractLinkPreviewsLists*(input: seq[LinkPreview]): (seq[StandardLinkPreview], seq[StatusLinkPreview]) =
|
||||||
|
var standard: seq[StandardLinkPreview]
|
||||||
|
var status: seq[StatusLinkPreview]
|
||||||
|
|
||||||
|
for preview in input:
|
||||||
|
case preview.previewType:
|
||||||
|
of PreviewType.StandardPreview:
|
||||||
|
if preview.standardPreview != nil:
|
||||||
|
preview.standardPreview.url = preview.url
|
||||||
|
standard.add(preview.standardPreview)
|
||||||
|
of PreviewType.StatusContactPreview:
|
||||||
|
let statusLinkPreview = StatusLinkPreview()
|
||||||
|
statusLinkPreview.url = preview.url
|
||||||
|
statusLinkPreview.contact = preview.statusContactPreview
|
||||||
|
status.add(statusLinkPreview)
|
||||||
|
of PreviewType.StatusCommunityPreview:
|
||||||
|
let statusLinkPreview = StatusLinkPreview()
|
||||||
|
statusLinkPreview.url = preview.url
|
||||||
|
statusLinkPreview.community = preview.statusCommunityPreview
|
||||||
|
status.add(statusLinkPreview)
|
||||||
|
of PreviewType.StatusCommunityChannelPreview:
|
||||||
|
let statusLinkPreview = StatusLinkPreview()
|
||||||
|
statusLinkPreview.url = preview.url
|
||||||
|
statusLinkPreview.channel = preview.statusCommunityChannelPreview
|
||||||
|
status.add(statusLinkPreview)
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
return (standard, status)
|
||||||
|
|
||||||
|
proc getChannelCommunity*(self: LinkPreview): StatusCommunityLinkPreview =
|
||||||
|
if self.statusCommunityChannelPreview == nil:
|
||||||
|
return nil
|
||||||
|
return self.statusCommunityChannelPreview.getCommunity()
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
import json, strformat, NimQml, chronicles
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type LinkPreviewThumbnail* = ref object of QObject
|
||||||
|
width: int
|
||||||
|
height: int
|
||||||
|
url: string
|
||||||
|
dataUri: string
|
||||||
|
|
||||||
|
proc setup*(self: LinkPreviewThumbnail) =
|
||||||
|
self.QObject.setup()
|
||||||
|
|
||||||
|
proc delete*(self: LinkPreviewThumbnail) =
|
||||||
|
self.QObject.delete()
|
||||||
|
|
||||||
|
proc update*(self: LinkPreviewThumbnail, width: int, height: int, url: string, dataUri: string) =
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.url = url
|
||||||
|
self.dataUri = dataUri
|
||||||
|
|
||||||
|
proc copy*(self: LinkPreviewThumbnail, other: LinkPreviewThumbnail) =
|
||||||
|
if other != nil:
|
||||||
|
self.update(other.width, other.height, other.url, other.dataUri)
|
||||||
|
else:
|
||||||
|
self.update(0, 0, "", "")
|
||||||
|
|
||||||
|
proc newLinkPreviewThumbnail*(width: int = 0, height: int = 0, url: string = "", dataUri: string = ""): LinkPreviewThumbnail =
|
||||||
|
new(result, delete)
|
||||||
|
result.setup()
|
||||||
|
result.update(width, height, url, dataUri)
|
||||||
|
|
||||||
|
proc widthChanged*(self: LinkPreviewThumbnail) {.signal.}
|
||||||
|
proc getWidth*(self: LinkPreviewThumbnail): int {.slot.} =
|
||||||
|
result = self.width
|
||||||
|
QtProperty[int] width:
|
||||||
|
read = getWidth
|
||||||
|
notify = widthChanged
|
||||||
|
|
||||||
|
proc heightChanged*(self: LinkPreviewThumbnail) {.signal.}
|
||||||
|
proc getHeight*(self: LinkPreviewThumbnail): int {.slot.} =
|
||||||
|
result = self.height
|
||||||
|
QtProperty[int] height:
|
||||||
|
read = getHeight
|
||||||
|
notify = heightChanged
|
||||||
|
|
||||||
|
proc urlChanged*(self: LinkPreviewThumbnail) {.signal.}
|
||||||
|
proc getUrl*(self: LinkPreviewThumbnail): string {.slot.} =
|
||||||
|
result = self.url
|
||||||
|
QtProperty[string] url:
|
||||||
|
read = getUrl
|
||||||
|
notify = urlChanged
|
||||||
|
|
||||||
|
proc dataUriChanged*(self: LinkPreviewThumbnail) {.signal.}
|
||||||
|
proc getDataUri*(self: LinkPreviewThumbnail): string {.slot.} =
|
||||||
|
result = self.dataUri
|
||||||
|
QtProperty[string] dataUri:
|
||||||
|
read = getDataUri
|
||||||
|
notify = dataUriChanged
|
||||||
|
|
||||||
|
|
||||||
|
proc toLinkPreviewThumbnail*(jsonObj: JsonNode): LinkPreviewThumbnail =
|
||||||
|
result = LinkPreviewThumbnail()
|
||||||
|
discard jsonObj.getProp("width", result.width)
|
||||||
|
discard jsonObj.getProp("height", result.height)
|
||||||
|
discard jsonObj.getProp("url", result.url)
|
||||||
|
discard jsonObj.getProp("dataUri", result.dataUri)
|
||||||
|
|
||||||
|
proc `$`*(self: LinkPreviewThumbnail): string =
|
||||||
|
result = fmt"""LinkPreviewThumbnail(
|
||||||
|
width: {self.width},
|
||||||
|
height: {self.height},
|
||||||
|
urlLength: {self.url.len},
|
||||||
|
dataUriLength: {self.dataUri.len}
|
||||||
|
)"""
|
||||||
|
|
||||||
|
proc `%`*(self: LinkPreviewThumbnail): JsonNode =
|
||||||
|
result = %*{
|
||||||
|
"width": self.width,
|
||||||
|
"height": self.height,
|
||||||
|
"url": self.url,
|
||||||
|
"dataUri": self.dataUri
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import json, strutils
|
import json, strutils, chronicles
|
||||||
import ../../../common/types
|
import ../../../common/types
|
||||||
import link_preview
|
import link_preview
|
||||||
|
|
||||||
@ -263,7 +263,12 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto =
|
|||||||
var linkPreviewsArr: JsonNode
|
var linkPreviewsArr: JsonNode
|
||||||
if jsonObj.getProp("linkPreviews", linkPreviewsArr):
|
if jsonObj.getProp("linkPreviews", linkPreviewsArr):
|
||||||
for element in linkPreviewsArr.getElems():
|
for element in linkPreviewsArr.getElems():
|
||||||
result.linkPreviews.add(element.toLinkPreview())
|
result.linkPreviews.add(element.toLinkPreview(true))
|
||||||
|
|
||||||
|
var statusLinkPreviewsArr: JsonNode
|
||||||
|
if jsonObj.getProp("statusLinkPreviews", statusLinkPreviewsArr):
|
||||||
|
for element in statusLinkPreviewsArr.getElems():
|
||||||
|
result.linkPreviews.add(element.toLinkPreview(false))
|
||||||
|
|
||||||
var parsedTextArr: JsonNode
|
var parsedTextArr: JsonNode
|
||||||
if(jsonObj.getProp("parsedText", parsedTextArr) and parsedTextArr.kind == JArray):
|
if(jsonObj.getProp("parsedText", parsedTextArr) and parsedTextArr.kind == JArray):
|
||||||
|
114
src/app_service/service/message/dto/standard_link_preview.nim
Normal file
114
src/app_service/service/message/dto/standard_link_preview.nim
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import json, strformat, NimQml
|
||||||
|
import ./link_preview_thumbnail
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
type
|
||||||
|
LinkType* {.pure.} = enum
|
||||||
|
Link = 0
|
||||||
|
Image
|
||||||
|
|
||||||
|
proc toLinkType*(value: int): LinkType =
|
||||||
|
try:
|
||||||
|
return LinkType(value)
|
||||||
|
except RangeDefect:
|
||||||
|
return LinkType.Link
|
||||||
|
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type StandardLinkPreview* = ref object of QObject
|
||||||
|
url*: string # this property is set manually and only used in`toJSON` conversion
|
||||||
|
hostname: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
linkType: LinkType
|
||||||
|
thumbnail: LinkPreviewThumbnail
|
||||||
|
|
||||||
|
proc setup*(self: StandardLinkPreview) =
|
||||||
|
self.QObject.setup
|
||||||
|
self.thumbnail = newLinkPreviewThumbnail()
|
||||||
|
|
||||||
|
proc delete*(self: StandardLinkPreview) =
|
||||||
|
self.QObject.delete
|
||||||
|
self.thumbnail.delete
|
||||||
|
|
||||||
|
proc newStandardLinkPreview*(hostname: string, title: string, description: string, thumbnail: LinkPreviewThumbnail, linkType: LinkType): StandardLinkPreview =
|
||||||
|
new(result, delete)
|
||||||
|
result.setup()
|
||||||
|
result.hostname = hostname
|
||||||
|
result.title = title
|
||||||
|
result.description = description
|
||||||
|
result.linkType = linkType
|
||||||
|
result.thumbnail.copy(thumbnail)
|
||||||
|
|
||||||
|
proc hostnameChanged*(self: StandardLinkPreview) {.signal.}
|
||||||
|
proc getHostname*(self: StandardLinkPreview): string {.slot.} =
|
||||||
|
result = self.hostname
|
||||||
|
QtProperty[string] hostname:
|
||||||
|
read = getHostname
|
||||||
|
notify = hostnameChanged
|
||||||
|
|
||||||
|
proc titleChanged*(self: StandardLinkPreview) {.signal.}
|
||||||
|
proc getTitle*(self: StandardLinkPreview): string {.slot.} =
|
||||||
|
result = self.title
|
||||||
|
QtProperty[string] title:
|
||||||
|
read = getTitle
|
||||||
|
notify = titleChanged
|
||||||
|
|
||||||
|
proc descriptionChanged*(self: StandardLinkPreview) {.signal.}
|
||||||
|
proc getDescription*(self: StandardLinkPreview): string {.slot.} =
|
||||||
|
result = self.description
|
||||||
|
QtProperty[string] description:
|
||||||
|
read = getDescription
|
||||||
|
notify = descriptionChanged
|
||||||
|
|
||||||
|
proc linkTypeChanged*(self: StandardLinkPreview) {.signal.}
|
||||||
|
proc getLinkType*(self: StandardLinkPreview): int {.slot.} =
|
||||||
|
result = self.linkType.int
|
||||||
|
QtProperty[int] linkType:
|
||||||
|
read = getLinkType
|
||||||
|
notify = linkTypeChanged
|
||||||
|
|
||||||
|
proc getThumbnail*(self: StandardLinkPreview): LinkPreviewThumbnail =
|
||||||
|
result = self.thumbnail
|
||||||
|
|
||||||
|
|
||||||
|
proc toStandardLinkPreview*(jsonObj: JsonNode): StandardLinkPreview =
|
||||||
|
var hostname: string
|
||||||
|
var title: string
|
||||||
|
var description: string
|
||||||
|
var linkType: LinkType
|
||||||
|
var thumbnail: LinkPreviewThumbnail
|
||||||
|
|
||||||
|
discard jsonObj.getProp("hostname", hostname)
|
||||||
|
discard jsonObj.getProp("title", title)
|
||||||
|
discard jsonObj.getProp("description", description)
|
||||||
|
linkType = toLinkType(jsonObj["type"].getInt)
|
||||||
|
|
||||||
|
var thumbnailJson: JsonNode
|
||||||
|
if jsonObj.getProp("thumbnail", thumbnailJson):
|
||||||
|
thumbnail = toLinkPreviewThumbnail(thumbnailJson)
|
||||||
|
|
||||||
|
result = newStandardLinkPreview(hostname, title, description, thumbnail, linkType)
|
||||||
|
|
||||||
|
proc `$`*(self: StandardLinkPreview): string =
|
||||||
|
result = fmt"""StandardLinkPreview(
|
||||||
|
type: {self.linkType},
|
||||||
|
hostname: {self.hostname},
|
||||||
|
title: {self.title},
|
||||||
|
description: {self.description},
|
||||||
|
thumbnail: {self.thumbnail}
|
||||||
|
)"""
|
||||||
|
|
||||||
|
# Custom JSON converter to force `linkType` integer instead of string
|
||||||
|
proc `%`*(self: StandardLinkPreview): JsonNode =
|
||||||
|
result = %* {
|
||||||
|
"url": self.url,
|
||||||
|
"type": self.linkType.int,
|
||||||
|
"hostname": self.hostname,
|
||||||
|
"title": self.title,
|
||||||
|
"description": self.description,
|
||||||
|
"thumbnail": %self.thumbnail,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc empty*(self: StandardLinkPreview): bool =
|
||||||
|
return self.hostname.len == 0
|
@ -0,0 +1,95 @@
|
|||||||
|
import json, strformat, NimQml, chronicles
|
||||||
|
import link_preview_thumbnail
|
||||||
|
import status_community_link_preview
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type StatusCommunityChannelLinkPreview* = ref object of QObject
|
||||||
|
channelUuid: string
|
||||||
|
emoji: string
|
||||||
|
displayName: string
|
||||||
|
description: string
|
||||||
|
color: string
|
||||||
|
community: StatusCommunityLinkPreview
|
||||||
|
|
||||||
|
proc setup*(self: StatusCommunityChannelLinkPreview) =
|
||||||
|
self.QObject.setup()
|
||||||
|
|
||||||
|
proc delete*(self: StatusCommunityChannelLinkPreview) =
|
||||||
|
self.QObject.delete()
|
||||||
|
self.community.delete()
|
||||||
|
|
||||||
|
proc channelUuidChanged*(self: StatusCommunityChannelLinkPreview) {.signal.}
|
||||||
|
proc getChannelUuid*(self: StatusCommunityChannelLinkPreview): string {.slot.} =
|
||||||
|
return self.channelUuid
|
||||||
|
QtProperty[string] channelUuid:
|
||||||
|
read = getChannelUuid
|
||||||
|
notify = channelUuidChanged
|
||||||
|
|
||||||
|
proc emojiChanged*(self: StatusCommunityChannelLinkPreview) {.signal.}
|
||||||
|
proc getEmoji*(self: StatusCommunityChannelLinkPreview): string {.slot.} =
|
||||||
|
return self.emoji
|
||||||
|
QtProperty[string] emoji:
|
||||||
|
read = getEmoji
|
||||||
|
notify = emojiChanged
|
||||||
|
|
||||||
|
proc displayNameChanged*(self: StatusCommunityChannelLinkPreview) {.signal.}
|
||||||
|
proc getDisplayName*(self: StatusCommunityChannelLinkPreview): string {.slot.} =
|
||||||
|
return self.displayName
|
||||||
|
QtProperty[string] displayName:
|
||||||
|
read = getDisplayName
|
||||||
|
notify = displayNameChanged
|
||||||
|
|
||||||
|
proc descriptionChanged*(self: StatusCommunityChannelLinkPreview) {.signal.}
|
||||||
|
proc getDescription*(self: StatusCommunityChannelLinkPreview): string {.slot.} =
|
||||||
|
return self.description
|
||||||
|
QtProperty[string] description:
|
||||||
|
read = getDescription
|
||||||
|
notify = descriptionChanged
|
||||||
|
|
||||||
|
proc colorChanged*(self: StatusCommunityChannelLinkPreview) {.signal.}
|
||||||
|
proc getColor*(self: StatusCommunityChannelLinkPreview): string {.slot.} =
|
||||||
|
return self.color
|
||||||
|
QtProperty[string] color:
|
||||||
|
read = getColor
|
||||||
|
notify = colorChanged
|
||||||
|
|
||||||
|
proc getCommunity*(self: StatusCommunityChannelLinkPreview): StatusCommunityLinkPreview =
|
||||||
|
return self.community
|
||||||
|
|
||||||
|
proc toStatusCommunityChannelLinkPreview*(jsonObj: JsonNode): StatusCommunityChannelLinkPreview =
|
||||||
|
new(result, delete)
|
||||||
|
result.setup()
|
||||||
|
|
||||||
|
discard jsonObj.getProp("channelUuid", result.channelUuid)
|
||||||
|
discard jsonObj.getProp("emoji", result.emoji)
|
||||||
|
discard jsonObj.getProp("displayName", result.displayName)
|
||||||
|
discard jsonObj.getProp("description", result.description)
|
||||||
|
discard jsonObj.getProp("color", result.color)
|
||||||
|
|
||||||
|
var communityJsonNode: JsonNode
|
||||||
|
if jsonObj.getProp("community", communityJsonNode):
|
||||||
|
result.community = toStatusCommunityLinkPreview(communityJsonNode)
|
||||||
|
|
||||||
|
proc `$`*(self: StatusCommunityChannelLinkPreview): string =
|
||||||
|
return fmt"""StatusCommunityChannelLinkPreview(
|
||||||
|
channelUuid: {self.channelUuid},
|
||||||
|
emoji: {self.emoji},
|
||||||
|
displayName: {self.displayName},
|
||||||
|
description: {self.description},
|
||||||
|
color: {self.color},
|
||||||
|
community: {self.community}
|
||||||
|
)"""
|
||||||
|
|
||||||
|
proc `%`*(self: StatusCommunityChannelLinkPreview): JsonNode =
|
||||||
|
return %* {
|
||||||
|
"channelUuid": self.channelUuid,
|
||||||
|
"emoji": self.emoji,
|
||||||
|
"displayName": self.displayName,
|
||||||
|
"description": self.description,
|
||||||
|
"color": self.color,
|
||||||
|
"community": self.community
|
||||||
|
}
|
||||||
|
|
||||||
|
proc empty*(self: StatusCommunityChannelLinkPreview): bool =
|
||||||
|
return self.channelUUID.len == 0
|
@ -0,0 +1,114 @@
|
|||||||
|
import json, strformat, NimQml, chronicles
|
||||||
|
import link_preview_thumbnail
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type StatusCommunityLinkPreview* = ref object of QObject
|
||||||
|
communityID: string
|
||||||
|
displayName: string
|
||||||
|
description: string
|
||||||
|
membersCount: int
|
||||||
|
color: string
|
||||||
|
icon: LinkPreviewThumbnail
|
||||||
|
banner: LinkPreviewThumbnail
|
||||||
|
|
||||||
|
proc setup*(self: StatusCommunityLinkPreview) =
|
||||||
|
self.QObject.setup()
|
||||||
|
self.icon = newLinkPreviewThumbnail()
|
||||||
|
self.banner = newLinkPreviewThumbnail()
|
||||||
|
|
||||||
|
proc delete*(self: StatusCommunityLinkPreview) =
|
||||||
|
self.QObject.delete()
|
||||||
|
self.icon.delete()
|
||||||
|
self.banner.delete()
|
||||||
|
|
||||||
|
|
||||||
|
proc communityIdChanged*(self: StatusCommunityLinkPreview) {.signal.}
|
||||||
|
proc getCommunityId*(self: StatusCommunityLinkPreview): string {.slot.} =
|
||||||
|
result = self.communityID
|
||||||
|
QtProperty[string] communityId:
|
||||||
|
read = getCommunityId
|
||||||
|
notify = communityIdChanged
|
||||||
|
|
||||||
|
proc displayNameChanged*(self: StatusCommunityLinkPreview) {.signal.}
|
||||||
|
proc getDisplayName*(self: StatusCommunityLinkPreview): string {.slot.} =
|
||||||
|
result = self.displayName
|
||||||
|
QtProperty[string] displayName:
|
||||||
|
read = getDisplayName
|
||||||
|
notify = displayNameChanged
|
||||||
|
|
||||||
|
proc descriptionChanged*(self: StatusCommunityLinkPreview) {.signal.}
|
||||||
|
proc getDescription*(self: StatusCommunityLinkPreview): string {.slot.} =
|
||||||
|
result = self.description
|
||||||
|
QtProperty[string] description:
|
||||||
|
read = getDescription
|
||||||
|
notify = descriptionChanged
|
||||||
|
|
||||||
|
proc membersCountChanged*(self: StatusCommunityLinkPreview) {.signal.}
|
||||||
|
proc getMembersCount*(self: StatusCommunityLinkPreview): int {.slot.} =
|
||||||
|
result = int(self.membersCount)
|
||||||
|
QtProperty[int] membersCount:
|
||||||
|
read = getMembersCount
|
||||||
|
notify = membersCountChanged
|
||||||
|
|
||||||
|
proc colorChanged*(self: StatusCommunityLinkPreview) {.signal.}
|
||||||
|
proc getColor*(self: StatusCommunityLinkPreview): string {.slot.} =
|
||||||
|
result = self.color
|
||||||
|
QtProperty[string] color:
|
||||||
|
read = getColor
|
||||||
|
notify = colorChanged
|
||||||
|
|
||||||
|
proc getIcon*(self: StatusCommunityLinkPreview): LinkPreviewThumbnail =
|
||||||
|
result = self.icon
|
||||||
|
|
||||||
|
proc getBanner*(self: StatusCommunityLinkPreview): LinkPreviewThumbnail =
|
||||||
|
result = self.banner
|
||||||
|
|
||||||
|
proc toStatusCommunityLinkPreview*(jsonObj: JsonNode): StatusCommunityLinkPreview =
|
||||||
|
new(result, delete)
|
||||||
|
result.setup()
|
||||||
|
|
||||||
|
var icon: LinkPreviewThumbnail
|
||||||
|
var banner: LinkPreviewThumbnail
|
||||||
|
|
||||||
|
discard jsonObj.getProp("communityId", result.communityID)
|
||||||
|
discard jsonObj.getProp("displayName", result.displayName)
|
||||||
|
discard jsonObj.getProp("description", result.description)
|
||||||
|
discard jsonObj.getProp("membersCount", result.membersCount)
|
||||||
|
discard jsonObj.getProp("color", result.color)
|
||||||
|
|
||||||
|
var iconJson: JsonNode
|
||||||
|
if jsonObj.getProp("icon", iconJson):
|
||||||
|
icon = toLinkPreviewThumbnail(iconJson)
|
||||||
|
|
||||||
|
var bannerJson: JsonNode
|
||||||
|
if jsonObj.getProp("banner", bannerJson):
|
||||||
|
banner = toLinkPreviewThumbnail(bannerJson)
|
||||||
|
|
||||||
|
result.icon.copy(icon)
|
||||||
|
result.banner.copy(banner)
|
||||||
|
|
||||||
|
proc `$`*(self: StatusCommunityLinkPreview): string =
|
||||||
|
result = fmt"""StatusCommunityLinkPreview(
|
||||||
|
communityId: {self.communityID},
|
||||||
|
displayName: {self.displayName},
|
||||||
|
description: {self.description},
|
||||||
|
membersCount: {self.membersCount},
|
||||||
|
color: {self.color},
|
||||||
|
icon: {self.icon},
|
||||||
|
banner: {self.banner}
|
||||||
|
)"""
|
||||||
|
|
||||||
|
proc `%`*(self: StatusCommunityLinkPreview): JsonNode =
|
||||||
|
result = %* {
|
||||||
|
"communityID": self.communityID,
|
||||||
|
"displayName": self.displayName,
|
||||||
|
"description": self.description,
|
||||||
|
"membersCount": self.membersCount,
|
||||||
|
"color": self.color,
|
||||||
|
"icon": self.icon,
|
||||||
|
"banner": self.banner
|
||||||
|
}
|
||||||
|
|
||||||
|
proc empty*(self: StatusCommunityLinkPreview): bool =
|
||||||
|
return self.communityID.len == 0
|
@ -0,0 +1,87 @@
|
|||||||
|
import json, strformat, NimQml, chronicles
|
||||||
|
import link_preview_thumbnail
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type StatusContactLinkPreview* = ref object of QObject
|
||||||
|
publicKey: string
|
||||||
|
displayName: string
|
||||||
|
description: string
|
||||||
|
icon: LinkPreviewThumbnail
|
||||||
|
|
||||||
|
proc setup*(self: StatusContactLinkPreview) =
|
||||||
|
self.QObject.setup()
|
||||||
|
self.icon = newLinkPreviewThumbnail()
|
||||||
|
|
||||||
|
proc delete*(self: StatusContactLinkPreview) =
|
||||||
|
self.QObject.delete()
|
||||||
|
self.icon.delete()
|
||||||
|
|
||||||
|
proc newStatusContactLinkPreview*(publicKey: string, displayName: string, description: string, icon: LinkPreviewThumbnail): StatusContactLinkPreview =
|
||||||
|
new(result, delete)
|
||||||
|
result.setup()
|
||||||
|
result.publicKey = publicKey
|
||||||
|
result.displayName = displayName
|
||||||
|
result.description = description
|
||||||
|
result.icon.copy(icon)
|
||||||
|
|
||||||
|
proc publicKeyChanged*(self: StatusContactLinkPreview) {.signal.}
|
||||||
|
proc getPublicKey*(self: StatusContactLinkPreview): string {.slot.} =
|
||||||
|
result = self.publicKey
|
||||||
|
QtProperty[string] publicKey:
|
||||||
|
read = getPublicKey
|
||||||
|
notify = publicKeyChanged
|
||||||
|
|
||||||
|
proc displayNameChanged*(self: StatusContactLinkPreview) {.signal.}
|
||||||
|
proc getDisplayName*(self: StatusContactLinkPreview): string {.slot.} =
|
||||||
|
result = self.displayName
|
||||||
|
QtProperty[string] displayName:
|
||||||
|
read = getDisplayName
|
||||||
|
notify = displayNameChanged
|
||||||
|
|
||||||
|
proc descriptionChanged*(self: StatusContactLinkPreview) {.signal.}
|
||||||
|
proc getDescription*(self: StatusContactLinkPreview): string {.slot.} =
|
||||||
|
result = self.description
|
||||||
|
QtProperty[string] description:
|
||||||
|
read = getDescription
|
||||||
|
notify = descriptionChanged
|
||||||
|
|
||||||
|
proc getIcon*(self: StatusContactLinkPreview): LinkPreviewThumbnail =
|
||||||
|
result = self.icon
|
||||||
|
|
||||||
|
|
||||||
|
proc toStatusContactLinkPreview*(jsonObj: JsonNode): StatusContactLinkPreview =
|
||||||
|
var publicKey: string
|
||||||
|
var displayName: string
|
||||||
|
var description: string
|
||||||
|
var icon: LinkPreviewThumbnail
|
||||||
|
|
||||||
|
discard jsonObj.getProp("publicKey", publicKey)
|
||||||
|
discard jsonObj.getProp("displayName", displayName)
|
||||||
|
discard jsonObj.getProp("description", description)
|
||||||
|
|
||||||
|
var iconJson: JsonNode
|
||||||
|
if jsonObj.getProp("icon", iconJson):
|
||||||
|
icon = toLinkPreviewThumbnail(iconJson)
|
||||||
|
|
||||||
|
result = newStatusContactLinkPreview(publicKey, displayName, description, icon)
|
||||||
|
|
||||||
|
proc `$`*(self: StatusContactLinkPreview): string =
|
||||||
|
result = fmt"""StatusContactLinkPreview(
|
||||||
|
publicKey: {self.publicKey},
|
||||||
|
displayName: {self.displayName},
|
||||||
|
description: {self.description},
|
||||||
|
icon: {self.icon}
|
||||||
|
)"""
|
||||||
|
|
||||||
|
proc `%`*(self: StatusContactLinkPreview): JsonNode =
|
||||||
|
return %* {
|
||||||
|
"publicKey": self.publicKey,
|
||||||
|
"displayName": self.displayName,
|
||||||
|
"description": self.description,
|
||||||
|
"icon": self.icon
|
||||||
|
}
|
||||||
|
|
||||||
|
proc empty*(self: StatusContactLinkPreview): bool =
|
||||||
|
return self.publicKey.len == 0
|
41
src/app_service/service/message/dto/status_link_preview.nim
Normal file
41
src/app_service/service/message/dto/status_link_preview.nim
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import json, strformat, NimQml, chronicles
|
||||||
|
import link_preview_thumbnail
|
||||||
|
import status_contact_link_preview
|
||||||
|
import status_community_link_preview
|
||||||
|
import status_community_channel_link_preview
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
|
||||||
|
type StatusLinkPreview* = ref object
|
||||||
|
url*: string
|
||||||
|
contact*: StatusContactLinkPreview
|
||||||
|
community*: StatusCommunityLinkPreview
|
||||||
|
channel*: StatusCommunityChannelLinkPreview
|
||||||
|
|
||||||
|
proc toStatusLinkPreview*(jsonObj: JsonNode): StatusLinkPreview =
|
||||||
|
result = StatusLinkPreview()
|
||||||
|
discard jsonObj.getProp("url", result.url)
|
||||||
|
|
||||||
|
var contact: JsonNode
|
||||||
|
if jsonObj.getProp("contact", contact):
|
||||||
|
result.contact = toStatusContactLinkPreview(contact)
|
||||||
|
|
||||||
|
var community: JsonNode
|
||||||
|
if jsonObj.getProp("community", community):
|
||||||
|
result.community = toStatusCommunityLinkPreview(contact)
|
||||||
|
|
||||||
|
var channel: JsonNode
|
||||||
|
if jsonObj.getProp("channel", channel):
|
||||||
|
result.channel = toStatusCommunityChannelLinkPreview(contact)
|
||||||
|
|
||||||
|
proc `%`*(self: StatusLinkPreview): JsonNode =
|
||||||
|
var obj = %*{
|
||||||
|
"url": self.url
|
||||||
|
}
|
||||||
|
if self.contact != nil:
|
||||||
|
obj["contact"] = %*self.contact
|
||||||
|
if self.community != nil:
|
||||||
|
obj["community"] = %*self.community
|
||||||
|
if self.channel != nil:
|
||||||
|
obj["channel"] = %*self.channel
|
||||||
|
return obj
|
@ -18,6 +18,7 @@ import ../chat/dto/chat as chat_dto
|
|||||||
import ./dto/pinned_message_update as pinned_msg_update_dto
|
import ./dto/pinned_message_update as pinned_msg_update_dto
|
||||||
import ./dto/removed_message as removed_msg_dto
|
import ./dto/removed_message as removed_msg_dto
|
||||||
import ./dto/link_preview
|
import ./dto/link_preview
|
||||||
|
import ./dto/status_link_preview
|
||||||
import ./message_cursor
|
import ./message_cursor
|
||||||
|
|
||||||
import ../../common/message as message_common
|
import ../../common/message as message_common
|
||||||
@ -863,11 +864,20 @@ QtObject:
|
|||||||
if responseObj.getProp("requestedUrls", requestedUrlsArr):
|
if responseObj.getProp("requestedUrls", requestedUrlsArr):
|
||||||
requestedUrls = map(requestedUrlsArr.getElems(), proc(x: JsonNode): string = x.getStr)
|
requestedUrls = map(requestedUrlsArr.getElems(), proc(x: JsonNode): string = x.getStr)
|
||||||
|
|
||||||
var linkPreviewsArr: JsonNode
|
let unfurlResponse = responseObj["response"]
|
||||||
|
|
||||||
var linkPreviews: Table[string, LinkPreview]
|
var linkPreviews: Table[string, LinkPreview]
|
||||||
if responseObj.getProp("response", linkPreviewsArr):
|
var linkPreviewsArr: JsonNode
|
||||||
|
var statusLinkPreviewsArr: JsonNode
|
||||||
|
|
||||||
|
if unfurlResponse.getProp("linkPreviews", linkPreviewsArr):
|
||||||
for element in linkPreviewsArr.getElems():
|
for element in linkPreviewsArr.getElems():
|
||||||
let linkPreview = element.toLinkPreview()
|
let linkPreview = element.toLinkPreview(true)
|
||||||
|
linkPreviews[linkPreview.url] = linkPreview
|
||||||
|
|
||||||
|
if unfurlResponse.getProp("statusLinkPreviews", statusLinkPreviewsArr):
|
||||||
|
for element in statusLinkPreviewsArr.getElems():
|
||||||
|
let linkPreview = element.toLinkPreview(false)
|
||||||
linkPreviews[linkPreview.url] = linkPreview
|
linkPreviews[linkPreview.url] = linkPreview
|
||||||
|
|
||||||
for url in requestedUrls:
|
for url in requestedUrls:
|
||||||
|
@ -3,6 +3,11 @@ import core, ../app_service/common/utils
|
|||||||
import response_type
|
import response_type
|
||||||
import interpret/cropped_image
|
import interpret/cropped_image
|
||||||
import ../app_service/service/message/dto/link_preview
|
import ../app_service/service/message/dto/link_preview
|
||||||
|
import ../app_service/service/message/dto/standard_link_preview
|
||||||
|
import ../app_service/service/message/dto/status_link_preview
|
||||||
|
import ../app_service/service/message/dto/status_contact_link_preview
|
||||||
|
import ../app_service/service/message/dto/status_community_link_preview
|
||||||
|
import ../app_service/service/message/dto/status_community_channel_link_preview
|
||||||
|
|
||||||
export response_type
|
export response_type
|
||||||
|
|
||||||
@ -66,6 +71,7 @@ proc sendChatMessage*(
|
|||||||
stickerHash: string = "",
|
stickerHash: string = "",
|
||||||
stickerPack: string = "0",
|
stickerPack: string = "0",
|
||||||
): RpcResponse[JsonNode] {.raises: [Exception].} =
|
): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||||
|
let (standardLinkPreviews, statusLinkPreviews) = extractLinkPreviewsLists(linkPreviews)
|
||||||
result = callPrivateRPC("sendChatMessage".prefix, %* [
|
result = callPrivateRPC("sendChatMessage".prefix, %* [
|
||||||
{
|
{
|
||||||
"chatId": chatId,
|
"chatId": chatId,
|
||||||
@ -78,7 +84,8 @@ proc sendChatMessage*(
|
|||||||
},
|
},
|
||||||
"contentType": contentType,
|
"contentType": contentType,
|
||||||
"communityId": communityId,
|
"communityId": communityId,
|
||||||
"linkPreviews": linkPreviews
|
"linkPreviews": standardLinkPreviews,
|
||||||
|
"statusLinkPreviews": statusLinkPreviews
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -4,11 +4,121 @@ import QtQuick.Layouts 1.15
|
|||||||
import shared.views.chat 1.0
|
import shared.views.chat 1.0
|
||||||
|
|
||||||
SplitView {
|
SplitView {
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: mockedLinkPreviewModel
|
||||||
|
|
||||||
|
// Create the model dynamically, because `ListElement` doesnt suppport nested elements
|
||||||
|
Component.onCompleted: {
|
||||||
|
const emptyObject = {
|
||||||
|
"unfurled": true,
|
||||||
|
"immutable": false,
|
||||||
|
"empty": false,
|
||||||
|
"url": "https://www.youtube.com/watch?v=9bZkp7q19f0",
|
||||||
|
"previewType": 1,
|
||||||
|
"standardPreview": {
|
||||||
|
"hostname": "www.youtube.com",
|
||||||
|
"title": "PSY - GANGNAM STYLE(강남스타일) M/V",
|
||||||
|
"description": "PSY - ‘I LUV IT’ M/V @ https://youtu.be/Xvjnoagk6GU PSY - ‘New Face’ M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp...",
|
||||||
|
"linkType": 0,
|
||||||
|
},
|
||||||
|
"standardPreviewThumbnail": {
|
||||||
|
"width": 480,
|
||||||
|
"height": 360,
|
||||||
|
"url": "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg",
|
||||||
|
"dataUri": "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg",
|
||||||
|
},
|
||||||
|
"statusContactPreview": {},
|
||||||
|
"statusContactPreviewThumbnail": {},
|
||||||
|
"statusCommunityPreview": {},
|
||||||
|
"statusCommunityPreviewIcon": {},
|
||||||
|
"statusCommunityPreviewBanner": {},
|
||||||
|
"statusCommunityChannelPreview": {},
|
||||||
|
"statusCommunityChannelCommunityPreview": {},
|
||||||
|
"statusCommunityChannelCommunityPreviewIcon": {},
|
||||||
|
"statusCommunityChannelCommunityPreviewBanner": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
const preview1 = Object.assign({}, emptyObject)
|
||||||
|
preview1.url = "https://www.youtube.com/watch?v=9bZkp7q19f0"
|
||||||
|
preview1.previewType = 1
|
||||||
|
preview1.standardPreview = {}
|
||||||
|
preview1.standardPreviewThumbnail = {}
|
||||||
|
preview1.standardPreview.hostname = "www.youtube.com"
|
||||||
|
preview1.standardPreview.title = "PSY - GANGNAM STYLE(강남스타일) M/V"
|
||||||
|
preview1.standardPreview.description = "PSY - ‘I LUV IT’ M/V @ https://youtu.be/Xvjnoagk6GU PSY - ‘New Face’ M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp..."
|
||||||
|
preview1.standardPreview.standardLinkType = 0
|
||||||
|
preview1.standardPreviewThumbnail.width = 480
|
||||||
|
preview1.standardPreviewThumbnail.height = 360
|
||||||
|
preview1.standardPreviewThumbnail.url = "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
||||||
|
preview1.standardPreviewThumbnail.dataUri = ""
|
||||||
|
|
||||||
|
|
||||||
|
const preview2 = Object.assign({}, emptyObject)
|
||||||
|
preview2.url = "https://status.app/u/Ow==#zQ3shgmVJjmwwhkfAemjDizYJtv9nzot7QD4iRJ52ZkgdU6Ci"
|
||||||
|
preview2.previewType = 2
|
||||||
|
preview2.statusContactPreview = {}
|
||||||
|
preview2.statusContactPreview.publicKey = "zQ3shgmVJjmwwhkfAemjDizYJtv9nzot7QD4iRJ52ZkgdU6Ci"
|
||||||
|
preview2.statusContactPreview.displayName = "Test contact display name"
|
||||||
|
preview2.statusContactPreview.description = "Test description"
|
||||||
|
preview2.statusContactPreviewThumbnail = {}
|
||||||
|
preview2.statusContactPreviewThumbnail.width = 64
|
||||||
|
preview2.statusContactPreviewThumbnail.height = 64
|
||||||
|
preview2.statusContactPreviewThumbnail.url = "https://placehold.co/64x64"
|
||||||
|
preview2.statusContactPreviewThumbnail.dataUri = ""
|
||||||
|
|
||||||
|
const preview3 = Object.assign({}, emptyObject)
|
||||||
|
preview3.url = "https://status.app/c/ixiACjAKDlRlc3QgQ29tbXVuaXR5Eg9PcGVuIGZvciBhbnlvbmUYdiIHI0ZGMDAwMCoCHwkD#zQ3shnd55dNx9yTihuL6XMbmyM6UNjzU6jk77h5Js31jxcT5V"
|
||||||
|
preview3.previewType = 3
|
||||||
|
preview3.statusCommunityPreview = {}
|
||||||
|
preview3.statusCommunityPreview.communityId = "zQ3shnd55dNx9yTihuL6XMbmyM6UNjzU6jk77h5Js31jxcT5V"
|
||||||
|
preview3.statusCommunityPreview.displayName = "Test community display name"
|
||||||
|
preview3.statusCommunityPreview.description = "Test community description"
|
||||||
|
preview3.statusCommunityPreview.membersCount = 10
|
||||||
|
preview3.statusCommunityPreview.color = "#123456"
|
||||||
|
preview3.statusCommunityPreviewIcon = {}
|
||||||
|
preview3.statusCommunityPreviewIcon.width = 64
|
||||||
|
preview3.statusCommunityPreviewIcon.height = 64
|
||||||
|
preview3.statusCommunityPreviewIcon.url = "https://placehold.co/64x64"
|
||||||
|
preview3.statusCommunityPreviewIcon.dataUri = ""
|
||||||
|
preview3.statusCommunityPreviewBanner = {}
|
||||||
|
preview3.statusCommunityPreviewBanner.width = 320
|
||||||
|
preview3.statusCommunityPreviewBanner.height = 180
|
||||||
|
preview3.statusCommunityPreviewBanner.url = "https://placehold.co/320x180"
|
||||||
|
preview3.statusCommunityPreviewBanner.dataUri = ""
|
||||||
|
|
||||||
|
mockedLinkPreviewModel.append(preview1)
|
||||||
|
mockedLinkPreviewModel.append(preview2)
|
||||||
|
mockedLinkPreviewModel.append(preview3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
id: messageViewWrapper
|
id: messageViewWrapper
|
||||||
SplitView.fillWidth: true
|
SplitView.fillWidth: true
|
||||||
SplitView.fillHeight: true
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
component LinkPreviewObject: QtObject {
|
||||||
|
required property string url
|
||||||
|
required property bool unfurled
|
||||||
|
required property bool empty
|
||||||
|
required property int previewType
|
||||||
|
}
|
||||||
|
|
||||||
|
component StandardPreviewObject: QtObject {
|
||||||
|
required property string hostname
|
||||||
|
required property string title
|
||||||
|
required property string description
|
||||||
|
required property int linkType // 0 = link, 1 = image
|
||||||
|
}
|
||||||
|
|
||||||
|
component ThumbnailObject: QtObject {
|
||||||
|
required property int width
|
||||||
|
required property int height
|
||||||
|
required property string url
|
||||||
|
required property string dataUri
|
||||||
|
}
|
||||||
|
|
||||||
LinksMessageView {
|
LinksMessageView {
|
||||||
id: linksMessageView
|
id: linksMessageView
|
||||||
|
|
||||||
@ -16,57 +126,7 @@ SplitView {
|
|||||||
|
|
||||||
store: {}
|
store: {}
|
||||||
messageStore: {}
|
messageStore: {}
|
||||||
linkPreviewModel: ListModel {
|
linkPreviewModel: mockedLinkPreviewModel
|
||||||
id: linkPreviewModel
|
|
||||||
ListElement {
|
|
||||||
url: "https://www.youtube.com/watch?v=9bZkp7q19f0"
|
|
||||||
unfurled: true
|
|
||||||
hostname: "www.youtube.com"
|
|
||||||
title: "PSY - GANGNAM STYLE(강남스타일) M/V"
|
|
||||||
description: "PSY - ‘I LUV IT’ M/V @ https://youtu.be/Xvjnoagk6GU PSY - ‘New Face’ M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp..."
|
|
||||||
linkType: 0 // 0 = link, 1 = image
|
|
||||||
thumbnailWidth: 480
|
|
||||||
thumbnailHeight: 360
|
|
||||||
thumbnailUrl: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
thumbnailDataUri: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
url: "https://www.youtube.com/watch?v=9bZkp7q19f0"
|
|
||||||
unfurled: true
|
|
||||||
hostname: "www.youtube.com"
|
|
||||||
title: "PSY - GANGNAM STYLE(강남스타일) M/V"
|
|
||||||
description: "PSY - ‘I LUV IT’ M/V @ https://youtu.be/Xvjnoagk6GU PSY - ‘New Face’ M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp..."
|
|
||||||
linkType: 0 // 0 = link, 1 = image
|
|
||||||
thumbnailWidth: 480
|
|
||||||
thumbnailHeight: 360
|
|
||||||
thumbnailUrl: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
thumbnailDataUri: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
url: "https://www.youtube.com/watch?v=9bZkp7q19f0"
|
|
||||||
unfurled: true
|
|
||||||
hostname: "www.youtube.com"
|
|
||||||
title: "PSY - GANGNAM STYLE(강남스타일) M/V"
|
|
||||||
description: "PSY - ‘I LUV IT’ M/V @ https://youtu.be/Xvjnoagk6GU PSY - ‘New Face’ M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp..."
|
|
||||||
linkType: 0 // 0 = link, 1 = image
|
|
||||||
thumbnailWidth: 480
|
|
||||||
thumbnailHeight: 360
|
|
||||||
thumbnailUrl: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
thumbnailDataUri: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
url: "https://www.youtube.com/watch?v=9bZkp7q19f0"
|
|
||||||
unfurled: true
|
|
||||||
hostname: "www.youtube.com"
|
|
||||||
title: "PSY - GANGNAM STYLE(강남스타일) M/V"
|
|
||||||
description: "PSY - ‘I LUV IT’ M/V @ https://youtu.be/Xvjnoagk6GU PSY - ‘New Face’ M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp..."
|
|
||||||
linkType: 0 // 0 = link, 1 = image
|
|
||||||
thumbnailWidth: 480
|
|
||||||
thumbnailHeight: 360
|
|
||||||
thumbnailUrl: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
thumbnailDataUri: "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
localUnfurlLinks: {}
|
localUnfurlLinks: {}
|
||||||
isCurrentUser: true
|
isCurrentUser: true
|
||||||
|
|
||||||
@ -94,4 +154,4 @@ SplitView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
133
ui/imports/shared/controls/LinkPreviewDebugView.qml
Normal file
133
ui/imports/shared/controls/LinkPreviewDebugView.qml
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool unfurled
|
||||||
|
required property bool empty
|
||||||
|
required property string url
|
||||||
|
required property int previewType
|
||||||
|
required property var standardPreview
|
||||||
|
required property var standardPreviewThumbnail
|
||||||
|
required property var statusContactPreview
|
||||||
|
required property var statusContactPreviewThumbnail
|
||||||
|
required property var statusCommunityPreview
|
||||||
|
required property var statusCommunityPreviewIcon
|
||||||
|
required property var statusCommunityPreviewBanner
|
||||||
|
required property var statusCommunityChannelPreview
|
||||||
|
required property var statusCommunityChannelCommunityPreview
|
||||||
|
required property var statusCommunityChannelCommunityPreviewIcon
|
||||||
|
required property var statusCommunityChannelCommunityPreviewBanner
|
||||||
|
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
|
function getThumbnailString(thumbnail) {
|
||||||
|
const thumbnailWidth = thumbnail ? thumbnail.width : ""
|
||||||
|
const thumbnailHeight = thumbnail ? thumbnail.height : ""
|
||||||
|
const thumbnailUrl = thumbnail ? thumbnail.url : ""
|
||||||
|
const thumbnailDataUri = thumbnail ? thumbnail.dataUri : ""
|
||||||
|
return `(${thumbnailWidth}*${thumbnailHeight}, url: ${thumbnailUrl.length} symbols, data: ${thumbnailDataUri.length} symbols)`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStandardPreviewString(preview, thumbnail) {
|
||||||
|
const hostname = standardPreview ? standardPreview.hostname : ""
|
||||||
|
const title = standardPreview ? standardPreview.title : ""
|
||||||
|
const description = standardPreview ? standardPreview.description : ""
|
||||||
|
const thumbnailInfo = getThumbnailString(thumbnail)
|
||||||
|
return `(hostname: ${hostname}): ${title}\n` +
|
||||||
|
`description: ${description}\n` +
|
||||||
|
`thumbnail: ${thumbnailInfo}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusContactPreviewString(preview, thumbnail) {
|
||||||
|
const publicKey = preview ? preview.publicKey : ""
|
||||||
|
const displayName = preview ? preview.displayName : ""
|
||||||
|
const description = preview ? preview.description : ""
|
||||||
|
const thumbnailInfo = getThumbnailString(thumbnail)
|
||||||
|
return `(publicKey: ${publicKey})\n` +
|
||||||
|
`displayName: ${displayName}\n` +
|
||||||
|
`description: ${description}\n` +
|
||||||
|
`icon: ${thumbnailInfo}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusCommunityPreviewString(preview, icon, banner) {
|
||||||
|
const communityId = preview ? preview.communityId : ""
|
||||||
|
const displayName = preview ? preview.displayName : ""
|
||||||
|
const description = preview ? preview.description : ""
|
||||||
|
const membersCount = preview ? preview.membersCount : ""
|
||||||
|
const color = preview ? preview.color : ""
|
||||||
|
const iconInfo = getThumbnailString(icon)
|
||||||
|
const bannerInfo = getThumbnailString(banner)
|
||||||
|
return `communityId: ${communityId}\n` +
|
||||||
|
`displayName: ${displayName}\n` +
|
||||||
|
`description: ${description}\n` +
|
||||||
|
`membersCount: ${membersCount}\n` +
|
||||||
|
`color: ${color}\n` +
|
||||||
|
`icon: ${iconInfo}\n` +
|
||||||
|
`banner: ${bannerInfo}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusChannelPreviewString(channel, community, communityIcon, communityBanner) {
|
||||||
|
const channelUuid = channel ? channel.channelUuid : ""
|
||||||
|
const displayName = channel ? channel.displayName : ""
|
||||||
|
const description = channel ? channel.description : ""
|
||||||
|
const emoji = channel ? channel.emoji : ""
|
||||||
|
const color = channel ? channel.color : ""
|
||||||
|
const communityInfo = getStatusCommunityPreviewString(community, communityIcon, communityBanner)
|
||||||
|
return `channelUuid: ${channelUuid}\n` +
|
||||||
|
`displayName: ${displayName}\n` +
|
||||||
|
`description: ${description}\n` +
|
||||||
|
`emoji: ${emoji}\n` +
|
||||||
|
`color: ${color}\n` +
|
||||||
|
`- communityInfo: \n${communityInfo}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkPreviewTypeString(t) {
|
||||||
|
switch (t) {
|
||||||
|
case Constants.LinkPreviewType.NoPreview:
|
||||||
|
return "NoPreview"
|
||||||
|
case Constants.LinkPreviewType.Standard:
|
||||||
|
return "Standard"
|
||||||
|
case Constants.LinkPreviewType.StatusContact:
|
||||||
|
return "StatusContact"
|
||||||
|
case Constants.LinkPreviewType.StatusCommunity:
|
||||||
|
return "StatusCommunity"
|
||||||
|
case Constants.LinkPreviewType.StatusCommunityChannel:
|
||||||
|
return "StatusCommunityChannel"
|
||||||
|
}
|
||||||
|
return "???"
|
||||||
|
}
|
||||||
|
|
||||||
|
text: {
|
||||||
|
const stateEmoji = unfurled ? (empty ? '❌' : '✅') : '👀'
|
||||||
|
let previewString = ""
|
||||||
|
|
||||||
|
switch (previewType) {
|
||||||
|
case Constants.LinkPreviewType.Standard:
|
||||||
|
previewString = getStandardPreviewString(standardPreview,
|
||||||
|
standardPreviewThumbnail)
|
||||||
|
break
|
||||||
|
case Constants.LinkPreviewType.StatusContact:
|
||||||
|
previewString = getStatusContactPreviewString(statusContactPreview,
|
||||||
|
statusContactPreviewThumbnail)
|
||||||
|
break
|
||||||
|
case Constants.LinkPreviewType.StatusCommunity:
|
||||||
|
previewString = getStatusCommunityPreviewString(statusCommunityPreview,
|
||||||
|
statusCommunityPreviewIcon,
|
||||||
|
statusCommunityPreviewBanner)
|
||||||
|
break
|
||||||
|
case Constants.LinkPreviewType.StatusCommunityChannel:
|
||||||
|
previewString = getStatusChannelPreviewString(statusCommunityChannelPreview,
|
||||||
|
statusCommunityChannelCommunityPreview,
|
||||||
|
statusCommunityChannelCommunityPreviewIcon,
|
||||||
|
statusCommunityChannelCommunityPreviewBanner)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${stateEmoji} ${linkPreviewTypeString(previewType)} ${url}\n${previewString}`
|
||||||
|
}
|
||||||
|
}
|
@ -101,32 +101,54 @@ Control {
|
|||||||
model: d.filteredModel
|
model: d.filteredModel
|
||||||
delegate: LinkPreviewMiniCard {
|
delegate: LinkPreviewMiniCard {
|
||||||
// Model properties
|
// Model properties
|
||||||
required property string title
|
|
||||||
required property string url
|
|
||||||
required property bool unfurled
|
|
||||||
required property bool immutable
|
|
||||||
required property string hostname
|
|
||||||
required property string description
|
|
||||||
required property int linkType
|
|
||||||
required property int thumbnailWidth
|
|
||||||
required property int thumbnailHeight
|
|
||||||
required property string thumbnailUrl
|
|
||||||
required property string thumbnailDataUri
|
|
||||||
|
|
||||||
required property int index
|
required property int index
|
||||||
|
required property bool unfurled
|
||||||
|
required property bool empty
|
||||||
|
required property string url
|
||||||
|
required property bool immutable
|
||||||
|
required property int previewType
|
||||||
|
required property var standardPreview
|
||||||
|
required property var standardPreviewThumbnail
|
||||||
|
required property var statusContactPreview
|
||||||
|
required property var statusContactPreviewThumbnail
|
||||||
|
required property var statusCommunityPreview
|
||||||
|
required property var statusCommunityPreviewIcon
|
||||||
|
required property var statusCommunityPreviewBanner
|
||||||
|
required property var statusCommunityChannelPreview
|
||||||
|
required property var statusCommunityChannelCommunityPreview
|
||||||
|
required property var statusCommunityChannelCommunityPreviewIcon
|
||||||
|
required property var statusCommunityChannelCommunityPreviewBanner
|
||||||
|
|
||||||
|
readonly property var thumbnail: {
|
||||||
|
switch (previewType) {
|
||||||
|
case Constants.Standard:
|
||||||
|
return standardPreviewThumbnail
|
||||||
|
case Constants.StatusContact:
|
||||||
|
return statusContactPreviewThumbnail
|
||||||
|
case Constants.StatusCommunity:
|
||||||
|
return statusCommunityPreviewIcon
|
||||||
|
case Constants.StatusCommunityChannel:
|
||||||
|
return statusCommunityChannelCommunityPreviewIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property string thumbnailUrl: thumbnail ? thumbnail.url : ""
|
||||||
|
readonly property string thumbnailDataUri: thumbnail ? thumbnail.dataUri : ""
|
||||||
|
|
||||||
|
|
||||||
Layout.preferredHeight: 64
|
Layout.preferredHeight: 64
|
||||||
|
|
||||||
titleStr: title
|
titleStr: standardPreview ? standardPreview.title : statusContactPreview ? statusContactPreview.displayName : ""
|
||||||
domain: hostname //TODO: use domain when available
|
domain: standardPreview ? standardPreview.hostname : "" //TODO: use domain when available
|
||||||
favIconUrl: "" //TODO: use favicon when available
|
favIconUrl: "" //TODO: use favicon when available
|
||||||
communityName: "" //TODO: add community info when available
|
communityName: statusCommunityPreview ? statusCommunityPreview.displayName : ""
|
||||||
channelName: "" //TODO: add community info when available
|
channelName: statusCommunityChannelPreview ? statusCommunityChannelPreview.displayName : ""
|
||||||
|
|
||||||
thumbnailImageUrl: thumbnailUrl.length > 0 ? thumbnailUrl : thumbnailDataUri
|
thumbnailImageUrl: thumbnailUrl.length > 0 ? thumbnailUrl : thumbnailDataUri
|
||||||
type: linkType === 0 ? LinkPreviewMiniCard.Type.Link : LinkPreviewMiniCard.Type.Image
|
type: getCardType(previewType, standardPreview)
|
||||||
previewState: unfurled && hostname != "" ? LinkPreviewMiniCard.State.Loaded :
|
previewState: unfurled && !empty ? LinkPreviewMiniCard.State.Loaded :
|
||||||
unfurled && hostname === "" ? LinkPreviewMiniCard.State.LoadingFailed :
|
unfurled && empty ? LinkPreviewMiniCard.State.LoadingFailed :
|
||||||
!unfurled ? LinkPreviewMiniCard.State.Loading : LinkPreviewMiniCard.State.Invalid
|
!unfurled ? LinkPreviewMiniCard.State.Loading : LinkPreviewMiniCard.State.Invalid
|
||||||
|
|
||||||
onClose: root.dismissLinkPreview(d.filteredModel.mapToSource(index))
|
onClose: root.dismissLinkPreview(d.filteredModel.mapToSource(index))
|
||||||
|
@ -21,6 +21,7 @@ CalloutCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
|
Unknown = 0,
|
||||||
Link,
|
Link,
|
||||||
Image,
|
Image,
|
||||||
Community,
|
Community,
|
||||||
@ -28,6 +29,30 @@ CalloutCard {
|
|||||||
User
|
User
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCardType(previewType, standardLinkPreview) {
|
||||||
|
switch (previewType) {
|
||||||
|
case Constants.StatusContact:
|
||||||
|
return LinkPreviewMiniCard.Type.User
|
||||||
|
case Constants.StatusCommunity:
|
||||||
|
return LinkPreviewMiniCard.Type.Community
|
||||||
|
case Constants.StatusCommunityChannel:
|
||||||
|
return LinkPreviewMiniCard.Type.Channel
|
||||||
|
case Constants.Standard:
|
||||||
|
if (!standardLinkPreview)
|
||||||
|
return LinkPreviewMiniCard.Type.Unknown
|
||||||
|
switch (standardLinkPreview.linkType) {
|
||||||
|
case Constants.StandardLinkPreviewType.Link:
|
||||||
|
return LinkPreviewMiniCard.Type.Link
|
||||||
|
case Constants.StandardLinkPreviewType.Image:
|
||||||
|
return LinkPreviewMiniCard.Type.Image
|
||||||
|
default:
|
||||||
|
return LinkPreviewMiniCard.Type.Unknown
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return LinkPreviewMiniCard.Type.Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
required property string titleStr
|
required property string titleStr
|
||||||
required property string domain
|
required property string domain
|
||||||
required property string communityName
|
required property string communityName
|
||||||
|
@ -18,6 +18,7 @@ InformationTag 1.0 InformationTag.qml
|
|||||||
InformationTile 1.0 InformationTile.qml
|
InformationTile 1.0 InformationTile.qml
|
||||||
Input 1.0 Input.qml
|
Input 1.0 Input.qml
|
||||||
LoadingTokenDelegate 1.0 LoadingTokenDelegate.qml
|
LoadingTokenDelegate 1.0 LoadingTokenDelegate.qml
|
||||||
|
LinkPreviewDebugView 1.0 LinkPreviewDebugView.qml
|
||||||
RadioButtonSelector 1.0 RadioButtonSelector.qml
|
RadioButtonSelector 1.0 RadioButtonSelector.qml
|
||||||
RecipientSelector 1.0 RecipientSelector.qml
|
RecipientSelector 1.0 RecipientSelector.qml
|
||||||
SearchBox 1.0 SearchBox.qml
|
SearchBox 1.0 SearchBox.qml
|
||||||
|
@ -7,6 +7,7 @@ import StatusQ.Core.Theme 0.1
|
|||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
|
|
||||||
|
import shared.controls 1.0
|
||||||
import shared.status 1.0
|
import shared.status 1.0
|
||||||
import shared.panels 1.0
|
import shared.panels 1.0
|
||||||
import shared.stores 1.0
|
import shared.stores 1.0
|
||||||
@ -89,44 +90,90 @@ Flow {
|
|||||||
model: root.linkPreviewModel
|
model: root.linkPreviewModel
|
||||||
delegate: Loader {
|
delegate: Loader {
|
||||||
id: linkMessageLoader
|
id: linkMessageLoader
|
||||||
|
|
||||||
// properties from the model
|
// properties from the model
|
||||||
required property string url
|
|
||||||
required property bool unfurled
|
required property bool unfurled
|
||||||
required property string hostname
|
required property bool empty
|
||||||
required property string title
|
required property string url
|
||||||
required property string description
|
required property bool immutable
|
||||||
required property int linkType
|
required property int previewType
|
||||||
required property int thumbnailWidth
|
required property var standardPreview
|
||||||
required property int thumbnailHeight
|
required property var standardPreviewThumbnail
|
||||||
required property string thumbnailUrl
|
required property var statusContactPreview
|
||||||
required property string thumbnailDataUri
|
required property var statusContactPreviewThumbnail
|
||||||
|
required property var statusCommunityPreview
|
||||||
|
required property var statusCommunityPreviewIcon
|
||||||
|
required property var statusCommunityPreviewBanner
|
||||||
|
required property var statusCommunityChannelPreview
|
||||||
|
required property var statusCommunityChannelCommunityPreview
|
||||||
|
required property var statusCommunityChannelCommunityPreviewIcon
|
||||||
|
required property var statusCommunityChannelCommunityPreviewBanner
|
||||||
|
|
||||||
|
readonly property string hostname: standardPreview ? standardPreview.hostname : ""
|
||||||
|
readonly property string title: standardPreview ? standardPreview.title : ""
|
||||||
|
readonly property string description: standardPreview ? standardPreview.description : ""
|
||||||
|
readonly property int standardLinkType: standardPreview ? standardPreview.linkType : ""
|
||||||
|
readonly property int thumbnailWidth: standardPreviewThumbnail ? standardPreviewThumbnail.width : ""
|
||||||
|
readonly property int thumbnailHeight: standardPreviewThumbnail ? standardPreviewThumbnail.height : ""
|
||||||
|
readonly property string thumbnailUrl: standardPreviewThumbnail ? standardPreviewThumbnail.url : ""
|
||||||
|
readonly property string thumbnailDataUri: standardPreviewThumbnail ? standardPreviewThumbnail.dataUri : ""
|
||||||
property bool animated: false
|
property bool animated: false
|
||||||
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
active: unfurled && hostname != ""
|
active: unfurled && !empty
|
||||||
|
|
||||||
sourceComponent: LinkPreviewCard {
|
StateGroup {
|
||||||
id: unfurledLink
|
//Using StateGroup as a warkardound for https://bugreports.qt.io/browse/QTBUG-47796
|
||||||
leftTail: !root.isCurrentUser
|
states: [
|
||||||
|
State {
|
||||||
bannerImageSource: thumbnailUrl.length > 0 ? thumbnailUrl : thumbnailDataUri
|
name: "standardLinkPreview"
|
||||||
title: parent.title
|
when: linkMessageLoader.previewType === Constants.LinkPreviewType.Standard
|
||||||
description: parent.description
|
PropertyChanges { target: linkMessageLoader; sourceComponent: standardLinkPreviewCard }
|
||||||
footer: hostname
|
},
|
||||||
onClicked:
|
State {
|
||||||
(mouse) => {
|
name: "statusContactLinkPreview"
|
||||||
switch (mouse.button) {
|
when: linkMessageLoader.previewType === Constants.LinkPreviewType.StatusContact
|
||||||
case Qt.RightButton:
|
PropertyChanges { target: linkMessageLoader; sourceComponent: unfurledProfileLinkComponent }
|
||||||
root.imageClicked(unfurledLink, mouse, "", url) // request a dumb context menu with just "copy/open link" items
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
Global.openLinkWithConfirmation(url, hostname)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
highlight: root.highlightLink === url
|
]
|
||||||
onHoveredChanged: linksRepeater.hoveredUrl = hovered ? url : ""
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: standardLinkPreviewCard
|
||||||
|
LinkPreviewCard {
|
||||||
|
leftTail: !root.isCurrentUser // WARNING: Is this by design?
|
||||||
|
bannerImageSource: standardPreviewThumbnail ? standardPreviewThumbnail.url : ""
|
||||||
|
title: standardPreview ? standardPreview.title : ""
|
||||||
|
description: standardPreview ? standardPreview.description : ""
|
||||||
|
footer: standardPreview ? standardPreview.hostname : ""
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
switch (mouse.button) {
|
||||||
|
case Qt.RightButton:
|
||||||
|
root.imageClicked(unfurledLink, mouse, "", url) // request a dumb context menu with just "copy/open link" items
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
Global.openLinkWithConfirmation(url, hostname)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: unfurledProfileLinkComponent
|
||||||
|
UserProfileCard {
|
||||||
|
id: unfurledProfileLink
|
||||||
|
|
||||||
|
leftTail: !root.isCurrentUser
|
||||||
|
userName: statusContactPreview && statusContactPreview.displayName ? statusContactPreview.displayName : ""
|
||||||
|
userPublicKey: statusContactPreview && statusContactPreview.publicKey ? statusContactPreview.publicKey : ""
|
||||||
|
userBio: statusContactPreview && statusContactPreview.description ? statusContactPreview.description : ""
|
||||||
|
userImage: statusContactPreviewThumbnail ? statusContactPreviewThumbnail.url : ""
|
||||||
|
ensVerified: false // not supported yet
|
||||||
|
onClicked: {
|
||||||
|
Global.openProfilePopup(userPublicKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,15 +181,12 @@ Flow {
|
|||||||
//TODO: Remove this once we have gif support in new unfurling flow
|
//TODO: Remove this once we have gif support in new unfurling flow
|
||||||
Component {
|
Component {
|
||||||
id: unfurledImageComponent
|
id: unfurledImageComponent
|
||||||
|
|
||||||
CalloutCard {
|
CalloutCard {
|
||||||
implicitWidth: linkImage.width
|
implicitWidth: linkImage.width
|
||||||
implicitHeight: linkImage.height
|
implicitHeight: linkImage.height
|
||||||
leftTail: !root.isCurrentUser
|
leftTail: !root.isCurrentUser
|
||||||
|
|
||||||
StatusChatImageLoader {
|
StatusChatImageLoader {
|
||||||
id: linkImage
|
id: linkImage
|
||||||
|
|
||||||
readonly property bool globalAnimationEnabled: root.messageStore.playAnimation
|
readonly property bool globalAnimationEnabled: root.messageStore.playAnimation
|
||||||
readonly property string urlLink: link
|
readonly property string urlLink: link
|
||||||
property bool localAnimationEnabled: true
|
property bool localAnimationEnabled: true
|
||||||
@ -195,15 +239,11 @@ Flow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code below can be dropped when New unfurling flow suppports GIFs.
|
// Code below can be dropped when New unfurling flow suppports GIFs.
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: invitationBubble
|
id: invitationBubble
|
||||||
|
|
||||||
InvitationBubbleView {
|
InvitationBubbleView {
|
||||||
property var invitationData: root.store.getLinkDataForStatusLinks(link)
|
property var invitationData: root.store.getLinkDataForStatusLinks(link)
|
||||||
|
|
||||||
store: root.store
|
store: root.store
|
||||||
communityId: invitationData && invitationData.communityData ? invitationData.communityData.communityId : ""
|
communityId: invitationData && invitationData.communityData ? invitationData.communityData.communityId : ""
|
||||||
communityData: invitationData && invitationData.communityData ? invitationData.communityData : null
|
communityData: invitationData && invitationData.communityData ? invitationData.communityData : null
|
||||||
@ -214,7 +254,6 @@ Flow {
|
|||||||
if (!invitationData)
|
if (!invitationData)
|
||||||
linksModel.remove(index)
|
linksModel.remove(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
enabled: !!invitationData && invitationData.fetching
|
enabled: !!invitationData && invitationData.fetching
|
||||||
target: root.store.communitiesModuleInst
|
target: root.store.communitiesModuleInst
|
||||||
@ -225,10 +264,8 @@ Flow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
readonly property string uuid: Utils.uuid()
|
readonly property string uuid: Utils.uuid()
|
||||||
readonly property string whiteListedImgExtensions: Constants.acceptedImageExtensions.toString()
|
readonly property string whiteListedImgExtensions: Constants.acceptedImageExtensions.toString()
|
||||||
readonly property string whiteListedUrls: JSON.stringify(localAccountSensitiveSettings.whitelistedUnfurlingSites)
|
readonly property string whiteListedUrls: JSON.stringify(localAccountSensitiveSettings.whitelistedUnfurlingSites)
|
||||||
@ -241,18 +278,14 @@ Flow {
|
|||||||
whiteListedImgExtensions,
|
whiteListedImgExtensions,
|
||||||
localAccountSensitiveSettings.displayChatImages)
|
localAccountSensitiveSettings.displayChatImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onGetLinkPreviewDataIdChanged: {
|
onGetLinkPreviewDataIdChanged: {
|
||||||
linkFetchConnections.enabled = root.localUnfurlLinks !== ""
|
linkFetchConnections.enabled = root.localUnfurlLinks !== ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
id: linkFetchConnections
|
id: linkFetchConnections
|
||||||
enabled: false
|
enabled: false
|
||||||
target: root.messageStore.messageModule
|
target: root.messageStore.messageModule
|
||||||
|
|
||||||
function onLinkPreviewDataWasReceived(previewData, uuid) {
|
function onLinkPreviewDataWasReceived(previewData, uuid) {
|
||||||
if (d.uuid !== uuid)
|
if (d.uuid !== uuid)
|
||||||
return
|
return
|
||||||
@ -265,12 +298,9 @@ Flow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: linksModel
|
id: linksModel
|
||||||
|
|
||||||
property var rawData
|
property var rawData
|
||||||
|
|
||||||
onRawDataChanged: {
|
onRawDataChanged: {
|
||||||
linksModel.clear()
|
linksModel.clear()
|
||||||
rawData.links.forEach((link) => {
|
rawData.links.forEach((link) => {
|
||||||
@ -279,35 +309,8 @@ Flow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
|
||||||
id: unfurledProfileLinkComponent
|
|
||||||
UserProfileCard {
|
|
||||||
id: unfurledProfileLink
|
|
||||||
readonly property var contact: Utils.parseContactUrl(parent.link)
|
|
||||||
readonly property var contactDetails: Utils.getContactDetailsAsJson(contact.publicKey)
|
|
||||||
|
|
||||||
readonly property string nickName: contactDetails ? contactDetails.localNickname : ""
|
|
||||||
readonly property string ensName: contactDetails ? contactDetails.name : ""
|
|
||||||
readonly property string displayName: contact && contact.displayName ? contact.displayName :
|
|
||||||
contactDetails && contactDetails.displayName ? contactDetails.displayName : ""
|
|
||||||
readonly property string aliasName: contactDetails ? contactDetails.alias : ""
|
|
||||||
|
|
||||||
leftTail: !root.isCurrentUser
|
|
||||||
userName: ProfileUtils.displayName(nickName, ensName, displayName, aliasName)
|
|
||||||
|
|
||||||
userPublicKey: contactDetails && contactDetails.publicKey ? contactDetails.publicKey : ""
|
|
||||||
userBio: contactDetails && contactDetails.bio ? contactDetails.bio : ""
|
|
||||||
userImage: contactDetails && contactDetails.thumbnailImage ? contactDetails.thumbnailImage : ""
|
|
||||||
ensVerified: contactDetails && contactDetails.ensVerified ? contactDetails.ensVerified : false
|
|
||||||
onClicked: {
|
|
||||||
Global.openProfilePopup(userPublicKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: enableLinkComponent
|
id: enableLinkComponent
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: enableLinkRoot
|
id: enableLinkRoot
|
||||||
width: 300
|
width: 300
|
||||||
@ -316,7 +319,6 @@ Flow {
|
|||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: Style.current.border
|
border.color: Style.current.border
|
||||||
color: Style.current.background
|
color: Style.current.background
|
||||||
|
|
||||||
StatusFlatRoundButton {
|
StatusFlatRoundButton {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: Style.current.smallPadding
|
anchors.topMargin: Style.current.smallPadding
|
||||||
@ -327,7 +329,6 @@ Flow {
|
|||||||
icon.name: "close-circle"
|
icon.name: "close-circle"
|
||||||
onClicked: linksModel.remove(index)
|
onClicked: linksModel.remove(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: unfurlingImage
|
id: unfurlingImage
|
||||||
source: Style.png("unfurling-image")
|
source: Style.png("unfurling-image")
|
||||||
@ -337,7 +338,6 @@ Flow {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: Style.current.smallPadding
|
anchors.topMargin: Style.current.smallPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
id: enableText
|
id: enableText
|
||||||
text: isImage ? qsTr("Enable automatic image unfurling") :
|
text: isImage ? qsTr("Enable automatic image unfurling") :
|
||||||
@ -349,7 +349,6 @@ Flow {
|
|||||||
anchors.topMargin: Style.current.halfPadding
|
anchors.topMargin: Style.current.halfPadding
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
id: infoText
|
id: infoText
|
||||||
text: qsTr("Once enabled, links posted in the chat may share your metadata with their owners")
|
text: qsTr("Once enabled, links posted in the chat may share your metadata with their owners")
|
||||||
@ -360,13 +359,11 @@ Flow {
|
|||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
id: sep1
|
id: sep1
|
||||||
anchors.top: infoText.bottom
|
anchors.top: infoText.bottom
|
||||||
anchors.topMargin: Style.current.smallPadding
|
anchors.topMargin: Style.current.smallPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusFlatButton {
|
StatusFlatButton {
|
||||||
id: enableBtn
|
id: enableBtn
|
||||||
objectName: "LinksMessageView_enableBtn"
|
objectName: "LinksMessageView_enableBtn"
|
||||||
@ -380,19 +377,16 @@ Flow {
|
|||||||
background.radius = 0;
|
background.radius = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
id: sep2
|
id: sep2
|
||||||
anchors.top: enableBtn.bottom
|
anchors.top: enableBtn.bottom
|
||||||
anchors.topMargin: 0
|
anchors.topMargin: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 44
|
height: 44
|
||||||
anchors.top: sep2.bottom
|
anchors.top: sep2.bottom
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
StatusFlatButton {
|
StatusFlatButton {
|
||||||
id: dontAskBtn
|
id: dontAskBtn
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
@ -71,7 +71,7 @@ Loader {
|
|||||||
return []
|
return []
|
||||||
const separator = " "
|
const separator = " "
|
||||||
const arr = links.split(separator)
|
const arr = links.split(separator)
|
||||||
const filtered = arr.filter(v => v.toLowerCase().endsWith('.gif') || v.toLowerCase().startsWith(Constants.userLinkPrefix.toLowerCase()))
|
const filtered = arr.filter(v => v.toLowerCase().endsWith('.gif'))
|
||||||
const out = filtered.join(separator)
|
const out = filtered.join(separator)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -1216,6 +1216,14 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum LinkPreviewType {
|
enum LinkPreviewType {
|
||||||
|
NoPreview = 0,
|
||||||
|
Standard = 1,
|
||||||
|
StatusContact = 2,
|
||||||
|
StatusCommunity = 3,
|
||||||
|
StatusCommunityChannel = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StandardLinkPreviewType {
|
||||||
Link = 0,
|
Link = 0,
|
||||||
Image = 1
|
Image = 1
|
||||||
}
|
}
|
||||||
|
2
vendor/status-go
vendored
2
vendor/status-go
vendored
@ -1 +1 @@
|
|||||||
Subproject commit ac813ef5d8f012ba4a0b532483ceeebc553aa3b1
|
Subproject commit aded258ccb68f88dc995e22f8b4e06157bb642db
|
Loading…
x
Reference in New Issue
Block a user