feat: Unfurl GIFs locally (#11977)

This commit is contained in:
Igor Sirotin 2023-08-22 18:46:26 +03:00 committed by GitHub
parent cc83098263
commit 7e34260aef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 247 additions and 2 deletions

View File

@ -40,6 +40,7 @@ Control {
property string messageAttachments: "" property string messageAttachments: ""
property var reactionIcons: [] property var reactionIcons: []
property var linkPreviewModel property var linkPreviewModel
property var localUnfurlLinks
property string messageId: "" property string messageId: ""
property bool editMode: false property bool editMode: false
@ -349,7 +350,9 @@ Control {
Loader { Loader {
id: linksLoader id: linksLoader
Layout.fillWidth: true Layout.fillWidth: true
active: !root.editMode && root.linkPreviewModel && root.linkPreviewModel.count > 0 active: !root.editMode &&
((!!root.linkPreviewModel && root.linkPreviewModel.count > 0)
|| (!!root.localUnfurlLinks && root.localUnfurlLinks.length > 0))
visible: active visible: active
} }
Loader { Loader {

View File

@ -99,6 +99,7 @@ StatusDialog {
sticker: model.sticker sticker: model.sticker
stickerPack: model.stickerPack stickerPack: model.stickerPack
linkPreviewModel: model.linkPreviewModel linkPreviewModel: model.linkPreviewModel
links: model.links
transactionParams: model.transactionParameters transactionParams: model.transactionParameters
quotedMessageText: model.quotedMessageParsedText quotedMessageText: model.quotedMessageParsedText
quotedMessageFrom: model.quotedMessageFrom quotedMessageFrom: model.quotedMessageFrom

View File

@ -297,6 +297,7 @@ Item {
onEditModeOnChanged: root.editModeChanged(editModeOn) onEditModeOnChanged: root.editModeChanged(editModeOn)
isEdited: model.isEdited isEdited: model.isEdited
linkPreviewModel: model.linkPreviewModel linkPreviewModel: model.linkPreviewModel
links: model.links
messageAttachments: model.messageAttachments messageAttachments: model.messageAttachments
transactionParams: model.transactionParameters transactionParams: model.transactionParameters
hasMention: model.mentioned hasMention: model.mentioned

View File

@ -18,7 +18,9 @@ ColumnLayout {
property var store property var store
property var messageStore property var messageStore
property var linkPreviewModel property var linkPreviewModel
property var localUnfurlLinks
property bool isCurrentUser: false property bool isCurrentUser: false
@ -42,6 +44,7 @@ ColumnLayout {
required property int thumbnailHeight required property int thumbnailHeight
required property string thumbnailUrl required property string thumbnailUrl
required property string thumbnailDataUri required property string thumbnailDataUri
property bool animated: false
asynchronous: true asynchronous: true
@ -93,7 +96,7 @@ ColumnLayout {
playing: globalAnimationEnabled && localAnimationEnabled playing: globalAnimationEnabled && localAnimationEnabled
isOnline: root.store.mainModuleInst.isOnline isOnline: root.store.mainModuleInst.isOnline
asynchronous: true asynchronous: true
isAnimated: false // FIXME: GIFs are not supported with new unfurling yet isAnimated: animated // FIXME: GIFs are not supported with new unfurling yet
onClicked: { onClicked: {
if (isAnimated && !playing) if (isAnimated && !playing)
localAnimationEnabled = true localAnimationEnabled = true
@ -231,4 +234,226 @@ ColumnLayout {
} }
} }
} }
// Code below can be dropped when New unfurling flow suppports GIFs.
QtObject {
id: d
readonly property string uuid: Utils.uuid()
readonly property string whiteListedImgExtensions: Constants.acceptedImageExtensions.toString()
readonly property string whiteListedUrls: JSON.stringify(localAccountSensitiveSettings.whitelistedUnfurlingSites)
readonly property string getLinkPreviewDataId: {
if (root.localUnfurlLinks === "")
return ""
return root.messageStore.messageModule.getLinkPreviewData(root.localUnfurlLinks,
d.uuid,
whiteListedUrls,
whiteListedImgExtensions,
localAccountSensitiveSettings.displayChatImages)
}
onGetLinkPreviewDataIdChanged: {
linkFetchConnections.enabled = root.localUnfurlLinks !== ""
}
}
Connections {
id: linkFetchConnections
enabled: false
target: root.messageStore.messageModule
function onLinkPreviewDataWasReceived(previewData, uuid) {
if (d.uuid !== uuid)
return
linkFetchConnections.enabled = false
try {
linksModel.rawData = JSON.parse(previewData)
}
catch(e) {
console.warn("error parsing link preview data", previewData)
}
}
}
ListModel {
id: linksModel
property var rawData
onRawDataChanged: {
linksModel.clear()
rawData.links.forEach((link) => {
linksModel.append(link)
})
}
}
Repeater {
id: tempRepeater
visible: !RootStore.neverAskAboutUnfurlingAgain
model: linksModel
delegate: Loader {
id: tempLoader
required property var result
required property string link
required property int index
required property bool unfurl
required property bool success
required property bool isStatusDeepLink
readonly property bool isImage: result.contentType ? result.contentType.startsWith("image/") : false
readonly property string thumbnailUrl: result && result.thumbnailUrl ? result.thumbnailUrl : ""
readonly property string title: result && result.title ? result.title : ""
readonly property string hostname: result && result.site ? result.site : ""
readonly property bool animated: true
StateGroup {
//Using StateGroup as a warkardound for https://bugreports.qt.io/browse/QTBUG-47796
id: linkPreviewLoaderState
states: [
State {
name: "askToEnableUnfurling"
when: !tempLoader.unfurl
PropertyChanges { target: tempLoader; sourceComponent: enableLinkComponent }
},
State {
name: "loadImage"
when: tempLoader.unfurl && tempLoader.isImage
PropertyChanges { target: tempLoader; sourceComponent: unfurledImageComponent }
}
// State {
// name: "loadLinkPreview"
// when: unfurl && !isImage && !isStatusDeepLink
// PropertyChanges { target: tempLoader; sourceComponent: unfurledLinkComponent }
// },
// State {
// name: "statusInvitation"
// when: unfurl && isStatusDeepLink
// PropertyChanges { target: tempLoader; sourceComponent: invitationBubble }
// }
]
}
}
}
Component {
id: enableLinkComponent
Rectangle {
id: enableLinkRoot
width: 300
height: childrenRect.height + Style.current.smallPadding
radius: 16
border.width: 1
border.color: Style.current.border
color: Style.current.background
StatusFlatRoundButton {
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
icon.width: 20
icon.height: 20
icon.name: "close-circle"
onClicked: linksModel.remove(index)
}
Image {
id: unfurlingImage
source: Style.png("unfurling-image")
width: 132
height: 94
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
}
StatusBaseText {
id: enableText
text: isImage ? qsTr("Enable automatic image unfurling") :
qsTr("Enable link previews in chat?")
horizontalAlignment: Text.AlignHCenter
width: parent.width
wrapMode: Text.WordWrap
anchors.top: unfurlingImage.bottom
anchors.topMargin: Style.current.halfPadding
color: Theme.palette.directColor1
}
StatusBaseText {
id: infoText
text: qsTr("Once enabled, links posted in the chat may share your metadata with their owners")
horizontalAlignment: Text.AlignHCenter
width: parent.width
wrapMode: Text.WordWrap
anchors.top: enableText.bottom
font.pixelSize: 13
color: Theme.palette.baseColor1
}
Separator {
id: sep1
anchors.top: infoText.bottom
anchors.topMargin: Style.current.smallPadding
}
StatusFlatButton {
id: enableBtn
objectName: "LinksMessageView_enableBtn"
text: qsTr("Enable in Settings")
onClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.messaging);
}
width: parent.width
anchors.top: sep1.bottom
Component.onCompleted: {
background.radius = 0;
}
}
Separator {
id: sep2
anchors.top: enableBtn.bottom
anchors.topMargin: 0
}
Item {
width: parent.width
height: 44
anchors.top: sep2.bottom
clip: true
StatusFlatButton {
id: dontAskBtn
width: parent.width
height: (parent.height+Style.current.padding)
anchors.top: parent.top
anchors.topMargin: -Style.current.padding
contentItem: Item {
StatusBaseText {
anchors.centerIn: parent
anchors.verticalCenterOffset: Style.current.halfPadding
font: dontAskBtn.font
color: dontAskBtn.enabled ? dontAskBtn.textColor : dontAskBtn.disabledTextColor
text: qsTr("Don't ask me again")
}
}
onClicked: RootStore.setNeverAskAboutUnfurlingAgain(true)
Component.onCompleted: {
background.radius = Style.current.padding;
}
}
}
}
}
} }

View File

@ -64,6 +64,19 @@ Loader {
property string messageAttachments: "" property string messageAttachments: ""
property var transactionParams property var transactionParams
// These 2 properties can be dropped when the new unfurling flow supports GIFs
property var links
readonly property var localUnfurlLinks: {
if (!links)
return []
const separator = " "
const arr = links.split(separator)
const filtered = arr.filter(v => v.toLowerCase().endsWith('.gif'))
const out = filtered.join(separator)
console.log(`<<<${arr}->${out}`)
return out
}
property string responseToMessageWithId: "" property string responseToMessageWithId: ""
property string quotedMessageText: "" property string quotedMessageText: ""
property string quotedMessageFrom: "" property string quotedMessageFrom: ""
@ -518,6 +531,7 @@ Loader {
resendError: root.resendError resendError: root.resendError
reactionsModel: root.reactionsModel reactionsModel: root.reactionsModel
linkPreviewModel: root.linkPreviewModel linkPreviewModel: root.linkPreviewModel
localUnfurlLinks: root.localUnfurlLinks
showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply || showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply ||
root.prevMessageContentType === Constants.messageContentType.systemMessagePrivateGroupType || root.prevMessageContentType === Constants.messageContentType.systemMessagePrivateGroupType ||
@ -744,6 +758,7 @@ Loader {
LinksMessageView { LinksMessageView {
id: linksMessageView id: linksMessageView
linkPreviewModel: root.linkPreviewModel linkPreviewModel: root.linkPreviewModel
localUnfurlLinks: root.localUnfurlLinks
messageStore: root.messageStore messageStore: root.messageStore
store: root.rootStore store: root.rootStore
isCurrentUser: root.amISender isCurrentUser: root.amISender