2023-09-13 09:12:47 +00:00
|
|
|
import QtQuick 2.15
|
|
|
|
import QtQuick.Layouts 1.15
|
2023-10-09 12:41:27 +00:00
|
|
|
import QtQuick.Window 2.15
|
2023-09-13 09:12:47 +00:00
|
|
|
|
|
|
|
import StatusQ.Core 0.1
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
import StatusQ.Components 0.1
|
|
|
|
|
2023-10-25 15:20:02 +00:00
|
|
|
import shared.controls 1.0
|
2023-09-13 09:12:47 +00:00
|
|
|
import shared.status 1.0
|
2023-10-09 12:41:27 +00:00
|
|
|
import utils 1.0
|
2023-09-13 09:12:47 +00:00
|
|
|
|
2023-10-25 15:20:02 +00:00
|
|
|
import "./private"
|
|
|
|
|
2023-09-13 09:12:47 +00:00
|
|
|
CalloutCard {
|
|
|
|
id: root
|
2023-10-25 15:20:02 +00:00
|
|
|
|
|
|
|
readonly property LinkData linkData: LinkData { }
|
|
|
|
readonly property UserData userData: UserData { }
|
|
|
|
readonly property CommunityData communityData: CommunityData { }
|
|
|
|
readonly property ChannelData channelData: ChannelData { }
|
|
|
|
|
|
|
|
property int type: Constants.LinkPreviewType.NoPreview
|
2023-10-09 12:41:27 +00:00
|
|
|
|
|
|
|
property bool highlight: false
|
2023-09-13 09:12:47 +00:00
|
|
|
|
2023-10-09 14:53:59 +00:00
|
|
|
signal clicked(var mouse)
|
2023-09-13 09:12:47 +00:00
|
|
|
|
|
|
|
borderWidth: 1
|
|
|
|
implicitHeight: 290
|
|
|
|
implicitWidth: 305
|
2023-10-09 12:41:27 +00:00
|
|
|
hoverEnabled: true
|
2023-10-16 07:27:55 +00:00
|
|
|
dropShadow: d.highlight
|
|
|
|
borderColor: d.highlight ? Style.current.background : Style.current.border
|
2023-10-09 12:41:27 +00:00
|
|
|
|
|
|
|
Behavior on borderColor {
|
|
|
|
ColorAnimation { duration: 200 }
|
|
|
|
}
|
2023-09-13 09:12:47 +00:00
|
|
|
|
|
|
|
contentItem: ColumnLayout {
|
2023-10-25 15:20:02 +00:00
|
|
|
Loader {
|
|
|
|
id: bannerImageLoader
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.fillWidth: true
|
2023-10-09 12:41:27 +00:00
|
|
|
Layout.leftMargin: d.bannerImageMargins
|
|
|
|
Layout.rightMargin: d.bannerImageMargins
|
|
|
|
Layout.topMargin: d.bannerImageMargins
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.preferredHeight: 170
|
2023-10-25 15:20:02 +00:00
|
|
|
active: !!d.bannerImageSource
|
|
|
|
sourceComponent: StatusImage {
|
|
|
|
id: bannerImage
|
|
|
|
asynchronous: true
|
|
|
|
source: d.bannerImageSource
|
|
|
|
fillMode: Image.PreserveAspectCrop
|
|
|
|
layer.enabled: true
|
|
|
|
layer.effect: root.clippingEffect
|
|
|
|
}
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2023-09-15 11:37:29 +00:00
|
|
|
Layout.margins: 12
|
2023-10-25 15:20:02 +00:00
|
|
|
Loader {
|
|
|
|
id: userImageLoader
|
|
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
|
|
|
Layout.topMargin: 8
|
|
|
|
Layout.bottomMargin: 8
|
|
|
|
visible: active
|
|
|
|
active: root.type === Constants.LinkPreviewType.StatusContact
|
|
|
|
sourceComponent: UserImage {
|
|
|
|
interactive: false
|
|
|
|
imageWidth: 58
|
|
|
|
imageHeight: imageWidth
|
|
|
|
ensVerified: root.userData.ensVerified
|
|
|
|
name: root.userData.name
|
|
|
|
pubkey: root.userData.publicKey
|
|
|
|
image: root.userData.image
|
|
|
|
}
|
|
|
|
}
|
2023-09-13 09:12:47 +00:00
|
|
|
RowLayout {
|
2023-10-25 15:20:02 +00:00
|
|
|
id: titleLayout
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2023-10-25 15:20:02 +00:00
|
|
|
Layout.maximumHeight: description.text.length ? 28 : 72
|
|
|
|
Layout.minimumHeight: 18
|
2023-09-13 09:12:47 +00:00
|
|
|
StatusSmartIdenticon {
|
2023-10-25 15:20:02 +00:00
|
|
|
id: logo
|
|
|
|
Layout.alignment: Qt.AlignTop
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.preferredWidth: 28
|
|
|
|
Layout.preferredHeight: 28
|
2023-10-25 15:20:02 +00:00
|
|
|
asset.width: width
|
|
|
|
asset.height: height
|
|
|
|
visible: false
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|
|
|
|
StatusBaseText {
|
2023-10-25 15:20:02 +00:00
|
|
|
id: title
|
|
|
|
// One line centered next to the logo
|
|
|
|
// Two or more lines, or no logo, top aligned
|
|
|
|
readonly property bool centerText: lineCount == 1 && height === logo.height && logo.visible
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2023-10-25 15:20:02 +00:00
|
|
|
Layout.alignment: Qt.AlignTop
|
|
|
|
Layout.topMargin: verticalAlignment === Text.AlignTop && contentHeight < logo.height ? (logo.height - contentHeight) / 2 : 0
|
2023-09-13 09:12:47 +00:00
|
|
|
font.pixelSize: 13
|
|
|
|
font.weight: Font.Medium
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
elide: Text.ElideRight
|
2023-10-25 15:20:02 +00:00
|
|
|
verticalAlignment: centerText ? Text.AlignVCenter : Text.AlignTop
|
|
|
|
visible: text.length
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-25 15:20:02 +00:00
|
|
|
EmojiHash {
|
|
|
|
Layout.topMargin: 4
|
|
|
|
Layout.bottomMargin: 6
|
|
|
|
visible: root.type === Constants.LinkPreviewType.StatusContact
|
|
|
|
publicKey: root.userData.publicKey
|
|
|
|
oneRow: true
|
|
|
|
}
|
2023-09-13 09:12:47 +00:00
|
|
|
StatusBaseText {
|
2023-10-25 15:20:02 +00:00
|
|
|
id: description
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
font.pixelSize: 12
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
elide: Text.ElideRight
|
|
|
|
color: Theme.palette.baseColor1
|
2023-10-25 15:20:02 +00:00
|
|
|
visible: description.text.length
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|
2023-10-25 15:20:02 +00:00
|
|
|
Loader {
|
|
|
|
id: footerLoader
|
2023-09-13 09:12:47 +00:00
|
|
|
Layout.fillWidth: true
|
2023-10-25 15:20:02 +00:00
|
|
|
visible: active
|
|
|
|
sourceComponent: FooterText {
|
|
|
|
}
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-25 15:20:02 +00:00
|
|
|
|
2023-09-13 09:12:47 +00:00
|
|
|
MouseArea {
|
|
|
|
anchors.fill: root
|
|
|
|
hoverEnabled: true
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
2023-10-09 14:53:59 +00:00
|
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
onClicked: root.clicked(mouse)
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|
2023-10-09 12:41:27 +00:00
|
|
|
|
2023-10-25 15:20:02 +00:00
|
|
|
component FooterText: StatusBaseText {
|
|
|
|
font.pixelSize: 12
|
|
|
|
lineHeight: 16
|
|
|
|
lineHeightMode: Text.FixedHeight
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
elide: Text.ElideRight
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
verticalAlignment: Text.AlignBottom
|
|
|
|
text: root.linkData.domain
|
|
|
|
maximumLineCount: 1
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: channelFooterComponent
|
|
|
|
RowLayout {
|
|
|
|
spacing: 4
|
|
|
|
FooterText {
|
|
|
|
Layout.fillHeight: true
|
|
|
|
text: qsTr("Channel in")
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
}
|
|
|
|
StatusRoundedImage {
|
|
|
|
Layout.preferredHeight: 16
|
|
|
|
Layout.preferredWidth: height
|
|
|
|
image.source: channelData.communityData.image
|
|
|
|
}
|
|
|
|
FooterText {
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
text: channelData.communityData.name
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
color: Theme.palette.directColor1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: communityFooterComponent
|
|
|
|
RowLayout {
|
|
|
|
spacing: 2
|
|
|
|
StatusIcon {
|
|
|
|
icon: "group"
|
|
|
|
color: Theme.palette.directColor1
|
|
|
|
width: 16
|
|
|
|
height: width
|
|
|
|
}
|
|
|
|
FooterText {
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: communityData.activeMembersCount === -1 //TODO: remove magic number once we have activeMembersCount
|
|
|
|
color: Theme.palette.directColor1
|
|
|
|
text: LocaleUtils.numberToLocaleStringInCompactForm(communityData.membersCount)
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
}
|
|
|
|
StatusIcon {
|
|
|
|
Layout.leftMargin: 6
|
|
|
|
icon: "active-members"
|
|
|
|
color: Theme.palette.directColor1
|
|
|
|
width: 16
|
|
|
|
height: width
|
|
|
|
visible: communityData.activeMembersCount > -1
|
|
|
|
}
|
|
|
|
FooterText {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
color: Theme.palette.directColor1
|
|
|
|
text: LocaleUtils.numberToLocaleStringInCompactForm(communityData.activeMembersCount)
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
visible: communityData.activeMembersCount > -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//behavior
|
|
|
|
states: [
|
|
|
|
State {
|
|
|
|
name: "noPreview"
|
|
|
|
when: root.type === Constants.LinkPreviewType.NoPreview
|
|
|
|
PropertyChanges { target: root; visible: false }
|
|
|
|
},
|
|
|
|
State {
|
|
|
|
name: "linkPreview"
|
|
|
|
when: root.type === Constants.LinkPreviewType.Standard
|
|
|
|
PropertyChanges {
|
|
|
|
target: logo
|
|
|
|
visible: !!root.linkData.image
|
|
|
|
name: root.linkData.domain
|
|
|
|
asset.name: root.linkData.image
|
|
|
|
asset.isImage: !!root.linkData.image
|
|
|
|
asset.color: Theme.palette.baseColor2
|
|
|
|
}
|
|
|
|
PropertyChanges { target: bannerImageLoader; visible: true }
|
|
|
|
PropertyChanges { target: title; text: root.linkData.title }
|
|
|
|
PropertyChanges { target: description; text: root.linkData.description }
|
|
|
|
PropertyChanges { target: d; bannerImageSource: root.linkData.thumbnail }
|
|
|
|
},
|
|
|
|
State {
|
|
|
|
name: "community"
|
|
|
|
when: root.type === Constants.LinkPreviewType.StatusCommunity
|
|
|
|
PropertyChanges {
|
|
|
|
target: logo
|
|
|
|
visible: true
|
|
|
|
name: root.communityData.name
|
|
|
|
asset.name: root.communityData.image
|
|
|
|
asset.isImage: !!root.communityData.image
|
|
|
|
asset.color: root.communityData.color
|
|
|
|
}
|
|
|
|
PropertyChanges { target: bannerImageLoader; visible: true }
|
|
|
|
PropertyChanges { target: title; text: root.communityData.name }
|
|
|
|
PropertyChanges { target: description; text: root.communityData.description }
|
|
|
|
PropertyChanges { target: d; bannerImageSource: root.communityData.banner }
|
|
|
|
PropertyChanges { target: footerLoader; active: true; visible: true; sourceComponent: communityFooterComponent }
|
|
|
|
},
|
|
|
|
State {
|
|
|
|
name: "channel"
|
|
|
|
when: root.type === Constants.LinkPreviewType.StatusCommunityChannel
|
|
|
|
PropertyChanges {
|
|
|
|
target: logo
|
|
|
|
visible: true
|
|
|
|
name: root.channelData.name
|
|
|
|
asset.name: ""
|
|
|
|
asset.isImage: false
|
|
|
|
asset.color: root.channelData.color
|
|
|
|
asset.emoji: root.channelData.emoji
|
|
|
|
}
|
|
|
|
PropertyChanges { target: bannerImageLoader; visible: true }
|
|
|
|
PropertyChanges { target: title; text: "#" + root.channelData.name }
|
|
|
|
PropertyChanges { target: description; text: root.channelData.description || root.channelData.communityData.description }
|
|
|
|
PropertyChanges { target: d; bannerImageSource: root.channelData.communityData.banner }
|
|
|
|
PropertyChanges { target: footerLoader; active: true; visible: true; sourceComponent: channelFooterComponent }
|
|
|
|
},
|
|
|
|
State {
|
|
|
|
name: "contact"
|
|
|
|
when: root.type === Constants.LinkPreviewType.StatusContact
|
|
|
|
PropertyChanges { target: root; implicitHeight: 187 }
|
|
|
|
PropertyChanges { target: bannerImageLoader; visible: false }
|
|
|
|
PropertyChanges { target: footerLoader; active: false; visible: !root.userData.bio; Layout.fillHeight: true }
|
|
|
|
PropertyChanges { target: title; text: root.userData.name }
|
|
|
|
PropertyChanges { target: description; text: root.userData.bio; Layout.minimumHeight: 32; visible: true }
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2023-10-09 12:41:27 +00:00
|
|
|
QtObject {
|
|
|
|
id: d
|
|
|
|
property real bannerImageMargins: 1 / Screen.devicePixelRatio // image size isn't pixel perfect..
|
2023-10-16 07:27:55 +00:00
|
|
|
property bool highlight: root.highlight || root.hovered
|
2023-10-25 15:20:02 +00:00
|
|
|
property string bannerImageSource: ""
|
2023-10-09 12:41:27 +00:00
|
|
|
}
|
2023-09-13 09:12:47 +00:00
|
|
|
}
|