2023-05-04 10:01:59 +00:00
|
|
|
import QtQuick 2.15
|
2023-03-07 11:32:45 +00:00
|
|
|
import QtQuick.Layouts 1.14
|
2023-05-04 10:01:59 +00:00
|
|
|
import QtGraphicalEffects 1.0
|
2023-03-07 11:32:45 +00:00
|
|
|
|
2024-02-28 18:02:44 +00:00
|
|
|
import StatusQ 0.1
|
2023-03-07 11:32:45 +00:00
|
|
|
import StatusQ.Core 0.1
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
import StatusQ.Controls 0.1
|
|
|
|
import StatusQ.Components 0.1
|
2023-05-16 14:50:43 +00:00
|
|
|
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
2023-03-07 11:32:45 +00:00
|
|
|
|
|
|
|
import utils 1.0
|
|
|
|
import shared.panels 1.0
|
|
|
|
|
2023-06-23 06:17:04 +00:00
|
|
|
import AppLayouts.Communities.helpers 1.0
|
|
|
|
import AppLayouts.Communities.panels 1.0
|
2023-03-07 11:32:45 +00:00
|
|
|
|
2023-07-27 20:29:31 +00:00
|
|
|
import SortFilterProxyModel 0.2
|
|
|
|
|
2023-03-07 11:32:45 +00:00
|
|
|
StatusScrollView {
|
|
|
|
id: root
|
|
|
|
|
|
|
|
property int viewWidth: 560 // by design
|
|
|
|
property bool preview: false
|
2024-02-28 18:02:44 +00:00
|
|
|
property bool isOwnerTokenItem: false
|
2023-06-22 21:24:30 +00:00
|
|
|
|
|
|
|
// https://bugreports.qt.io/browse/QTBUG-84269
|
2023-07-03 14:56:25 +00:00
|
|
|
/* required */ property TokenObject token
|
2023-09-01 09:27:44 +00:00
|
|
|
/* required */ property string feeText
|
|
|
|
/* required */ property string feeErrorText
|
|
|
|
/* required */ property bool isFeeLoading
|
|
|
|
|
2023-06-22 21:24:30 +00:00
|
|
|
|
2023-07-03 14:44:02 +00:00
|
|
|
readonly property bool isAssetView: token.type === Constants.TokenType.ERC20
|
2023-06-22 21:24:30 +00:00
|
|
|
|
|
|
|
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
|
2023-12-19 08:55:47 +00:00
|
|
|
readonly property int multiplierIndex: token.multiplierIndex
|
2023-06-01 10:38:56 +00:00
|
|
|
|
2023-07-03 14:56:25 +00:00
|
|
|
readonly property bool deploymentCompleted:
|
|
|
|
deployState === Constants.ContractTransactionStatus.Completed
|
|
|
|
|
2023-07-27 20:29:31 +00:00
|
|
|
readonly property string feeLabel:
|
|
|
|
isAssetView ? qsTr("Mint asset on %1").arg(token.chainName)
|
|
|
|
: qsTr("Mint collectible on %1").arg(token.chainName)
|
2023-09-01 09:27:44 +00:00
|
|
|
|
2023-06-01 10:38:56 +00:00
|
|
|
// Models:
|
2023-05-25 10:31:32 +00:00
|
|
|
property var tokenOwnersModel
|
2024-02-28 18:02:44 +00:00
|
|
|
property var membersModel
|
2023-05-25 10:31:32 +00:00
|
|
|
|
2023-07-27 20:29:31 +00:00
|
|
|
// Required for preview mode:
|
|
|
|
property var accounts
|
2023-06-01 10:38:56 +00:00
|
|
|
signal mintClicked()
|
2023-05-25 10:31:32 +00:00
|
|
|
|
2023-06-05 13:49:36 +00:00
|
|
|
signal airdropRequested(string address)
|
|
|
|
signal generalAirdropRequested
|
|
|
|
|
2023-08-17 07:24:14 +00:00
|
|
|
signal viewProfileRequested(string contactId)
|
|
|
|
signal viewMessagesRequested(string contactId)
|
|
|
|
|
2023-08-02 15:32:36 +00:00
|
|
|
signal remoteDestructRequested(string name, string address)
|
2023-09-21 13:02:18 +00:00
|
|
|
signal kickRequested(string name, string contactId, string address)
|
|
|
|
signal banRequested(string name, string contactId, string address)
|
2023-06-05 13:49:36 +00:00
|
|
|
|
2024-06-03 08:31:26 +00:00
|
|
|
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()
|
|
|
|
|
2023-03-07 11:32:45 +00:00
|
|
|
QtObject {
|
|
|
|
id: d
|
|
|
|
|
|
|
|
readonly property int iconSize: 20
|
2024-09-19 20:32:38 +00:00
|
|
|
property bool loadingTokenHolders: false
|
2024-02-28 18:02:44 +00:00
|
|
|
|
|
|
|
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"
|
|
|
|
}
|
2023-03-07 11:32:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
padding: 0
|
2023-06-20 06:55:16 +00:00
|
|
|
contentWidth: mainLayout.width
|
|
|
|
contentHeight: mainLayout.height
|
2023-03-07 11:32:45 +00:00
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
id: mainLayout
|
|
|
|
|
|
|
|
width: root.viewWidth
|
|
|
|
spacing: Style.current.padding
|
|
|
|
|
|
|
|
RowLayout {
|
2023-07-03 14:56:25 +00:00
|
|
|
visible: !root.preview && !root.deploymentCompleted
|
2023-03-07 11:32:45 +00:00
|
|
|
spacing: Style.current.halfPadding
|
|
|
|
|
2023-06-01 10:38:56 +00:00
|
|
|
StatusDotsLoadingIndicator { visible: (root.deployState === Constants.ContractTransactionStatus.InProgress) }
|
2023-05-17 10:00:52 +00:00
|
|
|
|
|
|
|
StatusIcon {
|
2023-05-05 11:03:59 +00:00
|
|
|
visible: (root.deployState === Constants.ContractTransactionStatus.Failed)
|
2023-05-17 10:00:52 +00:00
|
|
|
icon: "warning"
|
|
|
|
color: Theme.palette.dangerColor1
|
|
|
|
}
|
2023-03-07 11:32:45 +00:00
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
elide: Text.ElideRight
|
|
|
|
font.pixelSize: Theme.primaryTextFontSize
|
2023-05-05 11:03:59 +00:00
|
|
|
text: (root.deployState === Constants.ContractTransactionStatus.InProgress) ?
|
2023-05-25 10:31:32 +00:00
|
|
|
(root.isAssetView ?
|
|
|
|
qsTr("Asset is being minted") : qsTr("Collectible is being minted")) :
|
2023-05-05 11:03:59 +00:00
|
|
|
(root.deployState === Constants.ContractTransactionStatus.Failed) ?
|
2023-05-25 10:31:32 +00:00
|
|
|
(root.isAssetView ? qsTr("Asset minting failed") : qsTr("Collectible minting failed")) : ""
|
2023-05-05 11:03:59 +00:00
|
|
|
color: (root.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.directColor1
|
2023-03-07 11:32:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:38 +00:00
|
|
|
TokenInfoPanel {
|
2023-03-07 11:32:45 +00:00
|
|
|
Layout.fillWidth: true
|
|
|
|
|
2023-07-18 12:39:38 +00:00
|
|
|
token: root.token
|
2023-05-15 12:49:26 +00:00
|
|
|
}
|
|
|
|
|
2023-03-07 11:32:45 +00:00
|
|
|
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: Style.current.primaryTextFontSize
|
|
|
|
color: Theme.palette.baseColor1
|
2024-09-19 20:32:38 +00:00
|
|
|
text: qsTr("Review token details before minting it as they can't be edited later")
|
2023-03-07 11:32:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 20:29:31 +00:00
|
|
|
FeesBox {
|
|
|
|
id: feesBox
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.topMargin: Style.current.padding
|
|
|
|
|
|
|
|
implicitWidth: 0
|
2023-03-07 11:32:45 +00:00
|
|
|
visible: root.preview
|
2023-07-27 20:29:31 +00:00
|
|
|
|
|
|
|
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 !== ""
|
|
|
|
}
|
|
|
|
|
2023-08-09 12:31:58 +00:00
|
|
|
accountsSelector.model: root.accounts || null
|
2024-06-07 12:27:56 +00:00
|
|
|
accountsSelector.selectedAddress: root.token.accountAddress
|
2023-07-27 20:29:31 +00:00
|
|
|
|
2024-06-07 12:27:56 +00:00
|
|
|
Binding {
|
|
|
|
target: root.token
|
|
|
|
property: "accountAddress"
|
|
|
|
value: feesBox.accountsSelector.currentAccountAddress
|
|
|
|
}
|
2023-07-27 20:29:31 +00:00
|
|
|
|
2024-06-07 12:27:56 +00:00
|
|
|
Binding {
|
|
|
|
target: root.token
|
|
|
|
property: "accountName"
|
|
|
|
value: feesBox.accountsSelector.currentAccount.name
|
2023-07-27 20:29:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusButton {
|
2023-03-07 11:32:45 +00:00
|
|
|
Layout.preferredHeight: 44
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.topMargin: Style.current.halfPadding
|
2023-07-27 20:29:31 +00:00
|
|
|
|
|
|
|
visible: root.preview
|
|
|
|
enabled: !root.isFeeLoading && root.feeErrorText === ""
|
|
|
|
|
2023-03-07 11:32:45 +00:00
|
|
|
text: qsTr("Mint")
|
|
|
|
|
2023-06-01 10:38:56 +00:00
|
|
|
onClicked: root.mintClicked()
|
2023-03-07 11:32:45 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 18:02:44 +00:00
|
|
|
Loader {
|
|
|
|
id: tokenHolderLoader
|
|
|
|
|
2023-07-03 14:56:25 +00:00
|
|
|
visible: !root.preview && root.deploymentCompleted
|
2024-09-19 20:32:38 +00:00
|
|
|
sourceComponent: isOwnerTokenItem ? tokenHolderContact : (token.tokenHoldersLoading ? tokenHoldersLoadingComponent : sortableTokenHolderPanel)
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: tokenHoldersLoadingComponent
|
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
text: qsTr("Loading token holders...")
|
|
|
|
}
|
2024-02-28 18:02:44 +00:00
|
|
|
}
|
2023-06-05 13:49:36 +00:00
|
|
|
|
2024-02-28 18:02:44 +00:00
|
|
|
Component {
|
|
|
|
id: sortableTokenHolderPanel
|
2023-06-05 13:49:36 +00:00
|
|
|
|
2024-02-28 18:02:44 +00:00
|
|
|
SortableTokenHoldersPanel {
|
|
|
|
model: root.tokenOwnersModel
|
|
|
|
tokenName: root.name
|
|
|
|
showRemotelyDestructMenuItem: !root.isAssetView && root.remotelyDestruct
|
|
|
|
isAirdropEnabled: root.deploymentCompleted &&
|
|
|
|
(token.infiniteSupply || token.remainingTokens > 0)
|
|
|
|
multiplierIndex: root.multiplierIndex
|
2023-06-05 13:49:36 +00:00
|
|
|
|
2024-02-28 18:02:44 +00:00
|
|
|
Layout.topMargin: Style.current.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)
|
|
|
|
}
|
|
|
|
}
|
2023-08-02 15:32:36 +00:00
|
|
|
|
2024-02-28 18:02:44 +00:00
|
|
|
Component {
|
|
|
|
id: tokenHolderContact
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.topMargin: Style.current.padding
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
font.pixelSize: Style.current.primaryTextFontSize
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
|
|
|
|
text: qsTr("%1 token hodler").arg(root.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusInfoBoxPanel {
|
|
|
|
id: infoBoxPanel
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.topMargin: Style.current.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: Style.current.bigPadding
|
|
|
|
displayMarginEnd: anchors.bottomMargin
|
|
|
|
|
|
|
|
model: d.joinModel
|
|
|
|
delegate: StatusMemberListItem {
|
|
|
|
color: "transparent"
|
|
|
|
leftPadding: 0
|
|
|
|
rightPadding: 0
|
2024-09-06 13:11:47 +00:00
|
|
|
hoverEnabled: false
|
2024-02-28 18:02:44 +00:00
|
|
|
|
|
|
|
nickName: model.localNickname
|
|
|
|
userName: ProfileUtils.displayName("", model.ensName, model.displayName, model.alias)
|
|
|
|
pubKey: model.isEnsVerified ? "" : Utils.getCompressedPk(model.pubKey)
|
|
|
|
isContact: model.isContact
|
|
|
|
isVerified: model.verificationStatus === Constants.verificationStatus.verified
|
|
|
|
isUntrustworthy: model.trustStatus === Constants.trustStatus.untrustworthy
|
|
|
|
status: model.onlineStatus
|
2024-09-06 13:11:47 +00:00
|
|
|
icon.name: model.icon
|
|
|
|
icon.color: Utils.colorForPubkey(model.pubKey)
|
2024-02-28 18:02:44 +00:00
|
|
|
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-07 11:32:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|