From 4af2a9735817056cdf9b87d678376b405c3ac248 Mon Sep 17 00:00:00 2001 From: Alexandra Betouni <31625338+alexandraB99@users.noreply.github.com> Date: Thu, 15 Feb 2024 11:25:40 +0200 Subject: [PATCH] [ProfileShowcase] Updated delegates as per design + added web tab Closes #13421 Closes #13606 --- storybook/pages/ProfileDialogViewPage.qml | 36 +- storybook/src/Models/CommunitiesModel.qml | 32 +- .../src/Models/ManageCollectiblesModel.qml | 9 +- .../StatusAppCommunitiesPortalView.qml | 4 +- .../sandbox/pages/StatusCommunityCardPage.qml | 2 +- .../Components/StatusCommunityCard.qml | 167 ++-- .../Components/StatusSmartIdenticon.qml | 1 + .../src/assets/img/icons/tiny/locked.svg | 4 +- .../src/assets/img/icons/tiny/unlocked.svg | 4 +- .../Communities/views/CommunitiesGridView.qml | 2 +- ui/app/AppLayouts/Profile/ProfileLayout.qml | 3 + .../Profile/stores/ProfileSectionStore.qml | 1 + .../Profile/views/MyProfileView.qml | 9 + .../views/profile/MyProfilePreview.qml | 2 + .../controls/ManageTokensCommunityTag.qml | 6 +- ui/app/AppLayouts/stores/RootStore.qml | 29 +- ui/app/mainui/AppMain.qml | 24 +- ui/app/mainui/Popups.qml | 3 + .../shared/controls/delegates/InfoCard.qml | 120 +++ ui/imports/shared/controls/delegates/qmldir | 1 + ui/imports/shared/popups/ProfileDialog.qml | 3 + ui/imports/shared/views/ProfileDialogView.qml | 10 +- .../views/profile/ProfileShowcaseView.qml | 726 +++++++++++++----- 23 files changed, 882 insertions(+), 316 deletions(-) create mode 100644 ui/imports/shared/controls/delegates/InfoCard.qml diff --git a/storybook/pages/ProfileDialogViewPage.qml b/storybook/pages/ProfileDialogViewPage.qml index 86d689609c..10e5dcd8d9 100644 --- a/storybook/pages/ProfileDialogViewPage.qml +++ b/storybook/pages/ProfileDialogViewPage.qml @@ -124,6 +124,35 @@ SplitView { } } + ListModel { + id: linksModel + ListElement { + uuid: "0001" + text: "__github" + url: "https://github.com/caybro" + } + ListElement { + uuid: "0002" + text: "__twitter" + url: "https://twitter.com/caybro" + } + ListElement { + uuid: "0003" + text: "__personal_site" + url: "https://status.im" + } + ListElement { + uuid: "0004" + text: "__youtube" + url: "https://www.youtube.com/@LukasTinkl" + } + ListElement { + uuid: "0006" + text: "__telegram" + url: "https://t.me/ltinkl" + } + } + Logs { id: logs } Popups { @@ -281,9 +310,9 @@ SplitView { sourceComponent: ProfileDialogView { implicitWidth: 640 + enabledNetworks: NetworksModel.allNetworks readOnly: ctrlReadOnly.checked - publicKey: switchOwnProfile.checked ? "0xdeadbeef" : "0xrandomguy" onCloseRequested: logs.logEvent("closeRequested()") @@ -293,9 +322,12 @@ SplitView { showcaseCommunitiesModel: CommunitiesModel {} showcaseAccountsModel: WalletAccountsModel {} showcaseCollectiblesModel: ManageCollectiblesModel {} - showcaseSocialLinksModel: assetsStore.groupedAccountAssetsModel + showcaseSocialLinksModel: linksModel // TODO: showcaseAssetsModel + assetsModel: AssetsModel {} + collectiblesModel: CollectiblesModel {} + profileStore: QtObject { readonly property string pubkey: "0xdeadbeef" readonly property string ensName: name.text diff --git a/storybook/src/Models/CommunitiesModel.qml b/storybook/src/Models/CommunitiesModel.qml index 1fb37bec96..96b1f02fc2 100644 --- a/storybook/src/Models/CommunitiesModel.qml +++ b/storybook/src/Models/CommunitiesModel.qml @@ -19,7 +19,9 @@ ListModel { muted: false, members: [ { pubKey: "0xdeadbeef" } ], membersCount: 1, - loading: false + loading: false, + permissionsModel: null, + allTokenRequirementsMet: false }, { id: "0x0002", @@ -36,7 +38,9 @@ ListModel { muted: false, members: [ { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" } ], membersCount: 3, - loading: false + loading: false, + permissionsModel: null, + allTokenRequirementsMet: false }, { id: "0x0003", @@ -48,12 +52,14 @@ ListModel { spectated: true, memberRole: Constants.memberRole.none, isControlNode: false, - image: ModelsData.icons.coinbase, + image: ModelsData.icons.dragonereum, color: "red", muted: false, members: [ { pubKey: "0xdeadbeef" } ], membersCount: 1, - loading: false + loading: false, + permissionsModel: PermissionsModel.moreThanTwoInitialShortPermissionsModel, + allTokenRequirementsMet: false }, { id: "0x0004", @@ -65,12 +71,14 @@ ListModel { spectated: false, memberRole: Constants.memberRole.none, isControlNode: false, - image: "", + image: ModelsData.icons.coinbase, color: "whitesmoke", muted: true, members: [], membersCount: 0, - loading: false + loading: false, + permissionsModel: null, + allTokenRequirementsMet: false }, { id: "0x0005", @@ -87,7 +95,9 @@ ListModel { muted: false, members: [{ pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }], membersCount: 4, - loading: false + loading: false, + permissionsModel: null, + allTokenRequirementsMet: false }, { id: "0x0006", @@ -104,7 +114,9 @@ ListModel { muted: false, members: [{ pubKey: "0xdeadbeef" }], membersCount: 1, - loading: false + loading: false, + permissionsModel: null, + allTokenRequirementsMet: false }, { id: "0x0007", @@ -120,7 +132,9 @@ ListModel { muted: false, members: [{ pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }], membersCount: 2, - loading: false + loading: false, + permissionsModel: null, + allTokenRequirementsMet: false } ]) } diff --git a/storybook/src/Models/ManageCollectiblesModel.qml b/storybook/src/Models/ManageCollectiblesModel.qml index b65a8cc2f5..f67db0302b 100644 --- a/storybook/src/Models/ManageCollectiblesModel.qml +++ b/storybook/src/Models/ManageCollectiblesModel.qml @@ -19,12 +19,13 @@ ListModel { { uid: "123", chainId: 5, + userHas: 9, name: "Punx not dead!", collectionUid: "", collectionName: "", communityId: "", communityName: "", - communityImage: "", + communityImage: ModelsData.icons.status, imageUrl: ModelsData.collectibles.cryptoPunks, isLoading: false, backgroundColor: "", @@ -44,6 +45,7 @@ ListModel { { uid: "pp23", chainId: 5, + userHas: 0, name: "pepepunk#23", collectionUid: "pepepunks", collectionName: "Pepepunks", @@ -64,6 +66,7 @@ ListModel { { uid: "34545656768", chainId: 420, + userHas: 1, name: "Kitty 1", collectionUid: "KT", collectionName: "Kitties", @@ -84,6 +87,7 @@ ListModel { { uid: "123456", chainId: 420, + userHas: 0, name: "Kitty 2", collectionUid: "KT", collectionName: "Kitties", @@ -104,6 +108,7 @@ ListModel { { uid: "12345645459537432", chainId: 421613, + userHas: 0, name: "Big Kitty", collectionUid: "KT", collectionName: "Kitties", @@ -129,6 +134,7 @@ ListModel { { uid: "pp21", chainId: 421613, + userHas: 0, name: "pepepunk#21", collectionUid: "pepepunks", collectionName: "Pepepunks", @@ -149,6 +155,7 @@ ListModel { { uid: "lp#666a", chainId: 421613, + userHas: 0, name: "Lonely Panda #666", collectionUid: "lpan_collection", collectionName: "Lonely Panda Collection", diff --git a/ui/StatusQ/sandbox/demoapp/StatusAppCommunitiesPortalView.qml b/ui/StatusQ/sandbox/demoapp/StatusAppCommunitiesPortalView.qml index b9746a74a6..e7dca33ce1 100644 --- a/ui/StatusQ/sandbox/demoapp/StatusAppCommunitiesPortalView.qml +++ b/ui/StatusQ/sandbox/demoapp/StatusAppCommunitiesPortalView.qml @@ -100,7 +100,7 @@ StatusSectionLayout { locale: Qt.locale("es") communityId: model.communityId loaded: model.available - logo: model.logo + asset.source: model.logo name: model.name description: model.description members: model.members @@ -138,7 +138,7 @@ StatusSectionLayout { locale: Qt.locale("es") communityId: model.communityId loaded: model.available - logo: model.logo + asset.source: model.logo name: model.name description: model.description members: model.members diff --git a/ui/StatusQ/sandbox/pages/StatusCommunityCardPage.qml b/ui/StatusQ/sandbox/pages/StatusCommunityCardPage.qml index d6794d5af2..a430c07ea7 100644 --- a/ui/StatusQ/sandbox/pages/StatusCommunityCardPage.qml +++ b/ui/StatusQ/sandbox/pages/StatusCommunityCardPage.qml @@ -26,7 +26,7 @@ GridLayout { locale: Qt.locale("en") communityId: model.communityId loaded: model.available - logo: model.logo + asset.source: model.logo banner: model.banner name: model.name description: model.description diff --git a/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml b/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml index 11c87b5144..481ab95817 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusCommunityCard.qml @@ -22,7 +22,7 @@ import StatusQ.Core.Theme 0.1 locale: "en" communityId: model.communityId loaded: model.available - logo: model.icon + asset.source: model.icon name: model.name description: model.description members: model.members @@ -37,6 +37,31 @@ import StatusQ.Core.Theme 0.1 Rectangle { id: root + property int cardSize: StatusCommunityCard.Size.Big + enum Size { + Big, + Small + } + /*! + \qmlproperty bool StatusCommunityCard::memberCountVisible + This property sets the member's count visibility. + */ + property bool memberCountVisible: true + /*! + \qmlproperty bool StatusCommunityCard::hovered + This property indicates whether the card contains mouse. + */ + property bool hovered: sensor.containsMouse + /*! + \qmlproperty int StatusCommunityCard::titleFontSize + This property holds the title's font size. + */ + property int titleFontSize: 19 + /*! + \qmlproperty int StatusCommunityCard::descriptionFontSize + This property holds the description's font size. + */ + property int descriptionFontSize: 15 /*! \qmlproperty string StatusCommunityCard::communityId This property holds the community identifier value. @@ -47,11 +72,6 @@ Rectangle { This property holds a boolean value that represents if the community information is loaded or not. */ property bool loaded: true - /*! - \qmlproperty url StatusCommunityCard::logo - This property holds the community logo source. - */ - property url logo: "" /*! \qmlproperty string StatusCommunityCard::name This property holds the community name. @@ -122,6 +142,28 @@ Rectangle { */ property alias rigthHeaderComponent: rightHeaderLoader.sourceComponent + /*! + \qmlproperty Item StatusCommunityCard::bottomRowComponent + This property holds an extra info bottom row component that will be displayed on bottom left of the card. + Example: Community token permissions row. + */ + property alias bottomRowComponent: bottomRowLoader.sourceComponent + /*! + \qmlproperty color StatusCommunityCard::descriptionFontColor + This property holds the description font color. + If not provided, default value in Light Theme is "#000000" and in Dark Theme is "#FFFFFF". + */ + property color descriptionFontColor: Theme.palette.directColor1 + + /*! + \qmlproperty StatusAssetSettings StatusCommunityCard::asset + This property holds the card's asset settings for the logo image. + */ + property StatusAssetSettings asset: StatusAssetSettings { + height: 40 + width: 40 + } + /*! \qmlsignal StatusCommunityCard::clicked(string communityId) This signal is emitted when the card item is clicked. @@ -131,11 +173,12 @@ Rectangle { QtObject { id: d readonly property int cardWidth: 335 - readonly property int bannerHeigth: 64 - readonly property int cardHeigth: 190 - readonly property int totalHeigth: 230 + readonly property int bannerHeight: (root.cardSize === StatusCommunityCard.Size.Big) ? 64 : 55 + 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: 20 + readonly property int bannerRadius: (root.cardSize === StatusCommunityCard.Size.Big) ? 20 : 16 + readonly property int bannerRadiusHovered: (root.cardSize === StatusCommunityCard.Size.Big) ? 30 : 16 readonly property int cardRadius: 16 readonly property color cardColor: Theme.palette.name === "light" ? Theme.palette.indirectColor1 : Theme.palette.baseColor2 readonly property color fontColor: Theme.palette.directColor1 @@ -169,7 +212,7 @@ Rectangle { source: root horizontalOffset: 0 verticalOffset: 2 - radius: sensor.containsMouse ? 30 : d.bannerRadius + radius: sensor.containsMouse ? d.bannerRadiusHovered : d.bannerRadius samples: 25 spread: 0 color: sensor.containsMouse ? Theme.palette.backdropColor : Theme.palette.dropShadow @@ -181,7 +224,7 @@ Rectangle { anchors.top: parent.top width: parent.width - height: d.bannerHeigth + height: d.bannerHeight Rectangle { id: mask @@ -220,10 +263,10 @@ Rectangle { Rectangle { z: content.z + 1 anchors.top: parent.top - anchors.topMargin: 16 + anchors.topMargin: (root.cardSize === StatusCommunityCard.Size.Big) ? 16 : 8 anchors.left: parent.left anchors.leftMargin: 12 - width: 48 + width: root.asset.width + 4 height: width radius: width / 2 color: root.loaded ? d.cardColor : d.loadingColor1 @@ -233,7 +276,7 @@ Rectangle { anchors.centerIn: parent width: parent.width - 4 height: width - image.source: root.logo + image.source: root.asset.source color: "transparent" } } // End of community logo @@ -244,8 +287,8 @@ Rectangle { z: banner.z + 1 visible: root.loaded anchors.top: parent.top - anchors.topMargin: 40 - width: d.cardWidth + anchors.topMargin: (root.cardSize === StatusCommunityCard.Size.Big) ? 40 : 23 + width: parent.width height: d.cardHeigth color: d.cardColor radius: d.cardRadius @@ -262,27 +305,29 @@ Rectangle { // Community info ColumnLayout { - anchors.fill: parent - anchors.topMargin: 32 + anchors.top: parent.top + anchors.topMargin: (root.cardSize === StatusCommunityCard.Size.Big) ? 32 : 26 + anchors.left: parent.left anchors.leftMargin: d.margins + anchors.right: parent.right anchors.rightMargin: d.margins - anchors.bottomMargin: d.margins - clip: true - spacing: 6 + spacing: (root.cardSize === StatusCommunityCard.Size.Big) ? 6 : 0 StatusBaseText { Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true text: root.name font.weight: Font.Bold - font.pixelSize: 19 + font.pixelSize: root.titleFontSize color: d.fontColor + elide: Text.ElideRight } StatusBaseText { Layout.fillWidth: true Layout.fillHeight: true text: root.description - font.pixelSize: 15 + font.pixelSize: root.descriptionFontSize lineHeight: 1.2 - color: d.fontColor + color: root.descriptionFontColor maximumLineCount: 2 wrapMode: Text.WordWrap elide: Text.ElideRight @@ -290,17 +335,18 @@ Rectangle { } } ColumnLayout { - anchors.fill: parent - anchors.topMargin: 116 + anchors.bottom: parent.bottom + anchors.left: parent.left anchors.leftMargin: d.margins + anchors.right: parent.right anchors.rightMargin: d.margins anchors.bottomMargin: d.margins - clip: true - spacing: 18 + spacing: (root.cardSize === StatusCommunityCard.Size.Big) ? 18 : 0 Row { Layout.alignment: Qt.AlignVCenter spacing: 20 // Members + visible: root.memberCountVisible Row { height: membersTxt.height spacing: 4 @@ -338,39 +384,46 @@ Rectangle { } } - StatusRollArea { - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true + // Bottom Row extra info component + Loader { + id: bottomRowLoader + Layout.fillWidth: (!!item && item.width===0) + Layout.preferredHeight: 24 + active: ((root.categories.count > 0) || !!root.bottomRowComponent) + sourceComponent: tagsListComponent + } - visible: root.categories.count > 0 - arrowsGradientColor: d.cardColor + Component { + id: tagsListComponent + StatusRollArea { + arrowsGradientColor: d.cardColor - // TODO: Replace by `StatusListItemTagRow` - To be done! - content: Row { - spacing: 8 - clip: true + // TODO: Replace by `StatusListItemTagRow` - To be done! + content: Row { + spacing: 8 + clip: true - Repeater { - model: root.categories - delegate: StatusListItemTag { - bgColor: "transparent" - bgRadius: 20 - bgBorderColor: Theme.palette.baseColor2 - height: 24 - closeButtonVisible: false - asset.emoji: model.emoji - asset.width: 24 - asset.height: 24 - asset.color: "transparent" - asset.isLetterIdenticon: true - title: model.name - titleText.font.pixelSize: 13 - titleText.color: d.fontColor + Repeater { + model: root.categories + delegate: StatusListItemTag { + bgColor: "transparent" + bgRadius: 20 + bgBorderColor: Theme.palette.baseColor2 + height: 24 + closeButtonVisible: false + asset.emoji: model.emoji + asset.width: 24 + asset.height: 24 + asset.color: "transparent" + asset.isLetterIdenticon: true + title: model.name + titleText.font.pixelSize: 13 + titleText.color: d.fontColor + } } } } } - } } // End of content card @@ -378,8 +431,8 @@ Rectangle { Rectangle { visible: !root.loaded anchors.top: parent.top - anchors.topMargin: 40 - width: d.cardWidth + anchors.topMargin: (root.cardSize === StatusCommunityCard.Size.Big) ? 40 : 23 + width: parent.width height: d.cardHeigth color: d.cardColor radius: d.cardRadius diff --git a/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml b/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml index b1d64f44c5..127c0aa982 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml @@ -3,6 +3,7 @@ import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 + Loader { id: root diff --git a/ui/StatusQ/src/assets/img/icons/tiny/locked.svg b/ui/StatusQ/src/assets/img/icons/tiny/locked.svg index 5a5e54adba..5b5a133313 100644 --- a/ui/StatusQ/src/assets/img/icons/tiny/locked.svg +++ b/ui/StatusQ/src/assets/img/icons/tiny/locked.svg @@ -1,3 +1,3 @@ - - + + diff --git a/ui/StatusQ/src/assets/img/icons/tiny/unlocked.svg b/ui/StatusQ/src/assets/img/icons/tiny/unlocked.svg index d08af20512..377d8c4bea 100644 --- a/ui/StatusQ/src/assets/img/icons/tiny/unlocked.svg +++ b/ui/StatusQ/src/assets/img/icons/tiny/unlocked.svg @@ -1,3 +1,3 @@ - - + + diff --git a/ui/app/AppLayouts/Communities/views/CommunitiesGridView.qml b/ui/app/AppLayouts/Communities/views/CommunitiesGridView.qml index 0f0c6c7fe7..d2f854917a 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitiesGridView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitiesGridView.qml @@ -74,7 +74,7 @@ StatusScrollView { communityId: model.id loaded: model.available - logo: model.icon + asset.source: model.icon banner: model.banner communityColor: model.color name: model.name diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index 77077ff060..2e347ec7f6 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -150,6 +150,9 @@ StatusSectionLayout { accountsShowcaseModel: root.store.ownShowcaseAccountsModel collectiblesShowcaseModel: root.store.ownShowcaseCollectiblesModel socialLinksShowcaseModel: root.store.ownShowcaseSocialLinksModel + + assetsModel: root.globalStore.globalAssetsModel + collectiblesModel: root.globalStore.globalCollectiblesModel } } diff --git a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml index af6d9d42e7..6853c30916 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml @@ -81,6 +81,7 @@ QtObject { property bool walletMenuItemEnabled: profileStore.isWalletEnabled property var communitiesModuleInst: Global.appIsReady? communitiesModule : null + property var communitiesList: SortFilterProxyModel { sourceModel: root.mainModuleInst.sectionsModel filters: ValueFilter { diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml index ca2c064225..8cac7e5bdf 100644 --- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml +++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml @@ -38,6 +38,9 @@ SettingsContentBase { property alias collectiblesShowcaseModel: showcaseModels.collectiblesSourceModel property alias socialLinksShowcaseModel: showcaseModels.socialLinksSourceModel + property var assetsModel + property var collectiblesModel + property bool sideBySidePreview property bool toastClashesWithDirtyBubble readonly property alias sideBySidePreviewComponent: myProfilePreviewComponent @@ -400,6 +403,9 @@ SettingsContentBase { showcaseCollectiblesModel: priv.showcaseModels.collectiblesVisibleModel showcaseSocialLinksModel: priv.showcaseModels.socialLinksVisibleModel //showcaseAssetsModel: priv.showcaseModels.assetsVisibleModel + + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel } } @@ -417,6 +423,9 @@ SettingsContentBase { showcaseCollectiblesModel: priv.showcaseModels.collectiblesVisibleModel showcaseSocialLinksModel: priv.showcaseModels.socialLinksVisibleModel //showcaseAssetsModel: priv.showcaseModels.assetsVisibleModel + + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel } } diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml index 87e2b41017..92a5abdb68 100644 --- a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml +++ b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml @@ -21,6 +21,8 @@ Item { property alias showcaseSocialLinksModel: profilePreview.showcaseSocialLinksModel property alias showcaseAssetsModel: profilePreview.showcaseAssetsModel + property alias assetsModel: profilePreview.assetsModel + property alias collectiblesModel: profilePreview.collectiblesModel implicitHeight: profilePreview.implicitHeight + layout.anchors.topMargin diff --git a/ui/app/AppLayouts/Wallet/controls/ManageTokensCommunityTag.qml b/ui/app/AppLayouts/Wallet/controls/ManageTokensCommunityTag.qml index 0ab79b0b83..d307245b57 100644 --- a/ui/app/AppLayouts/Wallet/controls/ManageTokensCommunityTag.qml +++ b/ui/app/AppLayouts/Wallet/controls/ManageTokensCommunityTag.qml @@ -49,8 +49,8 @@ Control { visible: !root.loading StatusSmartIdenticon { id: identicon - Layout.preferredWidth: visible ? 16 : 0 - Layout.preferredHeight: visible ? 16 : 0 + Layout.preferredWidth: visible ? asset.width : 0 + Layout.preferredHeight: visible ? asset.width : 0 asset.width: 16 asset.height: 16 visible: root.useLongTextDescription && !!asset.source @@ -64,7 +64,7 @@ Control { StatusBaseText { Layout.fillWidth: true - + visible: (!!root.communityName || d.unknownCommunityName) font.pixelSize: Style.current.tertiaryTextFontSize font.weight: Font.Medium text: { diff --git a/ui/app/AppLayouts/stores/RootStore.qml b/ui/app/AppLayouts/stores/RootStore.qml index 269d141c2b..4aeebe4c4c 100644 --- a/ui/app/AppLayouts/stores/RootStore.qml +++ b/ui/app/AppLayouts/stores/RootStore.qml @@ -58,8 +58,10 @@ QtObject { root.communitiesModuleInst.myRevealedAirdropAddressForCurrentCommunity.toLowerCase() property var walletAccountsModel: WalletStore.RootStore.nonWatchAccounts - property var assetsModel: SortFilterProxyModel { + + readonly property var globalAssetsModel: SortFilterProxyModel { sourceModel: communitiesModuleInst.tokenList + proxyRoles: ExpressionRole { function tokenIcon(symbol) { return Constants.tokenIcon(symbol) @@ -67,6 +69,22 @@ QtObject { name: "iconSource" expression: !!model.icon ? model.icon : tokenIcon(model.symbol) } + } + + readonly property var globalCollectiblesModel: SortFilterProxyModel { + sourceModel: communitiesModuleInst.collectiblesModel + + proxyRoles: ExpressionRole { + function icon(icon) { + return !!icon ? icon : Style.png("tokens/DEFAULT-TOKEN") + } + name: "iconSource" + expression: icon(model.icon) + } + } + + property var assetsModel: SortFilterProxyModel { + sourceModel: globalAssetsModel filters: [ AnyOf { // We accept tokens from this community or general (empty community ID) @@ -83,14 +101,7 @@ QtObject { ] } property var collectiblesModel: SortFilterProxyModel { - sourceModel: communitiesModuleInst.collectiblesModel - proxyRoles: ExpressionRole { - function collectibleIcon(icon) { - return !!icon ? icon : Style.png("tokens/DEFAULT-TOKEN") - } - name: "iconSource" - expression: collectibleIcon(model.icon) - } + sourceModel: globalCollectiblesModel filters: [ AnyOf { // We accept tokens from this community or general (empty community ID) diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 1a936c07da..5c99763428 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -1270,28 +1270,8 @@ Item { CommunitiesPortalLayout { anchors.fill: parent communitiesStore: appMain.communitiesStore - assetsModel: SortFilterProxyModel { - sourceModel: appMain.communitiesStore.communitiesModuleInst.tokenList - - proxyRoles: ExpressionRole { - function tokenIcon(symbol) { - return Constants.tokenIcon(symbol) - } - name: "iconSource" - expression: !!model.icon ? model.icon : tokenIcon(model.symbol) - } - } - collectiblesModel: SortFilterProxyModel { - sourceModel: appMain.communitiesStore.communitiesModuleInst.collectiblesModel - - proxyRoles: ExpressionRole { - function icon(icon) { - return !!icon ? icon : Style.png("tokens/DEFAULT-TOKEN") - } - name: "iconSource" - expression: icon(model.icon) - } - } + assetsModel: appMain.rootStore.globalAssetsModel + collectiblesModel: appMain.rootStore.globalCollectiblesModel notificationCount: appMain.activityCenterStore.unreadNotificationsCount hasUnseenNotifications: activityCenterStore.hasUnseenNotifications } diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index 03ca7c95b2..df66889b0e 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -545,6 +545,9 @@ QtObject { showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel : rootStore.profileSectionStore.contactShowcaseCollectiblesModel showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel : rootStore.profileSectionStore.contactShowcaseSocialLinksModel + assetsModel: rootStore.globalAssetsModel + collectiblesModel: rootStore.globalCollectiblesModel + onOpened: { isCurrentUser ? rootStore.profileSectionStore.requestOwnShowcase() : rootStore.profileSectionStore.requestContactShowcase(publicKey) diff --git a/ui/imports/shared/controls/delegates/InfoCard.qml b/ui/imports/shared/controls/delegates/InfoCard.qml new file mode 100644 index 0000000000..33e66644b8 --- /dev/null +++ b/ui/imports/shared/controls/delegates/InfoCard.qml @@ -0,0 +1,120 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import StatusQ.Core 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Core.Theme 0.1 + +import StatusQ.Components 0.1 +import AppLayouts.Wallet.controls 1.0 + +import utils 1.0 + +Control { + id: root + + padding: 12 + + property string title: "" + property string subTitle: "" + property string tagIcon: "" + property var enabledNetworks + property bool loading: false + property alias rightSideButtons: rightSideButtonsLoader.sourceComponent + + property StatusAssetSettings asset: StatusAssetSettings { + height: 32 + width: 32 + bgRadius: bgWidth / 2 + } + + background: Rectangle { + anchors.fill: parent + color: Style.current.background + radius: Style.current.radius + border.width: 1 + border.color: Theme.palette.baseColor2 + } + + contentItem: Item { + ColumnLayout { + id: titleColumn + anchors.fill: parent + spacing: 0 + + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: root.asset.height + StatusSmartIdenticon { + asset: root.asset + active: ((root.asset.isLetterIdenticon || + !!root.asset.name || + !!root.asset.emoji) && !root.showLoadingIndicator) + loading: root.loading + } + Item { Layout.fillWidth: true } + Loader { + id: rightSideButtonsLoader + Layout.alignment: Qt.AlignRight + } + } + + StatusTextWithLoadingState { + text: root.title + Layout.preferredHeight: 22 + Layout.topMargin: Style.current.halfPadding + Layout.fillWidth: true + elide: Text.ElideRight + font.weight: Font.Medium + loading: root.loading + } + + StatusTextWithLoadingState { + id: statusListItemSubTitle + objectName: "statusListItemSubTitle" + Layout.fillWidth: true + Layout.preferredHeight: 16 + text: root.subTitle + font.pixelSize: Style.current.tertiaryTextFontSize + lineHeight: 16 + customColor: !root.enabled || !root.tertiaryTitle ? + Theme.palette.baseColor1 : Theme.palette.directColor1 + visible: !!root.subTitle + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + loading: root.loading + maximumLineCount: 3 + elide: Text.ElideRight + } + Item { Layout.fillHeight: true } + Row { + Layout.fillWidth: true + Layout.preferredHeight: 20 + spacing: -4 + visible: (chainRepeater.count > 0) + Repeater { + id: chainRepeater + model: root.enabledNetworks + delegate: StatusRoundedImage { + width: 20 + height: 20 + visible: image.source !== "" + image.source: Style.svg(model.iconUrl) + z: index + 1 + } + } + } + + ManageTokensCommunityTag { + Layout.preferredWidth: 24 + Layout.preferredHeight: 24 + horizontalPadding: 2 + verticalPadding: 0 + spacing: 0 + visible: !!root.tagIcon + asset.name: root.tagIcon + asset.width: 20 + asset.height: 20 + } + } + } +} diff --git a/ui/imports/shared/controls/delegates/qmldir b/ui/imports/shared/controls/delegates/qmldir index 81e214886b..45e2a69f02 100644 --- a/ui/imports/shared/controls/delegates/qmldir +++ b/ui/imports/shared/controls/delegates/qmldir @@ -2,3 +2,4 @@ ContactListItemDelegate 1.0 ContactListItemDelegate.qml LinkPreviewCardDelegate 1.0 LinkPreviewCardDelegate.qml LinkPreviewGifDelegate 1.0 LinkPreviewGifDelegate.qml LinkPreviewMiniCardDelegate 1.0 LinkPreviewMiniCardDelegate.qml +InfoCard 1.0 InfoCard.qml diff --git a/ui/imports/shared/popups/ProfileDialog.qml b/ui/imports/shared/popups/ProfileDialog.qml index d0df32a195..714673c800 100644 --- a/ui/imports/shared/popups/ProfileDialog.qml +++ b/ui/imports/shared/popups/ProfileDialog.qml @@ -23,6 +23,9 @@ StatusDialog { property alias showcaseSocialLinksModel: profileView.showcaseSocialLinksModel property alias showcaseAssetsModel: profileView.showcaseAssetsModel + property alias assetsModel: profileView.assetsModel + property alias collectiblesModel: profileView.collectiblesModel + property alias dirtyValues: profileView.dirtyValues property alias dirty: profileView.dirty diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml index 118b9f6107..666e5d8cbd 100644 --- a/ui/imports/shared/views/ProfileDialogView.qml +++ b/ui/imports/shared/views/ProfileDialogView.qml @@ -35,6 +35,7 @@ Pane { property var contactsStore property alias sendToAccountEnabled: showcaseView.sendToAccountEnabled + property alias enabledNetworks: showcaseView.enabledNetworks property var dirtyValues: ({}) property bool dirty: false @@ -47,6 +48,9 @@ Pane { property alias showcaseMaxVisibility: showcaseView.maxVisibility + property alias assetsModel: showcaseView.globalAssetsModel + property alias collectiblesModel: showcaseView.globalCollectiblesModel + signal closeRequested() padding: 0 @@ -604,6 +608,10 @@ Pane { // width: implicitWidth // text: qsTr("Assets") // } + StatusTabButton { + width: implicitWidth + text: qsTr("Web") + } } // Profile Showcase @@ -621,7 +629,7 @@ Pane { communitiesModel: root.showcaseCommunitiesModel accountsModel: root.showcaseAccountsModel collectiblesModel: root.showcaseCollectiblesModel - // socialLinksModel: root.showcaseSocialLinksModel + socialLinksModel: root.showcaseSocialLinksModel // assetsModel: root.showcaseAssetsModel onCloseRequested: root.closeRequested() diff --git a/ui/imports/shared/views/profile/ProfileShowcaseView.qml b/ui/imports/shared/views/profile/ProfileShowcaseView.qml index 676cbcc627..5113edbf35 100644 --- a/ui/imports/shared/views/profile/ProfileShowcaseView.qml +++ b/ui/imports/shared/views/profile/ProfileShowcaseView.qml @@ -10,10 +10,12 @@ import StatusQ.Components 0.1 import StatusQ.Popups.Dialog 0.1 import StatusQ.Core.Utils 0.1 as StatusQUtils +import SortFilterProxyModel 0.2 + import utils 1.0 import shared.controls 1.0 // Timer - -import SortFilterProxyModel 0.2 +import shared.controls.delegates 1.0 +import AppLayouts.Communities.controls 1.0 Control { id: root @@ -28,10 +30,14 @@ Control { property alias assetsModel: assetsProxyModel.sourceModel property alias socialLinksModel: socialLinksProxyModel.sourceModel + property var globalAssetsModel + property var globalCollectiblesModel + required property string mainDisplayName required property bool readOnly required property bool sendToAccountEnabled - + property var enabledNetworks + signal closeRequested() signal copyToClipboard(string text) @@ -41,6 +47,11 @@ Control { StatusQUtils.QObject { id: d + property int delegateWidthS: 152 + property int delegateHeightS: 152 + property int delegateWidthM: 202 + property int delegateHeightM: 160 + readonly property string copyLiteral: qsTr("Copy") } @@ -91,7 +102,6 @@ Control { background: StatusDialogBackground { color: Theme.palette.baseColor4 - Rectangle { anchors.left: parent.left anchors.right: parent.right @@ -99,13 +109,24 @@ Control { height: parent.radius color: parent.color } + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + 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 { + width: parent.width + height: parent.height StatusBaseText { Layout.fillWidth: true Layout.fillHeight: true @@ -114,52 +135,121 @@ Control { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Theme.palette.directColor1 - text: qsTr("%1 hasn't joined any communities yet").arg(root.mainDisplayName) + text: qsTr("%1 has not shared any communities").arg(root.mainDisplayName) } - - StatusGridView { + Item { Layout.fillWidth: true Layout.fillHeight: true - id: communitiesView - model: communitiesProxyModel - rightMargin: Style.current.halfPadding - cellWidth: (width-rightMargin)/2 - cellHeight: cellWidth/2 - visible: count - ScrollBar.vertical: StatusScrollBar { } - delegate: StatusListItem { // TODO custom delegate - width: GridView.view.cellWidth - Style.current.smallPadding - height: GridView.view.cellHeight - Style.current.smallPadding - title: model.name ?? "" - statusListItemTitle.font.pixelSize: 17 - statusListItemTitle.font.bold: true - subTitle: model.description ?? "" - tertiaryTitle: qsTr("%n member(s)", "", model.membersCount ?? 0) - asset.name: model.image ?? model.name ?? "" - asset.isImage: asset.name.startsWith(Constants.dataImagePrefix) - asset.isLetterIdenticon: !model.image - asset.color: model.color ?? "" - asset.width: 40 - asset.height: 40 - border.width: 1 - border.color: Theme.palette.baseColor2 - loading: !model.id - components: [ - StatusIcon { - visible: !!model.memberRole && - model.memberRole === Constants.memberRole.owner || - model.memberRole === Constants.memberRole.admin || - model.memberRole === Constants.memberRole.tokenMaster - anchors.verticalCenter: parent.verticalCenter - icon: "crown" - color: Theme.palette.directColor1 + 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") + } + } + } + } + + Component { + id: permissionsRowComponent + PermissionsRow { + hoverEnabled: false + assetsModel: root.globalAssetsModel + collectiblesModel: root.globalCollectiblesModel + model: profileDialogCommunityCard.permissionsList + requirementsMet: profileDialogCommunityCard.requirementsMet + } + } + + onClicked: { + print ("!!communitiesProxyModel", JSON.stringify(StatusQUtils.ModelUtils.modelToArray(communitiesProxyModel))) + + 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 } - ] - onClicked: { - if (root.readOnly || loading) - return - root.closeRequested() - Global.switchToCommunity(model.id) } } } @@ -167,6 +257,8 @@ Control { // wallets/accounts ColumnLayout { + width: parent.width + height: parent.height StatusBaseText { Layout.fillWidth: true Layout.fillHeight: true @@ -175,72 +267,139 @@ Control { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Theme.palette.directColor1 - text: qsTr("%1 doesn't have any wallet accounts yet").arg(root.mainDisplayName) + text: qsTr("%1 has not shared any accounts").arg(root.mainDisplayName) } - - StatusListView { + Item { Layout.fillWidth: true Layout.fillHeight: true - id: accountsView - model: accountsProxyModel - spacing: Style.current.halfPadding - visible: count - delegate: StatusListItem { - id: accountDelegate - - 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: !model.saved - text: model.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 - }) + 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 { - 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.copyToClipboard(model.address) - Backpressure.setTimeout(this, 2000, () => tooltip.text = d.copyLiteral) + 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); + // } + // } + // ] + // } } } } @@ -255,77 +414,98 @@ Control { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Theme.palette.directColor1 - text: qsTr("%1 doesn't have any collectibles/NFTs yet").arg(root.mainDisplayName) + text: qsTr("%1 has not shared any collectibles").arg(root.mainDisplayName) } - - StatusGridView { + Item { Layout.fillWidth: true Layout.fillHeight: true - id: collectiblesView - model: collectiblesProxyModel - rightMargin: Style.current.halfPadding - cellWidth: (width-rightMargin)/4 - cellHeight: cellWidth - visible: count - ScrollBar.vertical: StatusScrollBar { } - delegate: StatusRoundedImage { - width: GridView.view.cellWidth - Style.current.smallPadding - height: GridView.view.cellHeight - Style.current.smallPadding - 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 ?? "" - - RowLayout { - anchors.left: parent.left - anchors.leftMargin: Style.current.halfPadding - anchors.bottom: parent.bottom - anchors.bottomMargin: Style.current.halfPadding - anchors.right: parent.right - anchors.rightMargin: Style.current.halfPadding + 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 ?? "" Control { - Layout.maximumWidth: parent.width - horizontalPadding: Style.current.halfPadding - verticalPadding: Style.current.halfPadding/2 - visible: !!model.id + 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) background: Rectangle { - radius: Style.current.halfPadding/2 + radius: 30 color: Theme.palette.indirectColor2 } + contentItem: StatusBaseText { - font.pixelSize: 13 - font.weight: Font.Medium - maximumLineCount: 1 - elide: Text.ElideRight - text: `#${model.id}` + id: amountText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pixelSize: Style.current.asideTextFontSize + text: "x"+model.userHas } } - } - StatusToolTip { - visible: hhandler.hovered && (!!model.name || !!model.collectionName) - text: { - const name = model.name - const descr = model.collectionName - const sep = !!name && !!descr ? "
" : "" - return `${name}${sep}${descr}` + 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 } - } - HoverHandler { - id: hhandler - cursorShape: hovered ? Qt.PointingHandCursor : undefined - } - - TapHandler { - onSingleTapped: { - Global.openLink(model.permalink) + TapHandler { + onSingleTapped: { + //TODO https://github.com/status-im/status-desktop/issues/13702 + Global.openLink(model.permalink) + } } } } @@ -333,61 +513,199 @@ Control { } // 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? + // // } + // // } + // } + // } + // } + + // social links ColumnLayout { StatusBaseText { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignCenter - visible: assetsView.count == 0 + visible: webView.count == 0 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Theme.palette.directColor1 - text: qsTr("%1 doesn't have any assets/tokens yet").arg(root.mainDisplayName) + text: qsTr("%1 has not shared any links").arg(root.mainDisplayName) } - StatusGridView { + Item { Layout.fillWidth: true Layout.fillHeight: true - id: assetsView - model: assetsProxyModel - rightMargin: Style.current.halfPadding - cellWidth: (width-rightMargin)/3 - cellHeight: cellWidth/2.5 - visible: count - ScrollBar.vertical: StatusScrollBar { } - 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 ? "↓" : "↑" + Layout.topMargin: (webView.contentY > Style.current.padding) ? 1 : Style.current.padding + Behavior on Layout.topMargin { NumberAnimation { duration: 50 } } + clip: true - 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) + 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 + } + } + } + } + } + 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") } - ] - onClicked: { - if (root.readOnly) - return - // TODO what to do here? } } }