feat(ProfileShowcasePopup): Adding interactions in delegates

Closes #13702
This commit is contained in:
Alexandra Betouni 2024-02-27 19:11:03 +02:00 committed by Alex Jbanca
parent 8f5efc6cb0
commit 53db09412a
23 changed files with 1300 additions and 597 deletions

View File

@ -25,6 +25,7 @@ type
CommunityName
CommunityColor
CommunityPrivilegesLevel
CommunityImage
TokenType
QtObject:
@ -146,6 +147,7 @@ QtObject:
CollectibleRole.CommunityName.int:"communityName",
CollectibleRole.CommunityColor.int:"communityColor",
CollectibleRole.CommunityPrivilegesLevel.int:"communityPrivilegesLevel",
CollectibleRole.CommunityImage.int:"communityImage",
CollectibleRole.TokenType.int:"tokenType",
}.toTable
@ -197,6 +199,8 @@ QtObject:
result = newQVariant(item.getCommunityColor())
of CollectibleRole.CommunityPrivilegesLevel:
result = newQVariant(item.getCommunityPrivilegesLevel())
of CollectibleRole.CommunityImage:
result = newQVariant(item.getCommunityImage())
of CollectibleRole.TokenType:
result = newQVariant(item.getTokenType())
@ -222,6 +226,7 @@ QtObject:
of "communityName": result = item.getCommunityName()
of "communityColor": result = item.getCommunityColor()
of "communityPrivilegesLevel": result = $item.getCommunityPrivilegesLevel()
of "communityImage": result = item.getCommunityImage()
proc resetCollectibleItems(self: Model, newItems: seq[CollectiblesEntry] = @[]) =
self.beginResetModel()

View File

