feat(@wallet): Show lightbox when clicking collectible (#14168)

This commit is contained in:
Cuteivist 2024-05-15 11:36:56 +02:00 committed by GitHub
parent 2565c8a135
commit d70f2dcf23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 341 additions and 68 deletions

View File

@ -0,0 +1,66 @@
import QtQuick 2.13
import QtQuick.Controls 2.12
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype LoadingErrorComponent
\inherits Control
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief A component that can be used to adding a load error state to a widget
Example:
\qml
AnimatedImage {
id: root
LoadingErrorComponent {
visible: root.status === AnimatedImage.Error
anchors.fill: parent
radius: 8
}
}
\endqml
For a list of components available see StatusQ.
*/
Control {
id: root
/*!
\qmlproperty bool LoadingComponent::radius
This property lets user set custom radius
*/
property int radius: 4
/*!
\qmlproperty string LoadingComponent::text
This property lets user set error message
*/
property string text: qsTr("Failed\nto load")
background: Rectangle {
color: Theme.palette.baseColor5
radius: root.radius
}
contentItem: Item {
Column {
anchors.centerIn: parent
spacing: 10
StatusIcon {
anchors.horizontalCenter: parent.horizontalCenter
icon: "frowny"
opacity: 0.1
color: Theme.palette.directColor1
}
StatusBaseText {
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Qt.AlignHCenter
color: Theme.palette.directColor6
text: root.text
}
}
}
}

View File

@ -85,6 +85,20 @@ StatusRoundedComponent {
*/ */
property int manualMaxDimension: 0 property int manualMaxDimension: 0
/*!
\qmlproperty bool StatusRoundedMedia::interactive
Enable mouse interaction with the media.
*/
property bool interactive: false
/*!
\qmlproperty bool StatusRoundedMedia::isEmpty
Media source is empty.
*/
property bool isEmpty: false
readonly property int componentMediaType: { readonly property int componentMediaType: {
if (root.mediaType.startsWith("image")) { if (root.mediaType.startsWith("image")) {
return StatusRoundedMedia.MediaType.Image return StatusRoundedMedia.MediaType.Image
@ -94,6 +108,11 @@ StatusRoundedComponent {
return StatusRoundedMedia.MediaType.Unknown return StatusRoundedMedia.MediaType.Unknown
} }
signal imageClicked(var image, bool plain)
signal videoClicked(var mediaUrl)
signal openImageContextMenu(var url, bool isGif)
signal openVideoContextMenu(var url)
isLoading: { isLoading: {
if (mediaLoader.status === Loader.Ready) { if (mediaLoader.status === Loader.Ready) {
return mediaLoader.item.isLoading return mediaLoader.item.isLoading
@ -115,14 +134,23 @@ StatusRoundedComponent {
} }
} }
Binding on isEmpty {
when: mediaLoader.status === Loader.Ready
value: !!mediaLoader.item && mediaLoader.item.source.toString() === ""
delayed: true
restoreMode: Binding.RestoreBindingOrValue
}
QtObject { QtObject {
id: d id: d
property bool isFallback: false property bool isFallback: false
property int errorCounter: 0 property int errorCounter: 0
property bool plainImage: false
function reset() { function reset() {
isFallback = false isFallback = false
errorCounter = 0 errorCounter = 0
plainImage = false
} }
} }
@ -141,6 +169,33 @@ StatusRoundedComponent {
else return root.manualMaxDimension else return root.manualMaxDimension
} }
MouseArea {
anchors.fill: parent
enabled: root.enabled && root.interactive && mediaLoader.visible && mediaLoader.item
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (root.isError || root.isEmpty) {
return
}
if (mouse.button == Qt.RightButton) {
if (d.isFallback || componentMediaType === StatusRoundedMedia.MediaType.Image) {
root.openImageContextMenu(mediaLoader.item.source, !!mediaLoader.item.playing)
} else if (componentMediaType === StatusRoundedMedia.MediaType.Video) {
root.openVideoContextMenu(mediaUrl)
}
return
}
if (!d.isFallback && componentMediaType === StatusRoundedMedia.MediaType.Video) {
root.videoClicked(root.mediaUrl)
} else {
root.imageClicked(mediaLoader.item, d.plainImage)
}
}
}
Component.onCompleted: updateMediaLoader() Component.onCompleted: updateMediaLoader()
onMediaUrlChanged: updateMediaLoader() onMediaUrlChanged: updateMediaLoader()
onComponentMediaTypeChanged: updateMediaLoader() onComponentMediaTypeChanged: updateMediaLoader()
@ -182,6 +237,7 @@ StatusRoundedComponent {
if (!d.isFallback) { if (!d.isFallback) {
// AnimatedImage sometimes cannot load stuff that plan Image can, try that first // AnimatedImage sometimes cannot load stuff that plan Image can, try that first
if (componentMediaType === StatusRoundedMedia.MediaType.Image && d.errorCounter <= 1) { if (componentMediaType === StatusRoundedMedia.MediaType.Image && d.errorCounter <= 1) {
d.plainImage = true
mediaLoader.setSource("StatusImage.qml", mediaLoader.setSource("StatusImage.qml",
{ {
"source": root.mediaUrl, "source": root.mediaUrl,
@ -197,6 +253,7 @@ StatusRoundedComponent {
} }
function setFallbackImage() { function setFallbackImage() {
d.plainImage = true
d.isFallback = true d.isFallback = true
mediaLoader.setSource("StatusImage.qml", mediaLoader.setSource("StatusImage.qml",
{ {
@ -206,6 +263,7 @@ StatusRoundedComponent {
} }
function setEmptyComponent() { function setEmptyComponent() {
d.plainImage = true
mediaLoader.setSource("StatusImage.qml", mediaLoader.setSource("StatusImage.qml",
{ {
"source": "", "source": "",

View File

@ -31,6 +31,7 @@ Item {
readonly property bool isLoading: player.playbackState !== MediaPlayer.PlayingState readonly property bool isLoading: player.playbackState !== MediaPlayer.PlayingState
readonly property bool isError: player.status === MediaPlayer.InvalidMedia readonly property bool isError: player.status === MediaPlayer.InvalidMedia
property alias source: player.source
property alias player: player property alias player: player
property alias output: output property alias output: output
property alias fillMode: output.fillMode property alias fillMode: output.fillMode

View File

@ -1,6 +1,7 @@
module StatusQ.Components module StatusQ.Components
LoadingComponent 0.1 LoadingComponent.qml LoadingComponent 0.1 LoadingComponent.qml
LoadingErrorComponent 0.1 LoadingErrorComponent.qml
StatusAddress 0.1 StatusAddress.qml StatusAddress 0.1 StatusAddress.qml
StatusAddressPanel 0.1 StatusAddressPanel.qml StatusAddressPanel 0.1 StatusAddressPanel.qml
StatusAnimatedImage 0.1 StatusAnimatedImage.qml StatusAnimatedImage 0.1 StatusAnimatedImage.qml

View File

@ -1,6 +1,7 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>StatusQ/Components/LoadingComponent.qml</file> <file>StatusQ/Components/LoadingComponent.qml</file>
<file>StatusQ/Components/LoadingErrorComponent.qml</file>
<file>StatusQ/Components/StatusAddress.qml</file> <file>StatusQ/Components/StatusAddress.qml</file>
<file>StatusQ/Components/StatusAddressPanel.qml</file> <file>StatusQ/Components/StatusAddressPanel.qml</file>
<file>StatusQ/Components/StatusAnimatedImage.qml</file> <file>StatusQ/Components/StatusAnimatedImage.qml</file>

View File

@ -14,6 +14,7 @@ import AppLayouts.Communities.panels 1.0
import utils 1.0 import utils 1.0
import shared.controls 1.0 import shared.controls 1.0
import shared.views 1.0 import shared.views 1.0
import shared.popups 1.0
import "../../stores" import "../../stores"
import "../../controls" import "../../controls"
@ -149,11 +150,11 @@ Item {
property int modelIndex: index property int modelIndex: index
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
sourceComponent: isCollectibleLoading ? sourceComponent: root.isCollectibleLoading ?
collectibleimage: collectibleimageComponent:
root.isCommunityCollectible && (root.isOwnerTokenType || root.isTMasterTokenType) ? root.isCommunityCollectible && (root.isOwnerTokenType || root.isTMasterTokenType) ?
privilegedCollectibleImage: privilegedCollectibleImageComponent:
collectibleimage collectibleimageComponent
active: root.visible active: root.visible
} }
Loader { Loader {
@ -345,7 +346,7 @@ Item {
} }
} }
Component { Component {
id: privilegedCollectibleImage id: privilegedCollectibleImageComponent
// Special artwork representation for community `Owner and Master Token` token types: // Special artwork representation for community `Owner and Master Token` token types:
PrivilegedTokenArtworkPanel { PrivilegedTokenArtworkPanel {
size: PrivilegedTokenArtworkPanel.Size.Large size: PrivilegedTokenArtworkPanel.Size.Large
@ -356,43 +357,52 @@ Item {
} }
Component { Component {
id: collectibleimage id: collectibleimageComponent
StatusRoundedMedia { StatusRoundedMedia {
id: collectibleImage id: collectibleImage
readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString() readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString()
radius: Style.current.radius radius: Style.current.radius
color: isError || isEmpty ? Theme.palette.baseColor5 : collectible.backgroundColor color: isError || isEmpty ? Theme.palette.baseColor5 : collectible.backgroundColor
mediaUrl: collectible.mediaUrl ?? "" mediaUrl: collectible.mediaUrl ?? ""
mediaType: !!collectible ? (modelIndex > 0 && collectible.mediaType.startsWith("video")) ? "" : collectible.mediaType: "" mediaType: !!collectible ? (modelIndex > 0 && collectible.mediaType.startsWith("video")) ? "" : collectible.mediaType: ""
fallbackImageUrl: collectible.imageUrl fallbackImageUrl: collectible.imageUrl
manualMaxDimension: 240 manualMaxDimension: 240
interactive: !isError && !isEmpty
enabled: interactive
onImageClicked: (image, plain) => Global.openImagePopup(image, "", plain)
onVideoClicked: (url) => Global.openVideoPopup(url)
onOpenImageContextMenu: (url, isGif) => Global.openMenu(imageContextMenu, collectibleImage, { imageSource: url, isGif: isGif, isVideo: false })
onOpenVideoContextMenu: (url) => Global.openMenu(imageContextMenu, collectibleImage, { imageSource: url, url: url, isVideo: true, isGif: false })
Column { Loader {
anchors.centerIn: parent anchors.fill: parent
visible: collectibleImage.isError || collectibleImage.isEmpty active: collectibleImage.isLoading
spacing: 10 sourceComponent: LoadingComponent {radius: collectibleImage.radius}
}
StatusIcon { Loader {
anchors.horizontalCenter: parent.horizontalCenter anchors.fill: parent
icon: "frowny" active: collectibleImage.isError || collectibleImage.isEmpty
opacity: 0.1 sourceComponent: LoadingErrorComponent {
color: Theme.palette.directColor1 radius: collectibleImage.radius
} text: {
StatusBaseText { if (collectibleImage.isError && collectibleImage.componentMediaType === StatusRoundedMedia.MediaType.Unkown) {
anchors.horizontalCenter: parent.horizontalCenter return qsTr("Unsupported\nfile format")
horizontalAlignment: Qt.AlignHCenter
color: Theme.palette.directColor6
text: {
if (collectibleImage.isError && collectibleImage.componentMediaType === StatusRoundedMedia.MediaType.Unkown) {
return qsTr("Unsupported\nfile format")
}
if (!collectible.description && !collectible.name) {
return qsTr("Info can't\nbe fetched")
}
return qsTr("Failed\nto load")
} }
if (!collectible.description && !collectible.name) {
return qsTr("Info can't\nbe fetched")
}
return qsTr("Failed\nto load")
} }
} }
} }
Component {
id: imageContextMenu
ImageContextMenu {
onClosed: destroy()
}
}
}
} }
} }

View File

@ -118,7 +118,7 @@ Control {
visible: root.isCommunityCollectible && root.isPrivilegedToken visible: root.isCommunityCollectible && root.isPrivilegedToken
size: PrivilegedTokenArtworkPanel.Size.Medium size: PrivilegedTokenArtworkPanel.Size.Medium
artwork: root.fallbackImageUrl artwork: visible ? root.fallbackImageUrl : ""
color: root.ornamentColor color: root.ornamentColor
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
isOwner: root.privilegesLevel === Constants.TokenPrivilegesLevel.Owner isOwner: root.privilegesLevel === Constants.TokenPrivilegesLevel.Owner

View File

@ -58,6 +58,7 @@ QtObject {
Global.openChooseBrowserPopup.connect(openChooseBrowserPopup) Global.openChooseBrowserPopup.connect(openChooseBrowserPopup)
Global.openDownloadModalRequested.connect(openDownloadModal) Global.openDownloadModalRequested.connect(openDownloadModal)
Global.openImagePopup.connect(openImagePopup) Global.openImagePopup.connect(openImagePopup)
Global.openVideoPopup.connect(openVideoPopup)
Global.openProfilePopupRequested.connect(openProfilePopup) Global.openProfilePopupRequested.connect(openProfilePopup)
Global.openNicknamePopupRequested.connect(openNicknamePopup) Global.openNicknamePopupRequested.connect(openNicknamePopup)
Global.markAsUntrustedRequested.connect(openMarkAsUntrustedPopup) Global.markAsUntrustedRequested.connect(openMarkAsUntrustedPopup)
@ -130,8 +131,12 @@ QtObject {
openPopup(downloadPageComponent, popupProperties) openPopup(downloadPageComponent, popupProperties)
} }
function openImagePopup(image, url) { function openImagePopup(image, url, plain) {
openPopup(imagePopupComponent, {image: image, url: url}) openPopup(imagePopupComponent, {image: image, url: url, plain: plain})
}
function openVideoPopup(url) {
openPopup(videoPopupComponent, { url: url })
} }
function openProfilePopup(publicKey: string, parentPopup, cb) { function openProfilePopup(publicKey: string, parentPopup, cb) {
@ -537,6 +542,14 @@ QtObject {
} }
}, },
Component {
id: videoPopupComponent
StatusVideoModal {
id: videoPopup
onClosed: destroy()
}
},
Component { Component {
id: profilePopupComponent id: profilePopupComponent
ProfileDialog { ProfileDialog {

View File

@ -9,24 +9,25 @@ StatusMenu {
property string imageSource property string imageSource
property string domain property string domain
property bool requireConfirmationOnOpen: false property bool requireConfirmationOnOpen: false
property bool isGif: root.imageSource.toLowerCase().endsWith(".gif")
property bool isVideo: root.imageSource.toLowerCase().endsWith(".mp4")
QtObject { QtObject {
id: d id: d
readonly property bool isUnfurled: (!!url&&url!=="") readonly property bool isUnfurled: (!!url&&url!=="")
readonly property bool isGif: root.imageSource.toLowerCase().endsWith(".gif")
} }
StatusAction { StatusAction {
text: d.isGif ? qsTr("Copy GIF") : qsTr("Copy image") text: root.isGif ? qsTr("Copy GIF") : qsTr("Copy image")
icon.name: "copy" icon.name: "copy"
enabled: !!root.imageSource enabled: !!root.imageSource && !root.isVideo
onTriggered: { onTriggered: {
Utils.copyImageToClipboardByUrl(root.imageSource) Utils.copyImageToClipboardByUrl(root.imageSource)
} }
} }
StatusAction { StatusAction {
text: d.isGif ? qsTr("Download GIF") : qsTr("Download image") text: root.isGif ? qsTr("Download GIF") : root.isVideo ? qsTr("Download video") : qsTr("Download image")
icon.name: "download" icon.name: "download"
enabled: !!root.imageSource enabled: !!root.imageSource
onTriggered: { onTriggered: {

View File

@ -32,3 +32,4 @@ SettingsDirtyToastMessage 1.0 SettingsDirtyToastMessage.qml
UnblockContactConfirmationDialog 1.0 UnblockContactConfirmationDialog.qml UnblockContactConfirmationDialog 1.0 UnblockContactConfirmationDialog.qml
UserAgreementPopup 1.0 UserAgreementPopup.qml UserAgreementPopup 1.0 UserAgreementPopup.qml
UserStatusContextMenu 1.0 UserStatusContextMenu.qml UserStatusContextMenu 1.0 UserStatusContextMenu.qml
ImageContextMenu 1.0 ImageContextMenu.qml

View File

@ -1195,7 +1195,7 @@ Rectangle {
} }
control.fileUrlsAndSources = urls control.fileUrlsAndSources = urls
} }
onImageClicked: (chatImage) => Global.openImagePopup(chatImage, "") onImageClicked: (chatImage) => Global.openImagePopup(chatImage, "", false)
onLinkReload: (link) => control.linkPreviewReloaded(link) onLinkReload: (link) => control.linkPreviewReloaded(link)
onLinkClicked: (link) => Global.openLink(link) onLinkClicked: (link) => Global.openLink(link)
onEnableLinkPreview: () => control.enableLinkPreview() onEnableLinkPreview: () => control.enableLinkPreview()

View File

@ -4,10 +4,12 @@ import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13 import QtQuick.Layouts 1.13
import QtGraphicalEffects 1.13 import QtGraphicalEffects 1.13
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0 import utils 1.0
import shared 1.0 import shared 1.0
import shared.views.chat 1.0 import shared.popups 1.0
StatusDialog { StatusDialog {
id: root id: root
@ -15,11 +17,10 @@ StatusDialog {
property var store property var store
property var image property var image
property string url: "" property string url: ""
property bool plain: false
width: (root.image.sourceSize.width > d.maxWidth) ? width: Math.min(root.image.sourceSize.width, d.maxWidth)
d.maxWidth : root.image.sourceSize.width height: Math.min(root.image.sourceSize.height, d.maxHeight)
height: (root.image.sourceSize.height > d.maxHeight) ?
d.maxHeight : root.image.sourceSize.height
padding: 0 padding: 0
background: null background: null
@ -31,39 +32,81 @@ StatusDialog {
property int maxHeight: Global.applicationWindow.height - 80 property int maxHeight: Global.applicationWindow.height - 80
property int maxWidth: Global.applicationWindow.width - 80 property int maxWidth: Global.applicationWindow.width - 80
readonly property int radius: Style.current.radius
} }
onOpened: { onOpened: imageLoader.source = root.image.source;
messageImage.source = root.image.source; onClosed: imageLoader.source = ""
}
contentItem: Loader {
id: imageLoader
readonly property bool isError: status === Loader.Error || (imageLoader.item && imageLoader.item.status === Image.Error)
readonly property bool isLoading: status === Loader.Loading || (imageLoader.item && imageLoader.item.status === Image.Loading)
property string source
contentItem: AnimatedImage {
id: messageImage
anchors.fill: parent anchors.fill: parent
asynchronous: true active: true
fillMode: Image.PreserveAspectFit sourceComponent: root.plain ? plainImage : animatedImage
mipmap: true
smooth: false
onStatusChanged: playing = (status == AnimatedImage.Ready)
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: { onClicked: {
if (mouse.button === Qt.LeftButton) if (mouse.button === Qt.LeftButton)
root.close() root.close()
if (mouse.button === Qt.RightButton) if (imageLoader.isError || imageLoader.isLoading || mouse.button !== Qt.RightButton)
Global.openMenu(imageContextMenu, return
messageImage, const isGif = (!root.plain && imageLoader.item && imageLoader.item.playing)
{ imageSource: messageImage.source, url: root.url}) Global.openMenu(imageContextMenu,
imageLoader.item,
{ imageSource: imageLoader.source, url: root.url, isGif: isGif})
} }
} }
Loader {
anchors.centerIn: parent
width: Math.min(root.width, 300)
height: Math.min(root.height, 300)
active: imageLoader.isError
sourceComponent: LoadingErrorComponent { radius: d.radius }
}
Loader {
anchors.fill: parent
active: imageLoader.isLoading
sourceComponent: LoadingComponent {radius: d.radius}
}
}
Component {
id: animatedImage
AnimatedImage {
asynchronous: true
fillMode: Image.PreserveAspectFit
mipmap: true
smooth: false
onStatusChanged: playing = (status == AnimatedImage.Ready)
source: imageLoader.source
}
}
Component {
id: plainImage
Image {
asynchronous: true
fillMode: Image.PreserveAspectFit
mipmap: true
smooth: false
source: imageLoader.source
}
} }
Component { Component {
id: imageContextMenu id: imageContextMenu
ImageContextMenu { ImageContextMenu {
isVideo: false
onClosed: { onClosed: {
destroy() destroy()
} }

View File

@ -0,0 +1,77 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtMultimedia 5.15
import StatusQ.Popups.Dialog 0.1
import StatusQ.Components 0.1
import utils 1.0
import shared.popups 1.0
StatusDialog {
id: root
property string url: ""
width: Math.min(d.maxWidth, videoItem.output.sourceRect.width)
height: Math.min(d.maxHeight, videoItem.output.sourceRect.height)
padding: 0
background: null
standardButtons: Dialog.NoButton
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
QtObject {
id: d
readonly property int maxHeight: Global.applicationWindow.height - 80
readonly property int maxWidth: Global.applicationWindow.width - 80
}
onOpened: {
videoItem.source = root.url
}
contentItem: StatusVideo {
id: videoItem
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton)
root.close()
if (mouse.button === Qt.RightButton)
Global.openMenu(imageContextMenu, videoItem)
}
}
Loader {
anchors.centerIn: parent
width: Math.min(root.width, 300)
height: Math.min(root.height, 300)
active: videoItem.isError
sourceComponent: LoadingErrorComponent { }
}
Loader {
anchors.fill: parent
active: videoItem.isLoading
sourceComponent: LoadingComponent { }
}
}
Component {
id: imageContextMenu
ImageContextMenu {
isGif: false
isVideo: true
url: root.url
imageSource: root.url
onClosed: {
destroy()
}
}
}
}

View File

@ -15,6 +15,7 @@ StatusEmojiSuggestionPopup 1.0 StatusEmojiSuggestionPopup.qml
StatusExpandableAddress 1.0 StatusExpandableAddress.qml StatusExpandableAddress 1.0 StatusExpandableAddress.qml
StatusGifPopup 1.0 StatusGifPopup.qml StatusGifPopup 1.0 StatusGifPopup.qml
StatusImageModal 1.0 StatusImageModal.qml StatusImageModal 1.0 StatusImageModal.qml
StatusVideoModal 1.0 StatusVideoModal.qml
StatusImageRadioButton 1.0 StatusImageRadioButton.qml StatusImageRadioButton 1.0 StatusImageRadioButton.qml
StatusInputListPopup 1.0 StatusInputListPopup.qml StatusInputListPopup 1.0 StatusInputListPopup.qml
StatusNotification 1.0 StatusNotification.qml StatusNotification 1.0 StatusNotification.qml

View File

@ -340,7 +340,7 @@ Loader {
function onImageClicked(image, mouse, imageSource, url = "") { function onImageClicked(image, mouse, imageSource, url = "") {
switch (mouse.button) { switch (mouse.button) {
case Qt.LeftButton: case Qt.LeftButton:
Global.openImagePopup(image, url) Global.openImagePopup(image, url, false)
break; break;
case Qt.RightButton: case Qt.RightButton:
Global.openMenu(imageContextMenuComponent, image, { imageSource, url }) Global.openMenu(imageContextMenuComponent, image, { imageSource, url })

View File

@ -11,6 +11,5 @@ ProfileHeaderContextMenuView 1.0 ProfileHeaderContextMenuView.qml
TransactionBubbleView 1.0 TransactionBubbleView.qml TransactionBubbleView 1.0 TransactionBubbleView.qml
NewMessagesMarker 1.0 NewMessagesMarker.qml NewMessagesMarker 1.0 NewMessagesMarker.qml
SimplifiedMessageView 1.0 SimplifiedMessageView.qml SimplifiedMessageView 1.0 SimplifiedMessageView.qml
ImageContextMenu 1.0 ImageContextMenu.qml
ProfileContextMenu 1.0 ProfileContextMenu.qml ProfileContextMenu 1.0 ProfileContextMenu.qml
MessageAddReactionContextMenu 1.0 MessageAddReactionContextMenu.qml MessageAddReactionContextMenu 1.0 MessageAddReactionContextMenu.qml

View File

@ -9,7 +9,7 @@ import StatusQ.Popups.Dialog 0.1
import utils 1.0 import utils 1.0
import shared.controls 1.0 import shared.controls 1.0
import shared.views.chat 1.0 import shared.popups 1.0
import shared.controls.chat 1.0 import shared.controls.chat 1.0
StatusDialog { StatusDialog {

View File

@ -38,7 +38,8 @@ QtObject {
signal openDownloadModalRequested(bool available, string version, string url) signal openDownloadModalRequested(bool available, string version, string url)
signal openChangeProfilePicPopup(var cb) signal openChangeProfilePicPopup(var cb)
signal openBackUpSeedPopup() signal openBackUpSeedPopup()
signal openImagePopup(var image, string url) signal openImagePopup(var image, string url, bool plain)
signal openVideoPopup(string url)
signal openProfilePopupRequested(string publicKey, var parentPopup, var cb) signal openProfilePopupRequested(string publicKey, var parentPopup, var cb)
signal openActivityCenterPopupRequested() signal openActivityCenterPopupRequested()
signal openSendIDRequestPopup(string publicKey, var contactDetails, var cb) signal openSendIDRequestPopup(string publicKey, var contactDetails, var cb)