Wallet(SendModal): Old HodlingSelector and TokensListView removed

This commit is contained in:
Michał Cieślak 2024-07-10 00:24:35 +02:00 committed by Michał
parent f6320f69cb
commit 4bf2f4df7a
16 changed files with 3 additions and 1305 deletions

View File

@ -1,67 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import Models 1.0
import Storybook 1.0
import shared.popups.send.views 1.0
import AppLayouts.Wallet.stores 1.0
import StatusQ.Core.Utils 0.1
import shared.stores 1.0
import shared.stores.send 1.0
SplitView {
id: root
orientation: Qt.Vertical
readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore {
assetsWithFilteredBalances: groupedAccountsAssetsModel
}
TransactionStore {
id: txStore
walletAssetStore: root.walletAssetStore
}
readonly property CurrenciesStore currencyStore: CurrenciesStore {}
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
Rectangle {
anchors.fill: parent
color: "lightgray"
}
TokenListView {
anchors.centerIn: parent
width: 400
height: 600
assets: txStore.processedAssetsModel
collectibles: WalletNestedCollectiblesModel {}
networksModel: NetworksModel.flatNetworks
formatCurrentCurrencyAmount: function(balance){
return currencyStore.formatCurrencyAmount(balance, "USD")
}
formatCurrencyAmountFromBigInt: function(balance, symbol, decimals){
return currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals)
}
}
}
LogsAndControlsPanel {
SplitView.minimumHeight: 100
SplitView.preferredHeight: 100
SplitView.fillWidth: true
}
}
// category: Views

View File

@ -1,112 +0,0 @@
import QtQuick 2.15
ListModel {
readonly property var rootData: [
{
uid: "ID-Anniversary",
chainId: 1,
name: "Anniversary",
iconUrl: ModelsData.collectibles.anniversary,
collectionUid: "anniversary",
collectionName: "Anniversary",
isCollection: false,
},
{
uid: "ID-SuperRare",
chainId: 1,
name: "SuperRare",
iconUrl: ModelsData.collectibles.superRare,
collectionUid: "super-rare",
collectionName: "SuperRare",
isCollection: false,
},
{
uid: "cryptokitties",
chainId: 1,
name: "CryptoKitties",
iconUrl: ModelsData.collectibles.cryptoKitties,
collectionUid: "cryptokitties",
collectionName: "CryptoKitties",
isCollection: true,
},
{
uid: "ID-Custom",
chainId: 1,
name: "Custom Collectible",
iconUrl: ModelsData.collectibles.custom,
collectionUid: "custom",
collectionName: "Custom",
isCollection: false,
},
{
uid: "ID-Community1",
chainId: 1,
name: "Community Admin Token",
iconUrl: ModelsData.collectibles.mana,
collectionUid: "community-uid-1",
isCollection: false,
communityId: "community-id-1"
},
]
readonly property var criptoKittiesData: [
{
uid: "ID-Kitty1",
chainId: 1,
name: "Furbeard",
iconUrl: ModelsData.collectibles.kitty1Big,
collectionUid: "cryptokitties",
collectionName: "CryptoKitties",
isCollection: false,
},
{
uid: "ID-Kitty2",
chainId: 1,
name: "Magicat",
iconUrl: ModelsData.collectibles.kitty2Big,
collectionUid: "cryptokitties",
collectionName: "CryptoKitties",
isCollection: false,
},
{
uid: "ID-Kitty3",
chainId: 1,
name: "Happy Meow",
iconUrl: ModelsData.collectibles.kitty3Big,
collectionUid: "cryptokitties",
collectionName: "CryptoKitties",
isCollection: false,
},
{
uid: "ID-Kitty4",
chainId: 1,
name: "Furbeard-2",
iconUrl: ModelsData.collectibles.kitty4Big,
collectionUid: "cryptokitties",
collectionName: "CryptoKitties",
isCollection: false,
},
{
uid: "ID-Kitty5",
chainId: 1,
name: "Magicat-3",
iconUrl: ModelsData.collectibles.kitty5Big,
collectionUid: "cryptokitties",
collectionName: "CryptoKitties",
isCollection: false,
}
]
property string currentCollectionUid
onCurrentCollectionUidChanged: {
clear()
if (currentCollectionUid === "") {
append(rootData)
} else if (currentCollectionUid === "cryptokitties") {
append(criptoKittiesData)
}
}
Component.onCompleted: append(rootData)
}

View File

@ -17,7 +17,6 @@ UsersModel 1.0 UsersModel.qml
WalletSendAccountsModel 1.0 WalletSendAccountsModel.qml WalletSendAccountsModel 1.0 WalletSendAccountsModel.qml
WalletAccountsModel 1.0 WalletAccountsModel.qml WalletAccountsModel 1.0 WalletAccountsModel.qml
WalletKeyPairModel 1.0 WalletKeyPairModel.qml WalletKeyPairModel 1.0 WalletKeyPairModel.qml
WalletNestedCollectiblesModel 1.0 WalletNestedCollectiblesModel.qml
WalletTransactionsModel 1.0 WalletTransactionsModel.qml WalletTransactionsModel 1.0 WalletTransactionsModel.qml
GroupedAccountsAssetsModel 1.0 GroupedAccountsAssetsModel.qml GroupedAccountsAssetsModel 1.0 GroupedAccountsAssetsModel.qml
TokensBySymbolModel 1.0 TokensBySymbolModel.qml TokensBySymbolModel 1.0 TokensBySymbolModel.qml

