feat(OwnerToken): Add all mint states views design details

- Added `storybook` support to change minted tokens model with Owner and TMaster tokens.
- Added new properties into the `tokenModel` model.
- Extended `CollectiblesView` to allow Owner and TMaster tokens representation.
- Updated `MintedTokensView` in order to display Owner and TMaster tokens.
- Added logic to `enable/disable` MINT and AIRDROP token depending on the owner /  tmaster tokens deploy state.
- Added temp buttons in MINT and AIRDROP pages that keeps enabled the flows although owner and tmaster backend is not ready.
- Extended navigation from outsite to minting section, depending on user profile and owner and tmaster states.
- Hide footer options in case of owner token item visualized.
- Added retry flow.

Closes #11299
This commit is contained in:
Noelia 2023-07-18 19:34:57 +02:00 committed by Noelia
parent 9800dad3ba
commit d2051c6247
15 changed files with 509 additions and 133 deletions

View File

@ -90,10 +90,17 @@ SplitView {
anchors.fill: parent
anchors.topMargin: 50
// User profile
isOwner: ownerChecked.checked
isTokenMasterOwner: masterTokenOwnerChecked.checked
isAdmin: adminChecked.checked
tokensModel: editorModelChecked.checked ? emptyModel : mintedTokensModel
// Owner and TMaster related props:
isOwnerTokenDeployed: deployCheck.checked
isTMasterTokenDeployed: deployCheck.checked
// Models
assetsModel: AssetsModel {}
collectiblesModel: ListModel {}
@ -228,10 +235,10 @@ SplitView {
}
CheckBox {
id: editorModelChecked
checked: true
id: deployCheck
checked: false
text: "No tokens minted yet"
text: "Owner and TMaster tokens deployed"
}
}
}

View File

