status-desktop/ui/app/AppLayouts/Communities/views/CommunityTokenView.qml

333 lines
12 KiB
QML

import QtQuick 2.15
import QtQuick.Layouts 1.15
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import utils 1.0
import shared.panels 1.0
import AppLayouts.Communities.helpers 1.0
import AppLayouts.Communities.panels 1.0
import SortFilterProxyModel 0.2
StatusScrollView {
id: root
property int viewWidth: 560 // by design
property bool preview: false
property bool isOwnerTokenItem: false
// https://bugreports.qt.io/browse/QTBUG-84269
/* required */ property TokenObject token
/* required */ property string feeText
/* required */ property string feeErrorText
/* required */ property bool isFeeLoading
readonly property bool isAssetView: token.type === Constants.TokenType.ERC20
readonly property string name: token.name
readonly property string description: token.description
readonly property string symbol: token.symbol
readonly property int supply: token.supply
readonly property url artworkSource: token.artworkSource
readonly property rect artworkCropRect: token.artworkCropRect
readonly property bool infiniteSupply: token.infiniteSupply
readonly property int remainingTokens: root.preview ? root.supply : token.remainingTokens
readonly property int deployState: token.deployState
readonly property string accountName: token.accountName
readonly property string chainName: token.chainName
readonly property string chainId: token.chainId
readonly property string accountAddress: token.accountAddress
readonly property bool remotelyDestruct: token.remotelyDestruct
readonly property int remotelyDestructState: token.remotelyDestructState
readonly property bool transferable: token.transferable
readonly property string chainIcon: token.chainIcon
readonly property int decimals: token.decimals
readonly property int multiplierIndex: token.multiplierIndex
readonly property bool deploymentCompleted:
deployState === Constants.ContractTransactionStatus.Completed
readonly property string feeLabel:
isAssetView ? qsTr("Mint asset on %1").arg(token.chainName)
: qsTr("Mint collectible on %1").arg(token.chainName)
// Models:
property var tokenOwnersModel
property var membersModel
// Required for preview mode:
property var accounts
signal mintClicked()
signal airdropRequested(string address)
signal generalAirdropRequested
signal viewProfileRequested(string contactId)
signal viewMessagesRequested(string contactId)
signal remoteDestructRequested(string name, string address)
signal kickRequested(string name, string contactId, string address)
signal banRequested(string name, string contactId, string address)
signal startTokenHoldersManagement(int chainId, string address)
signal stopTokenHoldersManagement()
onVisibleChanged: {
if (visible) {
root.startTokenHoldersManagement(root.chainId, root.token.tokenAddress)
} else {
root.stopTokenHoldersManagement()
}
}
Component.onCompleted: root.startTokenHoldersManagement(root.chainId, root.token.tokenAddress)
Component.onDestruction: root.stopTokenHoldersManagement()
QtObject {
id: d
readonly property int iconSize: 20
property bool loadingTokenHolders: false
readonly property var renamedTokenOwnersModel: RolesRenamingModel {
sourceModel: root.tokenOwnersModel
mapping: [
RoleRename {
from: "contactId"
to: "pubKey"
}
]
}
readonly property LeftJoinModel joinModel: LeftJoinModel {
leftModel: root.membersModel
rightModel: d.renamedTokenOwnersModel
joinRole: "pubKey"
}
}
padding: 0
contentWidth: mainLayout.width
contentHeight: mainLayout.height
ColumnLayout {
id: mainLayout
width: root.viewWidth
spacing: Theme.padding
RowLayout {
visible: !root.preview && !root.deploymentCompleted
spacing: Theme.halfPadding
StatusDotsLoadingIndicator { visible: (root.deployState === Constants.ContractTransactionStatus.InProgress) }
StatusIcon {
visible: (root.deployState === Constants.ContractTransactionStatus.Failed)
icon: "warning"
color: Theme.palette.dangerColor1
}
StatusBaseText {
elide: Text.ElideRight
font.pixelSize: Theme.primaryTextFontSize
text: (root.deployState === Constants.ContractTransactionStatus.InProgress) ?
(root.isAssetView ?
qsTr("Asset is being minted") : qsTr("Collectible is being minted")) :
(root.deployState === Constants.ContractTransactionStatus.Failed) ?
(root.isAssetView ? qsTr("Asset minting failed") : qsTr("Collectible minting failed")) : ""
color: (root.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.directColor1
}
}
TokenInfoPanel {
Layout.fillWidth: true
token: root.token
}
RowLayout {
visible: root.preview
Layout.fillWidth: true
StatusIcon {
Layout.preferredWidth: d.iconSize
Layout.preferredHeight: d.iconSize
Layout.alignment: Qt.AlignTop
color: Theme.palette.baseColor1
icon: "info"
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: Theme.primaryTextFontSize
color: Theme.palette.baseColor1
text: qsTr("Review token details before minting it as they can't be edited later")
}
}
FeesBox {
id: feesBox
Layout.fillWidth: true
Layout.topMargin: Theme.padding
implicitWidth: 0
visible: root.preview
accountErrorText: root.feeErrorText
model: QtObject {
readonly property string title: root.feeLabel
readonly property string feeText: root.isFeeLoading ?
"" : root.feeText
readonly property bool error: root.feeErrorText !== ""
}
accountsSelector.model: root.accounts || null
accountsSelector.selectedAddress: root.token.accountAddress
Binding {
target: root.token
property: "accountAddress"
value: feesBox.accountsSelector.currentAccountAddress
}
Binding {
target: root.token
property: "accountName"
value: feesBox.accountsSelector.currentAccount.name
}
}
StatusButton {
Layout.preferredHeight: 44
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.topMargin: Theme.halfPadding
visible: root.preview
enabled: !root.isFeeLoading && root.feeErrorText === ""
text: qsTr("Mint")
onClicked: root.mintClicked()
}
Loader {
id: tokenHolderLoader
visible: !root.preview && root.deploymentCompleted
sourceComponent: isOwnerTokenItem ? tokenHolderContact : (token.tokenHoldersLoading ? tokenHoldersLoadingComponent : sortableTokenHolderPanel)
}
Component {
id: tokenHoldersLoadingComponent
StatusBaseText {
text: qsTr("Loading token holders...")
}
}
Component {
id: sortableTokenHolderPanel
SortableTokenHoldersPanel {
model: root.tokenOwnersModel
tokenName: root.name
showRemotelyDestructMenuItem: !root.isAssetView && root.remotelyDestruct
isAirdropEnabled: root.deploymentCompleted &&
(token.infiniteSupply || token.remainingTokens > 0)
multiplierIndex: root.multiplierIndex
Layout.topMargin: Theme.padding
Layout.fillWidth: true
onViewProfileRequested: root.viewProfileRequested(contactId)
onViewMessagesRequested: root.viewMessagesRequested(contactId)
onAirdropRequested: root.airdropRequested(address)
onGeneralAirdropRequested: root.generalAirdropRequested()
onRemoteDestructRequested: root.remoteDestructRequested(name, address)
onKickRequested: root.kickRequested(name, contactId, address)
onBanRequested: root.banRequested(name, contactId, address)
}
}
Component {
id: tokenHolderContact
ColumnLayout {
Layout.topMargin: Theme.padding
Layout.fillWidth: true
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: Theme.primaryTextFontSize
color: Theme.palette.baseColor1
text: qsTr("%1 token hodler").arg(root.name)
}
StatusInfoBoxPanel {
id: infoBoxPanel
Layout.fillWidth: true
Layout.topMargin: Theme.padding
enabled: root.deploymentCompleted && (token.infiniteSupply || token.remainingTokens > 0)
visible: d.joinModel.rowCount() === 0
title: qsTr("No hodlers just yet")
text: qsTr("You can Airdrop tokens to deserving Community members or to give individuals token-based permissions.")
buttonText: qsTr("Airdrop")
onClicked: root.generalAirdropRequested()
}
StatusListView {
id: tokenOwnerList
objectName: "tokenOwnerList"
clip: false
Layout.fillWidth: true
Layout.fillHeight: true
anchors.bottomMargin: Theme.bigPadding
displayMarginEnd: anchors.bottomMargin
model: d.joinModel
delegate: StatusMemberListItem {
color: "transparent"
leftPadding: 0
rightPadding: 0
hoverEnabled: false
nickName: model.localNickname
userName: ProfileUtils.displayName("", model.ensName, model.displayName, model.alias)
pubKey: model.isEnsVerified ? "" : Utils.getCompressedPk(model.pubKey)
isContact: model.isContact
isVerified: model.trustStatus === Constants.trustStatus.trusted
isUntrustworthy: model.trustStatus === Constants.trustStatus.untrustworthy
status: model.onlineStatus
icon.name: model.icon
icon.color: Utils.colorForPubkey(model.pubKey)
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey)
}
}
}
}
}
}