feat(MintAssets): Update minted tokens view with assets

- Added assets list UI.
- Added shape rectangle for empty lists.
- Added filter by asset / by collectible
- Updated storybook accordingly.
- Added flow to open token view depending on type

Closes #10625
This commit is contained in:
Noelia 2023-05-25 16:45:46 +02:00 committed by Noelia
parent b557274dff
commit 86a0e8b9ec
8 changed files with 197 additions and 26 deletions

View File

@ -28,7 +28,7 @@ SplitView {
CommunityMintTokensSettingsPanel { CommunityMintTokensSettingsPanel {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 50 anchors.topMargin: 50
tokensModel: editorModelChecked.checked ? emptyModel : MintedCollectiblesModel.mintedCollectibleModel tokensModel: editorModelChecked.checked ? emptyModel : MintedTokensModel.mintedTokensModel
layer1Networks: NetworksModel.layer1Networks layer1Networks: NetworksModel.layer1Networks
layer2Networks: NetworksModel.layer2Networks layer2Networks: NetworksModel.layer2Networks
testNetworks: NetworksModel.testNetworks testNetworks: NetworksModel.testNetworks
@ -71,9 +71,9 @@ SplitView {
checked: true checked: true
onCheckedChanged:{ onCheckedChanged:{
if(checked) if(checked)
MintedCollectiblesModel.changeAllMintingStates(1/*In progress*/) MintedTokensModel.changeAllMintingStates(1/*In progress*/)
else else
MintedCollectiblesModel.changeAllMintingStates(2/*Deployed*/) MintedTokensModel.changeAllMintingStates(2/*Deployed*/)
} }
} }

View File

@ -27,7 +27,7 @@ SplitView {
CommunityMintedTokensView { CommunityMintedTokensView {
anchors.fill: parent anchors.fill: parent
anchors.margins: 50 anchors.margins: 50
model: MintedCollectiblesModel.mintedCollectibleModel model: MintedTokensModel.mintedTokensModel
onItemClicked: logs.logEvent("CommunityMintedTokensView::itemClicked") onItemClicked: logs.logEvent("CommunityMintedTokensView::itemClicked")
} }
} }
@ -39,6 +39,25 @@ SplitView {
SplitView.preferredHeight: 150 SplitView.preferredHeight: 150
logsView.logText: logs.logText logsView.logText: logs.logText
RowLayout {
RadioButton {
text: "Assets and collectibles"
checked: true
onCheckedChanged: if(checked) MintedTokensModel.buildMintedTokensModel(true, true)
}
RadioButton {
text: "Only assets"
onCheckedChanged: if(checked) MintedTokensModel.buildMintedTokensModel(true, false)
}
RadioButton {
text: "Only collectibles"
onCheckedChanged: if(checked) MintedTokensModel.buildMintedTokensModel(false, true)
}
}
} }
} }
} }

View File

@ -34,7 +34,7 @@ SplitView {
enabledNetworks: NetworksModel.enabledNetworks enabledNetworks: NetworksModel.enabledNetworks
allNetworks: enabledNetworks allNetworks: enabledNetworks
accounts: WalletAccountsModel {} accounts: WalletAccountsModel {}
tokensModel: MintedCollectiblesModel.mintedCollectibleModel tokensModel: MintedTokensModel.mintedTokensModel
onPreviewClicked: logs.logEvent("CommunityNewTokenView::previewClicked") onPreviewClicked: logs.logEvent("CommunityNewTokenView::previewClicked")
} }

View File