@ -6,6 +6,8 @@ import AppLayouts.Communities.panels 1.0
import AppLayouts.Chat.stores 1.0
import StatusQ.Core.Theme 0.1
import SortFilterProxyModel 0.2
import Storybook 1.0
import Models 1.0
@ -48,15 +50,37 @@ SplitView {
id: mintedTokensModel
}
SortFilterProxyModel {
id: privilegedTokensModel
sourceModel: mintedTokensModel
filters: ValueFilter {
roleName: "isPrivilegedToken"
value: true
}
}
anchors.fill: parent
anchors.topMargin: 50
tokensModel: editorModelChecked.checked ? emptyModel : mintedTokensModel
isAdmin: adminChecked.checked
isOwner: ownerChecked.checked
// General:
communityLogo: ModelsData.collectibles.doodles
communityColor: "#FFC4E9"
communityName: communityNameText.text
communityName: "Doodles" // It cannot be changed since owner token and tMaster token in tokenModel used are related to the `Doodles` community
// Profile type:
isAdmin: adminChecked.checked
isOwner: ownerChecked.checked
isTokenMasterOwner: masterTokenOwnerChecked.checked
// Owner and TMaster related props:
isOwnerTokenDeployed: deployCheck.checked
isTMasterTokenDeployed: deployCheck.checked
// Models:
tokensModel: editorModelChecked.checked ? emptyModel :
privilegedModelChecked.checked ? privilegedTokensModel : mintedTokensModel
layer1Networks: NetworksModel.layer1Networks
layer2Networks: NetworksModel.layer2Networks
testNetworks: NetworksModel.testNetworks
@ -68,10 +92,10 @@ SplitView {
symbol: "MAI"
}
}
onMintCollectible: logs.logEvent("CommunityMintTokensSettingsPanel::mintCollectible")
onMintAsset: logs.logEvent("CommunityMintTokensSettingsPanel::mintAssets")
onDeleteToken: logs.logEvent("CommunityMintTokensSettingsPanel::deleteToken: " + tokenKey)
onSignMintTransactionOpened: feesTimer.restart()
}
}
@ -80,24 +104,11 @@ SplitView {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 250
SplitView.preferredHeight: 300
logsView.logText: logs.logText
ColumnLayout {
Row {
Label {
text: "Community name: "
}
TextEdit {
id: communityNameText
text: "TEST COMMUNITY"
}
}
CheckBox {
id: ownerChecked
checked: true
@ -119,29 +130,47 @@ SplitView {
text: "Is admin? [Admis will be able to see token views, but NOT manage them, like creating new artwork or asset]"
}
CheckBox {
id: editorModelChecked
checked: true
RowLayout {
RadioButton {
id: editorModelChecked
text: "No tokens minted yet"
checked: true
text: "No tokens minted yet"
}
RadioButton {
id: privilegedModelChecked
text: "Owner token and TMaster token only"
}
RadioButton {
id: completeModelChecked
text: "Minted tokens list"
}
}
RowLayout {
Button {
RadioButton {
text: "Set all to 'In progress'"
onClicked: mintedTokensModel.changeAllMintingStates(1)
}
Button {
text: "Set all to 'Deployed'"
onClicked: mintedTokensModel.changeAllMintingStates(2)
}
Button {
RadioButton {
text: "Set all to 'Error'"
onClicked: mintedTokensModel.changeAllMintingStates(0)
}
RadioButton {
id: deployCheck
text: "Set all to 'Deployed'"
onClicked: mintedTokensModel.changeAllMintingStates(2)
}
}
}
}

View File

@ -51,6 +51,9 @@ SplitView {
anchors.fill: parent
anchors.margins: 50
model: filteredTokensModel
isOwner: true
isAdmin: false
onItemClicked: logs.logEvent("MintedTokensView::itemClicked",
["tokenKey"], [tokenKey])
}

View File

@ -7,6 +7,48 @@ ListModel {
readonly property var data: [
{
isPrivilegedToken: true,
isOwner: true,
contractUniqueKey: "0x15a23414a3",
tokenType: 2,
name: "Owner-Doodles",
image: ModelsData.collectibles.doodles,
deployState: 0,
symbol: "OWNDOO",
description: "Owner doodles desc",
supply: 1,
remainingSupply: 1,
infiniteSupply: false,
transferable: true,
remoteSelfDestruct: false,
chainId: 2,
chainName: "Optimism",
chainIcon: ModelsData.networks.optimism,
accountName: "Another account - generated"
},
{
isPrivilegedToken: true,
isOwner: false,
contractUniqueKey: "0x23124443",
tokenType: 2,
name: "TMaster-Doodles",
image: ModelsData.collectibles.doodles,
deployState: 0,
symbol: "TMDOO",
description: "Doodles Token master token description",
supply: 1,
remainingSupply: 1,
infiniteSupply: true,
transferable: false,
remoteSelfDestruct: true,
chainId: 2,
chainName: "Optimism",
chainIcon: ModelsData.networks.optimism,
accountName: "Another account - generated"
},
{
isPrivilegedToken: false,
isOwner: false,
contractUniqueKey: "0x1726362343",
tokenType: 2,
name: "SuperRare artwork",
@ -25,6 +67,8 @@ ListModel {
accountName: "Status Account"
},
{
isPrivilegedToken: false,
isOwner: false,
contractUniqueKey: "0x847843",
tokenType: 2,
name: "Kitty artwork",
@ -43,6 +87,8 @@ ListModel {
accountName: "Status New Account"
},
{
isPrivilegedToken: false,
isOwner: false,
contractUniqueKey: "0x1234525",
tokenType: 2,
name: "More artwork",
@ -61,6 +107,8 @@ ListModel {
accountName: "Other Account"
},
{
isPrivilegedToken: false,
isOwner: false,
contractUniqueKey: "0x38576852",
tokenType: 2,
name: "Crypto Punks artwork",
@ -80,6 +128,8 @@ ListModel {
tokenOwnersModel: root.tokenOwnersModel
},
{
isPrivilegedToken: false,
isOwner: false,
contractUniqueKey: "0x38745623865",
tokenType: 1,
name: "Unisocks",
@ -97,6 +147,8 @@ ListModel {
accountName: "Status SNT Account"
},
{
isPrivilegedToken: false,
isOwner: false,
contractUniqueKey: "0x872364871623",
tokenType: 1,
name: "Dai",

View File

@ -93,13 +93,19 @@ QtObject {
}
}
// OWNER AND TMASTER TOKENS related helpers:
readonly property string ownerTokenNameTag: "Owner-"
readonly property string tMasterTokenNameTag: "TMaster-"
readonly property string ownerTokenSymbolTag: "OWN"
readonly property string tMasterTokenSymbolTag: "TM"
// It generates a symbol from a given community name.
// It will be used to autogenerate the Owner and Token Master token symbols.
function autogenerateSymbol(isOwner, communityName) {
function communityNameToSymbol(isOwner, communityName) {
const shortName = communityName.substring(0, 3)
if(isOwner)
return "OWN" + shortName.toUpperCase()
return ownerTokenSymbolTag + shortName.toUpperCase()
else
return "TM" + shortName.toUpperCase()
return tMasterTokenSymbolTag + shortName.toUpperCase()
}
}

View File

@ -13,14 +13,21 @@ StackView {
// id, name, image, color, owner properties expected
required property var communityDetails
// User profiles
required property bool isOwner
required property bool isTokenMasterOwner
required property bool isAdmin
readonly property bool isPrivilegedTokenOwnerProfile: root.isOwner || root.isTokenMasterOwner
// Owner and TMaster token related properties:
readonly property bool arePrivilegedTokensDeployed: root.isOwnerTokenDeployed && root.isTMasterTokenDeployed
property bool isOwnerTokenDeployed: false
property bool isTMasterTokenDeployed: false
// Token models:
required property var assetsModel
required property var collectiblesModel
required property var tokensModel // Community minted tokens model
required property var membersModel
@ -55,7 +62,7 @@ StackView {
QtObject {
id: d
readonly property bool isAdminOnly: root.isAdmin && !root.isOwner && !root.isTokenMasterOwner
readonly property bool isAdminOnly: root.isAdmin && !root.isPrivilegedTokenOwnerProfile
signal selectToken(string key, int amount, int type)
signal addAddresses(var addresses)
@ -65,15 +72,33 @@ StackView {
implicitWidth: 0
title: qsTr("Airdrops")
buttons: StatusButton {
buttons: [
// TO BE REMOVED when Owner and TMaster backend is integrated. This is just to keep the airdrop flow available somehow
StatusButton {
objectName: "addNewItemButton"
text: qsTr("TEMP Airdrop")
text: qsTr("New Airdrop")
enabled: !d.isAdminOnly && root.tokensModel.count > 0 // TODO: Replace to checker to ensure owner token is deployed
onClicked: root.push(newAirdropView, StackView.Immediate)
onClicked: root.push(newAirdropView, StackView.Immediate)
}
StatusToolTip {
visible: parent.hovered
text: "TO BE REMOVED when Owner and TMaster backend is integrated. This is just to keep the airdrop flow available somehow"
orientation: StatusToolTip.Orientation.Bottom
y: parent.height + 12
maxWidth: 300
}
},
StatusButton {
objectName: "addNewItemButton"
text: qsTr("New Airdrop")
enabled: !d.isAdminOnly && root.arePrivilegedTokensDeployed
onClicked: root.push(newAirdropView, StackView.Immediate)
}
]
contentItem: WelcomeSettingsView {
viewWidth: root.viewWidth
@ -85,10 +110,10 @@ StackView {
qsTr("Incentivise joining, retention, moderation and desired behaviour"),
qsTr("Require holding a token or NFT to obtain exclusive membership rights")
]
infoBoxVisible: d.isAdminOnly || ((root.isOwner || root.isTokenMasterOwner) && root.tokensModel.count === 0) // TODO: Replace to checker to ensure owner token is NOT deployed yet
infoBoxVisible: d.isAdminOnly || (root.isPrivilegedTokenOwnerProfile && !root.arePrivilegedTokensDeployed)
infoBoxTitle: qsTr("Get started")
infoBoxText: d.isAdminOnly ? qsTr("Token airdropping can only be performed by admins that hodl the Communitys TokenMaster token. If you would like this permission, contact the Community founder (they will need to mint the Community Owner token before they can airdrop this to you)."):
qsTr("In order to Mint, Import and Airdrop community tokens, you first need to mint your Owner token which will give you permissions to access the token management features for your community.")
qsTr("In order to Mint, Import and Airdrop community tokens, you first need to mint your Owner token which will give you permissions to access the token management features for your community.")
buttonText: qsTr("Mint Owner token")
buttonVisible: root.isOwner
onClicked: root.navigateToMintTokenSettings(false)

View File

@ -5,6 +5,7 @@ import QtQml 2.15
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import AppLayouts.Communities.controls 1.0
import AppLayouts.Communities.helpers 1.0
@ -22,14 +23,25 @@ StackView {
id: root
// General properties:
required property bool isOwner
required property bool isTokenMasterOwner
required property bool isAdmin
property int viewWidth: 560 // by design
required property string communityName
required property string communityLogo
required property color communityColor
property int viewWidth: 560 // by design
// User profile props:
required property bool isOwner
required property bool isTokenMasterOwner
required property bool isAdmin
readonly property bool isAdminOnly: root.isAdmin && !root.isPrivilegedTokenOwnerProfile
readonly property bool isPrivilegedTokenOwnerProfile: root.isOwner || root.isTokenMasterOwner
// Owner and TMaster token related properties:
readonly property bool arePrivilegedTokensDeployed: root.isOwnerTokenDeployed && root.isTMasterTokenDeployed
property bool isOwnerTokenDeployed: false
property bool isTMasterTokenDeployed: false
// It will monitorize if Owner and/or TMaster token items are included in the `tokensModel` despite the deployment state
property bool ownerOrTMasterTokenItemsExist: false
// Models:
property var tokensModel
@ -77,51 +89,42 @@ StackView {
pop(initialItem, StackView.Immediate)
}
// This method will be called from the outsite from a different section like Airdrop or Permissions
function openNewTokenForm(isAssetView) {
resetNavigation()
if(d.isTokenOwnerDeployed) {
if(root.isAdminOnly) {
// Admins can only see the initial tokens page. They cannot mint
root.push(mintedTokensViewComponent, StackView.Immediate)
return
}
if(root.arePrivilegedTokensInProgress || root.arePrivilegedTokensFailed) {
// If Owner and TMaster tokens deployment action has been started at least ones, but still without success
root.push(mintedTokensViewComponent, StackView.Immediate)
return
}
if(root.ownerOrTMasterTokenItemsExist) {
// Regular minting flow, selecting the specific tab
const properties = { isAssetView }
root.push(newTokenViewComponent, properties, StackView.Immediate)
} else {
root.push(ownerTokenViewComponent, StackView.Immediate)
return
}
if(root.isOwner) {
// Owner and TMaster tokens to be deployed.
root.push(ownerTokenViewComponent, StackView.Immediate)
return
}
// Any other case, initial view
root.push(mintedTokensViewComponent, StackView.Immediate)
}
property string previousPageName: depth > 1 ? qsTr("Back") : ""
QtObject {
id: d
readonly property bool isTokenOwnerDeployed: root.tokensModel.count > 0 // TODO: Checker to ensure owner token is deployed
}
initialItem: SettingsPage {
implicitWidth: 0
title: qsTr("Tokens")
buttons: DisabledTooltipButton {
readonly property bool isAdminOnly: root.isAdmin && !root.isOwner && !root.isTokenMasterOwner
readonly property bool buttonEnabled: (root.isOwner || root.isTokenMasterOwner) && d.isTokenOwnerDeployed
buttonType: DisabledTooltipButton.Normal
aliasedObjectName: "addNewItemButton"
text: qsTr("Mint token")
enabled: isAdminOnly || buttonEnabled
interactive: buttonEnabled
onClicked: root.push(newTokenViewComponent, StackView.Immediate)
tooltipText: qsTr("In order to mint, you must hodl the TokenMaster token for %1").arg(root.communityName)
}
contentItem: MintedTokensView {
model: root.tokensModel
isOwner: root.isOwner
isAdmin: root.isAdmin
onItemClicked: root.push(tokenViewComponent, { tokenKey }, StackView.Immediate)
onMintOwnerTokenClicked: root.push(ownerTokenViewComponent, StackView.Immediate)
}
}
initialItem: mintedTokensViewComponent
Component {
id: tokenObjectComponent
@ -130,6 +133,60 @@ StackView {
}
// Mint tokens possible view contents:
Component {
id: mintedTokensViewComponent
SettingsPage {
implicitWidth: 0
title: qsTr("Tokens")
buttons: [
// TO BE REMOVED when Owner and TMaster backend is integrated. This is just to keep the minting flow available somehow
StatusButton {
text: qsTr("TEMP Mint token")
onClicked: root.push(newTokenViewComponent, StackView.Immediate)
StatusToolTip {
visible: parent.hovered
text: "TO BE REMOVED when Owner and TMaster backend is integrated. This is just to keep the airdrop flow available somehow"
orientation: StatusToolTip.Orientation.Bottom
y: parent.height + 12
maxWidth: 300
}
},
DisabledTooltipButton {
readonly property bool buttonEnabled: root.isPrivilegedTokenOwnerProfile && root.arePrivilegedTokensDeployed
buttonType: DisabledTooltipButton.Normal
aliasedObjectName: "addNewItemButton"
text: qsTr("Mint token")
enabled: root.isAdminOnly || buttonEnabled
interactive: buttonEnabled
onClicked: root.push(newTokenViewComponent, StackView.Immediate)
tooltipText: qsTr("In order to mint, you must hodl the TokenMaster token for %1").arg(root.communityName)
}
]
contentItem: MintedTokensView {
model: SortFilterProxyModel {
sourceModel: root.tokensModel
proxyRoles: ExpressionRole {
name: "color"
expression: root.communityColor
}
}
isOwner: root.isOwner
isAdmin: root.isAdmin
communityName: root.communityName
onItemClicked: root.push(tokenViewComponent, { tokenKey }, StackView.Immediate)
onMintOwnerTokenClicked: root.push(ownerTokenViewComponent, StackView.Immediate)
}
}
}
Component {
id: ownerTokenViewComponent
@ -155,6 +212,10 @@ StackView {
SettingsPage {
id: ownerTokenPage
property int chainId
property string accountName
property string accountAddress
title: qsTr("Mint Owner token")
contentItem: EditOwnerTokenView {
@ -166,9 +227,18 @@ StackView {
}
viewWidth: root.viewWidth
communityLogo: root.communityLogo
communityColor: root.communityColor
communityName: root.communityName
ownerToken.chainId: ownerTokenPage.chainId
ownerToken.accountName: ownerTokenPage.accountName
ownerToken.accountAddress: ownerTokenPage.accountAddress
tMasterToken.chainId: ownerTokenPage.chainId
tMasterToken.accountName: ownerTokenPage.accountName
tMasterToken.accountAddress: ownerTokenPage.accountAddress
layer1Networks: root.layer1Networks
layer2Networks: root.layer2Networks
testNetworks: root.testNetworks
@ -222,7 +292,7 @@ StackView {
property string referenceName: ""
property string referenceSymbol: ""
title: optionsTab.currentItem == assetsTab
title: optionsTab.currentItem === assetsTab
? qsTr("Mint asset") : qsTr("Mint collectible")
contentItem: ColumnLayout {
@ -252,7 +322,7 @@ StackView {
Layout.preferredWidth: root.viewWidth
Layout.fillHeight: true
currentIndex: optionsTab.currentItem == collectiblesTab ? 0 : 1
currentIndex: optionsTab.currentItem === collectiblesTab ? 0 : 1
CustomEditCommunityTokenView {
id: newCollectibleView
@ -279,7 +349,7 @@ StackView {
layer1Networks: root.layer1Networks
layer2Networks: root.layer2Networks
testNetworks: root.testNetworks
enabledNetworks: root.testNetworks
enabledNetworks: root.enabledNetworks
allNetworks: root.allNetworks
accounts: root.accounts
tokensModel: root.tokensModel
@ -363,10 +433,16 @@ StackView {
id: tokenViewPage
readonly property alias token: view.token
readonly property bool deploymentFailed: view.deployState === Constants.ContractTransactionStatus.Failed
property alias tokenOwnersModel: view.tokenOwnersModel
property alias airdropKey: view.airdropKey
// Owner and TMaster related props
readonly property bool isPrivilegedTokenItem: token.isPrivilegedToken
readonly property bool isOwnerTokenItem: token.isPrivilegedToken && token.isOwner
readonly property bool isTMasterTokenItem: token.isPrivilegedToken && !token.isOwner
title: view.name
subtitle: view.symbol
@ -375,22 +451,17 @@ StackView {
text: qsTr("Delete")
type: StatusBaseButton.Type.Danger
visible: view.deployState === Constants.ContractTransactionStatus.Failed
visible: (!tokenViewPage.isPrivilegedTokenItem) && !root.isAdminOnly && tokenViewPage.deploymentFailed
onClicked: deleteTokenAlertPopup.open()
},
StatusButton {
text: qsTr("Retry mint")
visible: view.deployState === Constants.ContractTransactionStatus.Failed
onClicked: {
function retryAssetOrCollectible() {
// https://bugreports.qt.io/browse/QTBUG-91917
var isAssetView = tokenViewPage.token.type === Constants.TokenType.ERC20
// copy TokenObject
var tokenObject = tokenObjectComponent.createObject(
null, view.token)
// Copy TokenObject
var tokenObject = tokenObjectComponent.createObject(null, view.token)
// Then move on to the new token view, but token pre-filled:
var properties = {
@ -402,11 +473,35 @@ StackView {
}
var tokenView = root.push(newTokenViewComponent, properties,
StackView.Immediate)
StackView.Immediate)
// cleanup dynamically created TokenObject
// Cleanup dynamically created TokenObject
tokenView.Component.destruction.connect(() => tokenObject.destroy())
}
// Owner or TMaster token
function retryPrivilegedToken() {
var properties = {
chainId: view.token.chainId,
accountName: view.token.accountName,
accountAddress: view.token.accountAddress,
}
root.push(ownerTokenEditViewComponent, properties,
StackView.Immediate)
}
text: qsTr("Retry mint")
visible: (tokenViewPage.isPrivilegedTokenItem && root.isOwner && tokenViewPage.deploymentFailed) ||
(!tokenViewPage.isPrivilegedTokenItem && !root.isAdminOnly && tokenViewPage.deploymentFailed)
onClicked: {
if(tokenViewPage.isPrivilegedTokenItem)
retryPrivilegedToken()
else
retryAssetOrCollectible()
}
}
]
@ -438,8 +533,7 @@ StackView {
readonly property TokenObject token: view.token
readonly property bool deployStateCompleted:
token.deployState === Constants.ContractTransactionStatus.Completed
readonly property bool deployStateCompleted: token.deployState === Constants.ContractTransactionStatus.Completed
function closePopups() {
remotelyDestructPopup.close()
@ -448,6 +542,16 @@ StackView {
burnTokensPopup.close()
}
visible: {
if(tokenViewPage.isOwnerTokenItem)
// Always hidden
return false
if(tokenViewPage.isTMasterTokenItem)
// Only footer if owner profile
return root.isOwner
// Always present
return true
}
airdropEnabled: deployStateCompleted &&
(token.infiniteSupply ||
token.remainingTokens !== 0)
@ -461,8 +565,8 @@ StackView {
remotelyDestructVisible: token.remotelyDestruct
burnVisible: !token.infiniteSupply
onAirdropClicked:root.airdropToken(view.airdropKey, // tokenKey instead when backend airdrop ready to use key instead of symbol
view.token.type, [])
onAirdropClicked: root.airdropToken(view.airdropKey, // tokenKey instead when backend airdrop ready to use key instead of symbol
view.token.type, [])
onRemotelyDestructClicked: remotelyDestructPopup.open()
onBurnClicked: burnTokensPopup.open()
@ -596,6 +700,9 @@ StackView {
tokenOwnersModel: model.tokenOwnersModel
airdropKey: model.symbol // TO BE REMOVED: When airdrop backend is ready to use token key instead of symbol
token.isPrivilegedToken: model.isPrivilegedToken
token.isOwner: model.isOwner
token.color: root.communityColor
token.accountName: model.accountName
token.artworkSource: model.image
token.chainIcon: model.chainIcon

View File

@ -23,14 +23,34 @@ Control {
QtObject {
id: d
readonly property int imageSize: size === PrivilegedTokenArtworkPanel.Size.Small ? 80 : 186
readonly property int bgSize: size === PrivilegedTokenArtworkPanel.Size.Small ? 120 : 280
readonly property int iconSize: size === PrivilegedTokenArtworkPanel.Size.Small ? 16 : 38
readonly property int iconMargins: size === PrivilegedTokenArtworkPanel.Size.Small ? 8 : 16
readonly property int imageSize: ({
[PrivilegedTokenArtworkPanel.Size.Small]: 80,
[PrivilegedTokenArtworkPanel.Size.Medium]: 109,
[PrivilegedTokenArtworkPanel.Size.Large]: 186
}[size])
readonly property int bgSize: ({
[PrivilegedTokenArtworkPanel.Size.Small]: 120,
[PrivilegedTokenArtworkPanel.Size.Medium]: 164,
[PrivilegedTokenArtworkPanel.Size.Large]: 280
}[size])
readonly property int iconSize: ({
[PrivilegedTokenArtworkPanel.Size.Small]: 14,
[PrivilegedTokenArtworkPanel.Size.Medium]: 16,
[PrivilegedTokenArtworkPanel.Size.Large]: 38
}[size])
readonly property int iconMargins: ({
[PrivilegedTokenArtworkPanel.Size.Small]: 8,
[PrivilegedTokenArtworkPanel.Size.Medium]: 12,
[PrivilegedTokenArtworkPanel.Size.Large]: 16
}[size])
}
enum Size {
Small,
Medium,
Large
}
@ -38,7 +58,7 @@ Control {
implicitHeight: implicitWidth
background: Rectangle {
color: "transparent"
color: Theme.palette.statusAppLayout.rightPanelBackgroundColor
radius: 8
border.color: Theme.palette.baseColor2
}

View File

@ -19,6 +19,8 @@ Control {
// Panel properties:
property bool preview: false
property bool accountBoxVisible: true
property bool networkBoxVisible: true
// Token object properties:
/* required */ property TokenObject token // https://bugreports.qt.io/browse/QTBUG-84269
@ -211,14 +213,14 @@ Control {
}
CustomPreviewBox {
visible: !token.isPrivilegedToken
visible: root.accountBoxVisible
label: qsTr("Account")
value: token.accountName
}
Rectangle {
visible: !token.isPrivilegedToken
visible: root.networkBoxVisible
height: symbolBox.height
width: rowChain.implicitWidth + 2 * Style.current.padding
border.width: 1

View File

@ -20,6 +20,7 @@ import utils 1.0
import AppLayouts.Communities.controls 1.0
import AppLayouts.Communities.panels 1.0
import AppLayouts.Communities.popups 1.0
import AppLayouts.Communities.helpers 1.0
StatusSectionLayout {
id: root
@ -315,12 +316,21 @@ StatusSectionLayout {
mintPanel.isFeeLoading = true
}
// General community props
communityName: root.community.name
communityLogo: root.community.image
communityColor: root.community.color
// User profile props
isOwner: root.isOwner
isAdmin: root.isAdmin
isTokenMasterOwner: false // TODO: Backend
// Owner and TMaster properties
isOwnerTokenDeployed: tokensModelChangesTracker.isOwnerTokenDeployed
isTMasterTokenDeployed: tokensModelChangesTracker.isTMasterTokenDeployed
// Models
tokensModel: root.community.communityTokens
tokensModelWallet: root.rootStore.tokensModelWallet
layer1Networks: communityTokensStore.layer1Networks
@ -382,10 +392,15 @@ StatusSectionLayout {
readonly property bool sectionEnabled: root.isOwner
communityDetails: d.communityDetails
// Profile type
isOwner: root.isOwner
isTokenMasterOwner: false // TODO: Backend
isAdmin: root.isAdmin
tokensModel: root.community.communityTokens
// Owner and TMaster properties
isOwnerTokenDeployed: tokensModelChangesTracker.isOwnerTokenDeployed
isTMasterTokenDeployed: tokensModelChangesTracker.isTMasterTokenDeployed
readonly property CommunityTokensStore communityTokensStore:
rootStore.communityTokensStore
@ -519,6 +534,64 @@ StatusSectionLayout {
}
}
StatusQUtils.ModelChangeTracker {
id: tokensModelChangesTracker
// Owner and TMaster token deployment states
property bool isOwnerTokenDeployed: false
property bool isTMasterTokenDeployed: false
// It will monitorize if Owner and/or TMaster token items are included in the `model` despite the deployment state
property bool ownerOrTMasterTokenItemsExist: false
function checkIfPrivilegedTokenItemsExist() {
return SQUtils.ModelUtils.contains(model, "name", PermissionsHelpers.ownerTokenNameTag + root.communityName) ||
SQUtils.ModelUtils.contains(model, "name", PermissionsHelpers.tMasterTokenNameTag + root.communityName)
}
function reviewTokenDeployState(tagType, isOwner) {
const index = SQUtils.ModelUtils.indexOf(model, "name", tagType + root.communityName)
if(index === -1)
return false
const token = SQUtils.ModelUtils.get(model, index)
// Some assertions:
if(!token.isPrivilegedToken)
return false
if(token.isOwner !== isOwner)
return false
// Deploy state check:
if(token.deployState !== Constants.ContractTransactionStatus.Completed)
return false
// Token deployed!!
return true
}
model: root.community.communityTokens
onRevisionChanged: {
// It will update property to know if Owner and TMaster token items have been added into the tokens list.
ownerOrTMasterTokenItemsExist = checkIfPrivilegedTokenItemsExist()
if(!ownerOrTMasterTokenItemsExist)
return
// It monitors the deployment:
if(!isOwnerTokenDeployed)
isOwnerTokenDeployed = reviewTokenDeployState(PermissionsHelpers.ownerTokenNameTag, true)
if(!isTMasterTokenDeployed)
isTMasterTokenDeployed = reviewTokenDeployState(PermissionsHelpers.tMasterTokenNameTag, false)
// Not necessary to track more changes since privileged tokens have been correctly deployed.
if(isOwnerTokenDeployed && isTMasterTokenDeployed)
tokensModelChangesTracker.enabled = false
}
}
MessageDialog {
id: errorDialog

View File

@ -44,7 +44,7 @@ StatusScrollView {
isOwner: true
artworkSource: root.communityLogo
color: root.communityColor
symbol: PermissionsHelpers.autogenerateSymbol(isOwner, root.communityName)
symbol: PermissionsHelpers.communityNameToSymbol(isOwner, root.communityName)
transferable: true
remotelyDestruct: false
supply: 1
@ -56,7 +56,7 @@ StatusScrollView {
isPrivilegedToken: true
artworkSource: root.communityLogo
color: root.communityColor
symbol: PermissionsHelpers.autogenerateSymbol(isOwner, root.communityName)
symbol: PermissionsHelpers.communityNameToSymbol(isOwner, root.communityName)
remotelyDestruct: true
description: qsTr("This is the %1 TokenMaster token. The hodler of this collectible has full admin rights for the %1 Community in Status and can mint and airdrop %1 Community tokens.").arg(root.communityName)
}
@ -90,13 +90,15 @@ StatusScrollView {
font.pixelSize: d.titleSize
font.bold: true
text: qsTr("Owner-%1").arg(root.communityName)
text: PermissionsHelpers.ownerTokenNameTag + root.communityName
}
TokenInfoPanel {
Layout.fillWidth: true
token: root.ownerToken
accountBoxVisible: false
networkBoxVisible: false
}
StatusModalDivider {
@ -114,13 +116,15 @@ StatusScrollView {
font.pixelSize: d.titleSize
font.bold: true
text: qsTr("TMaster-%1").arg(root.communityName)
text: PermissionsHelpers.tMasterTokenNameTag + root.communityName
}
TokenInfoPanel {
Layout.fillWidth: true
token: root.tMasterToken
accountBoxVisible: false
networkBoxVisible: false
}
StatusModalDivider {

View File

@ -11,16 +11,19 @@ import shared.controls 1.0
import AppLayouts.Wallet.views.collectibles 1.0
import AppLayouts.Communities.panels 1.0
import AppLayouts.Communities.helpers 1.0
StatusScrollView {
id: root
// User profile props
required property bool isOwner
required property bool isAdmin
// General props
property int viewWidth: 560 // by design
property var model
property string communityName
readonly property int count: assetsModel.count + collectiblesModel.count
signal itemClicked(string tokenKey,
@ -38,20 +41,31 @@ StatusScrollView {
readonly property int delegateAssetsHeight: 64
function getSubtitle(deployState, remainingSupply, supply,
isCollectible, isInfiniteSupply) {
function getDeployStateInfo(deployState) {
if(deployState === Constants.ContractTransactionStatus.Failed)
return qsTr("Minting failed")
if(deployState === Constants.ContractTransactionStatus.InProgress)
return qsTr("Minting...")
if(isInfiniteSupply)
return isCollectible ? qsTr("∞ remaining") : ""
return ""
}
return isCollectible
? qsTr("%1 / %2 remaining").arg(remainingSupply).arg(supply)
: ""
function getRemainingInfo(isOwnerToken, isPrivilegedToken,
remainingSupply, supply, isInfiniteSupply) {
// Owner token use case:
if(isOwnerToken)
return qsTr("1 of 1 (you hodl)")
// TMaster token use case:
if(isPrivilegedToken)
return "∞"
// Rest of collectible cases:
if(isInfiniteSupply)
return qsTr("∞ remaining")
return qsTr("%L1 / %L2 remaining").arg(remainingSupply).arg(supply)
}
}
@ -155,10 +169,7 @@ StatusScrollView {
components: [
StatusBaseText {
anchors.verticalCenter: parent.verticalCenter
text: d.getSubtitle(model.deployState,
model.remainingSupply,
model.supply, false,
model.infiniteSupply)
text: d.getDeployStateInfo(model.deployState)
color: model.deployState === Constants.ContractTransactionStatus.Failed
? Theme.palette.dangerColor1 : Theme.palette.baseColor1
font.pixelSize: 13
@ -214,16 +225,22 @@ StatusScrollView {
height: collectiblesGrid.cellHeight
width: collectiblesGrid.cellWidth
title: model.name ? model.name : "..."
subTitle: d.getSubtitle(model.deployState,
model.remainingSupply,
model.supply, true,
model.infiniteSupply)
subTitle: deployState === Constants.ContractTransactionStatus.Completed ?
d.getRemainingInfo(model.isOwner,
model.isPrivilegedToken,
model.remainingSupply,
model.supply,
model.infiniteSupply) :
d.getDeployStateInfo(model.deployState)
subTitleColor: model.deployState === Constants.ContractTransactionStatus.Failed
? Theme.palette.dangerColor1 : Theme.palette.baseColor1
fallbackImageUrl: model.image ? model.image : ""
backgroundColor: "transparent"
isLoading: false
navigationIconVisible: true
navigationIconVisible: false
isPrivilegedToken: model.isPrivilegedToken
isOwner: model.isOwner
ornamentColor: model.color
onClicked: root.itemClicked(model.contractUniqueKey,
model.chainId, model.chainName,

View File

@ -134,7 +134,7 @@ StatusScrollView {
Layout.alignment: Qt.AlignBottom
text: PermissionsHelpers.autogenerateSymbol(panel.isOwner, root.communityName)
text: PermissionsHelpers.communityNameToSymbol(panel.isOwner, root.communityName)
font.pixelSize: Style.current.primaryTextFontSize
color: Theme.palette.baseColor1
}

View File

@ -7,6 +7,8 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import AppLayouts.Communities.panels 1.0
import utils 1.0
Control {
@ -22,6 +24,11 @@ Control {
property bool isLoading: false
property bool navigationIconVisible: false
// Special Owner and TMaster token properties
property bool isPrivilegedToken: false // Owner or TMaster tokens
property bool isOwner: false // Owner token
property color ornamentColor // Relevant color for these special tokens (community color)
signal clicked
implicitHeight: 225
@ -43,6 +50,8 @@ Control {
Layout.margins: Style.current.halfPadding
Layout.fillWidth: true
Layout.preferredHeight: width
visible: !root.isPrivilegedToken
radius: 8
mediaUrl: root.mediaUrl
mediaType: root.mediaType
@ -59,6 +68,25 @@ Control {
}
}
PrivilegedTokenArtworkPanel {
Layout.alignment: Qt.AlignHCenter
Layout.margins: Style.current.halfPadding
Layout.fillWidth: true
Layout.preferredHeight: width
visible: root.isPrivilegedToken
size: PrivilegedTokenArtworkPanel.Size.Medium
artwork: root.fallbackImageUrl
color: root.ornamentColor
isOwner: root.isOwner
Loader {
anchors.fill: parent
active: root.isLoading
sourceComponent: LoadingComponent {radius: image.radius}
}
}
RowLayout {
Layout.leftMargin: Style.current.halfPadding
Layout.rightMargin: Layout.leftMargin
@ -90,6 +118,7 @@ Control {
id: subTitleItem
Layout.alignment: Qt.AlignLeft
Layout.topMargin: 3
Layout.leftMargin: Style.current.halfPadding
Layout.rightMargin: Layout.leftMargin
Layout.fillWidth: !root.isLoading

View File

@ -49,6 +49,8 @@ QtObject {
{
// NOTE for backend team: `ownerToken` and `tMasterToken` can be used to do an assertion before the deployment process starts, since
// the objects have been created to display the token details to the user and must be the same than backend builds.
// TODO: Backend will need to check if the ownerToken or tMasterToken have a valid tokenKey, so it means a deployment retry,
// otherwise, it is a new deployment.
console.log("TODO: Backend Owner and Token Master token deployment!")
}