@ -8,6 +8,7 @@ import shared.stores 1.0
import mainui 1.0
import StatusQ 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import AppLayouts.Wallet.stores 1.0
@ -127,29 +128,56 @@ SplitView {
ListModel {
id: linksModel
ListElement {
uuid: "0001"
text: "__github"
url: "https://github.com/caybro"
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
}
ListElement {
uuid: "0002"
text: "__twitter"
url: "https://twitter.com/caybro"
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
}
ListElement {
uuid: "0003"
text: "__personal_site"
url: "https://status.im"
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
}
ListElement {
uuid: "0004"
text: "__youtube"
url: "https://www.youtube.com/@LukasTinkl"
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
}
ListElement {
uuid: "0006"
text: "__telegram"
url: "https://t.me/ltinkl"
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
}
}
ManageCollectiblesModel {
id: manageCollectiblesModel
Component.onCompleted: {
for (let i = 0; i < this.count; i++) {
setProperty(i, "showcaseVisibility", Constants.ShowcaseVisibility.Everyone)
}
}
}
WalletAccountsModel {
id: walletAccountsModel
Component.onCompleted: {
for (let i = 0; i < this.count; i++) {
setProperty(i, "showcaseVisibility", Constants.ShowcaseVisibility.Everyone)
}
}
}
CommunitiesModel {
id: communitiesModel
Component.onCompleted: {
for (let i = 0; i < this.count; i++) {
setProperty(i, "showcaseVisibility", Constants.ShowcaseVisibility.Everyone)
}
}
}
@ -310,7 +338,6 @@ SplitView {
sourceComponent: ProfileDialogView {
implicitWidth: 640
enabledNetworks: NetworksModel.allNetworks
readOnly: ctrlReadOnly.checked
publicKey: switchOwnProfile.checked ? "0xdeadbeef" : "0xrandomguy"
@ -319,9 +346,9 @@ SplitView {
sendToAccountEnabled: true
showcaseCommunitiesModel: CommunitiesModel {}
showcaseAccountsModel: WalletAccountsModel {}
showcaseCollectiblesModel: ManageCollectiblesModel {}
showcaseCommunitiesModel: communitiesModel
showcaseAccountsModel: walletAccountsModel
showcaseCollectiblesModel: manageCollectiblesModel
showcaseSocialLinksModel: linksModel
// TODO: showcaseAssetsModel

View File

@ -11,7 +11,9 @@ ListModel {
shortName: "SOCKS",
symbol: "SOCKS",
category: TokenCategories.Category.Community,
communityId: ""
communityId: "",
communityImage: "",
address: "23534tlgtu90345t"
},
{
key: "zrx",
@ -20,7 +22,9 @@ ListModel {
shortName: "ZRX",
symbol: "ZRX",
category: TokenCategories.Category.Community,
communityId: ""
communityId: "",
communityImage: "",
address: "23534tlgtu90345t"
},
{
key: "1inch",
@ -29,7 +33,9 @@ ListModel {
shortName: "1INCH",
symbol: "1INCH",
category: TokenCategories.Category.Own,
communityId: ""
communityId: "",
communityImage: "",
address: "23534tlgtu90345t"
},
{
key: "Aave",
@ -38,7 +44,9 @@ ListModel {
shortName: "AAVE",
symbol: "AAVE",
category: TokenCategories.Category.Own,
communityId: ""
communityId: "",
communityImage: "",
address: "23534tlgtu90345t"
},
{
key: "Amp",
@ -47,7 +55,9 @@ ListModel {
shortName: "AMP",
symbol: "AMP",
category: TokenCategories.Category.Own,
communityId: ""
communityId: "",
communityImage: "",
address: "23534tlgtu90345t"
},
{
key: "Dai",
@ -56,7 +66,9 @@ ListModel {
shortName: "DAI",
symbol: "DAI",
category: TokenCategories.Category.General,
communityId: ""
communityId: "0x1",
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
address: "stgdrswaE2q"
},
{
key: "snt",
@ -65,7 +77,8 @@ ListModel {
shortName: "snt",
symbol: "SNT",
category: TokenCategories.Category.General,
communityId: ""
communityId: "",
address: "321312wdsadas"
},
{
key: "stt",
@ -74,7 +87,8 @@ ListModel {
shortName: "stt",
symbol: "STT",
category: TokenCategories.Category.Own,
communityId: ""
communityId: "",
address: "rwr32e1wqdscdwe43r34r"
},
{
key: "eth",
@ -83,7 +97,9 @@ ListModel {
shortName: "eth",
symbol: "ETH",
category: TokenCategories.Category.General,
communityId: ""
communityId: "000",
communityImage: ModelsData.icons.status,
address: "rwr43r34r"
}
]

View File

@ -29,6 +29,8 @@ ListModel {
imageUrl: ModelsData.collectibles.cryptoPunks,
isLoading: false,
backgroundColor: "",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
@ -74,6 +76,8 @@ ListModel {
imageUrl: "https://i.seadn.io/s/raw/files/ba2811bb5cd0bed67529d69fa92ef5aa.jpg?auto=format&dpr=1&w=1000",
isLoading: false,
backgroundColor: "",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
@ -114,6 +118,8 @@ ListModel {
imageUrl: ModelsData.collectibles.kitty1Big,
isLoading: true,
backgroundColor: "",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
@ -154,6 +160,8 @@ ListModel {
imageUrl: ModelsData.collectibles.kitty2Big,
isLoading: false,
backgroundColor: "",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
@ -197,6 +205,8 @@ ListModel {
imageUrl: ModelsData.collectibles.kitty3Big,
isLoading: false,
backgroundColor: "",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
@ -242,6 +252,8 @@ ListModel {
imageUrl: "https://i.seadn.io/s/raw/files/cfa559bb63e4378f17649c1e3b8f18fe.jpg?auto=format&dpr=1&w=1000",
isLoading: false,
backgroundColor: "",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
@ -274,6 +286,8 @@ ListModel {
imageUrl: "",
isLoading: false,
backgroundColor: "ivory",
permalink:"opensea.com",
domain:"opensea",
ownership: [
{
accountAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",

View File

@ -168,7 +168,7 @@ Rectangle {
\qmlsignal StatusCommunityCard::clicked(string communityId)
This signal is emitted when the card item is clicked.
*/
signal clicked(string communityId)
signal clicked(var mouse, string communityId)
QtObject {
id: d
@ -177,13 +177,14 @@ Rectangle {
readonly property int cardHeigth: (root.cardSize === StatusCommunityCard.Size.Big) ? 190 : 119
readonly property int totalHeigth: (root.cardSize === StatusCommunityCard.Size.Big) ? 230 : 144
readonly property int margins: 12
readonly property int bannerRadius: (root.cardSize === StatusCommunityCard.Size.Big) ? 20 : 16
readonly property int bannerRadius: (root.cardSize === StatusCommunityCard.Size.Big) ? 20 : 8
readonly property int bannerRadiusHovered: (root.cardSize === StatusCommunityCard.Size.Big) ? 30 : 16
readonly property int cardRadius: 16
readonly property int cardRadius: (root.cardSize === StatusCommunityCard.Size.Big) ? 16 : 8
readonly property color cardColor: Theme.palette.name === "light" ? Theme.palette.indirectColor1 : Theme.palette.baseColor2
readonly property color fontColor: Theme.palette.directColor1
readonly property color loadingColor1: Theme.palette.baseColor5
readonly property color loadingColor2: Theme.palette.baseColor4
readonly property int titleFontWeight: (root.cardSize === StatusCommunityCard.Size.Big) ? Font.Bold : Font.Medium
function numberFormat(number) {
var res = number
@ -287,11 +288,12 @@ Rectangle {
z: banner.z + 1
visible: root.loaded
anchors.top: parent.top
anchors.topMargin: (root.cardSize === StatusCommunityCard.Size.Big) ? 40 : 23
anchors.topMargin: (root.cardSize === StatusCommunityCard.Size.Big) ? 40 : 25
width: parent.width
height: d.cardHeigth
color: d.cardColor
radius: d.cardRadius
border.color: root.border.color
clip: true
// Right header extra info component
@ -314,16 +316,18 @@ Rectangle {
spacing: (root.cardSize === StatusCommunityCard.Size.Big) ? 6 : 0
StatusBaseText {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
Layout.fillWidth: (root.cardSize === StatusCommunityCard.Size.Big)
Layout.preferredHeight: 22
text: root.name
font.weight: Font.Bold
font.weight: d.titleFontWeight
font.pixelSize: root.titleFontSize
color: d.fontColor
elide: Text.ElideRight
}
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.fillHeight: (root.cardSize === StatusCommunityCard.Size.Big)
Layout.preferredHeight: 16
text: root.description
font.pixelSize: root.descriptionFontSize
lineHeight: 1.2
@ -516,7 +520,8 @@ Rectangle {
anchors.fill: parent
cursorShape: root.loaded ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: root.clicked(root.communityId)
onClicked: root.clicked(mouse ,root.communityId)
}
}

View File

@ -22,6 +22,7 @@ Row {
height: 40
isLetterIdenticon: false
imgIsIdenticon: false
bgBorderWidth: 1
}
spacing: 8
@ -63,7 +64,7 @@ Row {
height: statusImageWithTitle.asset.height
radius: statusImageWithTitle.asset.bgRadius || width/2
color: Theme.palette.statusRoundedImage.backgroundColor
border.width: 1
border.width: statusImageWithTitle.asset.bgBorderWidth
border.color: Theme.palette.directColor7
showLoadingIndicator: true
}
@ -118,6 +119,7 @@ Row {
width: !iconOrImage.active ? parent.width :
parent.width - iconOrImage.width - parent.spacing
anchors.verticalCenter: parent.verticalCenter
Row {
id: headerTitleRow
width: parent.width

View File

@ -79,6 +79,12 @@ Control {
*/
property color backgroundColor: Theme.palette.baseColor4
/*!
\qmlproperty color PermissionsRow::backgroundColor
This property holds the control background color, including border color of overlapped elements.
*/
property color backgroundBorderColor: Theme.palette.baseColor4
/*!
\qmlproperty int PermissionsRow::backgroundRadius
This property holds the background radius.
@ -169,6 +175,7 @@ Control {
background: Rectangle {
color: root.backgroundColor
radius: root.backgroundRadius
border.color: root.backgroundBorderColor
}
contentItem: RowLayout {

View File

@ -93,6 +93,10 @@ QObject {
function getShowcaseVisibility() {
return Constants.ShowcaseVisibility.Everyone
}
},
FastExpressionRole {
name: "canReceiveFromMyAccounts"
expression: true
}
]
}

View File

@ -80,6 +80,13 @@ QObject {
name: "showcaseKey"
expression: model.address
expectedRoles: ["address"]
},
FastExpressionRole {
function canReceiveFromMyAccounts() {
return accountsSourceModel.count > 1
}
name: "canReceiveFromMyAccounts"
expression: canReceiveFromMyAccounts()
}
]
}

View File

@ -52,6 +52,7 @@ QtObject {
Global.openOutgoingIDRequestPopup.connect(openOutgoingIDRequestPopup)
Global.openIncomingIDRequestPopup.connect(openIncomingIDRequestPopup)
Global.openInviteFriendsToCommunityPopup.connect(openInviteFriendsToCommunityPopup)
Global.openInviteFriendsToCommunityByIdPopup.connect(openInviteFriendsToCommunityByIdPopup)
Global.openContactRequestPopup.connect(openContactRequestPopup)
Global.openReviewContactRequestPopup.connect(openReviewContactRequestPopup)
Global.openChooseBrowserPopup.connect(openChooseBrowserPopup)
@ -215,6 +216,14 @@ QtObject {
openPopup(inviteFriendsToCommunityPopup, { community: community, communitySectionModule: communitySectionModule }, cb)
}
function openInviteFriendsToCommunityByIdPopup(communityId, cb) {
root.rootStore.mainModuleInst.prepareCommunitySectionModuleForCommunityId(communityId)
const communitySectionModuleData = root.rootStore.mainModuleInst.getCommunitySectionModule()
const communityData = root.communitiesStore.getCommunityDetails(communityId)
openPopup(inviteFriendsToCommunityPopup, { community: communityData, communitySectionModule: communitySectionModuleData }, cb)
}
function openContactRequestPopup(publicKey, contactDetails, cb) {
let details = contactDetails ?? Utils.getContactDetailsAsJson(publicKey, false)
const popupProperties = {
@ -478,7 +487,6 @@ QtObject {
onClosed: destroy()
}
},
Component {
id: sendContactRequestPopupComponent

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,112 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
Control {
id: root
width: 120
height: 50
anchors.left: parent.left
anchors.leftMargin: 12
anchors.bottom: parent.bottom
anchors.bottomMargin: 12
property string tagHeaderText
property string tagName
property string tagImage
property bool isIcon: false
property color backgroundColor: Theme.palette.baseColor4
property bool expanded: root.hovered
signal tagClicked()
contentItem: Item {
StatusBaseText {
id: textLabel
width: parent.width
visible: root.expanded && !!root.tagHeaderText
opacity: visible ? 1 : 0
color: Theme.palette.indirectColor1
Behavior on opacity { NumberAnimation {} }
verticalAlignment: Text.AlignVCenter
text: root.tagHeaderText
elide: Text.ElideRight
font.weight: Font.Medium
}
Rectangle {
id: tagBackground
width: Math.min(Math.max(tagRowLayout.implicitWidth + tagRowLayout.anchors.margins * 2, 24), parent.width)
Behavior on width { NumberAnimation {} }
height: 24
anchors.top: textLabel.bottom
anchors.topMargin: 4
radius: parent.width/2
color: root.backgroundColor
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: hovered ? Qt.PointingHandCursor : undefined
onClicked: {
root.tagClicked();
}
}
RowLayout {
id: tagRowLayout
anchors.fill: parent
anchors.margins: 2
spacing: 4
Loader {
id: tagImageLoader
Layout.preferredWidth: 20
Layout.preferredHeight: 20
Layout.alignment: Qt.AlignVCenter
sourceComponent: root.isIcon ? tagStatusRoundIcon : tagStatusRoundedImage
}
StatusBaseText {
id: tagName
Layout.preferredHeight: 20
Layout.fillWidth: true
Layout.rightMargin: 2
visible: (root.expanded && !!root.tagName)
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation {} }
verticalAlignment: Text.AlignVCenter
font.pixelSize: Style.current.tertiaryTextFontSize
text: root.tagName
elide: Text.ElideRight
}
}
}
}
Component {
id: tagStatusRoundedImage
StatusRoundedImage {
image.fillMode: Image.PreserveAspectFit
image.source: root.tagImage
}
}
Component {
id: tagStatusRoundIcon
StatusRoundIcon {
asset.width: 16
asset.height: 16
color: "transparent"
asset.name: root.tagImage
asset.color: tagName.color
}
}
}

View File

@ -1,6 +1,7 @@
import QtQuick 2.14
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
@ -15,12 +16,16 @@ Control {
padding: 12
property bool highlight: false
property string title: ""
property string subTitle: ""
property string tagIcon: ""
property var enabledNetworks
property bool loading: false
property alias rightSideButtons: rightSideButtonsLoader.sourceComponent
signal clicked(var mouse)
signal communityTagClicked(var mouse)
property StatusAssetSettings asset: StatusAssetSettings {
height: 32
@ -29,14 +34,34 @@ Control {
}
background: Rectangle {
id: background
anchors.fill: parent
color: Style.current.background
radius: Style.current.radius
border.width: 1
border.color: Theme.palette.baseColor2
layer.enabled: mouseArea.containsMouse || root.highlight
layer.effect: DropShadow {
source: background
horizontalOffset: 0
verticalOffset: 2
radius: 16
samples: 25
spread: 0
color: Theme.palette.backdropColor
}
}
contentItem: Item {
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton|Qt.RightButton
hoverEnabled: true
onClicked: {
root.clicked(mouse);
}
}
ColumnLayout {
id: titleColumn
anchors.fill: parent
@ -55,15 +80,15 @@ Control {
Item { Layout.fillWidth: true }
Loader {
id: rightSideButtonsLoader
Layout.alignment: Qt.AlignRight
Layout.alignment: Qt.AlignRight | Qt.AlignTop
}
}
StatusTextWithLoadingState {
text: root.title
Layout.fillWidth: true
Layout.preferredHeight: 22
Layout.topMargin: Style.current.halfPadding
Layout.fillWidth: true
text: root.title
elide: Text.ElideRight
font.weight: Font.Medium
loading: root.loading
@ -94,12 +119,18 @@ Control {
Repeater {
id: chainRepeater
model: root.enabledNetworks
delegate: StatusRoundedImage {
delegate: StatusRoundedComponent {
width: 20
height: 20
visible: image.source !== ""
image.source: Style.svg(model.iconUrl)
visible: model.iconUrl !== ""
color: Theme.palette.baseColor3
z: index + 1
border.color: Style.current.background
StatusIcon {
anchors.fill:parent
anchors.margins: 1
icon: Style.svg(model.iconUrl)
}
}
}
}
@ -111,9 +142,15 @@ Control {
verticalPadding: 0
spacing: 0
visible: !!root.tagIcon
asset.name: root.tagIcon
communityImage: root.tagIcon
asset.width: 20
asset.height: 20
MouseArea {
anchors.fill: parent
onClicked: {
root.communityTagClicked(mouse);
}
}
}
}
}

View File

@ -49,3 +49,4 @@ TransactionDetailsHeader.qml 1.0 TransactionDetailsHeader.qml
MockedKeycardReaderStateSelector 1.0 MockedKeycardReaderStateSelector.qml
MockedKeycardStateSelector 1.0 MockedKeycardStateSelector.qml
AssetsSectionDelegate 1.0 AssetsSectionDelegate.qml
ExpandableTag 1.0 ExpandableTag.qml

View File

@ -35,7 +35,6 @@ Pane {
property var contactsStore
property alias sendToAccountEnabled: showcaseView.sendToAccountEnabled
property alias enabledNetworks: showcaseView.enabledNetworks
property var dirtyValues: ({})
property bool dirty: false
@ -632,6 +631,8 @@ Pane {
socialLinksModel: root.showcaseSocialLinksModel
// assetsModel: root.showcaseAssetsModel
walletStore: WalletNS.RootStore
onCloseRequested: root.closeRequested()
onCopyToClipboard: root.profileStore.copyToClipboard(text)
}

View File

@ -0,0 +1,201 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Popups 0.1
import shared.controls.delegates 1.0
import utils 1.0
Item {
id: root
required property string mainDisplayName
required property bool sendToAccountEnabled
required property var accountsModel
required property var walletStore
property alias cellWidth: accountsView.cellWidth
property alias cellHeight: accountsView.cellHeight
signal copyToClipboard(string text)
StatusBaseText {
anchors.centerIn: parent
visible: (accountsView.count === 0)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any accounts").arg(root.mainDisplayName)
}
StatusGridView {
id: accountsView
anchors.fill: parent
topMargin: Style.current.bigPadding
bottomMargin: Style.current.bigPadding
leftMargin: Style.current.bigPadding
visible: count
ScrollBar.vertical: StatusScrollBar { anchors.right: parent.right; anchors.rightMargin: width / 2 }
model: root.accountsModel
delegate: InfoCard {
id: accountInfoDelegate
implicitWidth: GridView.view.cellWidth - Style.current.padding
implicitHeight: GridView.view.cellHeight - Style.current.padding
title: model.name
subTitle: StatusQUtils.Utils.elideText(model.address, 6, 4).replace("0x", "0×")
asset.color: Utils.getColorForId(model.colorId)
asset.emoji: model.emoji ?? ""
asset.name: asset.emoji || "filled-account"
asset.isLetterIdenticon: asset.emoji
asset.letterSize: 14
asset.bgColor: Theme.palette.primaryColor3
asset.isImage: asset.emoji
enabledNetworks: root.walletStore.filteredFlatModel // TODO: https://github.com/status-im/status-desktop/issues/14227
rightSideButtons: RowLayout {
StatusFlatRoundButton {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
visible: accountInfoDelegate.hovered && model.canReceiveFromMyAccounts
type: StatusFlatRoundButton.Type.Secondary
icon.name: "send"
icon.color: !hovered ? Theme.palette.baseColor1 : Theme.palette.directColor1
enabled: root.sendToAccountEnabled
onClicked: {
Global.openSendModal(model.address)
}
onHoveredChanged: accountInfoDelegate.highlight = hovered
}
StatusFlatRoundButton {
id: moreButton
Layout.preferredWidth: 32
Layout.preferredHeight: 32
visible: accountInfoDelegate.hovered
type: StatusFlatRoundButton.Type.Secondary
icon.name: "more"
icon.color: (hovered || d.menuOpened) ? Theme.palette.directColor1 : Theme.palette.baseColor1
highlighted: d.menuOpened
onClicked: {
const preferredChains = StatusQUtils.ModelUtils.modelToArray(accountInfoDelegate.enabledNetworks, ["chainId"]).map((item) => item.chainId).join(":")
Global.openMenu(delegatesActionsMenu, this, {
x: moreButton.x,
y : moreButton.y,
accountAddress: model.address,
accountName: model.name,
accountColorId: model.colorId,
accountPrefferedChains: preferredChains
});
}
onHoveredChanged: accountInfoDelegate.highlight = hovered
}
}
onClicked: {
if (mouse.button === Qt.RightButton) {
const preferredChains = StatusQUtils.ModelUtils.modelToArray(accountInfoDelegate.enabledNetworks, ["chainId"]).map((item) => item.chainId).join(":")
Global.openMenu(delegatesActionsMenu, this, {
accountAddress: model.address,
accountName: model.name,
accountColorId: model.colorId,
accountPrefferedChains: preferredChains
});
}
}
}
}
Component {
id: delegatesActionsMenu
StatusMenu {
id: contextMenu
property string accountAddress: ""
property string accountName: ""
property string accountColorId: ""
property var accountPrefferedChains: []
onOpened: { d.menuOpened = true; }
onClosed: { d.menuOpened = false; }
StatusSuccessAction {
id: copyAddressAction
successText: qsTr("Copied")
text: qsTr("Copy adress")
icon.name: "copy"
onTriggered: {
root.copyToClipboard(accountAddress)
}
}
StatusAction {
text: qsTr("Show address QR")
icon.name: "qr"
onTriggered: {
Global.openShowQRPopup({
showSingleAccount: true,
switchingAccounsEnabled: false,
changingPreferredChainsEnabled: false,
hasFloatingButtons: false,
name: contextMenu.accountName,
address: contextMenu.accountAddress,
preferredSharingChainIds: contextMenu.accountPrefferedChains,
colorId: contextMenu.accountColorId
})
}
}
StatusAction {
text: qsTr("Save address")
icon.name: "favourite"
onTriggered: {
Global.openAddEditSavedAddressesPopup({ addAddress: true, address: contextMenu.accountAddress })
}
}
StatusAction {
text: qsTr("View on Etherscan")
icon.name: "link"
onTriggered: {
let link = Utils.getUrlForAddressOnNetwork(Constants.networkShortChainNames.mainnet,
root.walletStore.areTestNetworksEnabled,
root.walletStore.isGoerliEnabled,
contextMenu.accountAddress);
Global.openLinkWithConfirmation(link, StatusQUtils.StringUtils.extractDomainFromLink(link));
}
}
StatusAction {
text: qsTr("View on Optimism Explorer")
icon.name: "link"
onTriggered: {
let link = Utils.getUrlForAddressOnNetwork(Constants.networkShortChainNames.optimism,
root.walletStore.areTestNetworksEnabled,
root.walletStore.isGoerliEnabled,
contextMenu.accountAddress);
Global.openLinkWithConfirmation(link, StatusQUtils.StringUtils.extractDomainFromLink(link));
}
}
StatusAction {
text: qsTr("View on Arbiscan")
icon.name: "link"
onTriggered: {
let link = Utils.getUrlForAddressOnNetwork(Constants.networkShortChainNames.arbitrum,
root.walletStore.areTestNetworksEnabled,
root.walletStore.isGoerliEnabled,
contextMenu.accountAddress);
Global.openLinkWithConfirmation(link, StatusQUtils.StringUtils.extractDomainFromLink(link));
}
}
}
}
QtObject {
id: d
property bool menuOpened: false
}
}

View File

@ -0,0 +1,131 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
import shared.controls 1.0
import shared.controls.delegates 1.0
import utils 1.0
Item {
id: root
required property string mainDisplayName
required property var assetsModel
required property bool sendToAccountEnabled
property alias cellWidth: accountsView.cellWidth
property alias cellHeight: accountsView.cellHeight
signal closeRequested()
signal visitCommunity(var model)
StatusBaseText {
anchors.centerIn: parent
visible: (assetsView.count === 0)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any assets").arg(root.mainDisplayName)
}
StatusGridView {
id: assetsView
anchors.fill: parent
topMargin: Style.current.bigPadding
bottomMargin: Style.current.bigPadding
leftMargin: Style.current.bigPadding
visible: count
model: root.assetsModel
ScrollBar.vertical: StatusScrollBar { anchors.right: parent.right; anchors.rightMargin: width / 2 }
delegate: InfoCard {
id: assetsInfoDelegate
width: GridView.view.cellWidth - Style.current.padding
height: GridView.view.cellHeight - Style.current.padding
title: model.name
//TODO show balance & symbol
subTitle: model.decimals + " " + model.symbol
asset.name: Constants.tokenIcon(model.symbol)
asset.isImage: true
ExpandableTag {
id: communityTag
visible: !!model.communityImage
tagName: model.communityName
tagImage: model.communityImage
onTagClicked: {
Global.switchToCommunity(model.communityId);
root.closeRequested();
}
}
rightSideButtons: RowLayout {
StatusFlatRoundButton {
implicitWidth: 24
implicitHeight: 24
visible: (assetsInfoDelegate.hovered && !communityTag.hovered && model.communityId === "")
type: StatusFlatRoundButton.Type.Secondary
icon.name: "external"
icon.width: 16
icon.height: 16
radius: width/2
icon.color: assetsInfoDelegate.hovered && !hovered ? Theme.palette.baseColor1 : Theme.palette.directColor1
enabled: root.sendToAccountEnabled
onClicked: {
//TODO check this open on CoinGecko
Global.openLink(model.url);
}
}
}
onCommunityTagClicked: {
Global.switchToCommunity(model.communityId);
root.closeRequested();
}
onClicked: {
if ((mouse.button === Qt.LeftButton) && (model.communityId !== "")) {
root.visitCommunity(model)
} else if (mouse.button === Qt.RightButton) {
Global.openMenu(delegatesActionsMenu, this, { accountAddress: model.address, communityId: model.communityId });
}
}
}
}
Component {
id: delegatesActionsMenu
StatusMenu {
id: contextMenu
property string communityId
property string accountAddress: ""
StatusAction {
text: qsTr("Visit community")
enabled: !!contextMenu.communityId
icon.name: "communities"
onTriggered: {
Global.switchToCommunity(contextMenu.communityId);
root.closeRequested();
}
}
StatusAction {
text: qsTr("View on CoinGecko")
enabled: false //contextMenu.communityId === ""
icon.name: "link"
onTriggered: {
//TODO: Get coingecko link for token
// let link = "";
// Global.openLinkWithConfirmation(link, StatusQUtils.StringUtils.extractDomainFromLink(link));
}
}
}
}
}

View File

@ -0,0 +1,209 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Popups 0.1
import shared.controls 1.0
import utils 1.0
Item {
id: root
required property string mainDisplayName
required property var collectiblesModel
required property var walletStore
property alias cellWidth: collectiblesView.cellWidth
property alias cellHeight: collectiblesView.cellHeight
signal closeRequested()
signal visitCommunity(var model)
StatusBaseText {
anchors.centerIn: parent
visible: (collectiblesView.count === 0)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any collectibles").arg(root.mainDisplayName)
}
StatusGridView {
id: collectiblesView
anchors.fill: parent
topMargin: Style.current.bigPadding
bottomMargin: Style.current.bigPadding
leftMargin: Style.current.bigPadding
visible: count
model: root.collectiblesModel
ScrollBar.vertical: StatusScrollBar { anchors.right: parent.right; anchors.rightMargin: width / 2 }
delegate: Item {
id: delegateItem
function getCollectibleURL() {
const networkShortName = root.walletStore.getNetworkShortNames(model.chainId);
return root.walletStore.getOpenSeaCollectibleUrl(networkShortName, model.contractAddress, model.tokenId)
}
function openCollectibleURL() {
const link = getCollectibleURL();
Global.openLinkWithConfirmation(link, StatusQUtils.StringUtils.extractDomainFromLink(link));
}
function openCollectionURL() {
let networkShortName = root.walletStore.getNetworkShortNames(model.chainId);
let link = root.walletStore.getOpenSeaCollectionUrl(networkShortName, model.contractAddress)
Global.openLinkWithConfirmation(link, StatusQUtils.StringUtils.extractDomainFromLink(link));
}
width: GridView.view.cellWidth - Style.current.padding
height: GridView.view.cellHeight - Style.current.padding
HoverHandler {
id: hoverHandler
cursorShape: hovered ? Qt.PointingHandCursor : undefined
}
StatusRoundedImage {
id: collectibleImage
anchors.fill: parent
color: !!model.backgroundColor ? model.backgroundColor : "transparent"
radius: Style.current.radius
showLoadingIndicator: true
isLoading: image.isLoading || !model.imageUrl
image.fillMode: Image.PreserveAspectCrop
image.source: model.imageUrl ?? ""
TapHandler {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onSingleTapped: {
if ((eventPoint.event.button === Qt.LeftButton) && (model.communityId !== "")) {
root.visitCommunity(model)
} else {
if (eventPoint.event.button === Qt.LeftButton) {
delegateItem.openCollectibleURL()
} else {
Global.openMenu(delegatesActionsMenu, collectibleImage, { communityId: model.communityId, url: getCollectibleURL()});
}
}
}
}
}
Image {
id: gradient
anchors.fill: collectibleImage
visible: hoverHandler.hovered
source: Style.png("profile/gradient")
}
//TODO Add drop shadow
Control {
id: amountControl
width: (amountText.contentWidth + Style.current.padding)
height: 24
anchors.left: parent.left
anchors.leftMargin: 12
anchors.top: parent.top
anchors.topMargin: 12
//TODO TBD, https://github.com/status-im/status-desktop/issues/13782
visible: (model.userHas > 1)
background: Rectangle {
radius: 30
color: amountControl.hovered ? Theme.palette.indirectColor1 : Theme.palette.indirectColor2
}
contentItem: StatusBaseText {
id: amountText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: Style.current.asideTextFontSize
text: "x"+model.userHas
}
}
StatusRoundButton {
implicitWidth: 24
implicitHeight: 24
anchors.right: parent.right
anchors.rightMargin: 12
anchors.top: parent.top
anchors.topMargin: 12
visible: (hoverHandler.hovered && model.communityId === "")
type: StatusFlatRoundButton.Type.Secondary
icon.name: "external"
icon.width: 16
icon.height: 16
radius: width/2
icon.color: Theme.palette.directColor1
icon.hoverColor: icon.color
color: hovered ? Theme.palette.indirectColor1 : Theme.palette.indirectColor2
onClicked: {
delegateItem.openCollectibleURL()
}
}
ExpandableTag {
id: expandableTag
readonly property bool isCommunity: model.communityId != ""
readonly property bool isCollection: model.collectionUid != ""
visible: isCommunity || (isCollection && hoverHandler.hovered)
tagHeaderText: model.name ?? ""
tagName: isCommunity ? (model.communityName ?? "")
: (model.collectionName ?? "")
tagImage: isCommunity ? (model.communityImage ?? "")
: (hovered ? "external" : "gallery")
isIcon: !isCommunity
backgroundColor: hovered ? Style.current.background : Theme.palette.indirectColor2
expanded: hoverHandler.hovered || hovered
onTagClicked: {
if (isCommunity) {
Global.switchToCommunity(model.communityId);
root.closeRequested();
} else {
delegateItem.openCollectionURL()
}
}
}
}
}
Component {
id: delegatesActionsMenu
StatusMenu {
id: contextMenu
property string url
property string communityId
StatusAction {
text: qsTr("Visit community")
enabled: !!contextMenu.communityId
icon.name: "communities"
onTriggered: {
Global.switchToCommunity(contextMenu.communityId);
root.closeRequested();
}
}
StatusAction {
text: qsTr("View on Opensea")
enabled: contextMenu.communityId === ""
icon.name: "link"
onTriggered: {
Global.openLinkWithConfirmation(contextMenu.url, StatusQUtils.StringUtils.extractDomainFromLink(contextMenu.url));
}
}
}
}
}

View File

@ -0,0 +1,181 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import AppLayouts.Communities.controls 1.0
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
import utils 1.0
Item {
id: root
required property string mainDisplayName
required property bool readOnly
required property var communitiesProxyModel
required property var globalAssetsModel
required property var globalCollectiblesModel
property alias cellWidth: communitiesView.cellWidth
property alias cellHeight: communitiesView.cellHeight
signal copyToClipboard(string text)
signal closeRequested()
StatusBaseText {
anchors.centerIn: parent
visible: (communitiesView.count === 0)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any communities").arg(root.mainDisplayName)
}
StatusGridView {
id: communitiesView
anchors.fill: parent
topMargin: Style.current.bigPadding
bottomMargin: Style.current.bigPadding
leftMargin: Style.current.bigPadding
visible: count
model: root.communitiesProxyModel
ScrollBar.vertical: StatusScrollBar { anchors.right: parent.right; anchors.rightMargin: width / 2 }
delegate: StatusCommunityCard {
id: profileDialogCommunityCard
readonly property var permissionsList: model.permissionsModel
readonly property bool requirementsMet: !!model.allTokenRequirementsMet ? model.allTokenRequirementsMet : false
cardSize: StatusCommunityCard.Size.Small
implicitWidth: GridView.view.cellWidth - Style.current.padding
implicitHeight: GridView.view.cellHeight - Style.current.padding
titleFontSize: 15
communityId: model.id ?? ""
loaded: !!model.id
asset.source: model.image ?? ""
asset.isImage: !!model.image
asset.width: 32
asset.height: 32
name: model.name ?? ""
memberCountVisible: false
layer.enabled: hovered
border.width: hovered ? 0 : 1
border.color: Theme.palette.baseColor2
banner: model.bannerImageData ?? ""
descriptionFontSize: 12
descriptionFontColor: Theme.palette.baseColor1
description: {
switch (model.memberRole) {
case (Constants.memberRole.owner):
return qsTr("Owner");
case (Constants.memberRole.admin) :
return qsTr("Admin");
case (Constants.memberRole.tokenMaster):
return qsTr("Token Master");
default:
return qsTr("Member");
}
}
communityColor: model.color ?? ""
// Community restrictions
bottomRowComponent: (model.joined && !root.readOnly) ?
communityMembershipComponent :
!!profileDialogCommunityCard.permissionsList && profileDialogCommunityCard.permissionsList.count > 0 ?
permissionsRowComponent : null
Component {
id: communityMembershipComponent
Item {
width: 125
height: 24
Rectangle {
anchors.fill: parent
radius: 20
color: Theme.palette.successColor1
opacity: .1
border.color: Theme.palette.successColor1
}
Row {
anchors.centerIn: parent
spacing: 2
StatusIcon {
width: 16
height: 16
color: Theme.palette.successColor1
icon: "tiny/checkmark"
}
StatusBaseText {
font.pixelSize: Theme.tertiaryTextFontSize
color: Theme.palette.successColor1
text: qsTr("Youre there too")
}
}
}
}
Component {
id: permissionsRowComponent
PermissionsRow {
hoverEnabled: false
assetsModel: root.globalAssetsModel
collectiblesModel: root.globalCollectiblesModel
model: profileDialogCommunityCard.permissionsList
requirementsMet: profileDialogCommunityCard.requirementsMet
backgroundBorderColor: Theme.palette.baseColor2
backgroundRadius: 20
}
}
onClicked: {
if (root.readOnly)
return
if (mouse.button === Qt.LeftButton) {
Global.switchToCommunity(model.id);
root.closeRequested();
} else {
Global.openMenu(delegatesActionsMenu, this, { communityId: model.id, url: Utils.getCommunityShareLink(model.id) });
}
}
}
}
Component {
id: delegatesActionsMenu
StatusMenu {
id: contextMenu
property string url
property string communityId
StatusAction {
text: qsTr("Visit community")
icon.name: "arrow-right"
onTriggered: {
Global.switchToCommunity(contextMenu.communityId);
root.closeRequested();
}
}
StatusAction {
text: qsTr("Invite People")
icon.name: "share-ios"
onTriggered: {
Global.openInviteFriendsToCommunityByIdPopup(contextMenu.communityId, null);
}
}
StatusSuccessAction {
id: copyAddressAction
successText: qsTr("Copied")
text: qsTr("Copy link to community")
icon.name: "copy"
onTriggered: {
root.copyToClipboard(contextMenu.url)
}
}
}
}
}

View File

@ -0,0 +1,134 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Popups 0.1
import shared.controls.delegates 1.0
import utils 1.0
Item {
id: root
required property string mainDisplayName
required property var socialLinksModel
property alias cellWidth: webView.cellWidth
property alias cellHeight: webView.cellHeight
signal copyToClipboard(string text)
StatusBaseText {
anchors.centerIn: parent
visible: (webView.count === 0)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any links").arg(root.mainDisplayName)
}
StatusGridView {
id: webView
anchors.fill: parent
topMargin: Style.current.bigPadding
bottomMargin: Style.current.bigPadding
leftMargin: Style.current.bigPadding
visible: count
model: root.socialLinksModel
ScrollBar.vertical: StatusScrollBar { anchors.right: parent.right; anchors.rightMargin: width / 2 }
delegate: InfoCard {
id: socialLinksInfoDelegate
readonly property int linkType: ProfileUtils.linkTextToType(model.text)
width: GridView.view.cellWidth - Style.current.padding
height: GridView.view.cellHeight - Style.current.padding
title: !!ProfileUtils.linkTypeToText(linkType) ? ProfileUtils.linkTypeToText(linkType) : model.text
asset.bgColor: ProfileUtils.linkTypeBgColor(linkType)
asset.name: ProfileUtils.linkTypeToIcon(linkType)
asset.color: ProfileUtils.linkTypeColor(linkType)
asset.width: 20
asset.height: 20
asset.bgWidth: 32
asset.bgHeight: 32
asset.isImage: false
subTitle: model.url
onClicked: {
if (mouse.button === Qt.RightButton) {
Global.openMenu(delegatesActionsMenu, this, { url: model.url });
}
}
highlight: hovered
rightSideButtons: RowLayout {
StatusFlatRoundButton {
implicitWidth: 24
implicitHeight: 24
type: StatusFlatRoundButton.Type.Secondary
icon.name: "external"
icon.width: 16
icon.height: 16
radius: width/2
highlighted: true
visible: socialLinksInfoDelegate.hovered
icon.color: socialLinksInfoDelegate.hovered && !hovered ? Theme.palette.baseColor1 : Theme.palette.directColor1
onClicked: {
Global.openLinkWithConfirmation(model.url, StatusQUtils.StringUtils.extractDomainFromLink(model.url));
}
}
}
}
}
Item {
width: 279
height: 32
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
visible: (webView.count > 0)
Rectangle {
anchors.fill: parent
color: Style.current.background
radius: 30
border.color: Theme.palette.baseColor2
}
Row {
anchors.centerIn: parent
spacing: 4
StatusIcon {
width: 16
height: 16
icon: "info"
color: Theme.palette.directColor1
}
StatusBaseText {
font.pixelSize: 13
text: qsTr("Social handles and links are unverified")
}
}
}
Component {
id: delegatesActionsMenu
StatusMenu {
id: contextMenu
property string url
StatusSuccessAction {
id: copyAddressAction
successText: qsTr("Copied")
text: qsTr("Copy link")
icon.name: "copy"
onTriggered: {
root.copyToClipboard(contextMenu.url);
}
}
}
}
}

View File

@ -1,6 +1,7 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import StatusQ 0.1
import StatusQ.Core 0.1
@ -13,9 +14,6 @@ import StatusQ.Core.Utils 0.1 as StatusQUtils
import SortFilterProxyModel 0.2
import utils 1.0
import shared.controls 1.0 // Timer
import shared.controls.delegates 1.0
import AppLayouts.Communities.controls 1.0
Control {
id: root
@ -33,10 +31,11 @@ Control {
property var globalAssetsModel
property var globalCollectiblesModel
property var walletStore
required property string mainDisplayName
required property bool readOnly
required property bool sendToAccountEnabled
property var enabledNetworks
signal closeRequested()
signal copyToClipboard(string text)
@ -51,8 +50,6 @@ Control {
property int delegateHeightS: 152
property int delegateWidthM: 202
property int delegateHeightM: 160
readonly property string copyLiteral: qsTr("Copy")
}
component PositionSFPM: SortFilterProxyModel {
@ -115,594 +112,197 @@ Control {
anchors.top: parent.top
height: 1
color: Theme.palette.baseColor2
visible: ((communitiesView.contentY + accountsView.contentY + collectiblesView.contentY
/*+ assetsView.contentY*/ + webView.contentY) > Style.current.xlPadding)
}
}
contentItem: StackLayout {
id: stackLayout
// communities
anchors.fill:parent
ColumnLayout {
ProfileShowcaseCommunitiesView {
width: parent.width
height: parent.height
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
visible: communitiesView.count == 0
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any communities").arg(root.mainDisplayName)
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: (communitiesView.contentY > Style.current.padding) ? 1 : Style.current.padding
Behavior on Layout.topMargin { NumberAnimation { duration: 50 } }
clip: true
StatusGridView {
id: communitiesView
width: 606
height: parent.height
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: Style.current.halfPadding
clip: false
cellWidth: d.delegateWidthM
cellHeight: d.delegateHeightM
visible: count
model: communitiesProxyModel
ScrollBar.vertical: StatusScrollBar { }
delegate: StatusCommunityCard {
id: profileDialogCommunityCard
readonly property var permissionsList: model.permissionsModel //TODO: Add permissions model in the community model
readonly property bool requirementsMet: !!model.allTokenRequirementsMet ? model.allTokenRequirementsMet : false
cardSize: StatusCommunityCard.Size.Small
width: GridView.view.cellWidth - Style.current.padding
height: GridView.view.cellHeight - Style.current.padding
titleFontSize: 15
descriptionFontSize: 12
communityId: model.id ?? ""
loaded: !!model.id
asset.source: model.image ?? ""
asset.isImage: !!model.image
asset.width: 32
asset.height: 32
name: model.name ?? ""
memberCountVisible: false
layer.enabled: hovered
border.width: hovered ? 0 : 1
border.color: Theme.palette.baseColor2
descriptionFontColor: Theme.palette.baseColor1
description: {
switch (model.memberRole) {
case (Constants.memberRole.owner):
return qsTr("Owner");
case (Constants.memberRole.admin) :
return qsTr("Admin");
case (Constants.memberRole.tokenMaster):
return qsTr("Token Master");
default:
return qsTr("Member");
}
}
communityColor: model.color ?? ""
// Community restrictions
bottomRowComponent: model.memberRole ?? -1 === Constants.memberRole.tokenMaster ?
communityMembershipComponent :
!!profileDialogCommunityCard.permissionsList && profileDialogCommunityCard.permissionsList.count > 0 ?
permissionsRowComponent : null
Component {
id: communityMembershipComponent
Item {
width: 125
height: 24
Rectangle {
anchors.fill: parent
radius: 20
color: Theme.palette.successColor1
opacity: .1
border.color: Theme.palette.successColor1
}
Row {
anchors.centerIn: parent
spacing: 2
StatusIcon {
width: 16
height: 16
color: Theme.palette.successColor1
icon: "tiny/checkmark"
}
StatusBaseText {
font.pixelSize: Theme.tertiaryTextFontSize
color: Theme.palette.successColor1
text: qsTr("Youre there too")
}
}
}
mainDisplayName: root.mainDisplayName
readOnly: root.readOnly
globalAssetsModel: root.globalAssetsModel
globalCollectiblesModel: root.globalCollectiblesModel
communitiesProxyModel: communitiesProxyModel
onCloseRequested: root.closeRequested()
onCopyToClipboard: root.copyToClipboard(text)
}
Component {
id: permissionsRowComponent
PermissionsRow {
hoverEnabled: false
assetsModel: root.globalAssetsModel
collectiblesModel: root.globalCollectiblesModel
model: profileDialogCommunityCard.permissionsList
requirementsMet: profileDialogCommunityCard.requirementsMet
}
}
onClicked: {
if (root.readOnly)
return
root.closeRequested()
Global.switchToCommunity(model.id)
//TODO https://github.com/status-im/status-desktop/issues/13702
//on right click add menu
}
}
}
}
}
// wallets/accounts
ColumnLayout {
ProfileShowcaseAccountsView {
width: parent.width
height: parent.height
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
visible: accountsView.count == 0
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any accounts").arg(root.mainDisplayName)
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: (accountsView.contentY > Style.current.padding) ? 1 : Style.current.padding
Behavior on Layout.topMargin { NumberAnimation { duration: 50 } }
clip: true
StatusGridView {
id: accountsView
width: 606
height: parent.height
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
mainDisplayName: root.mainDisplayName
sendToAccountEnabled: root.sendToAccountEnabled
accountsModel: accountsProxyModel
walletStore: root.walletStore
cellWidth: d.delegateWidthM
cellHeight: d.delegateHeightM
visible: count
clip: false
ScrollBar.vertical: StatusScrollBar { }
model: accountsProxyModel
delegate: InfoCard {
implicitWidth: GridView.view.cellWidth - Style.current.padding
implicitHeight: GridView.view.cellHeight - Style.current.padding
title: model.name
subTitle: StatusQUtils.Utils.elideText(model.address, 6, 4).replace("0x", "0×")
asset.color: Utils.getColorForId(model.colorId)
asset.emoji: model.emoji ?? ""
asset.name: asset.emoji || "filled-account"
asset.isLetterIdenticon: asset.emoji
asset.letterSize: 14
asset.bgColor: Theme.palette.primaryColor3
asset.isImage: asset.emoji
enabledNetworks: root.enabledNetworks
rightSideButtons: RowLayout {
StatusFlatRoundButton {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
type: StatusFlatRoundButton.Type.Secondary
icon.name: "send"
icon.color: Theme.palette.baseColor1
enabled: root.sendToAccountEnabled
onClicked: {
Global.openSendModal(model.address)
}
}
StatusFlatRoundButton {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
type: StatusFlatRoundButton.Type.Secondary
icon.name: "more"
icon.color: Theme.palette.baseColor1
onClicked: {
//TODO https://github.com/status-im/status-desktop/issues/13702
//open menu
}
}
}
}
//TODO remove when https://github.com/status-im/status-desktop/issues/13702
// delegate: StatusListItem {
// id: accountDelegate
// property bool saved: {
// let savedAddress = root.walletStore.getSavedAddress(model.address)
// if (savedAddress.name !== "")
// return true
// if (!!root.walletStore.lastCreatedSavedAddress) {
// if (root.walletStore.lastCreatedSavedAddress.address.toLowerCase() === model.address.toLowerCase()) {
// return !!root.walletStore.lastCreatedSavedAddress.error
// }
// }
// return false
// }
// border.width: 1
// border.color: Theme.palette.baseColor2
// width: ListView.view.width
// title: model.name
// subTitle: StatusQUtils.Utils.elideText(model.address, 6, 4).replace("0x", "0×")
// asset.color: Utils.getColorForId(model.colorId)
// asset.emoji: model.emoji ?? ""
// asset.name: asset.emoji || "filled-account"
// asset.isLetterIdenticon: asset.emoji
// asset.letterSize: 14
// asset.bgColor: Theme.palette.primaryColor3
// asset.isImage: asset.emoji
// components: [
// StatusIcon {
// anchors.verticalCenter: parent.verticalCenter
// icon: "show"
// color: Theme.palette.directColor1
// },
// StatusFlatButton {
// anchors.verticalCenter: parent.verticalCenter
// size: StatusBaseButton.Size.Small
// enabled: !accountDelegate.saved
// text: accountDelegate.saved ? qsTr("Address saved") : qsTr("Save Address")
// onClicked: {
// // From here, we should just run add saved address popup
// Global.openAddEditSavedAddressesPopup({
// addAddress: true,
// address: model.address
// })
// }
// },
// StatusFlatRoundButton {
// anchors.verticalCenter: parent.verticalCenter
// type: StatusFlatRoundButton.Type.Secondary
// icon.name: "send"
// tooltip.text: qsTr("Send")
// enabled: root.sendToAccountEnabled
// onClicked: {
// Global.openSendModal(model.address)
// }
// },
// StatusFlatRoundButton {
// anchors.verticalCenter: parent.verticalCenter
// type: StatusFlatRoundButton.Type.Secondary
// icon.name: "copy"
// tooltip.text: d.copyLiteral
// onClicked: {
// tooltip.text = qsTr("Copied")
// root.profileStore.copyToClipboard(model.address)
// d.timer.setTimeout(function() {
// tooltip.text = d.copyLiteral
// }, 2000);
// }
// }
// ]
// }
}
}
onCopyToClipboard: root.copyToClipboard(text)
}
// collectibles/NFTs
ColumnLayout {
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
visible: collectiblesView.count == 0
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any collectibles").arg(root.mainDisplayName)
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: (collectiblesView.contentY > Style.current.padding) ? 1 : Style.current.padding
Behavior on Layout.topMargin { NumberAnimation { duration: 50 } }
clip: true
StatusGridView {
id: collectiblesView
width: 608
ProfileShowcaseCollectiblesView {
width: parent.width
height: parent.height
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: Style.current.halfPadding
cellWidth: d.delegateWidthS
cellHeight: d.delegateHeightS
visible: count
clip: false
// TODO Issue #11637: Dedicated controller for user's list of collectibles (no watch-only entries)
model: collectiblesProxyModel
ScrollBar.vertical: StatusScrollBar { }
delegate: StatusRoundedImage {
width: GridView.view.cellWidth - Style.current.padding
height: GridView.view.cellHeight - Style.current.padding
border.width: 1
border.color: Theme.palette.directColor7
color: !!model.backgroundColor ? model.backgroundColor : "transparent"
radius: Style.current.radius
showLoadingIndicator: true
isLoading: image.isLoading || !model.imageUrl
image.fillMode: Image.PreserveAspectCrop
image.source: model.imageUrl ?? ""
Control {
width: (amountText.contentWidth + Style.current.padding)
height: 24
anchors.left: parent.left
anchors.leftMargin: 12
anchors.top: parent.top
anchors.topMargin: 12
//TODO TBD, we need to show the number if the user has more than 1 of each collectible
//not sure how to name the role
visible: (model.userHas > 1)
mainDisplayName: root.mainDisplayName
collectiblesModel: collectiblesProxyModel
walletStore: root.walletStore
background: Rectangle {
radius: 30
color: Theme.palette.indirectColor2
}
contentItem: StatusBaseText {
id: amountText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: Style.current.asideTextFontSize
text: "x"+model.userHas
onCloseRequested: root.closeRequested()
onVisitCommunity: {
Global.openPopup(visitComunityPopupComponent, {communityId: model.communityId, communityName: model.communityName,
communityLogo: model.communityImage, tokenName: model.name,
tokenImage: model.imageUrl, isAssetType: false });
}
}
Control {
width: 24
height: 24
anchors.left: parent.left
anchors.leftMargin: 12
anchors.bottom: parent.bottom
anchors.bottomMargin: 12
visible: !!model.communityImage
background: Rectangle {
radius: parent.width/2
color: Theme.palette.indirectColor2
}
contentItem: StatusRoundedImage {
anchors.fill: parent
anchors.margins: 4
image.fillMode: Image.PreserveAspectFit
image.source: model.communityImage
}
}
HoverHandler {
id: hhandler
cursorShape: hovered ? Qt.PointingHandCursor : undefined
}
TapHandler {
onSingleTapped: {
//TODO https://github.com/status-im/status-desktop/issues/13702
Global.openLink(model.permalink)
}
}
}
}
}
}
// assets/tokens
// ColumnLayout {
// StatusBaseText {
// Layout.fillWidth: true
// Layout.fillHeight: true
// Layout.alignment: Qt.AlignCenter
// visible: assetsView.count == 0
// horizontalAlignment: Text.AlignHCenter
// verticalAlignment: Text.AlignVCenter
// color: Theme.palette.directColor1
// text: qsTr("%1 has not shared any assets").arg(root.mainDisplayName)
// }
// Item {
// Layout.fillWidth: true
// Layout.fillHeight: true
// Layout.topMargin: (assetsView.contentY > Style.current.padding) ? 1 : Style.current.padding
// Behavior on Layout.topMargin { NumberAnimation { duration: 50 } }
// clip: true
// StatusGridView {
// id: assetsView
// width: 608
// ProfileShowcaseAssetsView {
// width: parent.width
// height: parent.height
// anchors.top: parent.top
// anchors.topMargin: Style.current.halfPadding
// anchors.bottom: parent.bottom
// anchors.bottomMargin: Style.current.halfPadding
// anchors.horizontalCenter: parent.horizontalCenter
// anchors.horizontalCenterOffset: Style.current.halfPadding
// cellWidth: d.delegateWidthS
// mainDisplayName: root.mainDisplayName
// assetsModel: assetsProxyModel
// sendToAccountEnabled: root.sendToAccountEnabled
// delegatesActionsMenu: delegatesActionsMenu
// cellHeight: d.delegateHeightS
// visible: count
// clip: false
// model: assetsProxyModel
// ScrollBar.vertical: StatusScrollBar { }
// delegate: InfoCard {
// width: GridView.view.cellWidth - Style.current.padding
// height: GridView.view.cellHeight - Style.current.padding
// title: model.name
// subTitle: LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance)
// asset.name: Constants.tokenIcon(model.symbol)
// asset.isImage: true
// tagIcon: !!model.communityImage ? model.communityImage : ""
// rightSideButtons: RowLayout {
// StatusFlatRoundButton {
// implicitWidth: 24
// implicitHeight: 24
// type: StatusFlatRoundButton.Type.Secondary
// icon.name: "external"
// icon.width: 16
// icon.height: 16
// icon.color: Theme.palette.baseColor1
// enabled: root.sendToAccountEnabled
// onClicked: {
// //TODO https://github.com/status-im/status-desktop/issues/13702
// //Global.openSendModal(model.address)
// //on right click open menu
// }
// }
// }
// }
// //TODO remove when https://github.com/status-im/status-desktop/issues/13702
// // delegate: StatusListItem {
// // readonly property double changePct24hour: model.changePct24hour ?? 0
// // readonly property string textColor: changePct24hour === 0
// // ? Theme.palette.baseColor1 : changePct24hour < 0
// // ? Theme.palette.dangerColor1 : Theme.palette.successColor1
// // readonly property string arrow: changePct24hour === 0 ? "" : changePct24hour < 0 ? "" : ""
// cellWidth: d.delegateWidthS
// // width: GridView.view.cellWidth - Style.current.halfPadding
// // height: GridView.view.cellHeight - Style.current.halfPadding
// // title: model.name
// // //subTitle: LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance)
// // statusListItemTitle.font.weight: Font.Medium
// // tertiaryTitle: qsTr("%1% today %2")
// // .arg(LocaleUtils.numberToLocaleString(changePct24hour, changePct24hour === 0 ? 0 : 2)).arg(arrow)
// // statusListItemTertiaryTitle.color: textColor
// // statusListItemTertiaryTitle.font.pixelSize: Theme.asideTextFontSize
// // statusListItemTertiaryTitle.anchors.topMargin: 6
// // leftPadding: Style.current.halfPadding
// // rightPadding: Style.current.halfPadding
// // border.width: 1
// // border.color: Theme.palette.baseColor2
// // components: [
// // Image {
// // width: 40
// // height: 40
// // anchors.verticalCenter: parent.verticalCenter
// // source: Constants.tokenIcon(model.symbol)
// // }
// // ]
// // onClicked: {
// // if (root.readOnly)
// // return
// // // TODO what to do here?
// // }
// // }
// }
// onCloseRequested: root.closeRequested()
// onVisitCommunity: {
// Global.openPopup(visitComunityPopupComponent, {communityId: model.communityId, communityName: model.communityName,
// communityLogo: model.communityImage, tokenName: model.name,
// tokenImage: Constants.tokenIcon(model.symbol), isAssetType: false });
// }
// }
// social links
ColumnLayout {
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
visible: webView.count == 0
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
text: qsTr("%1 has not shared any links").arg(root.mainDisplayName)
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: (webView.contentY > Style.current.padding) ? 1 : Style.current.padding
Behavior on Layout.topMargin { NumberAnimation { duration: 50 } }
clip: true
StatusGridView {
id: webView
width: 608
ProfileShowcaseSocialLinksView {
width: parent.width
height: parent.height
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: Style.current.halfPadding
cellWidth: d.delegateWidthS
cellHeight: d.delegateHeightS
visible: count
clip: false
model: socialLinksProxyModel
ScrollBar.vertical: StatusScrollBar { }
delegate: InfoCard {
readonly property int linkType: ProfileUtils.linkTextToType(model.text)
width: GridView.view.cellWidth - Style.current.padding
height: GridView.view.cellHeight - Style.current.padding
title: ProfileUtils.linkTypeToText(linkType)
asset.bgColor: Style.current.translucentBlue
asset.name: ProfileUtils.linkTypeToIcon(linkType)
asset.color: ProfileUtils.linkTypeColor(linkType)
asset.width: 20
asset.height: 20
asset.bgWidth: 32
asset.bgHeight: 32
asset.isImage: false
subTitle: ProfileUtils.stripSocialLinkPrefix(model.url, linkType)
rightSideButtons: RowLayout {
StatusFlatRoundButton {
implicitWidth: 24
implicitHeight: 24
type: StatusFlatRoundButton.Type.Secondary
icon.name: "external"
icon.width: 16
icon.height: 16
icon.color: Theme.palette.baseColor1
enabled: root.sendToAccountEnabled
onClicked: {
//TODO https://github.com/status-im/status-desktop/issues/13702
//on right click open menu
mainDisplayName: root.mainDisplayName
socialLinksModel: socialLinksProxyModel
onCopyToClipboard: root.copyToClipboard(text)
}
}
Component {
id: visitComunityPopupComponent
StatusDialog {
id: visitComunityPopup
// Community related props:
property string communityId
property string communityName
property string communityLogo
// Token related props:
property string tokenName
property string tokenImage
property bool isAssetType: false
width: 521 // by design
padding: 0
contentItem: StatusScrollView {
id: scrollView
padding: Style.current.padding
contentWidth: availableWidth
ColumnLayout {
width: scrollView.availableWidth
spacing: Style.current.padding
StatusBaseText {
Layout.fillWidth: true
text: visitComunityPopup.isAssetType ? qsTr("%1 is a community minted asset. Would you like to visit the community that minted it?").arg(visitComunityPopup.tokenName) :
qsTr("%1 is a community minted collectible. Would you like to visit the community that minted it?").arg(visitComunityPopup.tokenName)
textFormat: Text.RichText
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
lineHeight: 1.2
}
}
}
Item {
width: 279
height: 32
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
Rectangle {
anchors.fill: parent
color: Style.current.background
radius: 30
// Navigate to community button
StatusListItem {
Layout.fillWidth: true
Layout.bottomMargin: Style.current.halfPadding
title: visitComunityPopup.communityName
border.color: Theme.palette.baseColor2
}
Row {
anchors.centerIn: parent
spacing: 4
asset.name: visitComunityPopup.communityLogo
asset.isImage: true
asset.isLetterIdenticon: !asset.name
components: [
RowLayout {
StatusIcon {
width: 16
height: 16
icon: "info"
color: Theme.palette.directColor1
Layout.alignment: Qt.AlignVCenter
icon: "arrow-right"
color: Theme.palette.primaryColor1
}
StatusBaseText {
font.pixelSize: 13
text: qsTr("Social handles and links are unverified")
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Style.current.padding
text: visitComunityPopup.tokenName
font.pixelSize: Style.current.additionalTextSize
color: Theme.palette.primaryColor1
}
}
]
onClicked: {
Global.switchToCommunity(visitComunityPopup.communityId);
visitComunityPopup.close();
root.closeRequested();
}
}
}
}
header: StatusDialogHeader {
leftComponent: StatusRoundedImage {
Layout.alignment: Qt.AlignHCenter
Layout.margins: Style.current.padding
Layout.preferredWidth: 68
Layout.preferredHeight: Layout.preferredWidth
radius: visitComunityPopup.isAssetType ? width / 2 : 8
image.source: visitComunityPopup.tokenImage
showLoadingIndicator: false
image.fillMode: Image.PreserveAspectCrop
}
headline.title: visitComunityPopup.tokenName
headline.subtitle: qsTr("Minted by %1").arg(visitComunityPopup.communityName)
actions.closeButton.onClicked: { visitComunityPopup.close(); }
}
footer: StatusDialogFooter {
spacing: Style.current.padding
rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Cancel")
onClicked: {
visitComunityPopup.close();
}
}
}

View File

@ -46,6 +46,7 @@ QtObject {
signal markAsUntrustedRequested(string publicKey, var contactDetails)
signal removeContactRequested(string publicKey, var contactDetails)
signal openInviteFriendsToCommunityPopup(var community, var communitySectionModule, var cb)
signal openInviteFriendsToCommunityByIdPopup(string communityId, var cb)
signal openIncomingIDRequestPopup(string publicKey, var contactDetails, var cb)
signal openOutgoingIDRequestPopup(string publicKey, var contactDetails, var cb)
signal openDeleteMessagePopup(string messageId, var messageStore)