status-desktop/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml

427 lines
13 KiB
QML
Raw Normal View History

import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1
import AppLayouts.Chat.helpers 1.0
StatusDropdown {
id: root
property var store
property string assetKey: ""
property real assetAmount: 0
property string collectibleKey: ""
property real collectibleAmount: 1
property bool collectiblesSpecificAmount: false
property int ensType: EnsPanel.EnsType.Any
property string ensDomainName: ""
signal addAsset(string key, real amount)
signal addCollectible(string key, real amount)
signal addEns(bool any, string customDomain)
signal updateAsset(string key, real amount)
signal updateCollectible(string key, real amount)
signal updateEns(bool any, string customDomain)
signal removeClicked
function reset() {
d.currentHoldingType = HoldingTypes.Type.Asset
d.assetAmountText = ""
d.collectibleAmountText = ""
root.assetKey = ""
root.collectibleKey = ""
root.assetAmount = 0
root.collectibleAmount = 1
root.collectiblesSpecificAmount = false
root.ensType = EnsPanel.EnsType.Any
root.ensDomainName = ""
statesStack.clear()
}
width: d.defaultWidth
padding: d.padding
// force keeping within the bounds of the enclosing window
margins: 0
onClosed: root.reset()
enum FlowType {
Add, Update
}
function openFlow(flowType) {
switch (flowType) {
case HoldingsDropdown.FlowType.Add:
statesStack.push(d.addState)
break
case HoldingsDropdown.FlowType.Update:
statesStack.push(d.updateState)
break
default:
console.warn("Unknown flow type.")
return
}
open()
}
function setActiveTab(holdingType) {
d.currentHoldingType = holdingType
}
QtObject {
id: d
// Internal management properties and signals:
readonly property bool assetsReady: root.assetAmount > 0 && root.assetKey
readonly property bool collectiblesReady: root.collectibleAmount > 0 && root.collectibleKey
readonly property bool ensReady: root.ensType === EnsPanel.EnsType.Any || d.ensDomainNameValid
readonly property string addState: "ADD"
readonly property string updateState: "UPDATE"
readonly property string extendedState: "EXTENDED"
property int holdingsTabMode: HoldingsTabs.Mode.Add
property int extendedDropdownType: ExtendedDropdownContent.Type.Assets
property string assetAmountText: ""
property string collectibleAmountText: ""
property int currentHoldingType: HoldingTypes.Type.Asset
property bool ensDomainNameValid: false
signal addClicked
signal updateClicked
// By design values:
readonly property int padding: 8
readonly property int defaultWidth: 289
readonly property int extendedContentHeight: 380
readonly property int tabsAddModeBaseHeight: 232 - padding * 2
readonly property int tabsAddModeExtendedHeight: 277 - padding * 2
readonly property int tabsUpdateModeBaseHeight: 284 - padding * 2
readonly property int tabsUpdateModeExtendedHeight: tabsUpdateModeBaseHeight
+ (tabsAddModeExtendedHeight - tabsAddModeBaseHeight)
readonly property int backButtonWidth: 56
readonly property int backButtonHeight: 24
readonly property int backButtonToContentSpace: 8
readonly property string defaultAssetNameText: qsTr("Choose asset")
readonly property string defaultCollectibleNameText: qsTr("Choose collectible")
}
QtObject {
id: statesStack
property alias currentState: content.state
property int size: 0
property var states: []
function push(state) {
states.push(state)
currentState = state
size++
}
function pop() {
states.pop()
currentState = states.length ? states[states.length - 1] : ""
size--
}
function clear() {
currentState = ""
size = 0
states = []
}
}
contentItem: ColumnLayout {
id: content
spacing: d.backButtonToContentSpace
StatusIconTextButton {
id: backButton
Layout.preferredWidth: d.backButtonWidth
Layout.preferredHeight: d.backButtonHeight
visible: statesStack.size > 1
spacing: 0
leftPadding: 4
statusIcon: "next"
icon.width: 12
icon.height: 12
iconRotation: 180
text: qsTr("Back")
}
Loader {
id: loader
Layout.fillWidth: true
Layout.fillHeight: true
}
states: [
State {
name: d.addState
PropertyChanges {target: loader; sourceComponent: tabsView}
PropertyChanges {target: root; height: undefined} // use implicit height
},
State {
name: d.updateState
extend: d.addState
PropertyChanges {target: d; holdingsTabMode: HoldingsTabs.Mode.Update}
},
State {
name: d.extendedState
PropertyChanges {target: loader; sourceComponent: extendedView}
PropertyChanges {target: root; height: d.extendedContentHeight}
}
]
}
Component {
id: tabsView
HoldingsTabs {
id: holdingsTabs
readonly property var holdingTypes: [
HoldingTypes.Type.Asset, HoldingTypes.Type.Collectible, HoldingTypes.Type.Ens
]
readonly property var labels: [qsTr("Asset"), qsTr("Collectible"), qsTr("ENS")]
readonly property bool extendedHeight:
d.currentHoldingType === HoldingTypes.Type.Collectible && collectiblesSpecificAmount ||
d.currentHoldingType === HoldingTypes.Type.Ens && root.ensType === EnsPanel.EnsType.CustomSubdomain
implicitHeight: extendedHeight
? (mode === HoldingsTabs.Mode.Add ? d.tabsAddModeExtendedHeight : d.tabsUpdateModeExtendedHeight)
: (mode === HoldingsTabs.Mode.Add ? d.tabsAddModeBaseHeight : d.tabsUpdateModeBaseHeight)
states: [
State {
name: HoldingTypes.Type.Asset
PropertyChanges {target: holdingsTabs; sourceComponent: assetsLayout; addOrUpdateButtonEnabled: d.assetsReady}
},
State {
name: HoldingTypes.Type.Collectible
PropertyChanges {target: holdingsTabs; sourceComponent: collectiblesLayout; addOrUpdateButtonEnabled: d.collectiblesReady}
},
State {
name: HoldingTypes.Type.Ens
PropertyChanges {target: holdingsTabs; sourceComponent: ensLayout; addOrUpdateButtonEnabled: d.ensReady}
}
]
tabLabels: labels
state: d.currentHoldingType
mode: d.holdingsTabMode
currentIndex: holdingTypes.indexOf(d.currentHoldingType)
onCurrentIndexChanged: d.currentHoldingType = holdingTypes[currentIndex]
onAddClicked: d.addClicked()
onUpdateClicked: d.updateClicked()
onRemoveClicked: root.removeClicked()
Connections {
target: backButton
function onClicked() {
statesStack.pop()
}
}
}
}
Component {
id: assetsLayout
AssetsPanel {
id: assetsPanel
assetName: d.defaultAssetNameText
amountText: d.assetAmountText
onAmountTextChanged: d.assetAmountText = amountText
readonly property real effectiveAmount: amountValid ? amount : 0
onEffectiveAmountChanged: root.assetAmount = effectiveAmount
onPickerClicked: {
d.extendedDropdownType = ExtendedDropdownContent.Type.Assets
statesStack.push(d.extendedState)
}
readonly property string assetKey: root.assetKey
onAssetKeyChanged: {
const modelItem = CommunityPermissionsHelpers.getAssetByKey(
store.assetsModel, assetKey)
if (modelItem) {
assetsPanel.assetName = modelItem.shortName
assetsPanel.assetImage = modelItem.iconSource
} else {
assetsPanel.assetName = d.defaultAssetNameText
assetsPanel.assetImage = ""
}
}
Component.onCompleted: {
if (d.assetAmountText.length === 0 && root.assetAmount)
assetsPanel.setAmount(root.assetAmount)
}
Connections {
target: d
function onAddClicked() {
root.addAsset(root.assetKey, root.assetAmount)
}
function onUpdateClicked() {
root.updateAsset(root.assetKey, root.assetAmount)
}
}
}
}
Component {
id: collectiblesLayout
CollectiblesPanel {
id: collectiblesPanel
collectibleName: d.defaultCollectibleNameText
amountText: d.collectibleAmountText
onAmountTextChanged: d.collectibleAmountText = amountText
readonly property real effectiveAmount: amountValid ? amount : 0
onEffectiveAmountChanged: root.collectibleAmount = effectiveAmount
specificAmount: root.collectiblesSpecificAmount
onSpecificAmountChanged: root.collectiblesSpecificAmount = specificAmount
onPickerClicked: {
d.extendedDropdownType = ExtendedDropdownContent.Type.Collectibles
statesStack.push(d.extendedState)
}
Component.onCompleted: {
if (d.collectibleAmountText.length === 0 && root.collectibleAmount)
collectiblesPanel.setAmount(root.collectibleAmount)
}
function getAmount() {
return specificAmount ? effectiveAmount : 1
}
Connections {
target: d
function onAddClicked() {
root.addCollectible(root.collectibleKey, collectiblesPanel.getAmount())
}
function onUpdateClicked() {
root.updateCollectible(root.collectibleKey, collectiblesPanel.getAmount())
}
}
readonly property string collectibleKey: root.collectibleKey
onCollectibleKeyChanged: {
const modelItem = CommunityPermissionsHelpers.getCollectibleByKey(
store.collectiblesModel, collectibleKey)
if (modelItem) {
collectiblesPanel.collectibleName = modelItem.name
collectiblesPanel.collectibleImage = modelItem.iconSource
} else {
collectiblesPanel.collectibleName = d.defaultCollectibleNameText
collectiblesPanel.collectibleImage = ""
}
}
}
}
Component {
id: ensLayout
EnsPanel {
ensType: root.ensType
onEnsTypeChanged: root.ensType = ensType
domainName: root.ensDomainName
onDomainNameChanged: root.ensDomainName = domainName
onDomainNameValidChanged: d.ensDomainNameValid = domainNameValid
Connections {
target: d
function onAddClicked() {
root.addEns(root.ensType === EnsPanel.EnsType.Any, root.ensDomainName)
}
function onUpdateClicked() {
root.updateEns(root.ensType === EnsPanel.EnsType.Any, root.ensDomainName)
}
}
}
}
Component {
id: extendedView
ExtendedDropdownContent {
id: extendedDropdown
store: root.store
type: d.extendedDropdownType
onItemClicked: {
statesStack.pop()
if(d.extendedDropdownType === ExtendedDropdownContent.Type.Assets)
root.assetKey = key
else
root.collectibleKey = key
}
Connections {
target: backButton
function onClicked() {
if (extendedDropdown.canGoBack)
extendedDropdown.goBack()
else
statesStack.pop()
}
}
}
}
}