@ -14,11 +14,26 @@ QtObject {
} }
} }
readonly property ListModel mintedCollectibleModel: ListModel { function buildMintedTokensModel(isAssets, isCollectibles) {
id: model model.clear()
if(isAssets) {
for(var i = 0; i < mintedAssetsModel.count; i++)
model.append(mintedAssetsModel.get(i))
}
if(isCollectibles) {
for(var j = 0; j < collectiblesModel.count; j++)
model.append(collectiblesModel.get(j))
}
}
readonly property ListModel mintedCollectiblesModel: ListModel {
id: collectiblesModel
Component.onCompleted: append([ Component.onCompleted: append([
{ {
tokenType: 2,
name: "SuperRare artwork", name: "SuperRare artwork",
image: ModelsData.banners.superRare, image: ModelsData.banners.superRare,
deployState: 0, deployState: 0,
@ -35,6 +50,7 @@ QtObject {
accountName: "Status Account" accountName: "Status Account"
}, },
{ {
tokenType: 2,
name: "Kitty artwork", name: "Kitty artwork",
image: ModelsData.collectibles.kitty1Big, image: ModelsData.collectibles.kitty1Big,
deployState: 2, deployState: 2,
@ -51,6 +67,7 @@ QtObject {
accountName: "Status New Account" accountName: "Status New Account"
}, },
{ {
tokenType: 2,
name: "More artwork", name: "More artwork",
image: ModelsData.banners.status, image: ModelsData.banners.status,
deployState: 1, deployState: 1,
@ -67,6 +84,7 @@ QtObject {
accountName: "Other Account" accountName: "Other Account"
}, },
{ {
tokenType: 2,
name: "Crypto Punks artwork", name: "Crypto Punks artwork",
image: ModelsData.banners.cryptPunks, image: ModelsData.banners.cryptPunks,
deployState: 2, deployState: 2,
@ -84,4 +102,49 @@ QtObject {
} }
]) ])
} }
readonly property ListModel mintedAssetsModel: ListModel {
id: assetsModel
Component.onCompleted: append([
{
tokenType: 1,
name: "Unisocks",
image: ModelsData.assets.socks,
deployState: 2,
symbol: "SOCKS",
description: "Socks description",
supply: 14,
remainingTokens: 2,
infiniteSupply: false,
decimals: 2,
chainId: 2,
chainName: "Optimism",
chainIcon: ModelsData.networks.optimism,
accountName: "Status SNT Account"
},
{
tokenType: 1,
name: "Dai",
image: ModelsData.assets.dai,
deployState: 0,
symbol: "DAI",
description: "Desc",
supply: 1,
remainingTokens: 1,
infiniteSupply: true,
decimals: 1,
chainId: 1,
chainName: "Testnet",
chainIcon: ModelsData.networks.testnet,
accountName: "Status Account"
}
])
}
readonly property ListModel mintedTokensModel: ListModel {
id: model
Component.onCompleted: buildMintedTokensModel(true, true)
}
} }

View File

@ -9,7 +9,7 @@ TokenHoldersModel 1.0 TokenHoldersModel.qml
UsersModel 1.0 UsersModel.qml UsersModel 1.0 UsersModel.qml
WalletAccountsModel 1.0 WalletAccountsModel.qml WalletAccountsModel 1.0 WalletAccountsModel.qml
WalletAssetsModel 1.0 WalletAssetsModel.qml WalletAssetsModel 1.0 WalletAssetsModel.qml
singleton MintedCollectiblesModel 1.0 MintedCollectiblesModel.qml singleton MintedTokensModel 1.0 MintedTokensModel.qml
singleton ModelsData 1.0 ModelsData.qml singleton ModelsData 1.0 ModelsData.qml
singleton NetworksModel 1.0 NetworksModel.qml singleton NetworksModel 1.0 NetworksModel.qml
singleton PermissionsModel 1.0 PermissionsModel.qml singleton PermissionsModel 1.0 PermissionsModel.qml

View File

@ -96,7 +96,7 @@ SettingsPageLayout {
readonly property string initialViewState: "WELCOME_OR_LIST_TOKENS" readonly property string initialViewState: "WELCOME_OR_LIST_TOKENS"
readonly property string newTokenViewState: "NEW_TOKEN" readonly property string newTokenViewState: "NEW_TOKEN"
readonly property string previewTokenViewState: "PREVIEW_TOKEN" readonly property string previewTokenViewState: "PREVIEW_TOKEN"
readonly property string collectibleViewState: "VIEW_COLLECTIBLE" readonly property string tokenViewState: "VIEW_TOKEN"
readonly property string welcomePageTitle: qsTr("Tokens") readonly property string welcomePageTitle: qsTr("Tokens")
readonly property string newCollectiblePageTitle: qsTr("Mint collectible") readonly property string newCollectiblePageTitle: qsTr("Mint collectible")
@ -166,7 +166,7 @@ SettingsPageLayout {
PropertyChanges {target: root; headerWidth: 0} PropertyChanges {target: root; headerWidth: 0}
}, },
State { State {
name: d.collectibleViewState name: d.tokenViewState
PropertyChanges {target: root; previousPageName: d.backButtonText} PropertyChanges {target: root; previousPageName: d.backButtonText}
PropertyChanges {target: root; headerButtonVisible: false} PropertyChanges {target: root; headerButtonVisible: false}
PropertyChanges {target: root; headerWidth: 0} PropertyChanges {target: root; headerWidth: 0}
@ -226,7 +226,7 @@ SettingsPageLayout {
Binding { Binding {
target: root target: root
property: "title" property: "title"
value: optionsTab.currentItem == collectiblesTab ? d.newCollectiblePageTitle : d.newAssetPageTitle value: optionsTab.currentItem === collectiblesTab ? d.newCollectiblePageTitle : d.newAssetPageTitle
} }
} }
@ -494,8 +494,8 @@ SettingsPageLayout {
d.chainName = chainName d.chainName = chainName
d.accountName = accountName d.accountName = accountName
//d.tokenKey = key // TODO: Backend key role //d.tokenKey = key // TODO: Backend key role
stackManager.push(d.collectibleViewState, stackManager.push(d.tokenViewState,
collectibleView, tokenView,
{ {
preview: false, preview: false,
index index
@ -506,7 +506,7 @@ SettingsPageLayout {
} }
Component { Component {
id: collectibleView id: tokenView
CommunityTokenView { CommunityTokenView {
id: view id: view
@ -573,6 +573,7 @@ SettingsPageLayout {
delegate: QtObject { delegate: QtObject {
component Bind: Binding { target: view } component Bind: Binding { target: view }
readonly property list<Binding> bindings: [ readonly property list<Binding> bindings: [
Bind { property: "isAssetView"; value: model.tokenType === Constants.TokenType.ERC20 },
Bind { property: "deployState"; value: model.deployState }, Bind { property: "deployState"; value: model.deployState },
Bind { property: "remotelyDestructState"; value: model.remotelyDestructState }, Bind { property: "remotelyDestructState"; value: model.remotelyDestructState },
Bind { property: "burnState"; value: model.burnState }, Bind { property: "burnState"; value: model.burnState },
@ -588,7 +589,8 @@ SettingsPageLayout {
Bind { property: "chainName"; value: model.chainName }, Bind { property: "chainName"; value: model.chainName },
Bind { property: "chainIcon"; value: model.chainIcon }, Bind { property: "chainIcon"; value: model.chainIcon },
Bind { property: "accountName"; value: model.accountName }, Bind { property: "accountName"; value: model.accountName },
Bind { property: "tokenOwnersModel"; value: model.tokenOwnersModel } Bind { property: "tokenOwnersModel"; value: model.tokenOwnersModel },
Bind { property: "assetDecimals"; value: model.decimals }
] ]
} }
} }

View File

@ -5,7 +5,9 @@ import StatusQ.Core 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import SortFilterProxyModel 0.2
import utils 1.0 import utils 1.0
import shared.controls 1.0
import AppLayouts.Wallet.views.collectibles 1.0 import AppLayouts.Wallet.views.collectibles 1.0
@ -25,7 +27,9 @@ StatusScrollView {
QtObject { QtObject {
id: d id: d
function getSubtitle(deployState, remainingTokens, supply) { readonly property int delegateAssetsHeight: 64
function getSubtitle(deployState, remainingTokens, supply, isCollectible) {
if(deployState === Constants.ContractTransactionStatus.Failed) { if(deployState === Constants.ContractTransactionStatus.Failed) {
return qsTr("Minting failed") return qsTr("Minting failed")
} }
@ -39,7 +43,7 @@ StatusScrollView {
remainingTokens = 0 remainingTokens = 0
if(supply === 0) if(supply === 0)
supply = "∞" supply = "∞"
return qsTr("%1 / %2 remaining").arg(remainingTokens).arg(supply) return isCollectible ? qsTr("%1 / %2 remaining").arg(remainingTokens).arg(supply) : ""
} }
} }
@ -49,35 +53,111 @@ StatusScrollView {
id: mainLayout id: mainLayout
width: root.viewWidth width: root.viewWidth
spacing: Style.current.padding spacing: Style.current.halfPadding
StatusBaseText { StatusBaseText {
Layout.leftMargin: Style.current.padding
text: qsTr("Assets")
font.pixelSize: Theme.primaryTextFontSize
color: Theme.palette.baseColor1
}
StatusListView {
id: assetsList
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
visible: count > 0
model: SortFilterProxyModel {
sourceModel: root.model
filters: ValueFilter {
roleName: "tokenType"
value: Constants.TokenType.ERC20
}
}
delegate: StatusListItem {
height: 64
width: mainLayout.width
title: model.name
subTitle: model.symbol
asset.name: model.image ? model.image : ""
asset.isImage: true
components: [
StatusBaseText {
anchors.verticalCenter: parent.verticalCenter
text: d.getSubtitle(model.deployState, model.remainingTokens, model.supply, false)
color: (model.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.baseColor1
font.pixelSize: 13
},
StatusIcon {
anchors.verticalCenter: parent.verticalCenter
icon: "next"
color: Theme.palette.baseColor1
}
]
onClicked: root.itemClicked(model.index, model.chainId, model.chainName, model.accountName, model.address) // TODO: Replace to model.key when role exists in backend
}
}
// Empty placeholder when no assets; dashed rounded rectangle
ShapeRectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width - 4 // The rectangular path is rendered outside
Layout.preferredHeight: 44
visible: assetsList.count === 0
text: qsTr("You currently have no minted assets")
}
StatusBaseText {
Layout.leftMargin: Style.current.padding
Layout.topMargin: Style.current.halfPadding
text: qsTr("Collectibles") text: qsTr("Collectibles")
font.pixelSize: Theme.primaryTextFontSize font.pixelSize: Theme.primaryTextFontSize
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
} }
StatusGridView { StatusGridView {
id: gridView id: collectiblesGrid
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 500 // TODO Layout.preferredHeight: childrenRect.height
model: root.model
visible: count > 0
model: SortFilterProxyModel {
sourceModel: root.model
filters: ValueFilter {
roleName: "tokenType"
value: Constants.TokenType.ERC721
}
}
cellHeight: 229 cellHeight: 229
cellWidth: 176 cellWidth: 176
leftMargin: 16
delegate: CollectibleView { delegate: CollectibleView {
height: gridView.cellHeight height: collectiblesGrid.cellHeight
width: gridView.cellWidth width: collectiblesGrid.cellWidth
title: model.name ? model.name : "..." title: model.name ? model.name : "..."
subTitle: d.getSubtitle(model.deployState, model.remainingTokens, model.supply) subTitle: d.getSubtitle(model.deployState, model.remainingTokens, model.supply, true)
subTitleColor: (model.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.baseColor1 subTitleColor: (model.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.baseColor1
fallbackImageUrl: model.image ? model.image : "" fallbackImageUrl: model.image ? model.image : ""
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent" // TODO BACKEND backgroundColor: "transparent"
isLoading: false isLoading: false
navigationIconVisible: true navigationIconVisible: true
onClicked: root.itemClicked(model.index, model.chainId, model.contractUniqueKey, model.chainName, model.accountName, model.address) onClicked: root.itemClicked(model.index, model.chainId, model.contractUniqueKey, model.chainName, model.accountName, model.address)
} }
} }
// Empty placeholder when no collectibles; dashed rounded rectangle
ShapeRectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width - 4 // The rectangular path is rendered outside
Layout.preferredHeight: 44
visible: collectiblesGrid.count == 0
text: qsTr("You currently have no minted collectibles")
}
} }
} }

View File

@ -910,6 +910,13 @@ QtObject {
Dismissed = 4 Dismissed = 4
} }
enum TokenType {
Unknown = 0,
ERC20 = 1,
ERC721 = 2
}
readonly property QtObject walletSection: QtObject { readonly property QtObject walletSection: QtObject {
readonly property string cancelledMessage: "cancelled" readonly property string cancelledMessage: "cancelled"
} }