View File

@ -44,7 +44,7 @@ QtObject {
property var toNetworksRouteModel: NetworksModel.sendToNetworks property var toNetworksRouteModel: NetworksModel.sendToNetworks
property string selectedSenderAccountAddress property string selectedSenderAccountAddress
readonly property QtObject collectiblesModel: ManageCollectiblesModel {} readonly property QtObject collectiblesModel: ManageCollectiblesModel {}
readonly property QtObject nestedCollectiblesModel: WalletNestedCollectiblesModel {} readonly property QtObject nestedCollectiblesModel: ListModel {}
readonly property QtObject walletSectionSendInst: QtObject { readonly property QtObject walletSectionSendInst: QtObject {
signal transactionSent(var chainId, var txHash, var uuid, var error) signal transactionSent(var chainId, var txHash, var uuid, var error)
@ -94,48 +94,6 @@ QtObject {
return SQUtils.ModelUtils.get(assetsList, idx) return SQUtils.ModelUtils.get(assetsList, idx)
} }
function getCollectible(uid) {
const idx = SQUtils.ModelUtils.indexOf(collectiblesModel, "uid", uid)
if (idx < 0) {
return {}
}
return SQUtils.ModelUtils.get(collectiblesModel, idx)
}
function getSelectorCollectible(uid) {
const idx = SQUtils.ModelUtils.indexOf(nestedCollectiblesModel, "uid", uid)
if (idx < 0) {
return {}
}
return SQUtils.ModelUtils.get(nestedCollectiblesModel, idx)
}
function assetToSelectorAsset(asset) {
return asset
}
function collectibleToSelectorCollectible(collectible) {
return {
uid: collectible.uid,
chainId: collectible.chainId,
name: collectible.name,
iconUrl: collectible.imageUrl,
collectionUid: collectible.collectionUid,
collectionName: collectible.collectionName,
isCollection: false
}
}
function holdingToSelectorHolding(holding, holdingType) {
if (holdingType === Constants.TokenType.ERC20) {
return assetToSelectorAsset(holding)
} else if (holdingType === Constants.TokenType.ERC721) {
return collectibleToSelectorCollectible(holding)
} else {
return {}
}
}
readonly property string currentCurrency: "USD" readonly property string currentCurrency: "USD"
function getAllNetworksSupportedString() { function getAllNetworksSupportedString() {

View File

@ -10,7 +10,6 @@ import shared.stores.send 1.0
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Core.Utils 0.1 as SQUtils
import shared.popups.send.panels 1.0
import "./controls" import "./controls"
import "./views" import "./views"

View File

@ -1,56 +0,0 @@
import QtQuick 2.15
import QtQuick.Layouts 1.13
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
Rectangle {
property int count
property string name
signal backClicked()
QtObject {
id:d
readonly property int padding: 16
readonly property int backButtonWidth: 56
readonly property int backButtonHeight: 24
}
implicitHeight: 40
color: "transparent"
border.color: Theme.palette.baseColor2
border.width: 1
RowLayout{
anchors.fill: parent
StatusIconTextButton {
Layout.preferredWidth: d.backButtonWidth
Layout.preferredHeight: d.backButtonHeight
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: d.padding
statusIcon: "previous"
icon.width: 16
icon.height: 16
text: qsTr("Back")
onClicked: backClicked()
}
StatusBaseText {
Layout.fillWidth: true
Layout.rightMargin: d.padding
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignRight
elide: Text.ElideRight
text: "%1 %2".arg(count).arg(name)
font.pixelSize: 13
lineHeight: 18
lineHeightMode: Text.FixedHeight
color: Theme.palette.baseColor1
}
}
}

View File

@ -1,66 +0,0 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
StatusListItem {
id: root
signal itemSelected(var selectedItem)
signal itemHovered(var selectedItem, bool hovered)
QtObject {
id: d
function selectItem() {
root.itemSelected(model)
}
}
Connections {
target: root.sensor
function onContainsMouseChanged() {
root.itemHovered(model, root.sensor.containsMouse)
}
}
title: name
statusListItemTitleAside.font.pixelSize: 15
asset.name: iconUrl ?? ""
asset.isImage: true
asset.width: 32
asset.height: 32
statusListItemLabel.color: Theme.palette.directColor1
statusListItemInlineTagsSlot.spacing: 0
radius: sensor.containsMouse || root.highlighted ? 0 : 8
color: sensor.containsMouse || root.highlighted ? Theme.palette.baseColor2 : "transparent"
onClicked: d.selectItem()
components: [
StatusRoundedImage {
width: 20
height: 20
image.source: Style.svg("tiny/%1".arg(networkIconUrl)) ?? ""
visible: !isGroup && root.sensor.containsMouse
},
StatusBaseText {
id: label
text: count
font.pixelSize: 13
color: Theme.palette.baseColor1
visible: isGroup || (!root.sensor.containsMouse && count > 1)
},
StatusIcon {
icon: "tiny/chevron-right"
color: Theme.palette.baseColor1
width: 16
height: 16
visible: isGroup
}
]
}

View File

@ -1,84 +0,0 @@
import QtQuick 2.13
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import SortFilterProxyModel 0.2
import utils 1.0
StatusListItem {
id: root
objectName: "tokenBalancePerChainDelegate"
signal tokenSelected(var selectedToken)
signal tokenHovered(var selectedToken, bool hovered)
property var formatCurrentCurrencyAmount: function(balance){}
property var formatCurrencyAmountFromBigInt: function(balance, symbol, decimals){}
property var balancesModel
QtObject {
id: d
function selectToken() {
root.tokenSelected({name, symbol, balances, decimals})
}
}
Connections {
target: root.sensor
function onContainsMouseChanged() {
root.tokenHovered({name, symbol, balances, decimals},
root.sensor.containsMouse)
}
}
title: name
titleAsideText: symbol ?? ""
statusListItemTitleAside.font.pixelSize: 15
statusListItemTitleAside.width: statusListItemTitleArea.width - statusListItemTitle.width
statusListItemTitleAside.elide: Text.ElideRight
label: {
let balance = !!model && !!model.currentCurrencyBalance ? model.currentCurrencyBalance : 0
return root.formatCurrentCurrencyAmount(balance)
}
// Community assets have a dedicated image streamed from status-go
asset.name: !!model && !!model.image
? model.image
: Constants.tokenIcon(symbol)
asset.isImage: true
asset.width: 32
asset.height: 32
statusListItemLabel.anchors.verticalCenterOffset: -12
statusListItemLabel.color: Theme.palette.directColor1
statusListItemInlineTagsSlot.spacing: 0
tagsModel: root.balancesModel
tagsDelegate: expandedItem
tagsScrollBarVisible: false
radius: sensor.containsMouse || highlighted ? 0 : 8
color: sensor.containsMouse || highlighted ? Theme.palette.statusListItem.highlightColor : "transparent"
onClicked: d.selectToken()
Component {
id: expandedItem
StatusListItemTag {
height: 16
leftPadding: 0
title: root.formatCurrencyAmountFromBigInt(balance, symbol, decimals)
titleText.font.pixelSize: 12
closeButtonVisible: false
bgColor: "transparent"
asset.width: 16
asset.height: 16
asset.isImage: true
asset.name: Style.svg("tiny/%1".arg(model.iconUrl))
tagClickable: true
onTagClicked: d.selectToken()
}
}
}

View File

@ -3,11 +3,8 @@ GasSelector 1.0 GasSelector.qml
GasValidator 1.0 GasValidator.qml GasValidator 1.0 GasValidator.qml
ClearButton 1.0 ClearButton.qml ClearButton 1.0 ClearButton.qml
SavedAddressListItem 1.0 SavedAddressListItem.qml SavedAddressListItem 1.0 SavedAddressListItem.qml
TokenBalancePerChainDelegate 1.0 TokenBalancePerChainDelegate.qml
SearchBoxWithRightIcon 1.0 SearchBoxWithRightIcon.qml SearchBoxWithRightIcon 1.0 SearchBoxWithRightIcon.qml
AmountInputWithCursor 1.0 AmountInputWithCursor.qml AmountInputWithCursor 1.0 AmountInputWithCursor.qml
BalanceExceeded 1.0 BalanceExceeded.qml BalanceExceeded 1.0 BalanceExceeded.qml
CollectibleBackButtonWithInfo 1.0 CollectibleBackButtonWithInfo.qml
CollectibleNestedDelegate 1.0 CollectibleNestedDelegate.qml
HeaderTitleText 1.0 HeaderTitleText.qml HeaderTitleText 1.0 HeaderTitleText.qml
SendRecipientInput 1.0 SendRecipientInput.qml SendRecipientInput 1.0 SendRecipientInput.qml

View File

@ -1,137 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import utils 1.0
Item {
id: root
property var comboBoxModel
property var selectedItem
property var hoveredItem
property string defaultIconSource
property string placeholderText
property var itemIconSourceFn: function (item) {
return ""
}
property var itemTextFn: function (item) {
return ""
}
property alias comboBoxControl: comboBox.control
property alias comboBoxDelegate: comboBox.delegate
property alias comboBoxListViewSection: comboBox.comboBoxListViewSection
property var comboBoxPopupHeader
property int contentIconSize: 21
property int contentTextSize: 28
function openPopup() {
root.comboBoxControl.popup.open()
}
implicitWidth: comboBox.width
implicitHeight: comboBox.implicitHeight
onSelectedItemChanged: {
let iconSource = itemIconSourceFn(selectedItem)
d.iconSource = !selectedItem ? "" : !!iconSource ? iconSource : defaultIconSource
let itemText = itemTextFn(selectedItem)
d.text = !!itemText ? itemText : placeholderText
}
onHoveredItemChanged: {
let iconSource = itemIconSourceFn(hoveredItem)
d.iconSource = !!iconSource ? iconSource : defaultIconSource
let itemText = itemTextFn(hoveredItem)
d.text = !!itemText ? itemText : placeholderText
}
QtObject {
id: d
property string iconSource: ""
onIconSourceChanged: tokenIcon.image.source = iconSource
property string text: qsTr("Select asset")
readonly property bool isItemSelected: !!root.selectedItem || !!root.hoveredItem
}
StatusComboBox {
id: comboBox
objectName: "assetSelectorButton"
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
control.padding: 12
control.popup.width: 492
control.popup.x: -root.x
control.popup.verticalPadding: 0
popupContentItemObjectName: "assetSelectorList"
model: root.comboBoxModel
control.background: Rectangle {
color: !d.isItemSelected ? Theme.palette.primaryColor3 : "transparent"
border.width: d.isItemSelected ? 0 : 1
border.color: Theme.palette.directColor7
radius: 8
HoverHandler {
cursorShape: root.enabled ? Qt.PointingHandCursor : undefined
}
}
contentItem: RowLayout {
StatusRoundedImage {
id: tokenIcon
objectName: "holdingSelectorsTokenIcon"
Layout.preferredWidth: root.contentIconSize
Layout.preferredHeight: root.contentIconSize
visible: !!d.iconSource
image.source: d.iconSource
image.onStatusChanged: {
if (image.status === Image.Error) {
image.source = root.defaultIconSource
}
}
}
StatusBaseText {
objectName: "holdingSelectorsContentItemText"
Layout.fillWidth: true
font.pixelSize: !selectedItem && !hoveredItem ? Theme.primaryTextFontSize : root.contentTextSize
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
color: Theme.palette.primaryColor1
text: d.text
}
StatusIcon {
Layout.preferredWidth: 16
Layout.preferredHeight: 16
icon: "chevron-down"
color: Theme.palette.primaryColor1
}
}
control.indicator: null
Component.onCompleted: {
control.currentIndex = -1
control.popup.contentItem.header = root.comboBoxPopupHeader
}
control.popup.onOpened: {
control.currentIndex = -1
}
}
}

View File

@ -1,389 +0,0 @@
import QtQml 2.15
import QtQuick 2.15
import QtQuick.Layouts 1.15
import SortFilterProxyModel 0.2
import StatusQ 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import utils 1.0
import shared.controls 1.0
import shared.popups 1.0
import shared.popups.send 1.0
import "../controls"
Item {
id: root
property var assetsModel
property var collectiblesModel
property var networksModel
property bool onlyAssets: true
property string searchText
implicitWidth: holdingItemSelector.implicitWidth
implicitHeight: holdingItemSelector.implicitHeight
property var formatCurrentCurrencyAmount: function(balance){}
property var formatCurrencyAmountFromBigInt: function(balance, symbol, decimals){}
signal itemHovered(string holdingId, var holdingType)
signal itemSelected(string holdingId, var holdingType)
property alias selectedItem: holdingItemSelector.selectedItem
property alias hoveredItem: holdingItemSelector.hoveredItem
property string searchPlaceholderText: {
if (d.isCurrentBrowsingTypeAsset) {
return qsTr("Search for token or enter token address")
} else if (d.isBrowsingGroup) {
return qsTr("Search %1").arg(d.currentBrowsingGroupName ?? qsTr("collectibles in collection"))
} else {
return qsTr("Search collectibles")
}
}
function setSelectedItem(item, holdingType) {
d.browsingHoldingType = holdingType
holdingItemSelector.selectedItem = null
d.currentHoldingType = holdingType
holdingItemSelector.selectedItem = item
}
function setHoveredItem(item, holdingType) {
d.browsingHoldingType = holdingType
holdingItemSelector.hoveredItem = null
d.currentHoldingType = holdingType
holdingItemSelector.hoveredItem = item
}
QtObject {
id: d
// Internal management properties and signals:
readonly property var holdingTypes: onlyAssets ?
[Constants.TokenType.ERC20] :
[Constants.TokenType.ERC20, Constants.TokenType.ERC721]
readonly property var tabsModel: onlyAssets ?
[qsTr("Assets")] :
[qsTr("Assets"), qsTr("Collectibles")]
readonly property var updateSearchText: Backpressure.debounce(root, 500, function(inputText) {
root.searchText = inputText
})
function isAsset(type) {
return type === Constants.TokenType.ERC20
}
function isCommunityItem(type) {
return type === Constants.CollectiblesNestedItemType.CommunityCollectible ||
type === Constants.CollectiblesNestedItemType.Community
}
function isGroupItem(type) {
return type === Constants.CollectiblesNestedItemType.Collection ||
type === Constants.CollectiblesNestedItemType.Community
}
property int browsingHoldingType: Constants.TokenType.ERC20
readonly property bool isCurrentBrowsingTypeAsset: isAsset(browsingHoldingType)
readonly property bool isBrowsingGroup: !isCurrentBrowsingTypeAsset && !!root.collectiblesModel && root.collectiblesModel.currentGroupId !== ""
property string currentBrowsingGroupName
property var currentHoldingType: Constants.TokenType.Unknown
readonly property string uppercaseSearchText: searchText.toUpperCase()
property var assetTextFn: function (asset) {
return !!asset && asset.symbol ? asset.symbol : ""
}
property var assetIconSourceFn: function (asset) {
if (!asset) {
return ""
} else if (asset.image) {
// Community assets have a dedicated image streamed from status-go
return asset.image
}
return Constants.tokenIcon(asset.symbol)
}
property var collectibleTextFn: function (item) {
if (!!item) {
return !!item.groupName ? item.groupName + ": " + item.name : item.name
}
return ""
}
property var collectibleIconSourceFn: function (item) {
return !!item && item.iconUrl ? item.iconUrl : ""
}
readonly property RolesRenamingModel renamedAllNetworksModel: RolesRenamingModel {
sourceModel: root.networksModel
mapping: RoleRename {
from: "iconUrl"
to: "networkIconUrl"
}
}
readonly property LeftJoinModel collectibleNetworksJointModel: LeftJoinModel {
leftModel: root.collectiblesModel
rightModel: d.renamedAllNetworksModel
joinRole: "chainId"
}
property var collectibleComboBoxModel: SortFilterProxyModel {
sourceModel: d.collectibleNetworksJointModel
proxyRoles: [
FastExpressionRole {
name: "isCommunityAsset"
expression: d.isCommunityItem(model.itemType)
expectedRoles: ["itemType"]
},
FastExpressionRole {
name: "isGroup"
expression: d.isGroupItem(model.itemType)
expectedRoles: ["itemType"]
}
]
filters: [
ExpressionFilter {
expression: {
return d.uppercaseSearchText === "" || name.toUpperCase().startsWith(d.uppercaseSearchText)
}
}
]
sorters: [
RoleSorter {
roleName: "isCommunityAsset"
sortOrder: Qt.DescendingOrder
},
RoleSorter {
roleName: "isGroup"
sortOrder: Qt.DescendingOrder
}
]
}
// By design values:
readonly property int padding: 16
readonly property int headerTopMargin: 5
readonly property int tabBarTopMargin: 20
readonly property int tabBarHeight: 35
readonly property int bottomInset: 20
readonly property int assetContentIconSize: 21
readonly property int collectibleContentIconSize: 28
readonly property int assetContentTextSize: 28
readonly property int collectibleContentTextSize: 15
}
HoldingItemSelector {
id: holdingItemSelector
width: parent.width
height: parent.height
defaultIconSource: Style.png("tokens/DEFAULT-TOKEN@3x")
placeholderText: d.isCurrentBrowsingTypeAsset ? qsTr("Select asset") : qsTr("Select collectible")
property bool hasCommunityTokens: false
comboBoxDelegate: Item {
property var itemModel: model // read 'model' from the delegate's context
width: loader.width
height: loader.height
Loader {
id: loader
// inject model properties to the loaded item's context
// common
property var model: itemModel
property var chainId: model.chainId
property var name: model.name
property var tokenType: model.tokenType
// asset
property var symbol: model.symbol
property var totalBalance: model.totalBalance
property var marketDetails: model.marketDetails
property var decimals: model.decimals
property var balances: model.balancesModel
// collectible
property var uid: model.uid
property var iconUrl: model.iconUrl
property var networkIconUrl: model.networkIconUrl
property var groupId: model.groupId
property var groupName: model.groupName
property var isGroup: model.isGroup
property var count: model.count
sourceComponent: d.isCurrentBrowsingTypeAsset ? assetComboBoxDelegate : collectibleComboBoxDelegate
}
}
comboBoxModel: d.isCurrentBrowsingTypeAsset
? root.assetsModel
: d.collectibleComboBoxModel
comboBoxPopupHeader: headerComponent
itemTextFn: d.isCurrentBrowsingTypeAsset ? d.assetTextFn : d.collectibleTextFn
itemIconSourceFn: d.isCurrentBrowsingTypeAsset ? d.assetIconSourceFn : d.collectibleIconSourceFn
onComboBoxModelChanged: updateHasCommunityTokens()
function updateHasCommunityTokens() {
hasCommunityTokens = Helpers.modelHasCommunityTokens(comboBoxModel, d.isCurrentBrowsingTypeAsset)
}
contentIconSize: d.isAsset(d.currentHoldingType) ? d.assetContentIconSize : d.collectibleContentIconSize
contentTextSize: d.isAsset(d.currentHoldingType) ? d.assetContentTextSize : d.collectibleContentTextSize
comboBoxListViewSection.property: "isCommunityAsset"
// TODO allow for different header/sections for the Swap modal
comboBoxListViewSection.delegate: AssetsSectionDelegate {
height: !!text ? 52 : 0 // if we bind to some property instead of hardcoded value it wont work nice when switching tabs or going inside collection and back
width: ListView.view.width
required property bool section
text: Helpers.assetsSectionTitle(section, holdingItemSelector.hasCommunityTokens, d.isBrowsingGroup, d.isCurrentBrowsingTypeAsset)
onInfoButtonClicked: Global.openPopup(communityInfoPopupCmp)
}
comboBoxControl.popup.onOpened: comboBoxControl.popup.contentItem.headerItem.focusSearch()
comboBoxControl.popup.onClosed: comboBoxControl.popup.contentItem.headerItem.clear()
comboBoxControl.popup.x: root.width - comboBoxControl.popup.width
}
Component {
id: communityInfoPopupCmp
CommunityAssetsInfoPopup {}
}
Component {
id: headerComponent
ColumnLayout {
function focusSearch() {
searchInput.input.forceActiveFocus()
}
function clear() {
searchInput.input.edit.clear()
}
width: holdingItemSelector.comboBoxControl.popup.width
Layout.topMargin: d.headerTopMargin
spacing: -1 // Used to overlap rectangles from row components
StatusTabBar {
id: tabBar
visible: !root.onlyAssets
Layout.preferredHeight: d.tabBarHeight
Layout.fillWidth: true
Layout.leftMargin: d.padding
Layout.rightMargin: d.padding
Layout.topMargin: d.tabBarTopMargin
Layout.bottomMargin: 6
currentIndex: d.holdingTypes.indexOf(d.browsingHoldingType)
onCurrentIndexChanged: {
if (currentIndex >= 0) {
d.browsingHoldingType = d.holdingTypes[currentIndex]
}
}
Repeater {
id: tabLabelsRepeater
model: d.tabsModel
StatusTabButton {
text: modelData
width: implicitWidth
}
}
}
CollectibleBackButtonWithInfo {
Layout.fillWidth: true
visible: d.isBrowsingGroup
count: collectiblesModel ? collectiblesModel.count : 0
name: d.currentBrowsingGroupName
onBackClicked: {
if (!d.isCurrentBrowsingTypeAsset) {
searchInput.reset()
root.collectiblesModel.currentGroupId = ""
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: searchInput.input.implicitHeight
color: "transparent"
border.color: Theme.palette.baseColor2
border.width: 1
StatusInput {
id: searchInput
anchors.fill: parent
input.showBackground: false
placeholderText: root.searchPlaceholderText
onTextChanged: Qt.callLater(d.updateSearchText, text)
input.clearable: true
input.implicitHeight: 56
input.rightComponent: StatusFlatRoundButton {
icon.name: "search"
type: StatusFlatRoundButton.Type.Secondary
enabled: false
}
}
}
}
}
Component {
id: assetComboBoxDelegate
TokenBalancePerChainDelegate {
objectName: "AssetSelector_ItemDelegate_" + symbol
width: holdingItemSelector.comboBoxControl.popup.width
highlighted: !!holdingItemSelector.selectedItem && symbol === holdingItemSelector.selectedItem.symbol
balancesModel: LeftJoinModel {
leftModel: balances
rightModel: root.networksModel
joinRole: "chainId"
}
onTokenSelected: function (selectedToken) {
holdingItemSelector.selectedItem = selectedToken
d.currentHoldingType = Constants.TokenType.ERC20
root.itemSelected(selectedToken.symbol, Constants.TokenType.ERC20)
holdingItemSelector.comboBoxControl.popup.close()
}
formatCurrentCurrencyAmount: function(balance){
return root.formatCurrentCurrencyAmount(balance)
}
formatCurrencyAmountFromBigInt: function(balance, symbol, decimals){
return root.formatCurrencyAmountFromBigInt(balance, symbol, decimals)
}
}
}
Component {
id: collectibleComboBoxDelegate
CollectibleNestedDelegate {
objectName: "CollectibleSelector_ItemDelegate_" + groupId
width: holdingItemSelector.comboBoxControl.popup.width
highlighted: !!holdingItemSelector.selectedItem && uid === holdingItemSelector.selectedItem.uid
onItemSelected: {
if (isGroup) {
d.currentBrowsingGroupName = groupName
root.collectiblesModel.currentGroupId = groupId
} else {
holdingItemSelector.selectedItem = selectedItem
d.currentHoldingType = tokenType
root.itemSelected(selectedItem.uid, tokenType)
holdingItemSelector.comboBoxControl.popup.close()
}
}
}
}
}

View File

@ -17,7 +17,6 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils import StatusQ.Core.Utils 0.1 as StatusQUtils
import "../panels"
import "../controls" import "../controls"
import "../views" import "../views"

View File

@ -1,3 +1 @@
HoldingItemSelector 1.0 HoldingItemSelector.qml
HoldingSelector 1.0 HoldingSelector.qml
RecipientSelectorPanel 1.0 RecipientSelectorPanel.qml RecipientSelectorPanel 1.0 RecipientSelectorPanel.qml

View File

@ -1,297 +0,0 @@
import QtQml 2.15
import QtQuick 2.15
import QtQuick.Layouts 1.15
import SortFilterProxyModel 0.2
import StatusQ 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import utils 1.0
import shared.controls 1.0
import shared.popups 1.0
import shared.popups.send 1.0
import "../controls"
Item {
id: root
property var assets: null
property var collectibles: null
property var networksModel
property string assetSearchString
signal tokenSelected(string symbol, var holdingType)
signal tokenHovered(string symbol, var holdingType, bool hovered)
property bool onlyAssets: false
property int browsingHoldingType: Constants.TokenType.ERC20
property var formatCurrentCurrencyAmount: function(balance){}
property var formatCurrencyAmountFromBigInt: function(balance, symbol, decimals){}
onVisibleChanged: {
if(!visible) {
if (!!root.collectibles)
root.collectibles.currentGroupId = ""
// Send Modal doesn't open with a valid headerItem
if (!!tokenList.headerItem && !!tokenList.headerItem.input)
tokenList.headerItem.input.edit.clear()
}
}
QtObject {
id: d
readonly property var updateAssetSearchText: Backpressure.debounce(root, 1000, function(inputText) {
assetSearchString = inputText
})
property string collectibleSearchString
readonly property var updateCollectibleSearchText: Backpressure.debounce(root, 1000, function(inputText) {
d.collectibleSearchString = inputText
})
// Internal management properties and signals:
readonly property var holdingTypes: onlyAssets ?
[Constants.TokenType.ERC20] :
[Constants.TokenType.ERC20, Constants.TokenType.ERC721]
readonly property var tabsModel: onlyAssets ?
[qsTr("Assets")] :
[qsTr("Assets"), qsTr("Collectibles")]
property string currentBrowsingGroupName
readonly property RolesRenamingModel renamedAllNetworksModel: RolesRenamingModel {
sourceModel: root.networksModel
mapping: RoleRename {
from: "iconUrl"
to: "networkIconUrl"
}
}
readonly property LeftJoinModel collectiblesNetworksJointModel: LeftJoinModel {
leftModel: root.collectibles
rightModel: d.renamedAllNetworksModel
joinRole: "chainId"
}
readonly property bool isBrowsingTypeERC20: root.browsingHoldingType === Constants.TokenType.ERC20
readonly property bool isBrowsingGroup: !isBrowsingTypeERC20 && !!root.collectibles && root.collectibles.currentGroupId !== ""
function isCommunityItem(type) {
return type === Constants.CollectiblesNestedItemType.CommunityCollectible ||
type === Constants.CollectiblesNestedItemType.Community
}
function isGroupItem(type) {
return type === Constants.CollectiblesNestedItemType.Collection ||
type === Constants.CollectiblesNestedItemType.Community
}
}
StatusBaseText {
id: label
anchors.top: parent.top
elide: Text.ElideRight
text: qsTr("Token to send")
font.pixelSize: 13
color: Theme.palette.directColor1
}
Rectangle {
anchors.top: label.bottom
anchors.topMargin: 8
width: parent.width
height: parent.height
color: Theme.palette.indirectColor1
radius: 8
ColumnLayout {
id: column
anchors.fill: parent
anchors.topMargin: root.onlyAssets ? 0 : 20
StatusTabBar {
visible: !root.onlyAssets
Layout.preferredHeight: 40
Layout.fillWidth: true
currentIndex: d.holdingTypes.indexOf(root.browsingHoldingType)
onCurrentIndexChanged: {
if (currentIndex >= 0) {
root.browsingHoldingType = d.holdingTypes[currentIndex]
}
}
Repeater {
id: tabLabelsRepeater
model: d.tabsModel
StatusTabButton {
text: modelData
width: implicitWidth
}
}
}
StatusListView {
id: tokenList
Layout.fillWidth: true
Layout.fillHeight: true
// Control order of components not to mix models and delegates
function resetComponents() {
tokenList.model = []
tokenList.delegate = d.isBrowsingTypeERC20 ? tokenDelegate : collectiblesDelegate
tokenList.header = d.isBrowsingTypeERC20 ? tokenHeader : collectibleHeader
tokenList.model = d.isBrowsingTypeERC20 ? root.assets : root.collectiblesModel
}
Component.onCompleted: resetComponents()
Connections {
target: d
function onIsBrowsingTypeERC20Changed() {
tokenList.resetComponents()
}
}
property bool hasCommunityTokens: false
function updateHasCommunityTokens() {
hasCommunityTokens = Helpers.modelHasCommunityTokens(model, d.isBrowsingTypeERC20)
}
onModelChanged: updateHasCommunityTokens()
section {
property: "isCommunityAsset"
delegate: AssetsSectionDelegate {
required property bool section
width: parent.width
height: !!text ? 52 : 0 // if we bind to some property instead of hardcoded value it wont work nice when switching tabs or going inside collection and back
text: Helpers.assetsSectionTitle(section, tokenList.hasCommunityTokens, d.isBrowsingGroup, d.isBrowsingTypeERC20)
onInfoButtonClicked: Global.openPopup(communityInfoPopupCmp)
}
}
}
}
}
property var collectiblesModel: SortFilterProxyModel {
sourceModel: d.collectiblesNetworksJointModel
proxyRoles: [
FastExpressionRole {
name: "isCommunityAsset"
expression: d.isCommunityItem(model.itemType)
expectedRoles: ["itemType"]
},
FastExpressionRole {
name: "isGroup"
expression: d.isGroupItem(model.itemType)
expectedRoles: ["itemType"]
}
]
filters: [
ExpressionFilter {
expression: {
return d.collectibleSearchString === "" || name.toUpperCase().startsWith(d.collectibleSearchString.toUpperCase())
}
}
]
sorters: [
RoleSorter {
roleName: "isCommunityAsset"
sortOrder: Qt.DescendingOrder
},
RoleSorter {
roleName: "isGroup"
sortOrder: Qt.DescendingOrder
}
]
}
Component {
id: tokenDelegate
TokenBalancePerChainDelegate {
width: tokenList.width
tagsScrollBarVisible: true
balancesModel: LeftJoinModel {
leftModel: !!model & !!model.balancesModel ? model.balancesModel : null
rightModel: root.networksModel
joinRole: "chainId"
}
onTokenSelected: function (selectedToken) {
root.tokenSelected(selectedToken.symbol, Constants.TokenType.ERC20)
}
onTokenHovered: root.tokenHovered(selectedToken.symbol, Constants.TokenType.ERC20, hovered)
formatCurrentCurrencyAmount: function(balance){
return root.formatCurrentCurrencyAmount(balance)
}
formatCurrencyAmountFromBigInt: function(balance, symbol, decimals){
return root.formatCurrencyAmountFromBigInt(balance, symbol, decimals)
}
}
}
Component {
id: tokenHeader
SearchBoxWithRightIcon {
showTopBorder: !root.onlyAssets
showBottomBorder: false
width: tokenList.width
placeholderText: qsTr("Search for token or enter token address")
onTextChanged: Qt.callLater(d.updateAssetSearchText, text)
}
}
Component {
id: collectiblesDelegate
CollectibleNestedDelegate {
width: tokenList.width
onItemHovered: root.tokenHovered(selectedItem.uid, Constants.TokenType.ERC721, hovered)
onItemSelected: {
if (isGroup) {
d.currentBrowsingGroupName = groupName
root.collectibles.currentGroupId = groupId
} else {
root.tokenSelected(selectedItem.uid, Constants.TokenType.ERC721)
}
}
}
}
Component {
id: collectibleHeader
ColumnLayout {
width: tokenList.width
spacing: 0
CollectibleBackButtonWithInfo {
Layout.fillWidth: true
visible: d.isBrowsingGroup
count: root.collectibles.count
name: d.currentBrowsingGroupName
onBackClicked: {
searchBox.reset()
root.collectibles.currentGroupId = ""
}
}
SearchBoxWithRightIcon {
id: searchBox
Layout.fillWidth: true
showTopBorder: true
showBottomBorder: false
placeholderText: qsTr("Search collectibles")
onTextChanged: Qt.callLater(d.updateCollectibleSearchText, text)
}
}
}
Component {
id: communityInfoPopupCmp
CommunityAssetsInfoPopup {}
}
}

View File

@ -2,9 +2,9 @@ AmountToReceive 1.0 AmountToReceive.qml
AmountToSend 1.0 AmountToSend.qml AmountToSend 1.0 AmountToSend.qml
FeesView 1.0 FeesView.qml FeesView 1.0 FeesView.qml
NetworkCardsComponent 1.0 NetworkCardsComponent.qml NetworkCardsComponent 1.0 NetworkCardsComponent.qml
NetworksAdvancedCustomRoutingView 1.0 NetworksAdvancedCustomRoutingView.qml
NetworkSelector 1.0 NetworkSelector.qml NetworkSelector 1.0 NetworkSelector.qml
NetworksAdvancedCustomRoutingView 1.0 NetworksAdvancedCustomRoutingView.qml
NetworksSimpleRoutingView 1.0 NetworksSimpleRoutingView.qml NetworksSimpleRoutingView 1.0 NetworksSimpleRoutingView.qml
RecipientView 1.0 RecipientView.qml RecipientView 1.0 RecipientView.qml
TabAddressSelectorView 1.0 TabAddressSelectorView.qml
TransactionModalFooter 1.0 TransactionModalFooter.qml TransactionModalFooter 1.0 TransactionModalFooter.qml
TokenListView 1.0 TokenListView.qml

View File

@ -104,50 +104,6 @@ QtObject {
return ModelUtils.get(collectiblesModel, idx) return ModelUtils.get(collectiblesModel, idx)
} }
function getSelectorCollectible(uid) {
const idx = ModelUtils.indexOf(nestedCollectiblesModel, "uid", uid)
if (idx < 0) {
return {}
}
return ModelUtils.get(nestedCollectiblesModel, idx)
}
function assetToSelectorAsset(asset) {
return asset
}
function collectibleToSelectorCollectible(collectible) {
var groupId = collectible.collectionUid
var groupName = collectible.collectionName
var itemType = Constants.CollectiblesNestedItemType.Collectible
if (collectible.communityId !== "") {
groupId = collectible.communityId
groupName = collectible.communityName
itemType = Constants.CollectiblesNestedItemType.CommunityCollectible
}
return {
uid: collectible.uid,
chainId: collectible.chainId,
name: collectible.name,
iconUrl: collectible.imageUrl,
groupId: groupId,
groupName: groupName,
tokenType: collectible.tokenType,
itemType: itemType,
count: 1 // TODO: Properly handle count
}
}
function holdingToSelectorHolding(holding, holdingType) {
if (holdingType === Constants.TokenType.ERC20) {
return assetToSelectorAsset(holding)
} else if (holdingType === Constants.TokenType.ERC721 || holdingType === Constants.TokenType.ERC1155) {
return collectibleToSelectorCollectible(holding)
} else {
return {}
}
}
function setSenderAccount(address) { function setSenderAccount(address) {
walletSectionSendInst.setSenderAccount(address) walletSectionSendInst.setSenderAccount(address)
} }