feat(@wallet): Show lightbox when clicking collectible (#14168)
This commit is contained in:
parent
2565c8a135
commit
d70f2dcf23
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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": "",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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: {
|
|
@ -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
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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 })
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue