diff --git a/storybook/pages/AssetsViewNewPage.qml b/storybook/pages/AssetsViewNewPage.qml deleted file mode 100644 index 9ec15b497..000000000 --- a/storybook/pages/AssetsViewNewPage.qml +++ /dev/null @@ -1,271 +0,0 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 - -import shared.views 1.0 -import utils 1.0 - -import Storybook 1.0 - -import Qt.labs.settings 1.1 - -SplitView { - id: root - - ListModel { - id: assetsModel - - function format(amount, symbol) { - return `${amount.toLocaleString(Qt.locale())} ${symbol}` - } - - Component.onCompleted: { - const data = [ - { - key: "key_ETH", - symbol: "ETH", - name: "Ether", - icon: Constants.tokenIcon("ETH", false), - balance: 10.0, - balanceText: format(10.0, "ETH"), - error: "", - - marketDetailsAvailable: true, - marketDetailsLoading: true, - marketPrice: 0, - marketChangePct24hour: 0, - - communityId: "", - communityName: "", - communityIcon: Qt.resolvedUrl(""), - - position: 2, - canBeHidden: false - }, - { - key: "key_SNT", - symbol: "SNT", - name: "Status", - icon: Constants.tokenIcon("SNT", false), - balance: 20023.0, - balanceText: format(20023.0, "SNT"), - error: "", - - marketDetailsAvailable: true, - marketDetailsLoading: false, - marketPrice: 50.23, - marketChangePct24hour: 12, - - communityId: "", - communityName: "", - communityIcon: Qt.resolvedUrl(""), - - position: 1, - canBeHidden: true - }, - { - key: "key_MCT", - symbol: "MCT", - name: "My custom token", - icon: Constants.tokenIcon("ZRX", false), - balance: 102.4, - balanceText: format(102.4, "MCT"), - error: "", - - marketDetailsAvailable: false, - marketDetailsLoading: false, - marketPrice: 0, - marketChangePct24hour: 0, - - communityId: "34", - communityName: "Crypto Kitties", - communityIcon: Constants.tokenIcon("DAI", false), - - position: 4, - canBeHidden: true - }, - { - key: "key_DAI", - symbol: "DAI", - name: "Dai", - icon: Constants.tokenIcon("DAI", false), - balance: 123.24, - balanceText: format(123.24, "DAI"), - error: "", - - marketDetailsAvailable: true, - marketDetailsLoading: false, - marketPrice: 23.23, - marketChangePct24hour: 2.3, - - communityId: "", - communityName: "", - communityIcon: Qt.resolvedUrl(""), - - position: 3, - canBeHidden: true - }, - { - key: "key_USDT", - symbol: "USDT", - name: "USDT", - icon: Constants.tokenIcon("USDT", false), - balance: 15.24, - balanceText: format(15.24, "USDT"), - error: "", - - marketDetailsAvailable: true, - marketDetailsLoading: false, - marketPrice: 0.99, - marketChangePct24hour: 0, - - communityId: "", - communityName: "", - communityIcon: Qt.resolvedUrl(""), - - position: 5, - canBeHidden: true - }, - { - key: "key_TBT", - symbol: "TBT", - name: "The best token", - icon: Constants.tokenIcon("UNI", false), - balance: 102, - balanceText: format(102, "TBT"), - error: "Pocket Network (POKT) & Infura are currently both " - + "unavailable for %1. %1 balances are as of %2." - .arg("TBT").arg("10/06/2024"), - - marketDetailsAvailable: false, - marketDetailsLoading: false, - marketPrice: 0, - marketChangePct24hour: 0, - - communityId: "3423", - communityName: "Best tokens", - communityIcon: Constants.tokenIcon("UNI", false), - - position: 6, - canBeHidden: true - } - ] - - append(data) - } - } - - SplitView { - SplitView.fillWidth: true - SplitView.fillHeight: true - - orientation: Qt.Vertical - - Pane { - SplitView.fillWidth: true - SplitView.fillHeight: true - - AssetsViewNew { - anchors.fill: parent - - loading: loadingCheckBox.checked - sorterVisible: sorterVisibleCheckBox.checked - customOrderAvailable: customOrderAvailableCheckBox.checked - - sendEnabled: sendEnabledCheckBox.checked - swapEnabled: swapEnabledCheckBox.checked - swapVisible: swapVisibleCheckBox.checked - - balanceError: balanceErrorCheckBox.checked - ? "Balance error!" : "" - - marketDataError: marketDataErrorCheckBox.checked - ? "Market data error!" : "" - - model: assetsModel - - onSendRequested: logs.logEvent(`send requested: ${key}`) - onReceiveRequested: logs.logEvent(`receive requested: ${key}`) - onSwapRequested: logs.logEvent(`swap requested: ${key}`) - onAssetClicked: logs.logEvent(`asset clicked: ${key}`) - - onHideRequested: logs.logEvent(`hide requested: ${key}`) - onHideCommunityAssets: logs.logEvent(`hide community assets requested: ${communityKey}`) - onManageTokensRequested: logs.logEvent(`manage tokens requested`) - } - } - - Logs { - id: logs - } - - LogsView { - clip: true - - SplitView.preferredHeight: 150 - SplitView.fillWidth: true - - logText: logs.logText - } - } - - Pane { - SplitView.preferredWidth: 300 - - ColumnLayout { - CheckBox { - id: loadingCheckBox - - text: "loading" - } - CheckBox { - id: sorterVisibleCheckBox - - text: "sorter visible" - } - CheckBox { - id: customOrderAvailableCheckBox - - text: "custom order available" - } - CheckBox { - id: sendEnabledCheckBox - - text: "send enabled" - } - CheckBox { - id: swapEnabledCheckBox - - text: "swap enabled" - } - CheckBox { - id: swapVisibleCheckBox - - text: "swap visible" - } - CheckBox { - id: balanceErrorCheckBox - - text: "balance error" - } - CheckBox { - id: marketDataErrorCheckBox - - text: "market data error" - } - } - } - - Settings { - property alias loading: loadingCheckBox.checked - property alias filterVisible: sorterVisibleCheckBox.checked - property alias customOrderAvailable: customOrderAvailableCheckBox.checked - property alias sendEnabled: sendEnabledCheckBox.checked - property alias swapEnabled: swapEnabledCheckBox.checked - property alias swapVisible: swapVisibleCheckBox.checked - property alias balanceError: balanceErrorCheckBox.checked - property alias marketDataError: marketDataErrorCheckBox.checked - } -} - -// category: Views diff --git a/storybook/pages/AssetsViewPage.qml b/storybook/pages/AssetsViewPage.qml index 0e3cf283c..b3078470d 100644 --- a/storybook/pages/AssetsViewPage.qml +++ b/storybook/pages/AssetsViewPage.qml @@ -1,248 +1,271 @@ import QtQuick 2.15 -import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 -import Qt.labs.settings 1.0 - -import SortFilterProxyModel 0.2 - -import StatusQ 0.1 -import StatusQ.Models 0.1 -import StatusQ.Core 0.1 -import StatusQ.Core.Utils 0.1 as SQUtils - -import mainui 1.0 +import shared.views 1.0 import utils 1.0 -import shared.controls 1.0 -import shared.views 1.0 -import shared.stores 1.0 - import Storybook 1.0 -import Models 1.0 - -import AppLayouts.Wallet.views 1.0 -import AppLayouts.Wallet.stores 1.0 +import Qt.labs.settings 1.1 SplitView { id: root - Logs { id: logs } + ListModel { + id: assetsModel - orientation: Qt.Horizontal - - QtObject { - id: d - - readonly property string networksChainsCurrentlySelected: { - let supportedNwChains = [] - for (let i = 0; i< networksRepeater.count; i++) { - if (networksRepeater.itemAt(i).checked && networksRepeater.itemAt(i).visible) - supportedNwChains.push(networksRepeater.itemAt(i).chainID) - } - return supportedNwChains.join(":") + function format(amount, symbol) { + return `${amount.toLocaleString(Qt.locale())} ${symbol}` } - readonly property string addressesSelected: { - let supportedAddresses = [] - for (let i = 0; i< accountsRepeater.count; i++) { - if (accountsRepeater.itemAt(i).checked && accountsRepeater.itemAt(i).visible) - supportedAddresses.push(accountsRepeater.itemAt(i).address) - } - return supportedAddresses.join(":") - } + Component.onCompleted: { + const data = [ + { + key: "key_ETH", + symbol: "ETH", + name: "Ether", + icon: Constants.tokenIcon("ETH", false), + balance: 10.0, + balanceText: format(10.0, "ETH"), + error: "", - readonly property var currencyStore: CurrenciesStore {} + marketDetailsAvailable: true, + marketDetailsLoading: true, + marketPrice: 0, + marketChangePct24hour: 0, - property WalletAssetsStore walletAssetStore: WalletAssetsStore { - assetsWithFilteredBalances: d.assetsWithFilteredBalances - assetsController: assetsView.controller - } + communityId: "", + communityName: "", + communityIcon: Qt.resolvedUrl(""), - // Added this here simply because the network and address filtering wont work in Storybook applied in AssetsView - readonly property SubmodelProxyModel assetsWithFilteredBalances: SubmodelProxyModel { - sourceModel: d.walletAssetStore.groupedAccountsAssetsModel - submodelRoleName: "balances" - delegateModel: SortFilterProxyModel { - sourceModel: submodel - filters: FastExpressionFilter { - expression: { - d.networksChainsCurrentlySelected - return d.networksChainsCurrentlySelected.split(":").includes(model.chainId+"") - } - expectedRoles: ["chainId"] + position: 2, + canBeHidden: false + }, + { + key: "key_SNT", + symbol: "SNT", + name: "Status", + icon: Constants.tokenIcon("SNT", false), + balance: 20023.0, + balanceText: format(20023.0, "SNT"), + error: "", + + marketDetailsAvailable: true, + marketDetailsLoading: false, + marketPrice: 50.23, + marketChangePct24hour: 12, + + communityId: "", + communityName: "", + communityIcon: Qt.resolvedUrl(""), + + position: 1, + canBeHidden: true + }, + { + key: "key_MCT", + symbol: "MCT", + name: "My custom token", + icon: Constants.tokenIcon("ZRX", false), + balance: 102.4, + balanceText: format(102.4, "MCT"), + error: "", + + marketDetailsAvailable: false, + marketDetailsLoading: false, + marketPrice: 0, + marketChangePct24hour: 0, + + communityId: "34", + communityName: "Crypto Kitties", + communityIcon: Constants.tokenIcon("DAI", false), + + position: 4, + canBeHidden: true + }, + { + key: "key_DAI", + symbol: "DAI", + name: "Dai", + icon: Constants.tokenIcon("DAI", false), + balance: 123.24, + balanceText: format(123.24, "DAI"), + error: "", + + marketDetailsAvailable: true, + marketDetailsLoading: false, + marketPrice: 23.23, + marketChangePct24hour: 2.3, + + communityId: "", + communityName: "", + communityIcon: Qt.resolvedUrl(""), + + position: 3, + canBeHidden: true + }, + { + key: "key_USDT", + symbol: "USDT", + name: "USDT", + icon: Constants.tokenIcon("USDT", false), + balance: 15.24, + balanceText: format(15.24, "USDT"), + error: "", + + marketDetailsAvailable: true, + marketDetailsLoading: false, + marketPrice: 0.99, + marketChangePct24hour: 0, + + communityId: "", + communityName: "", + communityIcon: Qt.resolvedUrl(""), + + position: 5, + canBeHidden: true + }, + { + key: "key_TBT", + symbol: "TBT", + name: "The best token", + icon: Constants.tokenIcon("UNI", false), + balance: 102, + balanceText: format(102, "TBT"), + error: "Pocket Network (POKT) & Infura are currently both " + + "unavailable for %1. %1 balances are as of %2." + .arg("TBT").arg("10/06/2024"), + + marketDetailsAvailable: false, + marketDetailsLoading: false, + marketPrice: 0, + marketChangePct24hour: 0, + + communityId: "3423", + communityName: "Best tokens", + communityIcon: Constants.tokenIcon("UNI", false), + + position: 6, + canBeHidden: true } - } + ] + + append(data) } } - Popups { - popupParent: root - rootStore: QtObject {} - communityTokensStore: QtObject {} - walletAssetsStore: d.walletAssetStore - } - - StackLayout { - id: stack + SplitView { SplitView.fillWidth: true SplitView.fillHeight: true - currentIndex: 0 + orientation: Qt.Vertical - AssetsView { - id: assetsView - Layout.fillHeight: true - Layout.fillWidth: true - areAssetsLoading: loadingCheckbox.checked - controller: ManageTokensController { - sourceModel: d.walletAssetStore.groupedAccountAssetsModel - settingsKey: "WalletAssets" - serializeAsCollectibles: false + Pane { + SplitView.fillWidth: true + SplitView.fillHeight: true - onRequestSaveSettings: (jsonData) => { - savingStarted() - settingsStore.setValue(settingsKey, jsonData) - savingFinished() - } - onRequestLoadSettings: { - loadingStarted() - const jsonData = settingsStore.value(settingsKey, null) - loadingFinished(jsonData) - } - onRequestClearSettings: { - settingsStore.setValue(settingsKey, null) - } + AssetsView { + anchors.fill: parent - onTokenHidden: (symbol, name) => Global.displayToastMessage( - qsTr("%1 (%2) was successfully hidden").arg(name).arg(symbol), "", "checkmark-circle", - false, Constants.ephemeralNotificationType.success, "") - onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage( - qsTr("%1 community assets successfully hidden").arg(communityName), "", "checkmark-circle", - false, Constants.ephemeralNotificationType.success, "") - onTokenShown: (symbol, name) => Global.displayToastMessage(qsTr("%1 is now visible").arg(name), "", "checkmark-circle", - false, Constants.ephemeralNotificationType.success, "") - onCommunityTokenGroupShown: (communityName) => Global.displayToastMessage( - qsTr("%1 community assets are now visible").arg(communityName), "", "checkmark-circle", - false, Constants.ephemeralNotificationType.success, "") - } - filterVisible: ctrlFilterVisible.checked - currencyStore: d.currencyStore - tokensStore: TokensStore { - displayAssetsBelowBalance: ctrlBalanceThresholdSwitch.checked - getDisplayAssetsBelowBalanceThresholdDisplayAmount: () => ctrlBalanceThreshold.value - } - networkFilters: d.networksChainsCurrentlySelected - addressFilters: d.addressesSelected - onAssetClicked: { - stack.currentIndex = 1 - detailsView.token = token - logs.logEvent("onAssetClicked", ["token"], [token.symbol, token.communityId]) - } - onSendRequested: logs.logEvent("onSendRequested", ["symbol"], arguments) - onReceiveRequested: logs.logEvent("onReceiveRequested", ["symbol"], arguments) - onSwitchToCommunityRequested: logs.logEvent("onSwitchToCommunityRequested", ["communityId"], arguments) - onManageTokensRequested: logs.logEvent("onManageTokensRequested") + loading: loadingCheckBox.checked + sorterVisible: sorterVisibleCheckBox.checked + customOrderAvailable: customOrderAvailableCheckBox.checked - Settings { - id: settingsStore - category: "ManageTokens-" + assetsView.controller.settingsKey + sendEnabled: sendEnabledCheckBox.checked + swapEnabled: swapEnabledCheckBox.checked + swapVisible: swapVisibleCheckBox.checked + + balanceError: balanceErrorCheckBox.checked + ? "Balance error!" : "" + + marketDataError: marketDataErrorCheckBox.checked + ? "Market data error!" : "" + + model: assetsModel + + onSendRequested: logs.logEvent(`send requested: ${key}`) + onReceiveRequested: logs.logEvent(`receive requested: ${key}`) + onSwapRequested: logs.logEvent(`swap requested: ${key}`) + onAssetClicked: logs.logEvent(`asset clicked: ${key}`) + + onHideRequested: logs.logEvent(`hide requested: ${key}`) + onHideCommunityAssets: logs.logEvent(`hide community assets requested: ${communityKey}`) + onManageTokensRequested: logs.logEvent(`manage tokens requested`) } } - ColumnLayout { - Layout.fillHeight: true - Layout.fillWidth: true - Button { - text: "go back" - onClicked: stack.currentIndex = 0 - } - AssetsDetailView { - id: detailsView - Layout.fillHeight: true - Layout.fillWidth: true - currencyStore: d.currencyStore - allNetworksModel: NetworksModel.flatNetworks - networkFilters: d.networksChainsCurrentlySelected - } + Logs { + id: logs + } + + LogsView { + clip: true + + SplitView.preferredHeight: 150 + SplitView.fillWidth: true + + logText: logs.logText } } Pane { - SplitView.preferredWidth: 250 + SplitView.preferredWidth: 300 ColumnLayout { - spacing: 12 - anchors.fill: parent - - Switch { - id: ctrlFilterVisible - text: "Filter visible" - checked: true - } - CheckBox { - id: loadingCheckbox - checked: false + id: loadingCheckBox + text: "loading" } + CheckBox { + id: sorterVisibleCheckBox - ColumnLayout { - Layout.fillWidth: true - Text { - text: "select supported network(s)" - } - Repeater { - id: networksRepeater - model: NetworksModel.flatNetworks - delegate: CheckBox { - readonly property int chainID: chainId - width: parent.width - text: chainName - visible: isTest - checked: true - onToggled: { - isEnabled = checked - } - } - } + text: "sorter visible" } + CheckBox { + id: customOrderAvailableCheckBox - ColumnLayout { - Layout.fillWidth: true - Text { - text: "select account(s)" - } - Repeater { - id: accountsRepeater - model: WalletAccountsModel {} - delegate: CheckBox { - readonly property string address: model.address - checked: true - visible: index<2 - width: parent.width - text: name - } - } + text: "custom order available" } + CheckBox { + id: sendEnabledCheckBox - ColumnLayout { - Layout.fillWidth: true - Switch { - id: ctrlBalanceThresholdSwitch - text: qsTr("Currency balance threshold") - checked: false - } - CurrencyAmountInput { - id: ctrlBalanceThreshold - value: 10.1 - } + text: "send enabled" + } + CheckBox { + id: swapEnabledCheckBox + + text: "swap enabled" + } + CheckBox { + id: swapVisibleCheckBox + + text: "swap visible" + } + CheckBox { + id: balanceErrorCheckBox + + text: "balance error" + } + CheckBox { + id: marketDataErrorCheckBox + + text: "market data error" } } } + + Settings { + property alias loading: loadingCheckBox.checked + property alias filterVisible: sorterVisibleCheckBox.checked + property alias customOrderAvailable: customOrderAvailableCheckBox.checked + property alias sendEnabled: sendEnabledCheckBox.checked + property alias swapEnabled: swapEnabledCheckBox.checked + property alias swapVisible: swapVisibleCheckBox.checked + property alias balanceError: balanceErrorCheckBox.checked + property alias marketDataError: marketDataErrorCheckBox.checked + } } // category: Views -// https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?type=design&node-id=17159-67977&mode=design&t=s5EXsh6Vi4nTNYUh-0 -// https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?type=design&node-id=17171-285559&mode=design&t=s5EXsh6Vi4nTNYUh-0 diff --git a/storybook/pages/TokenDelegatePage.qml b/storybook/pages/TokenDelegatePage.qml index 2f81f44fc..56512fdda 100644 --- a/storybook/pages/TokenDelegatePage.qml +++ b/storybook/pages/TokenDelegatePage.qml @@ -14,7 +14,7 @@ SplitView { SplitView.fillWidth: true SplitView.fillHeight: true - TokenDelegateNew { + TokenDelegate { anchors.centerIn: parent name: nameTextFiled.text diff --git a/ui/app/AppLayouts/Browser/popups/BrowserWalletMenu.qml b/ui/app/AppLayouts/Browser/popups/BrowserWalletMenu.qml index 3fb39f73f..2b9a8b23b 100644 --- a/ui/app/AppLayouts/Browser/popups/BrowserWalletMenu.qml +++ b/ui/app/AppLayouts/Browser/popups/BrowserWalletMenu.qml @@ -206,12 +206,14 @@ Dialog { anchors.bottom: parent.bottom currentIndex: walletTabBar.currentIndex - AssetsView { - id: assetsTab - controller: popup.assetsStore.assetsController - currencyStore: popup.currencyStore - tokensStore: popup.tokensStore - } + // Disable because the refactored version of AssetView requires specific + // integration but the old version was not working properly neither. + //AssetsView { + // id: assetsTab + // controller: popup.assetsStore.assetsController + // currencyStore: popup.currencyStore + // tokensStore: popup.tokensStore + //} HistoryView { id: historyTab overview: WalletStore.dappBrowserAccount diff --git a/ui/app/AppLayouts/Wallet/views/RightTabView.qml b/ui/app/AppLayouts/Wallet/views/RightTabView.qml index 33ffb1011..b31e84fce 100644 --- a/ui/app/AppLayouts/Wallet/views/RightTabView.qml +++ b/ui/app/AppLayouts/Wallet/views/RightTabView.qml @@ -143,8 +143,7 @@ RightTabBaseView { Component { id: assetsView - AssetsViewNew { - + AssetsView { AssetsViewAdaptor { id: assetsViewAdaptor diff --git a/ui/imports/shared/controls/LoadingTokenDelegate.qml b/ui/imports/shared/controls/LoadingTokenDelegate.qml index 11e5c0586..0d11be837 100644 --- a/ui/imports/shared/controls/LoadingTokenDelegate.qml +++ b/ui/imports/shared/controls/LoadingTokenDelegate.qml @@ -1,27 +1,16 @@ -import QtQuick 2.15 - -import StatusQ.Core.Theme 0.1 - import utils 1.0 TokenDelegate { - id: root - title: Constants.dummyText subTitle: Constants.dummyText asset.name: Constants.dummyText - currencyBalance.text: Constants.dummyText - currencyBalance.loading: true - change24HourPercentage.text: Constants.dummyText - change24HourPercentage.loading: true - currencyPrice.text: Constants.dummyText - currencyPrice.loading: true - statusListItemSubTitle.loading: true statusListItemTitle.loading: true statusListItemIcon.loading: true - textColor: Theme.palette.baseColor1 + marketDetailsAvailable: true + marketDetailsLoading: true + enabled: false } diff --git a/ui/imports/shared/controls/LoadingTokenDelegateNew.qml b/ui/imports/shared/controls/LoadingTokenDelegateNew.qml deleted file mode 100644 index 1aa24db72..000000000 --- a/ui/imports/shared/controls/LoadingTokenDelegateNew.qml +++ /dev/null @@ -1,16 +0,0 @@ -import utils 1.0 - -TokenDelegateNew { - title: Constants.dummyText - subTitle: Constants.dummyText - asset.name: Constants.dummyText - - statusListItemSubTitle.loading: true - statusListItemTitle.loading: true - statusListItemIcon.loading: true - - marketDetailsAvailable: true - marketDetailsLoading: true - - enabled: false -} diff --git a/ui/imports/shared/controls/TokenDelegate.qml b/ui/imports/shared/controls/TokenDelegate.qml index 1efbf6085..636983c01 100644 --- a/ui/imports/shared/controls/TokenDelegate.qml +++ b/ui/imports/shared/controls/TokenDelegate.qml @@ -7,67 +7,63 @@ import StatusQ.Core 0.1 import StatusQ.Controls 0.1 import AppLayouts.Wallet.controls 1.0 - import utils 1.0 StatusListItem { id: root - // expected roles: name, symbol, currencyPrice, changePct24hour, communityId, communityName, communityImage + property string name + property url icon + property string balance - property alias currencyBalance: currencyBalance - property alias change24HourPercentage: change24HourPercentageText - property alias currencyPrice: currencyPrice + property bool marketDetailsAvailable: false + property string marketBalance + property bool marketDetailsLoading: false + property string marketCurrencyPrice + property real marketChangePct24hour + + property string communityId + property string communityName + property url communityIcon - property string currentCurrencySymbol - property string textColor: { - if (!modelData || !modelData.marketDetails) { - return Theme.palette.successColor1 - } - return modelData.marketDetails.changePct24hour === undefined ? - Theme.palette.baseColor1 : - modelData.marketDetails.changePct24hour === 0 ? - Theme.palette.baseColor1 : - modelData.marketDetails.changePct24hour < 0 ? - Theme.palette.dangerColor1 : - Theme.palette.successColor1 - } - property string errorTooltipText_1 property string errorTooltipText_2 - readonly property bool isCommunityToken: !!modelData && !!modelData.communityId - readonly property string symbolUrl: { - if (!modelData) - return "" - if (modelData.image) - return modelData.image - if (modelData.symbol) - return Constants.tokenIcon(modelData.symbol, false) - return "" - } - readonly property string upDownTriangle: { - if (!modelData || !modelData.marketDetails) - return "" - if (modelData.marketDetails.changePct24hour < 0) - return "▾" - if (modelData.marketDetails.changePct24hour > 0) - return "▴" - return "" - } - readonly property bool isUndefined: modelData && !modelData.marketDetailsLoading && title === "" + signal communityClicked(string communityId) - signal switchToCommunityRequested(string communityId) + QtObject { + id: d - title: modelData ? modelData.name : "" - subTitle: LocaleUtils.currencyAmountToLocaleString(modelData.enabledNetworkBalance) - asset.name: symbolUrl + readonly property bool isCommunityToken: !!root.communityId + + readonly property string textColor: { + if (!root.marketDetailsAvailable) + return Theme.palette.successColor1 + + if (root.marketChangePct24hour === 0) + return Theme.palette.baseColor1 + + return root.marketChangePct24hour < 0 + ? Theme.palette.dangerColor1 + : Theme.palette.successColor1 + } + + readonly property string upDownTriangle: { + if (root.marketChangePct24hour === 0) + return "" + + return root.marketChangePct24hour < 0 ? "▾" : "▴" + } + } + + title: root.name + subTitle: root.balance + asset.name: root.icon asset.isImage: true asset.width: 32 asset.height: 32 errorIcon.tooltip.maxWidth: 300 - height: isUndefined ? 0 : implicitHeight - visible: !isUndefined + height: implicitHeight statusListItemTitleIcons.sourceComponent: StatusFlatRoundButton { width: 14 @@ -94,26 +90,32 @@ StatusListItem { icon.color: Theme.palette.dangerColor1 tooltip.text: root.errorTooltipText_2 tooltip.maxWidth: 200 - visible: !!tooltip.text + visible: root.marketDetailsAvailable && !!tooltip.text } StatusTextWithLoadingState { id: currencyBalance + anchors.right: parent.right - loading: modelData && modelData.marketDetailsLoading - visible: !errorIcon.visible && !root.isCommunityToken + visible: !errorIcon.visible && root.marketDetailsAvailable + + loading: root.marketDetailsLoading + text: loading ? Constants.dummyText : root.marketBalance } Row { anchors.right: parent.right spacing: 6 - visible: !errorIcon.visible && !root.isCommunityToken + visible: !errorIcon.visible && root.marketDetailsAvailable + StatusTextWithLoadingState { id: change24HourPercentageText + anchors.verticalCenter: parent.verticalCenter - customColor: root.textColor + customColor: d.textColor font.pixelSize: 13 - loading: modelData && modelData.marketDetailsLoading - text: modelData && modelData.marketDetails && modelData.marketDetails.changePct24hour !== undefined ? "%1 %2%".arg(root.upDownTriangle).arg(LocaleUtils.numberToLocaleString(modelData.marketDetails.changePct24hour, 2)) - : "---" + loading: root.marketDetailsLoading + + text: qsTr("%1 %2%", "[up/down/none character depending on value sign] [localized percentage value]%") + .arg(d.upDownTriangle).arg(LocaleUtils.numberToLocaleString(root.marketChangePct24hour, 2)) } Rectangle { anchors.verticalCenter: parent.verticalCenter @@ -123,39 +125,45 @@ StatusListItem { } StatusTextWithLoadingState { id: currencyPrice + anchors.verticalCenter: parent.verticalCenter - customColor: root.textColor + customColor: d.textColor font.pixelSize: 13 - loading: modelData && modelData.marketDetailsLoading - text: modelData && modelData.marketDetails ? LocaleUtils.currencyAmountToLocaleString(modelData.marketDetails.currencyPrice) : "" + loading: root.marketDetailsLoading + text: loading ? Constants.dummyText : root.marketCurrencyPrice } } - ManageTokensCommunityTag { - anchors.right: parent.right - communityImage: !!modelData ? modelData.communityImage : "" - communityName: !!modelData && !!modelData.communityName ? modelData.communityName: "" - communityId: !!modelData && !!modelData.communityId ? modelData.communityId : "" - asset.letterSize: 12 - visible: root.isCommunityToken - - TapHandler { - acceptedButtons: Qt.LeftButton - onSingleTapped: root.switchToCommunityRequested(modelData.communityId) + + Loader { + active: d.isCommunityToken + + sourceComponent: ManageTokensCommunityTag { + anchors.right: parent.right + + communityImage: root.communityIcon + communityName: root.communityName + communityId: root.communityId + + asset.letterSize: 12 + + TapHandler { + acceptedButtons: Qt.LeftButton + onSingleTapped: root.communityClicked(root.communityId) + } } } } ] - states: [ - State { - name: "unknownToken" - when: !root.symbolUrl - PropertyChanges { - target: root.asset - isLetterIdenticon: true - color: Theme.palette.miscColor5 - name: !!modelData && modelData.symbol ? modelData.symbol : "" - } + states: State { + name: "unknownToken" + when: !root.icon.toString() + + PropertyChanges { + target: root.asset + isLetterIdenticon: true + color: Theme.palette.miscColor5 + name: root.name } - ] + } } diff --git a/ui/imports/shared/controls/TokenDelegateNew.qml b/ui/imports/shared/controls/TokenDelegateNew.qml deleted file mode 100644 index 636983c01..000000000 --- a/ui/imports/shared/controls/TokenDelegateNew.qml +++ /dev/null @@ -1,169 +0,0 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 - -import StatusQ.Core.Theme 0.1 -import StatusQ.Components 0.1 -import StatusQ.Core 0.1 -import StatusQ.Controls 0.1 - -import AppLayouts.Wallet.controls 1.0 -import utils 1.0 - -StatusListItem { - id: root - - property string name - property url icon - property string balance - - property bool marketDetailsAvailable: false - property string marketBalance - property bool marketDetailsLoading: false - property string marketCurrencyPrice - property real marketChangePct24hour - - property string communityId - property string communityName - property url communityIcon - - property string errorTooltipText_1 - property string errorTooltipText_2 - - signal communityClicked(string communityId) - - QtObject { - id: d - - readonly property bool isCommunityToken: !!root.communityId - - readonly property string textColor: { - if (!root.marketDetailsAvailable) - return Theme.palette.successColor1 - - if (root.marketChangePct24hour === 0) - return Theme.palette.baseColor1 - - return root.marketChangePct24hour < 0 - ? Theme.palette.dangerColor1 - : Theme.palette.successColor1 - } - - readonly property string upDownTriangle: { - if (root.marketChangePct24hour === 0) - return "" - - return root.marketChangePct24hour < 0 ? "▾" : "▴" - } - } - - title: root.name - subTitle: root.balance - asset.name: root.icon - asset.isImage: true - asset.width: 32 - asset.height: 32 - errorIcon.tooltip.maxWidth: 300 - height: implicitHeight - - statusListItemTitleIcons.sourceComponent: StatusFlatRoundButton { - width: 14 - height: visible ? 14 : 0 - icon.width: 14 - icon.height: 14 - icon.name: "tiny/warning" - icon.color: Theme.palette.dangerColor1 - tooltip.text: root.errorTooltipText_1 - tooltip.maxWidth: 300 - visible: !!tooltip.text - } - - components: [ - Column { - anchors.verticalCenter: parent.verticalCenter - StatusFlatRoundButton { - id: errorIcon - width: 14 - height: visible ? 14 : 0 - icon.width: 14 - icon.height: 14 - icon.name: "tiny/warning" - icon.color: Theme.palette.dangerColor1 - tooltip.text: root.errorTooltipText_2 - tooltip.maxWidth: 200 - visible: root.marketDetailsAvailable && !!tooltip.text - } - StatusTextWithLoadingState { - id: currencyBalance - - anchors.right: parent.right - visible: !errorIcon.visible && root.marketDetailsAvailable - - loading: root.marketDetailsLoading - text: loading ? Constants.dummyText : root.marketBalance - } - Row { - anchors.right: parent.right - spacing: 6 - visible: !errorIcon.visible && root.marketDetailsAvailable - - StatusTextWithLoadingState { - id: change24HourPercentageText - - anchors.verticalCenter: parent.verticalCenter - customColor: d.textColor - font.pixelSize: 13 - loading: root.marketDetailsLoading - - text: qsTr("%1 %2%", "[up/down/none character depending on value sign] [localized percentage value]%") - .arg(d.upDownTriangle).arg(LocaleUtils.numberToLocaleString(root.marketChangePct24hour, 2)) - } - Rectangle { - anchors.verticalCenter: parent.verticalCenter - width: 1 - height: 12 - color: Theme.palette.directColor9 - } - StatusTextWithLoadingState { - id: currencyPrice - - anchors.verticalCenter: parent.verticalCenter - customColor: d.textColor - font.pixelSize: 13 - loading: root.marketDetailsLoading - text: loading ? Constants.dummyText : root.marketCurrencyPrice - } - } - - Loader { - active: d.isCommunityToken - - sourceComponent: ManageTokensCommunityTag { - anchors.right: parent.right - - communityImage: root.communityIcon - communityName: root.communityName - communityId: root.communityId - - asset.letterSize: 12 - - TapHandler { - acceptedButtons: Qt.LeftButton - onSingleTapped: root.communityClicked(root.communityId) - } - } - } - } - ] - - states: State { - name: "unknownToken" - when: !root.icon.toString() - - PropertyChanges { - target: root.asset - isLetterIdenticon: true - color: Theme.palette.miscColor5 - name: root.name - } - } -} diff --git a/ui/imports/shared/controls/qmldir b/ui/imports/shared/controls/qmldir index 4731d6593..8c23fb410 100644 --- a/ui/imports/shared/controls/qmldir +++ b/ui/imports/shared/controls/qmldir @@ -22,7 +22,6 @@ InformationTag 1.0 InformationTag.qml InformationTile 1.0 InformationTile.qml Input 1.0 Input.qml LoadingTokenDelegate 1.0 LoadingTokenDelegate.qml -LoadingTokenDelegateNew 1.0 LoadingTokenDelegateNew.qml LinkPreviewDebugView 1.0 LinkPreviewDebugView.qml ProfilePerspectiveSelector 1.0 ProfilePerspectiveSelector.qml RadioButtonSelector 1.0 RadioButtonSelector.qml @@ -44,7 +43,6 @@ StyledTextEditWithLoadingState 1.0 StyledTextEditWithLoadingState.qml StyledTextField 1.0 StyledTextField.qml Timer 1.0 Timer.qml TokenDelegate 1.0 TokenDelegate.qml -TokenDelegateNew 1.0 TokenDelegateNew.qml TransactionAddress 1.0 TransactionAddress.qml TransactionAddressTile 1.0 TransactionAddressTile.qml TransactionDataTile 1.0 TransactionDataTile.qml diff --git a/ui/imports/shared/views/AssetsView.qml b/ui/imports/shared/views/AssetsView.qml index 3dd94b196..70387ebe5 100644 --- a/ui/imports/shared/views/AssetsView.qml +++ b/ui/imports/shared/views/AssetsView.qml @@ -1,315 +1,258 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 -import Qt.labs.settings 1.1 + +import QtQml.Models 2.15 import StatusQ 0.1 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 -import StatusQ.Core.Utils 0.1 as SQUtils -import StatusQ.Controls 0.1 -import StatusQ.Components 0.1 -import StatusQ.Popups 0.1 import StatusQ.Popups.Dialog 0.1 -import StatusQ.Models 0.1 -import StatusQ.Internal 0.1 + +import AppLayouts.Wallet.controls 1.0 +import shared.controls 1.0 +import shared.popups 1.0 +import utils 1.0 import SortFilterProxyModel 0.2 -import utils 1.0 -import shared.stores 1.0 -import shared.controls 1.0 -import shared.popups 1.0 - -import AppLayouts.Wallet.controls 1.0 - -ColumnLayout { +Control { id: root - // expected roles: name, symbol, balances, currencyPrice, changePct24hour, communityId, communityName, communityImage - required property var controller + /** + Expected model structure: - property var currencyStore - property var networkConnectionStore - required property var tokensStore - property var overview - property bool assetDetailsLaunched: false - property bool filterVisible - property bool areAssetsLoading: false - property string addressFilters - property string networkFilters + key [string] - unique identifier of a token, e.g "0x3234235" + symbol [string] - token's symbol e.g. "ETH" or "SNT" + name [string] - token's name e.g. "Ether" or "Dai" + icon [url] - token's icon url + balance [double] - tokens balance is the commonly used unit, e.g. 1.2 for 1.2 ETH, used + for sorting and computing market value + balanceText [string] - formatted and localized balance. This is not done internally because + it may depend on many external factors + error [string] - error message related to balance - signal assetClicked(var token) - signal sendRequested(string symbol) - signal receiveRequested(string symbol) - signal launchSwapModal(string tokensKey) - signal switchToCommunityRequested(string communityId) - signal manageTokensRequested() + marketDetailsAvailable [bool] - specifies if market datails are available for given token + marketDetailsLoading [bool] - specifies if market datails are available for given token + marketPrice [double] - specifies market price in currently used currency + marketChangePct24hour [double] - percentage price change in last 24 hours, e.g. 0.5 for 0.5% of price change - spacing: 0 + communityId [string] - for community assets, unique identifier of a community, e.g. "0x6734235" + communityName [string] - for community assets, name of a community e.g. "Crypto Kitties" + communityIcon [url] - for community assets, community's icon url + + position [int] - if custom order available, display position defined by the user via token management + canBeHidden [bool] - specifies if given token can be hidden (e.g. ETH should be always visible) + **/ + property var model + + // enables global loading state useful when real data are not yet available + property bool loading + + // shows/hides list sorter + property bool sorterVisible + + // allows/disables choosing custom sort order from a sorter + property bool customOrderAvailable + + // switches configuring right click menu + property bool sendEnabled: true + property bool swapEnabled: true + property bool swapVisible: true + + property string balanceError + + // global market data error, presented for all tokens expecting market data + property string marketDataError + + // formatting function for fiat currency values + property var formatFiat: balance => `${balance.toLocaleString(Qt.locale())} XYZ` + + signal sendRequested(string key) + signal receiveRequested(string key) + signal swapRequested(string key) + signal assetClicked(string key) + signal communityClicked(string communityKey) + signal hideRequested(string key) + signal hideCommunityAssets(string communityKey) + signal manageTokensRequested QtObject { id: d - property int selectedAssetIndex: -1 + readonly property int loadingItemsCount: 25 + } - readonly property bool isCustomView: cmbTokenOrder.currentValue === SortOrderComboBox.TokenOrderCustom + SortFilterProxyModel { + id: sfpm - function tokenIsVisible(symbol, currentCurrencyBalance, isCommunityAsset) { - // NOTE Backend returns ETH, SNT, STT and DAI by default - if (!root.controller.filterAcceptsSymbol(symbol)) // explicitely hidden - return false - if (isCommunityAsset) - return true - // Received tokens can have 0 balance, which indicate previously owned token - if (root.tokensStore.displayAssetsBelowBalance) { - const threshold = root.tokensStore.getDisplayAssetsBelowBalanceThresholdDisplayAmount() - if (threshold > 0) - return currentCurrencyBalance > threshold + sourceModel: root.model ?? null + + proxyRoles: [ + // helper role for rendering section delegate + FastExpressionRole { + name: "isCommunity" + expression: !!communityId ? "community" : "" + expectedRoles: ["communityId"] + }, + FastExpressionRole { + name: "marketBalance" + expression: balance * marketPrice + expectedRoles: ["balance", "marketPrice"] + }, + FastExpressionRole { + name: "change1DayFiat" + expression: marketBalance * (1 - (1 / (marketChangePct24hour / 100 + 1))) + expectedRoles: ["marketBalance", "marketChangePct24hour"] } - return true - } + ] - function getTotalBalance(balances, decimals, key) { - let totalBalance = 0 - let nwFilters = root.networkFilters.split(":") - let addrFilters = root.addressFilters.split(":") - for(let i=0; i 0 - Component.onDestruction: { - settings.currentSortValue = cmbTokenOrder.currentValue - } - - ColumnLayout { - Layout.fillWidth: true - Layout.preferredHeight: root.filterVisible ? implicitHeight : 0 - spacing: 20 - opacity: root.filterVisible ? 1 : 0 - visible: opacity > 0 - - Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } - Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } - - StatusDialogDivider { - Layout.fillWidth: true - } - - RowLayout { - Layout.fillWidth: true - spacing: Style.current.halfPadding - - StatusBaseText { - color: Theme.palette.baseColor1 - font.pixelSize: Style.current.additionalTextSize - text: qsTr("Sort by:") + Behavior on Layout.preferredHeight { + NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } - SortOrderComboBox { - id: cmbTokenOrder - objectName: "cmbTokenOrder" - hasCustomOrderDefined: root.controller.hasSettings - model: [ - { value: SortOrderComboBox.TokenOrderCurrencyBalance, text: qsTr("Asset balance value"), icon: "", sortRoleName: "currentCurrencyBalance" }, // custom SFPM ExpressionRole on "enabledNetworkCurrencyBalance" amount - { value: SortOrderComboBox.TokenOrderBalance, text: qsTr("Asset balance"), icon: "", sortRoleName: "currentBalance" }, // custom SFPM ExpressionRole on "enabledNetworkBalance" amount - { value: SortOrderComboBox.TokenOrderCurrencyPrice, text: qsTr("Asset value"), icon: "", sortRoleName: "tokenPrice" }, // custom SFPM ExpressionRole on "currencyPrice" amount - { value: SortOrderComboBox.TokenOrder1DChange, text: qsTr("1d change: balance value"), icon: "", sortRoleName: "change1DayFiat" }, // custom SFPM ExpressionRole - { value: SortOrderComboBox.TokenOrderAlpha, text: qsTr("Asset name"), icon: "", sortRoleName: "name" }, - { value: SortOrderComboBox.TokenOrderCustom, text: qsTr("Custom order"), icon: "", sortRoleName: "" }, - { value: SortOrderComboBox.TokenOrderNone, text: "---", icon: "", sortRoleName: "" }, // separator - { value: SortOrderComboBox.TokenOrderCreateCustom, text: hasCustomOrderDefined ? qsTr("Edit custom order →") : qsTr("Create custom order →"), - icon: "", sortRoleName: "" } - ] - onCreateOrEditRequested: { - root.manageTokensRequested() + Behavior on opacity { + NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } + } + + StatusDialogDivider { Layout.fillWidth: true } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + + spacing: Style.current.halfPadding + + StatusBaseText { + color: Theme.palette.baseColor1 + font.pixelSize: Style.current.additionalTextSize + text: qsTr("Sort by:") + } + + SortOrderComboBox { + id: sortOrderComboBox + + objectName: "cmbTokenOrder" + hasCustomOrderDefined: root.customOrderAvailable + + model: [ + { value: SortOrderComboBox.TokenOrderCurrencyBalance, + text: qsTr("Asset balance value"), icon: "", sortRoleName: "marketBalance" }, + { value: SortOrderComboBox.TokenOrderBalance, + text: qsTr("Asset balance"), icon: "", sortRoleName: "balance" }, + { value: SortOrderComboBox.TokenOrderCurrencyPrice, + text: qsTr("Asset value"), icon: "", sortRoleName: "marketPrice" }, + { value: SortOrderComboBox.TokenOrder1DChange, + text: qsTr("1d change: balance value"), icon: "", sortRoleName: "change1DayFiat" }, + { value: SortOrderComboBox.TokenOrderAlpha, + text: qsTr("Asset name"), icon: "", sortRoleName: "name" }, + { value: SortOrderComboBox.TokenOrderCustom, + text: qsTr("Custom order"), icon: "", sortRoleName: "position" }, + { value: SortOrderComboBox.TokenOrderNone, + text: "---", icon: "", sortRoleName: "" }, // separator + { value: SortOrderComboBox.TokenOrderCreateCustom, + text: hasCustomOrderDefined ? qsTr("Edit custom order →") : qsTr("Create custom order →"), + icon: "", sortRoleName: "" } + ] + onCreateOrEditRequested: { + root.manageTokensRequested() + } } } + + StatusDialogDivider { Layout.fillWidth: true } } - StatusDialogDivider { - Layout.fillWidth: true - } - } + DelegateModel { + id: regularModel + + model: sfpm + + delegate: TokenDelegate { + objectName: `AssetView_TokenListItem_${model.symbol}` - StatusListView { - id: assetsListView - Layout.fillWidth: true - Layout.topMargin: Style.current.padding - Layout.preferredHeight: contentHeight - Layout.fillHeight: true - objectName: "assetViewStatusListView" - model: root.areAssetsLoading ? d.loadingItemsCount : d.customSFPM - delegate: delegateLoader - section { - property: "isCommunityAsset" - delegate: Loader { width: ListView.view.width - required property string section - sourceComponent: section === "true" ? sectionDelegate : null - } - } - } - Component { - id: sectionDelegate - AssetsSectionDelegate { - width: parent.width - text: qsTr("Community minted") - onInfoButtonClicked: Global.openPopup(communityInfoPopupCmp) - } - } + name: model.name + icon: model.icon + balance: model.balanceText + marketBalance: root.formatFiat(model.marketBalance) - Component { - id: delegateLoader - Loader { - property var modelData: model - property int delegateIndex: index - width: ListView.view.width - sourceComponent: root.areAssetsLoading ? loadingTokenDelegate : tokenDelegate - } - } + marketDetailsAvailable: model.marketDetailsAvailable + marketDetailsLoading: model.marketDetailsLoading + marketCurrencyPrice: root.formatFiat(model.change1DayFiat) + marketChangePct24hour: model.marketChangePct24hour - Component { - id: loadingTokenDelegate - LoadingTokenDelegate { - objectName: "AssetView_LoadingTokenDelegate_" + delegateIndex - } - } + communityId: model.communityId + communityName: model.communityName ?? "" + communityIcon: model.communityIcon ?? "" - Component { - id: tokenDelegate - TokenDelegate { - objectName: "AssetView_TokenListItem_" + (!!modelData ? modelData.symbol : "") - readonly property string balance: !!modelData && !!modelData.currentBalance ? "%1".arg(modelData.currentBalance) : "" // Needed for the tests - errorTooltipText_1: !!modelData && !!networkConnectionStore ? networkConnectionStore.getBlockchainNetworkDownTextForToken(modelData.balances) : "" - errorTooltipText_2: !!networkConnectionStore ? networkConnectionStore.getMarketNetworkDownText() : "" - subTitle: { - if (!modelData || !modelData.symbol) { - return "" + errorTooltipText_1: model.error + errorTooltipText_2: root.marketDataError + + errorMode: !!root.balanceError + errorIcon.tooltip.text: root.balanceError + + onClicked: { + if (mouse.button === Qt.LeftButton) + root.assetClicked(model.key) + else if (mouse.button === Qt.RightButton) + tokenContextMenu.createObject(this, { model }).popup(mouse) } - if (networkConnectionStore && networkConnectionStore.noTokenBalanceAvailable) { - return "" - } - return LocaleUtils.currencyAmountToLocaleString(root.currencyStore.getCurrencyAmount(modelData.currentBalance, modelData.symbol)) + + onCommunityClicked: root.communityClicked(model.communityId) } - currencyBalance.text: { - let totalCurrencyBalance = modelData && modelData.currentCurrencyBalance ? modelData.currentCurrencyBalance : 0 - return currencyStore.formatCurrencyAmount(totalCurrencyBalance, currencyStore.currentCurrency) + } + + DelegateModel { + id: loadingModel + + model: d.loadingItemsCount + + delegate: LoadingTokenDelegate { + objectName: `AssetView_LoadingTokenDelegate_${model.index}` + + width: ListView.view.width } - errorMode: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCache && !networkConnectionStore.noMarketConnectionAndNoCache : false - errorIcon.tooltip.text: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCacheText : "" - onClicked: (itemId, mouse) => { - if (mouse.button === Qt.LeftButton) { - RootStore.getHistoricalDataForToken(modelData.symbol, root.currencyStore.currentCurrency) - d.selectedAssetIndex = delegateIndex - assetClicked(assetsListView.model.get(delegateIndex)) - } else if (mouse.button === Qt.RightButton) { - Global.openMenu(tokenContextMenu, this, - {symbol: modelData.symbol, assetName: modelData.name, assetImage: symbolUrl, - communityId: modelData.communityId, communityName: modelData.communityName, - communityImage: modelData.communityImage, tokensKey: modelData.tokensKey}) - } - } - onSwitchToCommunityRequested: root.switchToCommunityRequested(communityId) - Component.onCompleted: { - // on Model reset if the detail view is shown, update the data in background. - if(root.assetDetailsLaunched && delegateIndex === d.selectedAssetIndex) { - assetClicked(assetsListView.model.get(delegateIndex)) + } + + StatusListView { + id: listView + + objectName: "assetViewStatusListView" + + Layout.fillWidth: true + Layout.fillHeight: true + + model: root.loading ? loadingModel : regularModel + + section { + property: "isCommunity" + delegate: AssetsSectionDelegate { + width: parent.width + text: qsTr("Community minted") + onInfoButtonClicked: communityInfoPopup.createObject(this).open() } } } @@ -317,92 +260,73 @@ ColumnLayout { Component { id: tokenContextMenu - StatusMenu { + + AssetContextMenu { + required property var model + + readonly property string key: model.key + readonly property string communityKey: model.communityId + onClosed: destroy() - property string tokensKey - property string symbol - property string assetName - property string assetImage - property string communityId - property string communityName - property string communityImage + sendEnabled: root.sendEnabled + swapEnabled: root.swapEnabled + swapVisible: root.swapVisible + hideVisible: model.canBeHidden + communityHideVisible: !!model.isCommunity - StatusAction { - enabled: root.networkConnectionStore.sendBuyBridgeEnabled && !root.overview.isWatchOnlyAccount && root.overview.canSend - visibleOnDisabled: true - icon.name: "send" - text: qsTr("Send") - onTriggered: root.sendRequested(symbol) - } - StatusAction { - icon.name: "receive" - text: qsTr("Receive") - onTriggered: root.receiveRequested(symbol) - } - StatusAction { - icon.name: "swap" - text: qsTr("Swap") - enabled: Global.featureFlags.swapEnabled && !root.overview.isWatchOnlyAccount - visibleOnDisabled: Global.featureFlags.swapEnabled - onTriggered: root.launchSwapModal(tokensKey) - } - StatusMenuSeparator {} - StatusAction { - icon.name: "settings" - text: qsTr("Manage tokens") - onTriggered: root.manageTokensRequested() - } - StatusAction { - enabled: symbol !== Constants.ethToken - type: StatusAction.Type.Danger - icon.name: "hide" - text: qsTr("Hide asset") - onTriggered: Global.openConfirmHideAssetPopup(symbol, assetName, assetImage, !!communityId) - } - StatusAction { - enabled: !!communityId - type: StatusAction.Type.Danger - icon.name: "hide" - text: qsTr("Hide all assets from this community") - onTriggered: Global.openPopup(confirmHideCommunityAssetsPopup, {communityId, communityName, communityImage}) - } + onSendRequested: root.sendRequested(key) + onReceiveRequested: root.receiveRequested(key) + onSwapRequested: root.swapRequested(key) + + onHideRequested: + confirmHideAssetPopup.createObject(parent, { model }).open() + onCommunityHideRequested: + confirmHideCommunityAssetsPopup.createObject(parent, { model }).open() + + onManageTokensRequested: root.manageTokensRequested() } } Component { - id: communityInfoPopupCmp - CommunityAssetsInfoPopup {} + id: communityInfoPopup + + CommunityAssetsInfoPopup { + destroyOnClose: true + } + } + + Component { + id: confirmHideAssetPopup + + ConfirmHideAssetPopup { + destroyOnClose: true + + required property var model + + symbol: model.symbol + name: model.name + icon: model.icon + + onConfirmButtonClicked: { + root.hideRequested(model.key) + close() + } + } } Component { id: confirmHideCommunityAssetsPopup - ConfirmationDialog { - property string communityId - property string communityName - property string communityImage - width: 520 - destroyOnClose: true - confirmButtonLabel: qsTr("Hide '%1' assets").arg(communityName) - cancelBtnType: "" - showCancelButton: true - headerSettings.title: qsTr("Hide %1 community assets").arg(communityName) - headerSettings.asset.name: communityImage - confirmationText: qsTr("Are you sure you want to hide all community assets minted by %1? You will no longer see or be able to interact with these assets anywhere inside Status.").arg(communityName) - onCancelButtonClicked: close() + ConfirmHideCommunityAssetsPopup { + required property var model + + name: model.communityName + icon: model.communityIcon + onConfirmButtonClicked: { - root.controller.showHideGroup(communityId, false) - close() - Global.displayToastMessage( - qsTr("%1 community assets were successfully hidden. You can toggle asset visibility via %2.").arg(communityName) - .arg(`` + qsTr("Settings", "Go to Settings") + ""), - "", - "checkmark-circle", - false, - Constants.ephemeralNotificationType.success, - "" - ) + root.hideCommunityAssets(model.communityId) + close(); } } } diff --git a/ui/imports/shared/views/AssetsViewNew.qml b/ui/imports/shared/views/AssetsViewNew.qml deleted file mode 100644 index 3a5360aae..000000000 --- a/ui/imports/shared/views/AssetsViewNew.qml +++ /dev/null @@ -1,333 +0,0 @@ -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.Core 0.1 -import StatusQ.Core.Theme 0.1 -import StatusQ.Popups.Dialog 0.1 - -import AppLayouts.Wallet.controls 1.0 -import shared.controls 1.0 -import shared.popups 1.0 -import utils 1.0 - -import SortFilterProxyModel 0.2 - - -Control { - id: root - - /** - Expected model structure: - - key [string] - unique identifier of a token, e.g "0x3234235" - symbol [string] - token's symbol e.g. "ETH" or "SNT" - name [string] - token's name e.g. "Ether" or "Dai" - icon [url] - token's icon url - balance [double] - tokens balance is the commonly used unit, e.g. 1.2 for 1.2 ETH, used - for sorting and computing market value - balanceText [string] - formatted and localized balance. This is not done internally because - it may depend on many external factors - error [string] - error message related to balance - - marketDetailsAvailable [bool] - specifies if market datails are available for given token - marketDetailsLoading [bool] - specifies if market datails are available for given token - marketPrice [double] - specifies market price in currently used currency - marketChangePct24hour [double] - percentage price change in last 24 hours, e.g. 0.5 for 0.5% of price change - - communityId [string] - for community assets, unique identifier of a community, e.g. "0x6734235" - communityName [string] - for community assets, name of a community e.g. "Crypto Kitties" - communityIcon [url] - for community assets, community's icon url - - position [int] - if custom order available, display position defined by the user via token management - canBeHidden [bool] - specifies if given token can be hidden (e.g. ETH should be always visible) - **/ - property var model - - // enables global loading state useful when real data are not yet available - property bool loading - - // shows/hides list sorter - property bool sorterVisible - - // allows/disables choosing custom sort order from a sorter - property bool customOrderAvailable - - // switches configuring right click menu - property bool sendEnabled: true - property bool swapEnabled: true - property bool swapVisible: true - - property string balanceError - - // global market data error, presented for all tokens expecting market data - property string marketDataError - - // formatting function for fiat currency values - property var formatFiat: balance => `${balance.toLocaleString(Qt.locale())} XYZ` - - signal sendRequested(string key) - signal receiveRequested(string key) - signal swapRequested(string key) - signal assetClicked(string key) - signal communityClicked(string communityKey) - signal hideRequested(string key) - signal hideCommunityAssets(string communityKey) - signal manageTokensRequested - - QtObject { - id: d - - readonly property int loadingItemsCount: 25 - } - - SortFilterProxyModel { - id: sfpm - - sourceModel: root.model - - proxyRoles: [ - // helper role for rendering section delegate - FastExpressionRole { - name: "isCommunity" - expression: !!communityId ? "community" : "" - expectedRoles: ["communityId"] - }, - FastExpressionRole { - name: "marketBalance" - expression: balance * marketPrice - expectedRoles: ["balance", "marketPrice"] - }, - FastExpressionRole { - name: "change1DayFiat" - expression: marketBalance * (1 - (1 / (marketChangePct24hour / 100 + 1))) - expectedRoles: ["marketBalance", "marketChangePct24hour"] - } - ] - - sorters: [ - RoleSorter { - roleName: "isCommunity" - }, - RoleSorter { - roleName: sortOrderComboBox.currentSortRoleName - sortOrder: sortOrderComboBox.currentSortOrder - } - ] - } - - contentItem: ColumnLayout { - ColumnLayout { - Layout.fillHeight: false - Layout.preferredHeight: root.sorterVisible ? implicitHeight : 0 - - opacity: root.sorterVisible ? 1 : 0 - spacing: 20 - visible: opacity > 0 - - Behavior on Layout.preferredHeight { - NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } - } - - Behavior on opacity { - NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } - } - - StatusDialogDivider { Layout.fillWidth: true } - - RowLayout { - Layout.fillWidth: true - Layout.fillHeight: false - - spacing: Style.current.halfPadding - - StatusBaseText { - color: Theme.palette.baseColor1 - font.pixelSize: Style.current.additionalTextSize - text: qsTr("Sort by:") - } - - SortOrderComboBox { - id: sortOrderComboBox - - objectName: "cmbTokenOrder" - hasCustomOrderDefined: root.customOrderAvailable - - model: [ - { value: SortOrderComboBox.TokenOrderCurrencyBalance, - text: qsTr("Asset balance value"), icon: "", sortRoleName: "marketBalance" }, - { value: SortOrderComboBox.TokenOrderBalance, - text: qsTr("Asset balance"), icon: "", sortRoleName: "balance" }, - { value: SortOrderComboBox.TokenOrderCurrencyPrice, - text: qsTr("Asset value"), icon: "", sortRoleName: "marketPrice" }, - { value: SortOrderComboBox.TokenOrder1DChange, - text: qsTr("1d change: balance value"), icon: "", sortRoleName: "change1DayFiat" }, - { value: SortOrderComboBox.TokenOrderAlpha, - text: qsTr("Asset name"), icon: "", sortRoleName: "name" }, - { value: SortOrderComboBox.TokenOrderCustom, - text: qsTr("Custom order"), icon: "", sortRoleName: "position" }, - { value: SortOrderComboBox.TokenOrderNone, - text: "---", icon: "", sortRoleName: "" }, // separator - { value: SortOrderComboBox.TokenOrderCreateCustom, - text: hasCustomOrderDefined ? qsTr("Edit custom order →") : qsTr("Create custom order →"), - icon: "", sortRoleName: "" } - ] - onCreateOrEditRequested: { - root.manageTokensRequested() - } - } - } - - StatusDialogDivider { Layout.fillWidth: true } - } - - DelegateModel { - id: regularModel - - model: sfpm - - delegate: TokenDelegateNew { - objectName: `AssetView_TokenListItem_${model.symbol}` - - width: ListView.view.width - - name: model.name - icon: model.icon - balance: model.balanceText - marketBalance: root.formatFiat(model.marketBalance) - - marketDetailsAvailable: model.marketDetailsAvailable - marketDetailsLoading: model.marketDetailsLoading - marketCurrencyPrice: root.formatFiat(model.change1DayFiat) - marketChangePct24hour: model.marketChangePct24hour - - communityId: model.communityId - communityName: model.communityName ?? "" - communityIcon: model.communityIcon ?? "" - - errorTooltipText_1: model.error - errorTooltipText_2: root.marketDataError - - errorMode: !!root.balanceError - errorIcon.tooltip.text: root.balanceError - - onClicked: { - if (mouse.button === Qt.LeftButton) - root.assetClicked(model.key) - else if (mouse.button === Qt.RightButton) - tokenContextMenu.createObject(this, { model }).popup(mouse) - } - - onCommunityClicked: root.communityClicked(model.communityId) - } - } - - DelegateModel { - id: loadingModel - - model: d.loadingItemsCount - - delegate: LoadingTokenDelegateNew { - objectName: `AssetView_LoadingTokenDelegate_${model.index}` - - width: ListView.view.width - } - } - - StatusListView { - id: listView - - objectName: "assetViewStatusListView" - - Layout.fillWidth: true - Layout.fillHeight: true - - model: root.loading ? loadingModel : regularModel - - section { - property: "isCommunity" - delegate: AssetsSectionDelegate { - width: parent.width - text: qsTr("Community minted") - onInfoButtonClicked: communityInfoPopup.createObject(this).open() - } - } - } - } - - Component { - id: tokenContextMenu - - AssetContextMenu { - required property var model - - readonly property string key: model.key - readonly property string communityKey: model.communityId - - onClosed: destroy() - - sendEnabled: root.sendEnabled - swapEnabled: root.swapEnabled - swapVisible: root.swapVisible - hideVisible: model.canBeHidden - communityHideVisible: !!model.isCommunity - - onSendRequested: root.sendRequested(key) - onReceiveRequested: root.receiveRequested(key) - onSwapRequested: root.swapRequested(key) - - onHideRequested: - confirmHideAssetPopup.createObject(parent, { model }).open() - onCommunityHideRequested: - confirmHideCommunityAssetsPopup.createObject(parent, { model }).open() - - onManageTokensRequested: root.manageTokensRequested() - } - } - - Component { - id: communityInfoPopup - - CommunityAssetsInfoPopup { - destroyOnClose: true - } - } - - Component { - id: confirmHideAssetPopup - - ConfirmHideAssetPopup { - destroyOnClose: true - - required property var model - - symbol: model.symbol - name: model.name - icon: model.icon - - onConfirmButtonClicked: { - root.hideRequested(model.key) - close() - } - } - } - - Component { - id: confirmHideCommunityAssetsPopup - - ConfirmHideCommunityAssetsPopup { - required property var model - - name: model.communityName - icon: model.communityIcon - - onConfirmButtonClicked: { - root.hideCommunityAssets(model.communityId) - close(); - } - } - } -} diff --git a/ui/imports/shared/views/qmldir b/ui/imports/shared/views/qmldir index 59c4be398..d476d2638 100644 --- a/ui/imports/shared/views/qmldir +++ b/ui/imports/shared/views/qmldir @@ -1,7 +1,6 @@ AssetContextMenu 1.0 AssetContextMenu.qml AssetsView 1.0 AssetsView.qml AssetsViewAdaptor 1.0 AssetsViewAdaptor.qml -AssetsViewNew 1.0 AssetsViewNew.qml ConfirmHideAssetPopup 1.0 ConfirmHideAssetPopup.qml ConfirmHideCommunityAssetsPopup 1.0 ConfirmHideCommunityAssetsPopup.qml EnsResolver 1.0 EnsResolver.qml