feat(@desktop/wallet): Enable Collectibles tab before token is selected

fixes #12095
This commit is contained in:
Khushboo Mehta 2023-09-12 16:26:38 +02:00 committed by Anastasiya Semenkevich
parent 0d2c68411b
commit 296f70103a
12 changed files with 245 additions and 101 deletions

View File

@ -28,6 +28,7 @@ SplitView {
}
assets: WalletAssetsModel {}
collectibles: WalletNestedCollectiblesModel {}
}
}

View File

@ -156,7 +156,6 @@ Item {
root.sendModalPopup.open()
}
onLaunchBridgeModal: {
root.sendModalPopup.isBridgeTx = true
root.sendModalPopup.sendType = Constants.SendType.Bridge
root.sendModalPopup.preSelectedHoldingID = walletStore.currentViewedHoldingID
root.sendModalPopup.preSelectedHoldingType = walletStore.currentViewedHoldingType

View File

@ -134,7 +134,7 @@ QtObject {
}
property string currentViewedHoldingID: ""
property var currentViewedHoldingType
property int currentViewedHoldingType
// This should be exposed to the UI via "walletModule", WalletModule should use
// Accounts Service which keeps the info about that (isFirstTimeAccountLogin).

View File

@ -111,6 +111,9 @@ Item {
width: implicitWidth
text: qsTr("Activity")
}
onCurrentIndexChanged: {
RootStore.setCurrentViewedHoldingType(walletTabBar.currentIndex === 1 ? Constants.HoldingType.Collectible : Constants.HoldingType.Asset)
}
}
StackLayout {
Layout.fillWidth: true

View File

@ -1345,15 +1345,13 @@ Item {
this.active = false
}
property var selectedAccount
property bool isBridgeTx
property string preSelectedHoldingID
property var preSelectedHoldingType
property int preSelectedHoldingType
property int sendType: -1
sourceComponent: SendModal {
onlyAssets: false
onClosed: {
sendModal.closed()
sendModal.isBridgeTx = false
sendModal.sendType = -1
sendModal.preSelectedHoldingID = ""
sendModal.preSelectedHoldingType = Constants.HoldingType.Unknown
@ -1363,12 +1361,9 @@ Item {
if (!!sendModal.selectedAccount) {
item.selectedAccount = sendModal.selectedAccount
}
if(isBridgeTx) {
item.isBridgeTx = sendModal.isBridgeTx
}
if(sendModal.sendType >= 0) {
if(sendModal.sendType >= 0) {
item.sendType = sendModal.sendType
}
}
if(preSelectedHoldingType !== Constants.HoldingType.Unknown) {
item.preSelectedHoldingID = sendModal.preSelectedHoldingID
item.preSelectedHoldingType = sendModal.preSelectedHoldingType

View File

@ -0,0 +1,55 @@
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
text: "%1 %2".arg(count).arg(name)
font.pixelSize: 13
lineHeight: 18
lineHeightMode: Text.FixedHeight
color: Theme.palette.baseColor1
}
}
}

View File

@ -4,6 +4,8 @@ import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
StatusInput {
property bool showTopBorder: false
placeholderText: qsTr("Search")
input.implicitHeight: 56
input.background.color: Theme.palette.indirectColor1
@ -13,6 +15,13 @@ StatusInput {
type: StatusFlatRoundButton.Type.Secondary
enabled: false
}
Rectangle {
visible: showTopBorder
anchors.top: parent.top
height: 1
width: parent.width
color: Theme.palette.baseColor2
}
Rectangle {
anchors.bottom: parent.bottom
height: 1

View File

@ -53,23 +53,20 @@ Item {
implicitHeight: comboBox.implicitHeight
onSelectedItemChanged: {
if (!!selectedItem) {
d.iconSource = itemIconSourceFn(selectedItem) ?? defaultIconSource
d.text = itemTextFn(selectedItem) ?? placeholderText
}
d.iconSource = itemIconSourceFn(selectedItem) ?? defaultIconSource
d.text = itemTextFn(selectedItem) ?? placeholderText
}
onHoveredItemChanged: {
if (!!hoveredItem) {
d.iconSource = itemIconSourceFn(hoveredItem) ?? defaultIconSource
d.text = itemTextFn(hoveredItem) ?? placeholderText
}
d.iconSource = itemIconSourceFn(hoveredItem) ?? defaultIconSource
d.text = itemTextFn(hoveredItem) ?? placeholderText
}
QtObject {
id: d
property string iconSource: ""
onIconSourceChanged: tokenIcon.image.source = iconSource
property string text: ""
readonly property bool isItemSelected: !!root.selectedItem || !!root.hoveredItem
@ -102,6 +99,7 @@ Item {
id: rowLayout
implicitHeight: 38
StatusRoundedImage {
id: tokenIcon
Layout.preferredWidth: root.contentIconSize
Layout.preferredHeight: root.contentIconSize
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft

View File

@ -83,11 +83,11 @@ Item {
readonly property string uppercaseSearchText: searchText.toUpperCase()
property var assetTextFn: function (asset) {
return asset.symbol ? asset.symbol : ""
return !!asset && asset.symbol ? asset.symbol : ""
}
property var assetIconSourceFn: function (asset) {
return asset.symbol ? Style.png("tokens/%1".arg(asset.symbol)) : ""
return !!asset && asset.symbol ? Style.png("tokens/%1".arg(asset.symbol)) : ""
}
property var assetComboBoxModel: SortFilterProxyModel {
@ -115,7 +115,7 @@ Item {
}
property var collectibleIconSourceFn: function (item) {
return item.iconUrl ? item.iconUrl : ""
return !!item && item.iconUrl ? item.iconUrl : ""
}
property var collectibleComboBoxModel: SortFilterProxyModel {
@ -148,9 +148,6 @@ Item {
readonly property int headerTopMargin: 5
readonly property int tabBarTopMargin: 20
readonly property int tabBarHeight: 35
readonly property int backButtonWidth: 56
readonly property int backButtonHeight: 24
readonly property int backButtonToContentSpace: 8
readonly property int bottomInset: 20
readonly property int assetContentIconSize: 21
readonly property int collectibleContentIconSize: 28
@ -237,48 +234,14 @@ Item {
}
}
}
Rectangle {
CollectibleBackButtonWithInfo {
Layout.fillWidth: true
Layout.preferredHeight: 40
visible: d.isBrowsingCollection
color: "transparent"
border.color: Theme.palette.baseColor2
border.width: 1
RowLayout{
anchors.fill: parent
StatusIconTextButton {
id: backButton
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: {
if (!d.isCurrentBrowsingTypeAsset) {
root.collectiblesModel.currentCollectionUid = ""
}
}
}
StatusBaseText {
Layout.fillWidth: true
Layout.rightMargin: d.padding
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignRight
text: "%1 %2".arg(collectiblesModel.count).arg(d.currentBrowsingCollectionName)
font.pixelSize: 13
lineHeight: 18
lineHeightMode: Text.FixedHeight
color: Theme.palette.baseColor1
count: collectiblesModel.count
name: d.currentBrowsingCollectionName
onBackClicked: {
if (!d.isCurrentBrowsingTypeAsset) {
root.collectiblesModel.currentCollectionUid = ""
}
}
}

View File

@ -28,7 +28,7 @@ StatusDialog {
property string preDefinedAmountToSend
property var preSelectedHolding
property string preSelectedHoldingID
property var preSelectedHoldingType
property int preSelectedHoldingType
property bool interactive: true
property alias onlyAssets: holdingSelector.onlyAssets
@ -123,7 +123,8 @@ StatusDialog {
onSelectedHoldingChanged: {
if (d.selectedHoldingType === Constants.HoldingType.Asset) {
popup.sendType = Constants.SendType.Transfer
if(popup.sendType !== Constants.SendType.Bridge)
popup.sendType = Constants.SendType.Transfer
store.setSelectedAssetSymbol(selectedHolding.symbol)
} else if (d.selectedHoldingType === Constants.HoldingType.Collectible) {
popup.sendType = Constants.SendType.ERC721Transfer
@ -151,6 +152,7 @@ StatusDialog {
amountToSendInput.input.input.edit.forceActiveFocus()
if (popup.preSelectedHoldingType !== Constants.HoldingType.Unknown) {
tokenListRect.browsingHoldingType = popup.preSelectedHoldingType
if(!!popup.preSelectedHolding) {
d.setSelectedHolding(popup.preSelectedHolding, popup.preSelectedHoldingType)
} else if (!!popup.preSelectedHoldingID) {
@ -288,6 +290,8 @@ StatusDialog {
visible: !d.selectedHolding
assets: popup.selectedAccount && popup.selectedAccount.assets ? popup.selectedAccount.assets : null
collectibles: popup.selectedAccount ? popup.nestedCollectiblesModel : null
onlyAssets: holdingSelector.onlyAssets
searchTokenSymbolByAddressFn: function (address) {
return store.findTokenSymbolByAddress(address)
}
@ -295,11 +299,11 @@ StatusDialog {
return RootStore.getNetworkIcon(chainId)
}
onTokenSelected: {
d.setSelectedHoldingId(symbol, Constants.HoldingType.Asset)
d.setSelectedHoldingId(symbol, holdingType)
}
onTokenHovered: {
if(hovered) {
d.setHoveredHoldingId(symbol, Constants.HoldingType.Asset)
d.setHoveredHoldingId(symbol, holdingType)
} else {
d.setHoveredHoldingId("", Constants.HoldingType.Unknown)
}

View File

@ -16,6 +16,7 @@ QtObject {
property var mainModuleInst: mainModule
property var walletSectionSendInst: walletSectionSend
property var assets: walletSectionAssets.assets
property var fromNetworksModel: walletSectionSendInst.fromNetworksModel
property var toNetworksModel: walletSectionSendInst.toNetworksModel
property var senderAccounts: walletSectionSendInst.senderAccounts
@ -96,7 +97,7 @@ QtObject {
function getAsset(assetsList, symbol) {
for(var i=0; i< assetsList.count;i++) {
if(symbol === assetsList.rowData(i, "symbol"))
if(symbol === assetsList.rowData(i, "symbol")) {
return {
name: assetsList.rowData(i, "name"),
symbol: assetsList.rowData(i, "symbol"),
@ -105,6 +106,7 @@ QtObject {
balances: assetsList.rowData(i, "balances"),
decimals: assetsList.rowData(i, "decimals")
}
}
}
return {}
}
@ -221,6 +223,7 @@ QtObject {
function resetStoredProperties() {
walletSectionSendInst.resetStoredProperties()
nestedCollectiblesModel.currentCollectionUid = ""
}
// TODO: move to nim

View File

@ -16,19 +16,43 @@ Item {
id: root
property var assets: null
signal tokenSelected(string symbol)
signal tokenHovered(string symbol, bool hovered)
property var collectibles: null
signal tokenSelected(string symbol, var holdingType)
signal tokenHovered(string symbol, var holdingType, bool hovered)
property var searchTokenSymbolByAddressFn: function (address) {
return ""
}
property var getNetworkIcon: function(chainId){}
property bool onlyAssets: false
property int browsingHoldingType: Constants.HoldingType.Asset
onVisibleChanged: {
if(!visible)
root.collectibles.currentCollectionUid = ""
}
QtObject {
id: d
property string searchString
readonly property var updateSearchText: Backpressure.debounce(root, 1000, function(inputText) {
d.searchString = inputText
property string assetSearchString
readonly property var updateAssetSearchText: Backpressure.debounce(root, 1000, function(inputText) {
d.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.HoldingType.Asset] :
[Constants.HoldingType.Asset, Constants.HoldingType.Collectible]
readonly property var tabsModel: onlyAssets ?
[qsTr("Assets")] :
[qsTr("Assets"), qsTr("Collectibles")]
property string currentBrowsingCollectionName
}
implicitWidth: contentLayout.implicitWidth
@ -50,44 +74,134 @@ Item {
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: tokenList.height
Layout.preferredHeight: column.height
color: Theme.palette.indirectColor1
radius: 8
StatusListView {
id: tokenList
Column {
id: column
width: parent.width
height: tokenList.contentHeight
topPadding: 20
header: SearchBoxWithRightIcon {
StatusTabBar {
visible: !root.onlyAssets
height: 40
width: parent.width
placeholderText: qsTr("Search for token or enter token address")
onTextChanged: Qt.callLater(d.updateSearchText, text)
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
}
}
}
model: SortFilterProxyModel {
sourceModel: root.assets
filters: [
ExpressionFilter {
expression: {
var tokenSymbolByAddress = searchTokenSymbolByAddressFn(d.searchString)
tokenList.positionViewAtBeginning()
return visibleForNetwork && (
symbol.startsWith(d.searchString.toUpperCase()) || name.toUpperCase().startsWith(d.searchString.toUpperCase()) || (tokenSymbolByAddress!=="" && symbol.startsWith(tokenSymbolByAddress))
)
}
}
]
}
delegate: TokenBalancePerChainDelegate {
width: ListView.view.width
getNetworkIcon: root.getNetworkIcon
onTokenSelected: root.tokenSelected(symbol)
onTokenHovered: root.tokenHovered(symbol, hovered)
StatusListView {
id: tokenList
width: parent.width
height: tokenList.contentHeight
header: root.browsingHoldingType === Constants.HoldingType.Asset ? tokenHeader : collectibleHeader
model: root.browsingHoldingType === Constants.HoldingType.Asset ? tokensModel : collectiblesModel
delegate: root.browsingHoldingType === Constants.HoldingType.Asset ? tokenDelegate : collectiblesDelegate
}
}
}
}
property var tokensModel: SortFilterProxyModel {
sourceModel: root.assets
filters: [
ExpressionFilter {
expression: {
var tokenSymbolByAddress = searchTokenSymbolByAddressFn(d.assetSearchString)
tokenList.positionViewAtBeginning()
return visibleForNetwork && (
symbol.startsWith(d.assetSearchString.toUpperCase()) || name.toUpperCase().startsWith(d.assetSearchString.toUpperCase()) || (tokenSymbolByAddress!=="" && symbol.startsWith(tokenSymbolByAddress))
)
}
}
]
}
property var collectiblesModel: SortFilterProxyModel {
sourceModel: root.collectibles
filters: [
ExpressionFilter {
expression: {
return d.collectibleSearchString === "" || name.toUpperCase().startsWith(d.collectibleSearchString.toUpperCase())
}
}
]
sorters: RoleSorter {
roleName: "isCollection"
sortOrder: Qt.DescendingOrder
}
}
Component {
id: tokenDelegate
TokenBalancePerChainDelegate {
width: ListView.view.width
getNetworkIcon: root.getNetworkIcon
onTokenSelected: root.tokenSelected(symbol, Constants.HoldingType.Asset)
onTokenHovered: root.tokenHovered(symbol, Constants.HoldingType.Asset, hovered)
}
}
Component {
id: tokenHeader
SearchBoxWithRightIcon {
showTopBorder: true
width: parent.width
placeholderText: qsTr("Search for token or enter token address")
onTextChanged: Qt.callLater(d.updateAssetSearchText, text)
}
}
Component {
id: collectiblesDelegate
CollectibleNestedDelegate {
width: ListView.view.width
getNetworkIcon: root.getNetworkIcon
onItemHovered: root.tokenHovered(selectedItem.uid, Constants.HoldingType.Collectible, hovered)
onItemSelected: {
if (isCollection) {
d.currentBrowsingCollectionName = collectionName
root.collectibles.currentCollectionUid = collectionUid
} else {
root.tokenSelected(selectedItem.uid, Constants.HoldingType.Collectible)
}
}
}
}
Component {
id: collectibleHeader
ColumnLayout {
width: parent.width
spacing: 0
CollectibleBackButtonWithInfo {
Layout.fillWidth: true
visible: !!root.collectibles && root.collectibles.currentCollectionUid !== ""
count: root.collectibles.count
name: d.currentBrowsingCollectionName
onBackClicked: root.collectibles.currentCollectionUid = ""
}
SearchBoxWithRightIcon {
Layout.fillWidth: true
showTopBorder: true
placeholderText: qsTr("Search collectibles")
onTextChanged: Qt.callLater(d.updateCollectibleSearchText, text)
}
}
}
}