feat: show unfurled youtube links
This commit is contained in:
parent
a679758230
commit
b583a4d4bf
|
@ -438,6 +438,9 @@ QtObject:
|
||||||
proc copyToClipboard*(self: ChatsView, content: string) {.slot.} =
|
proc copyToClipboard*(self: ChatsView, content: string) {.slot.} =
|
||||||
setClipBoardText(content)
|
setClipBoardText(content)
|
||||||
|
|
||||||
|
proc getLinkPreviewData*(self: ChatsView, link: string): string {.slot.} =
|
||||||
|
result = $self.status.chat.getLinkPreviewData(link)
|
||||||
|
|
||||||
proc sendSticker*(self: ChatsView, hash: string, pack: int) {.slot.} =
|
proc sendSticker*(self: ChatsView, hash: string, pack: int) {.slot.} =
|
||||||
let sticker = Sticker(hash: hash, packId: pack)
|
let sticker = Sticker(hash: hash, packId: pack)
|
||||||
self.addRecentStickerToList(sticker)
|
self.addRecentStickerToList(sticker)
|
||||||
|
|
|
@ -32,6 +32,7 @@ type
|
||||||
AudioDurationMs = UserRole + 21
|
AudioDurationMs = UserRole + 21
|
||||||
EmojiReactions = UserRole + 22
|
EmojiReactions = UserRole + 22
|
||||||
CommandParameters = UserRole + 23
|
CommandParameters = UserRole + 23
|
||||||
|
LinkUrls = UserRole + 24
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -136,6 +137,7 @@ QtObject:
|
||||||
of ChatMessageRoles.Audio: result = newQVariant(message.audio)
|
of ChatMessageRoles.Audio: result = newQVariant(message.audio)
|
||||||
of ChatMessageRoles.AudioDurationMs: result = newQVariant(message.audioDurationMs)
|
of ChatMessageRoles.AudioDurationMs: result = newQVariant(message.audioDurationMs)
|
||||||
of ChatMessageRoles.EmojiReactions: result = newQVariant(self.getReactions(message.id))
|
of ChatMessageRoles.EmojiReactions: result = newQVariant(self.getReactions(message.id))
|
||||||
|
of ChatMessageRoles.LinkUrls: result = newQVariant(message.linkUrls)
|
||||||
# Pass the command parameters as a JSON string
|
# Pass the command parameters as a JSON string
|
||||||
of ChatMessageRoles.CommandParameters: result = newQVariant($(%*{
|
of ChatMessageRoles.CommandParameters: result = newQVariant($(%*{
|
||||||
"id": message.commandParameters.id,
|
"id": message.commandParameters.id,
|
||||||
|
@ -172,6 +174,7 @@ QtObject:
|
||||||
ChatMessageRoles.Audio.int: "audio",
|
ChatMessageRoles.Audio.int: "audio",
|
||||||
ChatMessageRoles.AudioDurationMs.int: "audioDurationMs",
|
ChatMessageRoles.AudioDurationMs.int: "audioDurationMs",
|
||||||
ChatMessageRoles.EmojiReactions.int: "emojiReactions",
|
ChatMessageRoles.EmojiReactions.int: "emojiReactions",
|
||||||
|
ChatMessageRoles.LinkUrls.int: "linkUrls",
|
||||||
ChatMessageRoles.CommandParameters.int: "commandParameters"
|
ChatMessageRoles.CommandParameters.int: "commandParameters"
|
||||||
}.toTable
|
}.toTable
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,9 @@ proc clearHistory*(self: ChatModel, chatId: string) =
|
||||||
let chat = self.channels[chatId]
|
let chat = self.channels[chatId]
|
||||||
self.events.emit("chatHistoryCleared", ChannelArgs(chat: chat))
|
self.events.emit("chatHistoryCleared", ChannelArgs(chat: chat))
|
||||||
|
|
||||||
|
proc getLinkPreviewData*(self: ChatModel, link: string): JsonNode =
|
||||||
|
result = status_chat.getLinkPreviewData(link)
|
||||||
|
|
||||||
proc setActiveChannel*(self: ChatModel, chatId: string) =
|
proc setActiveChannel*(self: ChatModel, chatId: string) =
|
||||||
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))
|
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ type Message* = object
|
||||||
stickerHash*: string
|
stickerHash*: string
|
||||||
outgoingStatus*: string
|
outgoingStatus*: string
|
||||||
imageUrls*: string
|
imageUrls*: string
|
||||||
|
linkUrls*: string
|
||||||
image*: string
|
image*: string
|
||||||
audio*: string
|
audio*: string
|
||||||
audioDurationMs*: int
|
audioDurationMs*: int
|
||||||
|
|
|
@ -198,3 +198,6 @@ proc muteChat*(chatId: string): string =
|
||||||
|
|
||||||
proc unmuteChat*(chatId: string): string =
|
proc unmuteChat*(chatId: string): string =
|
||||||
result = callPrivateRPC("unmuteChat".prefix, %*[chatId])
|
result = callPrivateRPC("unmuteChat".prefix, %*[chatId])
|
||||||
|
|
||||||
|
proc getLinkPreviewData*(link: string): JsonNode =
|
||||||
|
result = callPrivateRPC("getLinkPreviewData".prefix, %*[link]).parseJSON()["result"]
|
|
@ -1,5 +1,7 @@
|
||||||
import json, random, strutils, sequtils, sugar, chronicles
|
import json, random, strutils, sequtils, sugar, chronicles
|
||||||
import json_serialization
|
import json_serialization
|
||||||
|
import ../libstatus/core
|
||||||
|
import ../libstatus/utils
|
||||||
import ../libstatus/accounts as status_accounts
|
import ../libstatus/accounts as status_accounts
|
||||||
import ../libstatus/accounts/constants as constants
|
import ../libstatus/accounts/constants as constants
|
||||||
import ../libstatus/settings as status_settings
|
import ../libstatus/settings as status_settings
|
||||||
|
@ -187,6 +189,7 @@ proc toMessage*(jsonMsg: JsonNode): Message =
|
||||||
stickerHash: "",
|
stickerHash: "",
|
||||||
parsedText: @[],
|
parsedText: @[],
|
||||||
imageUrls: "",
|
imageUrls: "",
|
||||||
|
linkUrls: "",
|
||||||
image: $jsonMsg{"image"}.getStr,
|
image: $jsonMsg{"image"}.getStr,
|
||||||
audio: $jsonMsg{"audio"}.getStr,
|
audio: $jsonMsg{"audio"}.getStr,
|
||||||
audioDurationMs: jsonMsg{"audioDurationMs"}.getInt,
|
audioDurationMs: jsonMsg{"audioDurationMs"}.getInt,
|
||||||
|
@ -202,6 +205,12 @@ proc toMessage*(jsonMsg: JsonNode): Message =
|
||||||
.map(t => t.destination)
|
.map(t => t.destination)
|
||||||
.join(" ")
|
.join(" ")
|
||||||
|
|
||||||
|
|
||||||
|
message.linkUrls = concat(message.parsedText.map(t => t.children.filter(c => c.textType == "link")))
|
||||||
|
.filter(t => t.destination.startsWith("http"))
|
||||||
|
.map(t => t.destination)
|
||||||
|
.join(" ")
|
||||||
|
|
||||||
if message.contentType == ContentType.Sticker:
|
if message.contentType == ContentType.Sticker:
|
||||||
message.stickerHash = jsonMsg["sticker"]["hash"].getStr
|
message.stickerHash = jsonMsg["sticker"]["hash"].getStr
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,18 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: linksLoader
|
||||||
|
active: !!linkUrls
|
||||||
|
anchors.left: chatText.left
|
||||||
|
anchors.leftMargin: 8
|
||||||
|
anchors.top: chatText.bottom
|
||||||
|
|
||||||
|
sourceComponent: Component {
|
||||||
|
LinksMessage {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: audioPlayerLoader
|
id: audioPlayerLoader
|
||||||
active: isAudio
|
active: isAudio
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
import QtQuick 2.3
|
||||||
|
import "../../../../../imports"
|
||||||
|
import "../../../../../shared"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: linksItem
|
||||||
|
height: {
|
||||||
|
let h = 0
|
||||||
|
for (let i = 0; i < linksRepeater.count; i++) {
|
||||||
|
h += linksRepeater.itemAt(i).height
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
width: {
|
||||||
|
let w = 0
|
||||||
|
for (let i = 0; i < linksRepeater.count; i++) {
|
||||||
|
if (linksRepeater.itemAt(i).width > w) {
|
||||||
|
w = linksRepeater.itemAt(i).width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: linksRepeater
|
||||||
|
model: {
|
||||||
|
if (!linkUrls) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkUrls.split(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Loader {
|
||||||
|
property string linkString: modelData
|
||||||
|
active: true
|
||||||
|
sourceComponent: {
|
||||||
|
let linkExists = false
|
||||||
|
let linkWhiteListed = false
|
||||||
|
Object.keys(appSettings.whitelistedUnfurlingSites).some(function (site) {
|
||||||
|
// Check if our link contains the string part of the url
|
||||||
|
// TODO this might become not a reliable way to check since youtube has mutliple ways of being shown
|
||||||
|
if (modelData.includes(site)) {
|
||||||
|
linkExists = true
|
||||||
|
// check if it was enabled
|
||||||
|
linkWhiteListed = appSettings.whitelistedUnfurlingSites[site] === true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
if (linkWhiteListed) {
|
||||||
|
return unfurledLinkComponent
|
||||||
|
}
|
||||||
|
if (linkExists) {
|
||||||
|
return enableLinkComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: unfurledLinkComponent
|
||||||
|
Loader {
|
||||||
|
property var linkData: {
|
||||||
|
try {
|
||||||
|
const data = chatsModel.getLinkPreviewData(linkString)
|
||||||
|
return JSON.parse(data)
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error parsing link data", e)
|
||||||
|
return undfined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enabled: linkData !== undefined && !!linkData.title
|
||||||
|
sourceComponent: Component {
|
||||||
|
Rectangle {
|
||||||
|
id: rectangle
|
||||||
|
width: 200
|
||||||
|
height: childrenRect.height + Style.current.halfPadding
|
||||||
|
radius: 16
|
||||||
|
clip: true
|
||||||
|
border.width: 1
|
||||||
|
border.color: Style.current.border
|
||||||
|
color:Style.current.background
|
||||||
|
|
||||||
|
// TODO the clip doesnt seem to work. Find another way to have rounded corners and wait for designs
|
||||||
|
Image {
|
||||||
|
id: linkImage
|
||||||
|
source: linkData.thumbnailUrl
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: linkTitle
|
||||||
|
text: linkData.title
|
||||||
|
elide: Text.ElideRight
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: linkImage.bottom
|
||||||
|
anchors.rightMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.halfPadding
|
||||||
|
anchors.topMargin: Style.current.halfPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: linkSite
|
||||||
|
text: linkData.site
|
||||||
|
color: Style.current.secondaryText
|
||||||
|
anchors.top: linkTitle.bottom
|
||||||
|
anchors.topMargin: Style.current.halfPadding
|
||||||
|
anchors.left: linkTitle.left
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.top: linkImage.top
|
||||||
|
anchors.left: linkImage.left
|
||||||
|
anchors.right: linkImage.right
|
||||||
|
anchors.bottom: linkSite.bottom
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: Qt.openUrlExternally(linkString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: enableLinkComponent
|
||||||
|
Rectangle {
|
||||||
|
width: 300
|
||||||
|
height: 200
|
||||||
|
radius: 16
|
||||||
|
|
||||||
|
border.width: 1
|
||||||
|
border.color: Style.current.border
|
||||||
|
color:Style.current.background
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: qsTr("You need to enable this before being able to see it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -216,6 +216,21 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: linksLoader
|
||||||
|
active: !!linkUrls
|
||||||
|
anchors.left: !isCurrentUser ? chatImage.right : undefined
|
||||||
|
anchors.leftMargin: !isCurrentUser ? 8 : 0
|
||||||
|
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||||
|
anchors.rightMargin: !isCurrentUser ? 0 : Style.current.padding
|
||||||
|
anchors.top: chatBox.bottom
|
||||||
|
anchors.topMargin: Style.current.smallPadding
|
||||||
|
|
||||||
|
sourceComponent: Component {
|
||||||
|
LinksMessage {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: emojiReactionLoader
|
id: emojiReactionLoader
|
||||||
active: emojiReactions !== ""
|
active: emojiReactions !== ""
|
||||||
|
|
|
@ -148,6 +148,7 @@ DISTFILES += \
|
||||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/EmojiReactions.qml \
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/EmojiReactions.qml \
|
||||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ImageLoader.qml \
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/ImageLoader.qml \
|
||||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ImageMessage.qml \
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/ImageMessage.qml \
|
||||||
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/LinksMessage.qml \
|
||||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml \
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml \
|
||||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/NormalMessage.qml \
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/NormalMessage.qml \
|
||||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/RectangleCorner.qml \
|
app/AppLayouts/Chat/ChatColumn/MessageComponents/RectangleCorner.qml \
|
||||||
|
|
Loading…
Reference in New Issue