diff --git a/src/app/modules/shared_models/collectibles_model.nim b/src/app/modules/shared_models/collectibles_model.nim index 4e6f85d216..831c1d09eb 100644 --- a/src/app/modules/shared_models/collectibles_model.nim +++ b/src/app/modules/shared_models/collectibles_model.nim @@ -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() diff --git a/storybook/pages/ProfileDialogViewPage.qml b/storybook/pages/ProfileDialogViewPage.qml index 10e5dcd8d9..8946115ae2 100644 --- a/storybook/pages/ProfileDialogViewPage.qml +++ b/storybook/pages/ProfileDialogViewPage.qml @@ -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 diff --git a/storybook/src/Models/AssetsModel.qml b/storybook/src/Models/AssetsModel.qml index 378738db64..c85b17ea8d 100644 --- a/storybook/src/Models/AssetsModel.qml +++ b/storybook/src/Models/AssetsModel.qml @@ -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" } ] diff --git a/storybook/src/Models/ManageCollectiblesModel.qml b/storybook/src/Models/ManageCollectiblesModel.qml index e4b6d6cf15..14656fe328 100644 --- a/storybook/src/Models/ManageCollectiblesModel.qml +++ b/storybook/src/Models/ManageCollectiblesModel.qml @@ -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", diff --git a/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml b/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml index 481ab95817..516956ea79 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml @@ -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) } } diff --git a/ui/StatusQ/src/StatusQ/Popups/statusModal/StatusImageWithTitle.qml b/ui/StatusQ/src/StatusQ/Popups/statusModal/StatusImageWithTitle.qml index f1c7fcdf56..e56b20e925 100644 --- a/ui/StatusQ/src/StatusQ/Popups/statusModal/StatusImageWithTitle.qml +++ b/ui/StatusQ/src/StatusQ/Popups/statusModal/StatusImageWithTitle.qml @@ -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 diff --git a/ui/app/AppLayouts/Communities/controls/PermissionsRow.qml b/ui/app/AppLayouts/Communities/controls/PermissionsRow.qml index 914c7b148f..accccfac5e 100644 --- a/ui/app/AppLayouts/Communities/controls/PermissionsRow.qml +++ b/ui/app/AppLayouts/Communities/controls/PermissionsRow.qml @@ -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 { diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml index c1abceae44..a479b14640 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml @@ -93,6 +93,10 @@ QObject { function getShowcaseVisibility() { return Constants.ShowcaseVisibility.Everyone } + }, + FastExpressionRole { + name: "canReceiveFromMyAccounts" + expression: true } ] } diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml index 3907241adf..1237d5eb51 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml @@ -80,6 +80,13 @@ QObject { name: "showcaseKey" expression: model.address expectedRoles: ["address"] + }, + FastExpressionRole { + function canReceiveFromMyAccounts() { + return accountsSourceModel.count > 1 + } + name: "canReceiveFromMyAccounts" + expression: canReceiveFromMyAccounts() } ] } diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index 69a08dd10d..c8331074a4 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -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 diff --git a/ui/imports/assets/png/profile/gradient.png b/ui/imports/assets/png/profile/gradient.png new file mode 100644 index 0000000000..1bcca8be20 Binary files /dev/null and b/ui/imports/assets/png/profile/gradient.png differ diff --git a/ui/imports/assets/png/profile/gradient2x.png b/ui/imports/assets/png/profile/gradient2x.png new file mode 100644 index 0000000000..888e6eace5 Binary files /dev/null and b/ui/imports/assets/png/profile/gradient2x.png differ diff --git a/ui/imports/shared/controls/ExpandableTag.qml b/ui/imports/shared/controls/ExpandableTag.qml new file mode 100644 index 0000000000..5daf746769 --- /dev/null +++ b/ui/imports/shared/controls/ExpandableTag.qml @@ -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 + } + } +} diff --git a/ui/imports/shared/controls/delegates/InfoCard.qml b/ui/imports/shared/controls/delegates/InfoCard.qml index 33e66644b8..ddd9e0b4a6 100644 --- a/ui/imports/shared/controls/delegates/InfoCard.qml +++ b/ui/imports/shared/controls/delegates/InfoCard.qml @@ -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); + } + } } } } diff --git a/ui/imports/shared/controls/qmldir b/ui/imports/shared/controls/qmldir index 00ee697c70..ba80d1d752 100644 --- a/ui/imports/shared/controls/qmldir +++ b/ui/imports/shared/controls/qmldir @@ -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 diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml index 666e5d8cbd..10cbae9f5e 100644 --- a/ui/imports/shared/views/ProfileDialogView.qml +++ b/ui/imports/shared/views/ProfileDialogView.qml @@ -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) } diff --git a/ui/imports/shared/views/profile/ProfileShowcaseAccountsView.qml b/ui/imports/shared/views/profile/ProfileShowcaseAccountsView.qml new file mode 100644 index 0000000000..5b8c723cb6 --- /dev/null +++ b/ui/imports/shared/views/profile/ProfileShowcaseAccountsView.qml @@ -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 + } +} diff --git a/ui/imports/shared/views/profile/ProfileShowcaseAssetsView.qml b/ui/imports/shared/views/profile/ProfileShowcaseAssetsView.qml new file mode 100644 index 0000000000..6e9410c441 --- /dev/null +++ b/ui/imports/shared/views/profile/ProfileShowcaseAssetsView.qml @@ -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)); + } + } + } + } +} \ No newline at end of file diff --git a/ui/imports/shared/views/profile/ProfileShowcaseCollectiblesView.qml b/ui/imports/shared/views/profile/ProfileShowcaseCollectiblesView.qml new file mode 100644 index 0000000000..25c80a130d --- /dev/null +++ b/ui/imports/shared/views/profile/ProfileShowcaseCollectiblesView.qml @@ -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)); + } + } + } + } +} \ No newline at end of file diff --git a/ui/imports/shared/views/profile/ProfileShowcaseCommunitiesView.qml b/ui/imports/shared/views/profile/ProfileShowcaseCommunitiesView.qml new file mode 100644 index 0000000000..b6b636c49c --- /dev/null +++ b/ui/imports/shared/views/profile/ProfileShowcaseCommunitiesView.qml @@ -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("You’re 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) + } + } + } + } +} diff --git a/ui/imports/shared/views/profile/ProfileShowcaseSocialLinksView.qml b/ui/imports/shared/views/profile/ProfileShowcaseSocialLinksView.qml new file mode 100644 index 0000000000..be761e315e --- /dev/null +++ b/ui/imports/shared/views/profile/ProfileShowcaseSocialLinksView.qml @@ -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); + } + } + } + } +} diff --git a/ui/imports/shared/views/profile/ProfileShowcaseView.qml b/ui/imports/shared/views/profile/ProfileShowcaseView.qml index c6e31be1c2..be501598f8 100644 --- a/ui/imports/shared/views/profile/ProfileShowcaseView.qml +++ b/ui/imports/shared/views/profile/ProfileShowcaseView.qml @@ -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("You’re there too") - } - } - } - } + cellWidth: d.delegateWidthM + cellHeight: d.delegateHeightM - Component { - id: permissionsRowComponent - PermissionsRow { - hoverEnabled: false - assetsModel: root.globalAssetsModel - collectiblesModel: root.globalCollectiblesModel - model: profileDialogCommunityCard.permissionsList - requirementsMet: profileDialogCommunityCard.requirementsMet - } - } + mainDisplayName: root.mainDisplayName + readOnly: root.readOnly + globalAssetsModel: root.globalAssetsModel + globalCollectiblesModel: root.globalCollectiblesModel - 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 - } - } - } - } + communitiesProxyModel: communitiesProxyModel + + onCloseRequested: root.closeRequested() + onCopyToClipboard: root.copyToClipboard(text) } - // 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 - 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 - // } - // } + mainDisplayName: root.mainDisplayName + sendToAccountEnabled: root.sendToAccountEnabled + accountsModel: accountsProxyModel + walletStore: root.walletStore - // 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); - // } - // } - // ] - // } - } + cellWidth: d.delegateWidthM + cellHeight: d.delegateHeightM + + onCopyToClipboard: root.copyToClipboard(text) + } + + ProfileShowcaseCollectiblesView { + width: parent.width + height: parent.height + + cellWidth: d.delegateWidthS + cellHeight: d.delegateHeightS + + mainDisplayName: root.mainDisplayName + collectiblesModel: collectiblesProxyModel + walletStore: root.walletStore + + onCloseRequested: root.closeRequested() + onVisitCommunity: { + Global.openPopup(visitComunityPopupComponent, {communityId: model.communityId, communityName: model.communityName, + communityLogo: model.communityImage, tokenName: model.name, + tokenImage: model.imageUrl, isAssetType: false }); } } - // 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 - 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 ?? "" + // ProfileShowcaseAssetsView { + // width: parent.width + // height: parent.height - 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 + // assetsModel: assetsProxyModel + // sendToAccountEnabled: root.sendToAccountEnabled + // delegatesActionsMenu: delegatesActionsMenu - background: Rectangle { - radius: 30 - color: Theme.palette.indirectColor2 - } + // cellHeight: d.delegateHeightS + // cellWidth: d.delegateWidthS - contentItem: StatusBaseText { - id: amountText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pixelSize: Style.current.asideTextFontSize - text: "x"+model.userHas - } - } - - 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 - // 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: 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 ? "↓" : "↑" - - // // 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) - } + ProfileShowcaseSocialLinksView { + width: parent.width + height: parent.height - 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 + cellWidth: d.delegateWidthS + cellHeight: d.delegateHeightS - StatusGridView { - id: webView - width: 608 - 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 + } + + // Navigate to community button + StatusListItem { + Layout.fillWidth: true + Layout.bottomMargin: Style.current.halfPadding + + title: visitComunityPopup.communityName + border.color: Theme.palette.baseColor2 + asset.name: visitComunityPopup.communityLogo + asset.isImage: true + asset.isLetterIdenticon: !asset.name + components: [ + RowLayout { + StatusIcon { + Layout.alignment: Qt.AlignVCenter + icon: "arrow-right" + color: Theme.palette.primaryColor1 + } + + StatusBaseText { + 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(); } } } - 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 - 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") + 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(); } } } diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml index 9cbca6857b..4d0628d975 100644 --- a/ui/imports/utils/Global.qml +++ b/ui/imports/utils/Global.qml @@ -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)