feat: show unfurled youtube links

This commit is contained in:
Jonathan Rainville 2020-10-23 15:46:44 -04:00 committed by Iuri Matias
parent a679758230
commit b583a4d4bf
10 changed files with 196 additions and 0 deletions

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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"]

View File

@ -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

View File

@ -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

View File

@ -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")
}
}
}
}

View File

@ -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 !== ""

View File

@ -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 \