parent
1d728a5241
commit
4a6257282e
|
@ -0,0 +1,391 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Models 0.1
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
import utils 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
Pane {
|
||||
id: root
|
||||
|
||||
ListModel {
|
||||
id: listModel
|
||||
|
||||
readonly property var data: [
|
||||
// collection 2
|
||||
{
|
||||
tokenId: "id_3",
|
||||
name: "Multi-sequencer Test NFT 1",
|
||||
contractAddress: "contract_2",
|
||||
collectionName: "Multi-sequencer Test NFT",
|
||||
collectionUid: "collection_2",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059810
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ETH", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: Qt.resolvedUrl("")
|
||||
},
|
||||
{
|
||||
tokenId: "id_4",
|
||||
name: "Multi-sequencer Test NFT 2",
|
||||
contractAddress: "contract_2",
|
||||
collectionName: "Multi-sequencer Test NFT",
|
||||
collectionUid: "collection_2",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059811
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ETH", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: Qt.resolvedUrl("")
|
||||
},
|
||||
{
|
||||
tokenId: "id_5",
|
||||
name: "Multi-sequencer Test NFT 3",
|
||||
contractAddress: "contract_2",
|
||||
collectionName: "Multi-sequencer Test NFT",
|
||||
collectionUid: "collection_2",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059899
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ETH", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: Qt.resolvedUrl("")
|
||||
},
|
||||
// collection 1
|
||||
{
|
||||
tokenId: "id_1",
|
||||
name: "Genesis",
|
||||
contractAddress: "contract_1",
|
||||
collectionName: "ERC-1155 Faucet",
|
||||
collectionUid: "collection_1",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 23,
|
||||
txTimestamp: 1714059862
|
||||
},
|
||||
{
|
||||
accountAddress: "account_2",
|
||||
balance: 29,
|
||||
txTimestamp: 1714054862
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("DAI", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: Qt.resolvedUrl("")
|
||||
},
|
||||
{
|
||||
tokenId: "id_2",
|
||||
name: "QAERC1155",
|
||||
contractAddress: "contract_1",
|
||||
collectionName: "ERC-1155 Faucet",
|
||||
collectionUid: "collection_1",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 500,
|
||||
txTimestamp: 1714059864
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: Qt.resolvedUrl("")
|
||||
},
|
||||
// collection 3, community token
|
||||
{
|
||||
tokenId: "id_6",
|
||||
name: "My Token",
|
||||
contractAddress: "contract_3",
|
||||
collectionName: "My Token",
|
||||
collectionUid: "collection_3",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059899
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_1",
|
||||
communityName: "My community",
|
||||
communityImage: Constants.tokenIcon("KIN", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_7",
|
||||
name: "My Token",
|
||||
contractAddress: "contract_3",
|
||||
collectionName: "My Token",
|
||||
collectionUid: "collection_3",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059899
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_1",
|
||||
communityName: "My community",
|
||||
communityImage: Constants.tokenIcon("KIN", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_8",
|
||||
name: "My Token",
|
||||
contractAddress: "contract_3",
|
||||
collectionName: "My Token",
|
||||
collectionUid: "collection_3",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_2",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059999
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_1",
|
||||
communityName: "My community",
|
||||
communityImage: Constants.tokenIcon("KIN", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_9",
|
||||
name: "My Other Token",
|
||||
contractAddress: "contract_4",
|
||||
collectionName: "My Other Token",
|
||||
collectionUid: "collection_4",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059991
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_1",
|
||||
communityName: "My community",
|
||||
communityImage: Constants.tokenIcon("KIN", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_10",
|
||||
name: "My Community 2 Token",
|
||||
contractAddress: "contract_5",
|
||||
collectionName: "My Community 2 Token",
|
||||
collectionUid: "collection_5",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059777
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_2",
|
||||
communityName: "My community 2",
|
||||
communityImage: Constants.tokenIcon("ICOS", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_11",
|
||||
name: "My Community 2 Token",
|
||||
contractAddress: "contract_5",
|
||||
collectionName: "My Community 2 Token",
|
||||
collectionUid: "collection_5",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_1",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059778
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_2",
|
||||
communityName: "My community 2",
|
||||
communityImage: Constants.tokenIcon("ICOS", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_11",
|
||||
name: "My Community 2 Token",
|
||||
contractAddress: "contract_5",
|
||||
collectionName: "My Community 2 Token",
|
||||
collectionUid: "collection_5",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_2",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059779
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_2",
|
||||
communityName: "My community 2",
|
||||
communityImage: Constants.tokenIcon("ICOS", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_12",
|
||||
name: "My Community 2 Token",
|
||||
contractAddress: "contract_5",
|
||||
collectionName: "My Community 2 Token",
|
||||
collectionUid: "collection_5",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_3",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059779
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_2",
|
||||
communityName: "My community 2",
|
||||
communityImage: Constants.tokenIcon("ICOS", false)
|
||||
},
|
||||
{
|
||||
tokenId: "id_13",
|
||||
name: "My Community 2 Token",
|
||||
contractAddress: "contract_5",
|
||||
collectionName: "My Community 2 Token",
|
||||
collectionUid: "collection_5",
|
||||
ownership: [
|
||||
{
|
||||
accountAddress: "account_3",
|
||||
balance: 1,
|
||||
txTimestamp: 1714059788
|
||||
}
|
||||
],
|
||||
imageUrl: Constants.tokenIcon("ZRX", false),
|
||||
mediaUrl: Qt.resolvedUrl(""),
|
||||
communityId: "community_2",
|
||||
communityName: "My community 2",
|
||||
communityImage: Constants.tokenIcon("ICOS", false)
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: {
|
||||
append(data)
|
||||
|
||||
const accounts = new Set()
|
||||
|
||||
data.forEach(e => e.ownership.forEach(
|
||||
e => { accounts.add(e.accountAddress) }))
|
||||
|
||||
accountsSelector.model = [...accounts.values()]
|
||||
}
|
||||
}
|
||||
|
||||
CollectiblesSelectionAdaptor {
|
||||
id: adaptor
|
||||
|
||||
collectiblesModel: listModel
|
||||
accountKey: accountsSelector.selection
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
TokenSelectorNew {
|
||||
collectiblesModel: adaptor.model
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label { text: "Accounts:" }
|
||||
|
||||
RadioButtonFlowSelector {
|
||||
id: accountsSelector
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
GenericListView {
|
||||
label: "Input model"
|
||||
|
||||
model: listModel
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
skipEmptyRoles: true
|
||||
}
|
||||
|
||||
ListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
ScrollBar.vertical: ScrollBar {}
|
||||
clip: true
|
||||
spacing: 5
|
||||
|
||||
model: adaptor.model
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: ListView.view.width
|
||||
|
||||
readonly property var submodel: model.subitems
|
||||
readonly property int submodelCount:
|
||||
model.subitems.ModelCount.count
|
||||
|
||||
Label {
|
||||
text: (model.communityId ? "Community" : "Collection")
|
||||
+ `: ${model.groupName} (count: ${submodelCount})`
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: submodel
|
||||
|
||||
Label {
|
||||
text: "\t" + model.name + " (balance: " + model.balance + "), key: " + model.key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.property: "type"
|
||||
section.delegate: Label {
|
||||
text: section
|
||||
font.underline: true
|
||||
font.bold: true
|
||||
bottomPadding: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Adaptors
|
|
@ -0,0 +1,110 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import AppLayouts.Wallet.views 1.0
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import utils 1.0
|
||||
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
orientation: Qt.Vertical
|
||||
|
||||
Pane {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
Rectangle {
|
||||
color: Theme.palette.statusListItem.backgroundColor
|
||||
border.color: Theme.palette.primaryColor1
|
||||
border.width: 1
|
||||
|
||||
anchors.fill: delegate
|
||||
anchors.margins: -30
|
||||
}
|
||||
|
||||
TokenSelectorCollectibleDelegate {
|
||||
id: delegate
|
||||
|
||||
implicitWidth: 330
|
||||
anchors.centerIn: parent
|
||||
|
||||
name: nameTextField.text
|
||||
balance: balanceSpinBox.value ? balanceSpinBox.value : ""
|
||||
image: Constants.tokenIcon("ETH")
|
||||
|
||||
goDeeperIconVisible: goDeeperSwitch.checked
|
||||
|
||||
interactive: interactiveSwitch.checked
|
||||
highlighted: highlightedSwitch.checked
|
||||
}
|
||||
}
|
||||
|
||||
Pane {
|
||||
SplitView.minimumHeight: 250
|
||||
SplitView.preferredHeight: 250
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
Label {
|
||||
text: "name:"
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: nameTextField
|
||||
|
||||
text: "Crypto Kitties"
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label {
|
||||
text: "balance:"
|
||||
}
|
||||
|
||||
SpinBox {
|
||||
id: balanceSpinBox
|
||||
|
||||
value: 12
|
||||
|
||||
from: 0
|
||||
to: 20
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: interactiveSwitch
|
||||
text: "Interactive"
|
||||
checked: true
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: highlightedSwitch
|
||||
text: "Highlighted"
|
||||
checked: false
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: goDeeperSwitch
|
||||
text: "Go deeper icon visible"
|
||||
checked: false
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
property alias interactiveSwitchChecked: interactiveSwitch.checked
|
||||
property alias highlightedSwitchChecked: highlightedSwitch.checked
|
||||
property alias goDeeperSwitchChecked: goDeeperSwitch.checked
|
||||
}
|
||||
}
|
||||
|
||||
// category: Delegates
|
|
@ -0,0 +1,187 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import utils 1.0
|
||||
|
||||
Pane {
|
||||
readonly property var assetsData: [
|
||||
{
|
||||
tokensKey: "key_1",
|
||||
communityId: "",
|
||||
name: "Status Test Token",
|
||||
currencyBalanceAsString: "42,23 USD",
|
||||
symbol: "STT",
|
||||
iconSource: Constants.tokenIcon("STT"),
|
||||
tokensKey: "STT",
|
||||
|
||||
balances: [
|
||||
{
|
||||
balanceAsString: "0,56",
|
||||
iconUrl: "network/Network=Ethereum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,22",
|
||||
iconUrl: "network/Network=Arbitrum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,12",
|
||||
iconUrl: "network/Network=Optimism"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tokensKey: "key_2",
|
||||
communityId: "",
|
||||
name: "Ether",
|
||||
currencyBalanceAsString: "4 276,86 USD",
|
||||
symbol: "ETH",
|
||||
iconSource: Constants.tokenIcon("ETH"),
|
||||
tokensKey: "ETH",
|
||||
|
||||
balances: [
|
||||
{
|
||||
balanceAsString: "1,01",
|
||||
iconUrl: "network/Network=Optimism"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,47",
|
||||
iconUrl: "network/Network=Arbitrum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,12",
|
||||
iconUrl: "network/Network=Ethereum"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tokensKey: "key_2",
|
||||
communityId: "",
|
||||
name: "Dai Stablecoin",
|
||||
currencyBalanceAsString: "45,92 USD",
|
||||
symbol: "DAI",
|
||||
iconSource: Constants.tokenIcon("DAI"),
|
||||
tokensKey: "DAI",
|
||||
|
||||
balances: [
|
||||
{
|
||||
balanceAsString: "45,12",
|
||||
iconUrl: "network/Network=Arbitrum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,56",
|
||||
iconUrl: "network/Network=Optimism"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,12",
|
||||
iconUrl: "network/Network=Ethereum"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var collectiblesData: [
|
||||
{
|
||||
groupName: "My community",
|
||||
icon: Constants.tokenIcon("BQX"),
|
||||
type: "community",
|
||||
subitems: [
|
||||
{
|
||||
key: "my_community_key_1",
|
||||
name: "My token",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("CFI"),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Crypto Kitties",
|
||||
icon: Constants.tokenIcon("ENJ"),
|
||||
type: "other",
|
||||
subitems: [
|
||||
{
|
||||
key: "collection_1_key_1",
|
||||
name: "Furbeard",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("FUEL"),
|
||||
},
|
||||
{
|
||||
key: "collection_1_key_2",
|
||||
name: "Magicat",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("ENJ"),
|
||||
},
|
||||
{
|
||||
key: "collection_1_key_3",
|
||||
name: "Happy Meow",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("FUN"),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Super Rare",
|
||||
icon: Constants.tokenIcon("CVC"),
|
||||
type: "other",
|
||||
subitems: [
|
||||
{
|
||||
key: "collection_2_key_1",
|
||||
name: "Unicorn 1",
|
||||
balance: 12,
|
||||
icon: Constants.tokenIcon("CVC")
|
||||
},
|
||||
{
|
||||
key: "collection_2_key_2",
|
||||
name: "Unicorn 2",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("CVC")
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Unicorn",
|
||||
icon: Constants.tokenIcon("ELF"),
|
||||
type: "other",
|
||||
subitems: [
|
||||
{
|
||||
key: "collection_3_key_1",
|
||||
name: "Unicorn",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("ELF")
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
ListModel {
|
||||
id: assetsModel
|
||||
|
||||
Component.onCompleted: append(assetsData)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: collectiblesModel
|
||||
|
||||
Component.onCompleted: append(collectiblesData)
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.palette.baseColor3
|
||||
}
|
||||
|
||||
TokenSelectorNew {
|
||||
id: panel
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
assetsModel: assetsModel
|
||||
collectiblesModel: collectiblesModel
|
||||
|
||||
onCollectibleSelected: console.log("collectible selected:", key)
|
||||
onCollectionSelected: console.log("collection selected:", key)
|
||||
onAssetSelected: console.log("asset selected:", key)
|
||||
}
|
||||
}
|
||||
|
||||
// category: Controls
|
|
@ -0,0 +1,236 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
import utils 1.0
|
||||
|
||||
Pane {
|
||||
readonly property var assetsData: [
|
||||
{
|
||||
tokensKey: "key_1",
|
||||
communityId: "",
|
||||
name: "Status Test Token",
|
||||
currencyBalanceAsString: "42,23 USD",
|
||||
symbol: "STT",
|
||||
iconSource: Constants.tokenIcon("STT"),
|
||||
tokensKey: "STT",
|
||||
|
||||
balances: [
|
||||
{
|
||||
balanceAsString: "0,56",
|
||||
iconUrl: "network/Network=Ethereum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,22",
|
||||
iconUrl: "network/Network=Arbitrum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,12",
|
||||
iconUrl: "network/Network=Optimism"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tokensKey: "key_2",
|
||||
communityId: "",
|
||||
name: "Ether",
|
||||
currencyBalanceAsString: "4 276,86 USD",
|
||||
symbol: "ETH",
|
||||
iconSource: Constants.tokenIcon("ETH"),
|
||||
tokensKey: "ETH",
|
||||
|
||||
balances: [
|
||||
{
|
||||
balanceAsString: "1,01",
|
||||
iconUrl: "network/Network=Optimism"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,47",
|
||||
iconUrl: "network/Network=Arbitrum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,12",
|
||||
iconUrl: "network/Network=Ethereum"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tokensKey: "key_2",
|
||||
communityId: "",
|
||||
name: "Dai Stablecoin",
|
||||
currencyBalanceAsString: "45,92 USD",
|
||||
symbol: "DAI",
|
||||
iconSource: Constants.tokenIcon("DAI"),
|
||||
tokensKey: "DAI",
|
||||
|
||||
balances: [
|
||||
{
|
||||
balanceAsString: "45,12",
|
||||
iconUrl: "network/Network=Arbitrum"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,56",
|
||||
iconUrl: "network/Network=Optimism"
|
||||
},
|
||||
{
|
||||
balanceAsString: "0,12",
|
||||
iconUrl: "network/Network=Ethereum"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var collectiblesData: [
|
||||
{
|
||||
groupName: "My community",
|
||||
icon: Constants.tokenIcon("BQX"),
|
||||
type: "community",
|
||||
subitems: [
|
||||
{
|
||||
key: "my_community_key_1",
|
||||
name: "My token",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("CFI"),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Crypto Kitties",
|
||||
icon: Constants.tokenIcon("ENJ"),
|
||||
type: "other",
|
||||
subitems: [
|
||||
{
|
||||
key: "collection_1_key_1",
|
||||
name: "Furbeard",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("FUEL"),
|
||||
},
|
||||
{
|
||||
key: "collection_1_key_2",
|
||||
name: "Magicat",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("ENJ"),
|
||||
},
|
||||
{
|
||||
key: "collection_1_key_3",
|
||||
name: "Happy Meow",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("FUN"),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Super Rare",
|
||||
icon: Constants.tokenIcon("CVC"),
|
||||
type: "other",
|
||||
subitems: [
|
||||
{
|
||||
key: "collection_2_key_1",
|
||||
name: "Unicorn 1",
|
||||
balance: 12,
|
||||
icon: Constants.tokenIcon("CVC")
|
||||
},
|
||||
{
|
||||
key: "collection_2_key_2",
|
||||
name: "Unicorn 2",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("CVC")
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Unicorn",
|
||||
icon: Constants.tokenIcon("ELF"),
|
||||
type: "other",
|
||||
subitems: [
|
||||
{
|
||||
key: "collection_3_key_1",
|
||||
name: "Unicorn",
|
||||
balance: 1,
|
||||
icon: Constants.tokenIcon("ELF")
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
ListModel {
|
||||
id: assetsModel
|
||||
|
||||
Component.onCompleted: append(assetsData)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: collectiblesModel
|
||||
|
||||
Component.onCompleted: append(collectiblesData)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: panel
|
||||
anchors.margins: -1
|
||||
|
||||
color: "transparent"
|
||||
border.color: "lightgray"
|
||||
}
|
||||
|
||||
TokenSelectorPanel {
|
||||
id: panel
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: 350
|
||||
|
||||
assetsModel: assetsModelCheckBox.checked ? assetsModel : null
|
||||
collectiblesModel: collectiblesModelCheckBox.checked
|
||||
? collectiblesModel : null
|
||||
|
||||
onCollectibleSelected: {
|
||||
highlightedKey = key
|
||||
console.log("collectible selected:", key)
|
||||
}
|
||||
|
||||
onCollectionSelected: {
|
||||
highlightedKey = key
|
||||
console.log("collection selected:", key)
|
||||
}
|
||||
|
||||
onAssetSelected: {
|
||||
highlightedKey = key
|
||||
console.log("asset selected:", key)
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Button {
|
||||
text: "Select assets tab"
|
||||
|
||||
onClicked: panel.currentTab = TokenSelectorPanel.Tabs.Assets
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Select collectibles tab"
|
||||
|
||||
onClicked: panel.currentTab = TokenSelectorPanel.Tabs.Collectibles
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: assetsModelCheckBox
|
||||
|
||||
checked: true
|
||||
text: "Assets model assigned"
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: collectiblesModelCheckBox
|
||||
|
||||
checked: true
|
||||
text: "Collectibles model assigned"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Controls
|
|
@ -0,0 +1,185 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
/**
|
||||
Adaptor transforming input flat model of collectibles into grouped model,
|
||||
grouped by communities and collections to form expected by components like
|
||||
e.g. TokenSelector.
|
||||
|
||||
1. Ownership submodels filtered to have only entries for given `account`
|
||||
2. Total balance calculated for remaining ownership entries in submodels
|
||||
3. Balance exposed to the top level model
|
||||
4. Grouping value exposed depending if token comes from community or not
|
||||
(community collectibles are grouped by communtiyId, other by collectionId)
|
||||
5. Entries with zero balance filtered out
|
||||
6. Items are sorted by communityId and collectionId in order to group them correctly
|
||||
7. Grouping by groupingValue
|
||||
8. For community groups, group once again by collectionId
|
||||
9. Expose groupName and type according of it's community group or collection
|
||||
10. Expose sub-sub-groups count as a balance for sub-groups
|
||||
**/
|
||||
QObject {
|
||||
id: root
|
||||
|
||||
/** Account key used for filtering **/
|
||||
property string accountKey
|
||||
|
||||
/**
|
||||
Expected model structure:
|
||||
|
||||
tokenId [string] - unique identifier of a collectible
|
||||
collectionUid [string] - unique identifier of a collection
|
||||
contractAddress [string] - collectible's contract address
|
||||
name [string] - collectible's name e.g. "Magicat"
|
||||
collectionName [string] - collection name e.g. "Crypto Kitties"
|
||||
mediaUrl [url] - collectible's media url
|
||||
imageUrl [url] - collectible's image url
|
||||
communityId [string] - unique identifier of a community for community collectible or empty
|
||||
ownership [model] - submodel of balances per chain/account
|
||||
balance [int] - balance (always 1 for ERC-721)
|
||||
accountAddress [string] - unique identifier of an account
|
||||
**/
|
||||
property var collectiblesModel
|
||||
|
||||
/**
|
||||
Model structure:
|
||||
|
||||
groupName [string] - group name (from collection or community name)
|
||||
icon [url] - from imageUrl or mediaUrl
|
||||
type [string] - can be "community" or "other"
|
||||
subitems [model] - submodel of collectibles/collections of the group
|
||||
key [string] - key of collection (community type) or collectible (other type)
|
||||
name [string] - name of the subitem (of collectible or collection)
|
||||
balance [int] - balance of collection (in case of community collectibles)
|
||||
or collectible (in case of ERC-1155)
|
||||
icon [url] - icon of the subitem
|
||||
**/
|
||||
readonly property alias model: communityGroupsGrouppedByCollection
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: initiallyFilteredAndSorted
|
||||
|
||||
objectName: "collectiblesSelectionAdaptor_initiallyFilteredAndSorted"
|
||||
|
||||
sourceModel: ObjectProxyModel {
|
||||
sourceModel: collectiblesModel ?? null
|
||||
|
||||
delegate: QObject {
|
||||
readonly property int balance: balanceAggregator.value /* 3 */
|
||||
readonly property string groupingValue: model.communityId /* 4 */
|
||||
? model.communityId
|
||||
: model.collectionUid
|
||||
|
||||
readonly property string key: model.tokenId
|
||||
|
||||
readonly property url icon:
|
||||
model.imageUrl || model.mediaUrl || Qt.resolvedUrl("")
|
||||
|
||||
SortFilterProxyModel { /* 1 */
|
||||
id: ownershipFiltered
|
||||
|
||||
sourceModel: model.ownership
|
||||
|
||||
filters: ValueFilter {
|
||||
roleName: "accountAddress"
|
||||
value: root.accountKey
|
||||
}
|
||||
}
|
||||
|
||||
SumAggregator { /* 2 */
|
||||
id: balanceAggregator
|
||||
|
||||
model: ownershipFiltered
|
||||
roleName: "balance"
|
||||
}
|
||||
}
|
||||
|
||||
expectedRoles: [
|
||||
"ownership", "communityId", "collectionUid", "imageUrl",
|
||||
"mediaUrl", "tokenId"
|
||||
]
|
||||
exposedRoles: ["balance", "groupingValue", "icon", "key"]
|
||||
}
|
||||
|
||||
filters: RangeFilter { /* 5 */
|
||||
roleName: "balance"
|
||||
minimumValue: 1
|
||||
}
|
||||
|
||||
sorters: [ /* 6 */
|
||||
RoleSorter {
|
||||
roleName: "communityId"
|
||||
sortOrder: Qt.DescendingOrder
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: "collectionUid"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
GroupingModel { /* 7 */
|
||||
id: grouppedByCollectionOrCommunity
|
||||
|
||||
objectName: "collectiblesSelectionAdaptor_grouppedByCollectionOrCommunity"
|
||||
|
||||
sourceModel: initiallyFilteredAndSorted
|
||||
groupingRoleName: "groupingValue"
|
||||
submodelRoleName: "subitems"
|
||||
}
|
||||
|
||||
ObjectProxyModel {
|
||||
id: communityGroupsGrouppedByCollection
|
||||
|
||||
objectName: "collectiblesSelectionAdaptor_communityGroupsGrouppedByCollection"
|
||||
|
||||
sourceModel: grouppedByCollectionOrCommunity
|
||||
|
||||
delegate: QObject {
|
||||
readonly property var subitems:
|
||||
model.communityId ? collectionCountProxyLoader.item
|
||||
: model.subitems
|
||||
readonly property string type: /* 9 */
|
||||
model.communityId ? "community" : "other"
|
||||
readonly property string groupName:
|
||||
model.communityName || model.collectionName
|
||||
|
||||
readonly property url icon:
|
||||
model.communityId ? model.communityImage
|
||||
: (model.icon || Qt.resolvedUrl(""))
|
||||
|
||||
Loader {
|
||||
id: collectionCountProxyLoader
|
||||
|
||||
active: !!model.communityId
|
||||
|
||||
sourceComponent: ObjectProxyModel {
|
||||
sourceModel: GroupingModel { /* 8 */
|
||||
sourceModel: model.communityId ? model.subitems : null
|
||||
|
||||
groupingRoleName: "collectionUid"
|
||||
submodelRoleName: "subitems"
|
||||
}
|
||||
|
||||
delegate: QtObject { /* 10 */
|
||||
readonly property int balance: model.subitems.ModelCount.count
|
||||
readonly property string key: model.collectionUid
|
||||
}
|
||||
|
||||
expectedRoles: ["subitems", "collectionUid"]
|
||||
exposedRoles: ["balance", "key"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expectedRoles: [
|
||||
"subitems", "collectionName", "communityId",
|
||||
"communityName", "communityImage", "icon"
|
||||
]
|
||||
exposedRoles: ["subitems", "type", "groupName", "icon"]
|
||||
}
|
||||
}
|
|
@ -173,7 +173,7 @@ QObject {
|
|||
|
||||
RolesRenamingModel {
|
||||
id: renamedTokensBySymbolModel
|
||||
sourceModel: root.plainTokensBySymbolModel
|
||||
sourceModel: root.plainTokensBySymbolModel || null
|
||||
mapping: [
|
||||
RoleRename {
|
||||
from: "key"
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
CollectiblesSelectionAdaptor 1.0 CollectiblesSelectionAdaptor.qml
|
||||
TokenSelectorViewAdaptor 1.0 TokenSelectorViewAdaptor.qml
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Components.private 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
Control {
|
||||
id: root
|
||||
|
||||
/** Expected model structure: see TokenSelectorPanel::assetsModel **/
|
||||
property alias assetsModel: tokenSelectorPanel.assetsModel
|
||||
|
||||
/** Expected model structure: see TokenSelectorPanel::collectiblesModel **/
|
||||
property alias collectiblesModel: tokenSelectorPanel.collectiblesModel
|
||||
|
||||
signal assetSelected(string key)
|
||||
signal collectionSelected(string key)
|
||||
signal collectibleSelected(string key)
|
||||
|
||||
// Index of the current tab, indexes correspond to the
|
||||
// TokensSelectorPanel.Tabs enum values.
|
||||
property alias currentTab: tokenSelectorPanel.currentTab
|
||||
|
||||
function setCustom(name: string, icon: url, key: string) {
|
||||
d.isTokenSelected = true
|
||||
d.currentName = name
|
||||
d.currentIcon = icon
|
||||
tokenSelectorPanel.highlightedKey = key ?? ""
|
||||
}
|
||||
|
||||
padding: 10
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
property bool isTokenSelected: false
|
||||
|
||||
property string currentName
|
||||
property url currentIcon
|
||||
}
|
||||
|
||||
background: StatusComboboxBackground {
|
||||
border.width: 0
|
||||
color: {
|
||||
if (d.isTokenSelected)
|
||||
return "transparent"
|
||||
|
||||
return root.hovered || dropdown.opened
|
||||
? Theme.palette.primaryColor2
|
||||
: Theme.palette.primaryColor3
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Loader {
|
||||
sourceComponent: d.isTokenSelected ? selectedContent
|
||||
: notSelectedContent
|
||||
}
|
||||
|
||||
Component {
|
||||
id: notSelectedContent
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
StatusBaseText {
|
||||
objectName: "tokenSelectorContentItemText"
|
||||
font.pixelSize: root.font.pixelSize
|
||||
font.weight: Font.Medium
|
||||
color: Theme.palette.primaryColor1
|
||||
text: qsTr("Select token")
|
||||
}
|
||||
|
||||
StatusComboboxIndicator {
|
||||
color: Theme.palette.primaryColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: selectedContent
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
StatusRoundedImage {
|
||||
objectName: "tokenSelectorIcon"
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
image.source: d.currentIcon
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
objectName: "tokenSelectorContentItemText"
|
||||
font.pixelSize: 28
|
||||
color: root.hovered ? Theme.palette.blue : Theme.palette.darkBlue
|
||||
|
||||
text: d.currentName
|
||||
}
|
||||
|
||||
StatusComboboxIndicator {
|
||||
color: Theme.palette.primaryColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusDropdown {
|
||||
id: dropdown
|
||||
|
||||
y: parent.height + 4
|
||||
|
||||
closePolicy: Popup.CloseOnPressOutsideParent
|
||||
bottomPadding: 0
|
||||
|
||||
contentItem: TokenSelectorPanel {
|
||||
id: tokenSelectorPanel
|
||||
|
||||
function findSubitem(key) {
|
||||
const count = collectiblesModel.rowCount()
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const entry = ModelUtils.get(collectiblesModel, i)
|
||||
const subitem = ModelUtils.getByKey(
|
||||
entry.subitems, "key", key)
|
||||
if (subitem)
|
||||
return subitem
|
||||
}
|
||||
}
|
||||
|
||||
function setCurrentAndClose(name, icon) {
|
||||
d.currentName = name
|
||||
d.currentIcon = icon
|
||||
d.isTokenSelected = true
|
||||
dropdown.close()
|
||||
}
|
||||
|
||||
onAssetSelected: {
|
||||
const entry = ModelUtils.getByKey(assetsModel, "tokensKey", key)
|
||||
highlightedKey = key
|
||||
|
||||
setCurrentAndClose(entry.symbol,
|
||||
Constants.tokenIcon(entry.symbol))
|
||||
root.assetSelected(key)
|
||||
}
|
||||
|
||||
onCollectibleSelected: {
|
||||
highlightedKey = key
|
||||
|
||||
const subitem = findSubitem(key)
|
||||
setCurrentAndClose(subitem.name, subitem.icon)
|
||||
|
||||
root.collectibleSelected(key)
|
||||
}
|
||||
|
||||
onCollectionSelected: {
|
||||
highlightedKey = key
|
||||
|
||||
const subitem = findSubitem(key)
|
||||
setCurrentAndClose(subitem.name, subitem.icon)
|
||||
|
||||
root.collectionSelected(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: dropdown.opened ? dropdown.close() : dropdown.open()
|
||||
}
|
||||
}
|
|
@ -1,22 +1,23 @@
|
|||
NetworkFilter 1.0 NetworkFilter.qml
|
||||
NetworkSelectItemDelegate 1.0 NetworkSelectItemDelegate.qml
|
||||
AccountHeaderGradient 1.0 AccountHeaderGradient.qml
|
||||
StatusTxProgressBar 1.0 StatusTxProgressBar.qml
|
||||
StatusDateRangePicker 1.0 StatusDateRangePicker.qml
|
||||
ActivityFilterTagItem 1.0 ActivityFilterTagItem.qml
|
||||
SortOrderComboBox 1.0 SortOrderComboBox.qml
|
||||
CollectibleBalanceTag 1.0 CollectibleBalanceTag.qml
|
||||
CollectibleLinksTags 1.0 CollectibleLinksTags.qml
|
||||
DappsComboBox 1.0 DappsComboBox.qml
|
||||
EditSlippagePanel 1.0 EditSlippagePanel.qml
|
||||
FilterComboBox 1.0 FilterComboBox.qml
|
||||
InformationTileAssetDetails 1.0 InformationTileAssetDetails.qml
|
||||
ManageTokenMenuButton 1.0 ManageTokenMenuButton.qml
|
||||
ManageTokensCommunityTag 1.0 ManageTokensCommunityTag.qml
|
||||
ManageTokensDelegate 1.0 ManageTokensDelegate.qml
|
||||
ManageTokensGroupDelegate 1.0 ManageTokensGroupDelegate.qml
|
||||
MaxSendButton 1.0 MaxSendButton.qml
|
||||
InformationTileAssetDetails 1.0 InformationTileAssetDetails.qml
|
||||
NetworkFilter 1.0 NetworkFilter.qml
|
||||
NetworkSelectItemDelegate 1.0 NetworkSelectItemDelegate.qml
|
||||
SortOrderComboBox 1.0 SortOrderComboBox.qml
|
||||
StatusDateRangePicker 1.0 StatusDateRangePicker.qml
|
||||
StatusNetworkListItemTag 1.0 StatusNetworkListItemTag.qml
|
||||
CollectibleBalanceTag 1.0 CollectibleBalanceTag.qml
|
||||
CollectibleLinksTags 1.0 CollectibleLinksTags.qml
|
||||
DappsComboBox 1.0 DappsComboBox.qml
|
||||
StatusTxProgressBar 1.0 StatusTxProgressBar.qml
|
||||
SwapExchangeButton 1.0 SwapExchangeButton.qml
|
||||
EditSlippagePanel 1.0 EditSlippagePanel.qml
|
||||
TokenSelector 1.0 TokenSelector.qml
|
||||
SwapModalFooterInfoComponent 1.0 SwapModalFooterInfoComponent.qml
|
||||
TokenSelector 1.0 TokenSelector.qml
|
||||
TokenSelectorNew 1.0 TokenSelectorNew.qml
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
|
||||
import AppLayouts.Wallet.views 1.0
|
||||
import shared.controls 1.0
|
||||
import utils 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
/**
|
||||
Two-tabs panel holding searchable lists of assets (single level) and
|
||||
collectibles (two levels).
|
||||
|
||||
Structure:
|
||||
|
||||
TabBar (assets, collectibles)
|
||||
StackLayout (current index bound to tab bar's current index)
|
||||
Assets List (assets part)
|
||||
StackView (collectibles part)
|
||||
Collectibles List (top level - groups by collection/community)
|
||||
Collectibles List (nested level, on demand)
|
||||
*/
|
||||
Control {
|
||||
id: root
|
||||
|
||||
enum Tabs {
|
||||
Assets = 0,
|
||||
Collectibles = 1
|
||||
}
|
||||
|
||||
/**
|
||||
Expected model structure:
|
||||
|
||||
tokensKey [string] - unique asset's identifier
|
||||
name [string] - asset's name
|
||||
symbol [string] - asset's symbol
|
||||
iconSource [url] - asset's icon
|
||||
currencyBalanceAsString [string] - formatted balance
|
||||
balances [model] - submodel of balances per chain
|
||||
balanceAsString [string] - formatted balance per chain
|
||||
iconUrl [url] - chain's icon
|
||||
**/
|
||||
property alias assetsModel: assetsSfpm.sourceModel
|
||||
|
||||
/**
|
||||
Expected model structure:
|
||||
|
||||
groupName [string] - group name
|
||||
icon [url] - icon image of a group
|
||||
type [string] - group type, can be "community" or "other"
|
||||
subitems [model] - submodel of collectibles/collections of the group
|
||||
key [string] - balance
|
||||
name [string] - name of the subitem
|
||||
balance [int] - balance of the subitem
|
||||
icon [url] - icon of the subitem
|
||||
**/
|
||||
property alias collectiblesModel: collectiblesSfpm.sourceModel
|
||||
|
||||
// Index of the current tab, indexes correspond to the Tabs enum values.
|
||||
property alias currentTab: tabBar.currentIndex
|
||||
|
||||
signal assetSelected(string key)
|
||||
signal collectionSelected(string key)
|
||||
signal collectibleSelected(string key)
|
||||
|
||||
property string highlightedKey: ""
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: assetsSfpm
|
||||
|
||||
filters: AnyOf {
|
||||
SearchFilter {
|
||||
roleName: "name"
|
||||
searchPhrase: assetsSearchBox.text
|
||||
}
|
||||
SearchFilter {
|
||||
roleName: "symbol"
|
||||
searchPhrase: assetsSearchBox.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: collectiblesSfpm
|
||||
|
||||
filters: SearchFilter {
|
||||
roleName: "groupName"
|
||||
searchPhrase: collectiblesSearchBox.text
|
||||
}
|
||||
}
|
||||
|
||||
component SearchFilter: RegExpFilter {
|
||||
required property string searchPhrase
|
||||
|
||||
pattern: `*${searchPhrase}*`
|
||||
caseSensitivity : Qt.CaseInsensitive
|
||||
syntax: RegExpFilter.Wildcard
|
||||
}
|
||||
|
||||
component Search: SearchBox {
|
||||
input.leftPadding: root.leftPadding
|
||||
input.rightPadding: root.leftPadding
|
||||
minimumHeight: 56
|
||||
maximumHeight: 56
|
||||
input.showBackground: false
|
||||
focus: visible
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
StatusTabBar {
|
||||
id: tabBar
|
||||
|
||||
visible: !!root.assetsModel && !!root.collectiblesModel
|
||||
|
||||
currentIndex: !!root.assetsModel
|
||||
? TokenSelectorPanel.Tabs.Assets
|
||||
: TokenSelectorPanel.Tabs.Collectibles
|
||||
|
||||
StatusTabButton {
|
||||
text: qsTr("Assets")
|
||||
width: implicitWidth
|
||||
|
||||
visible: !!root.assetsModel
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
text: qsTr("Collectibles")
|
||||
width: implicitWidth
|
||||
|
||||
visible: !!root.collectiblesModel
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
Layout.maximumHeight: 400
|
||||
|
||||
visible: !!root.assetsModel || !!root.collectiblesModel
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
ColumnLayout {
|
||||
Layout.preferredHeight: visible ? implicitHeight : 0
|
||||
spacing: 0
|
||||
|
||||
Search {
|
||||
id: assetsSearchBox
|
||||
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Search assets")
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
visible: assetsListView.count
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
id: assetsListView
|
||||
|
||||
clip: true
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
|
||||
model: assetsSfpm
|
||||
|
||||
delegate: TokenSelectorAssetDelegate {
|
||||
required property var model
|
||||
required property int index
|
||||
|
||||
highlighted: tokensKey === root.highlightedKey
|
||||
|
||||
tokensKey: model.tokensKey
|
||||
name: model.name
|
||||
symbol: model.symbol
|
||||
currencyBalanceAsString: model.currencyBalanceAsString
|
||||
iconSource: model.iconSource
|
||||
balancesModel: model.balances
|
||||
|
||||
onClicked: root.assetSelected(model.tokensKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: collectiblesStackView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredHeight: visible ? currentItem.implicitHeight : 0
|
||||
|
||||
initialItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Search {
|
||||
id: collectiblesSearchBox
|
||||
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Search collectibles")
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
visible: collectiblesListView.count
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
id: collectiblesListView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
|
||||
clip: true
|
||||
model: collectiblesSfpm
|
||||
|
||||
delegate: TokenSelectorCollectibleDelegate {
|
||||
required property var model
|
||||
|
||||
readonly property int subitemsCount:
|
||||
model.subitems.ModelCount.count
|
||||
|
||||
readonly property bool isCommunity:
|
||||
model.type === "community"
|
||||
|
||||
readonly property bool showCount:
|
||||
subitemsCount > 1 || isCommunity
|
||||
|
||||
name: model.groupName
|
||||
balance: showCount ? subitemsCount : ""
|
||||
image: model.icon
|
||||
goDeeperIconVisible: subitemsCount > 1
|
||||
|| isCommunity
|
||||
highlighted: subitemsCount === 1 && !isCommunity
|
||||
? ModelUtils.get(model.subitems, 0, "key")
|
||||
=== root.highlightedKey
|
||||
: false
|
||||
|
||||
onClicked: {
|
||||
if (subitemsCount === 1 && !isCommunity) {
|
||||
const key = ModelUtils.get(model.subitems, 0, "key")
|
||||
root.collectibleSelected(key)
|
||||
return
|
||||
}
|
||||
|
||||
const parameters = {
|
||||
index: collectiblesSfpm.index(model.index, 0),
|
||||
model: model.subitems,
|
||||
isCommunity: isCommunity
|
||||
}
|
||||
|
||||
collectiblesStackView.push(
|
||||
collectiblesSublistComponent,
|
||||
parameters,
|
||||
StackView.Immediate)
|
||||
}
|
||||
}
|
||||
|
||||
section.property: "type"
|
||||
section.delegate: StatusBaseText {
|
||||
id: sectionTitle
|
||||
|
||||
color: Theme.palette.baseColor1
|
||||
topPadding: Style.current.padding
|
||||
|
||||
text: section === "community"
|
||||
? qsTr("Community minted")
|
||||
: qsTr("Other")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: collectiblesSublistComponent
|
||||
|
||||
ColumnLayout {
|
||||
property var index
|
||||
property alias model: sublistSfpm.sourceModel
|
||||
property bool isCommunity
|
||||
|
||||
spacing: 0
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: sublistSfpm
|
||||
|
||||
filters: SearchFilter {
|
||||
roleName: "name"
|
||||
searchPhrase: collectiblesSublistSearchBox.text
|
||||
}
|
||||
}
|
||||
|
||||
StatusIconTextButton {
|
||||
id: backButton
|
||||
|
||||
statusIcon: "previous"
|
||||
icon.width: 12
|
||||
icon.height: 12
|
||||
text: qsTr("Back")
|
||||
|
||||
onClicked: collectiblesStackView.pop(StackView.Immediate)
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
visible: collectiblesListView.count
|
||||
}
|
||||
|
||||
Search {
|
||||
id: collectiblesSublistSearchBox
|
||||
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Search collectibles")
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
visible: collectiblesListView.count
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
id: sublist
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
|
||||
model: sublistSfpm
|
||||
|
||||
clip: true
|
||||
|
||||
delegate: TokenSelectorCollectibleDelegate {
|
||||
required property var model
|
||||
|
||||
name: model.name
|
||||
balance: model.balance > 1 ? model.balance : ""
|
||||
image: model.icon
|
||||
goDeeperIconVisible: false
|
||||
highlighted: model.key === root.highlightedKey
|
||||
|
||||
onClicked: {
|
||||
if (isCommunity)
|
||||
root.collectionSelected(model.key)
|
||||
else
|
||||
root.collectibleSelected(model.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Detection if the related model entry has been removed.
|
||||
// Using model.Component.destruction.connect is not reliable because
|
||||
// is not called for submodels maintained in c++ by the parent model.
|
||||
ItemSelectionModel {
|
||||
id: selection
|
||||
|
||||
model: collectiblesSfpm
|
||||
|
||||
onHasSelectionChanged: {
|
||||
if (!hasSelection)
|
||||
collectiblesStackView.pop(StackView.Immediate)
|
||||
}
|
||||
|
||||
Component.onCompleted: select(index, ItemSelectionModel.Select)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
WalletHeader 1.0 WalletHeader.qml
|
||||
WalletTxProgressBlock 1.0 WalletTxProgressBlock.qml
|
||||
WalletNftPreview 1.0 WalletNftPreview.qml
|
||||
ActivityFilterPanel 1.0 ActivityFilterPanel.qml
|
||||
ContractInfoButtonWithMenu 1.0 ContractInfoButtonWithMenu.qml
|
||||
DAppsWorkflow 1.0 DAppsWorkflow.qml
|
||||
ManageAssetsPanel 1.0 ManageAssetsPanel.qml
|
||||
ManageCollectiblesPanel 1.0 ManageCollectiblesPanel.qml
|
||||
ManageHiddenPanel 1.0 ManageHiddenPanel.qml
|
||||
DAppsWorkflow 1.0 DAppsWorkflow.qml
|
||||
SwapInputPanel 1.0 SwapInputPanel.qml
|
||||
ContractInfoButtonWithMenu 1.0 ContractInfoButtonWithMenu.qml
|
||||
SignInfoBox 1.0 SignInfoBox.qml
|
||||
SwapInputPanel 1.0 SwapInputPanel.qml
|
||||
TokenSelectorPanel 1.0 TokenSelectorPanel.qml
|
||||
WalletHeader 1.0 WalletHeader.qml
|
||||
WalletNftPreview 1.0 WalletNftPreview.qml
|
||||
WalletTxProgressBlock 1.0 WalletTxProgressBlock.qml
|
||||
|
|
|
@ -18,6 +18,8 @@ QtObject {
|
|||
readonly property var _allCollectiblesModel: !!root._allCollectiblesModule ? root._allCollectiblesModule.allCollectiblesModel : null
|
||||
|
||||
readonly property var allCollectiblesModel: RolesRenamingModel {
|
||||
objectName: "allCollectiblesModel"
|
||||
|
||||
sourceModel: root._allCollectiblesModel
|
||||
|
||||
mapping: [
|
||||
|
@ -85,6 +87,8 @@ QtObject {
|
|||
|
||||
/* PRIVATE: This model joins the "Tokens By Symbol Model" and "Communities Model" by communityId */
|
||||
property LeftJoinModel _jointCollectiblesBySymbolModel: LeftJoinModel {
|
||||
objectName: "jointCollectiblesBySymbolModel"
|
||||
|
||||
leftModel: allCollectiblesModel
|
||||
rightModel: _renamedCommunitiesModel
|
||||
joinRole: "communityId"
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
ItemDelegate {
|
||||
id: root
|
||||
|
||||
required property string name
|
||||
required property string balance
|
||||
required property url image
|
||||
|
||||
property bool goDeeperIconVisible: true
|
||||
property bool interactive: true
|
||||
|
||||
spacing: Style.current.halfPadding
|
||||
horizontalPadding: Style.current.padding
|
||||
verticalPadding: 4
|
||||
|
||||
opacity: interactive ? 1 : 0.3
|
||||
|
||||
implicitWidth: ListView.view.width
|
||||
implicitHeight: 60
|
||||
|
||||
icon.width: 32
|
||||
icon.height: 32
|
||||
icon.source: root.image
|
||||
|
||||
enabled: interactive
|
||||
|
||||
background: Rectangle {
|
||||
radius: Style.current.radius
|
||||
color: (root.interactive && root.hovered) || root.highlighted
|
||||
? Theme.palette.statusListItem.highlightColor
|
||||
: "transparent"
|
||||
|
||||
HoverHandler {
|
||||
cursorShape: root.interactive ? Qt.PointingHandCursor : undefined
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: root.spacing
|
||||
|
||||
// asset icon
|
||||
StatusRoundedImage {
|
||||
Layout.preferredWidth: root.icon.width
|
||||
Layout.preferredHeight: root.icon.height
|
||||
image.source: root.icon.source
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
// name, symbol, total balance
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: root.spacing
|
||||
|
||||
StatusBaseText {
|
||||
id: nameText
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
text: root.name
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
text: root.balance
|
||||
visible: root.balance !== ""
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StatusIcon {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
icon: "tiny/chevron-right"
|
||||
visible: root.goDeeperIconVisible
|
||||
color: Theme.palette.baseColor1
|
||||
width: 16
|
||||
height: 16
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,4 +4,5 @@ NetworkSelectionView 1.0 NetworkSelectionView.qml
|
|||
NetworkSelectorView 1.0 NetworkSelectorView.qml
|
||||
SavedAddresses 1.0 SavedAddresses.qml
|
||||
TokenSelectorAssetDelegate 1.0 TokenSelectorAssetDelegate.qml
|
||||
TokenSelectorCollectibleDelegate 1.0 TokenSelectorCollectibleDelegate.qml
|
||||
TokenSelectorView 1.0 TokenSelectorView.qml
|
||||
|
|
|
@ -90,6 +90,8 @@ QObject {
|
|||
ObjectProxyModel {
|
||||
id: proxyModel
|
||||
|
||||
objectName: "assetsViewAdaptorProxyModel"
|
||||
|
||||
sourceModel: root.tokensModel ?? null
|
||||
|
||||
delegate: QObject {
|
||||
|
|
Loading…
Reference in New Issue