diff --git a/storybook/pages/TransactionDetailViewPage.qml b/storybook/pages/TransactionDetailViewPage.qml deleted file mode 100644 index a92b125426..0000000000 --- a/storybook/pages/TransactionDetailViewPage.qml +++ /dev/null @@ -1,285 +0,0 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 - -import Storybook 1.0 - -import StatusQ.Core.Theme 0.1 - -import AppLayouts.Wallet 1.0 -import AppLayouts.Wallet.stores 1.0 as WalletStores - -import "../../ui/app/AppLayouts/Wallet/views" // NOTE - there is no AppLayout.Wallet.views -import shared.controls 1.0 -import shared.stores 1.0 - -import utils 1.0 - -import Models 1.0 - -SplitView { - id: root - - property bool globalUtilsReady: false - property bool mainModuleReady: false - - property bool isIncoming: false - - RootStore { - id: rootStoreMock - - function getFiatValue(cryptoValue, symbol) { return (cryptoValue * 1800).toPrecision(2) } - function getLatestBlockNumber() { return 4 } - function formatCurrencyAmount(value, symbol) { return value + " " + symbol } - function getNameForSavedWalletAddress(address) { return "Saved Wallet Name" } - function getNameForAddress(address) { return "Address Name" } - function getEnsForSavedWalletAddress(address) { return "123" } - function getGasEthValue(gasAmount, gasPrice) { return (gasAmount * Math.pow(10, -9)).toPrecision(5) } - - readonly property string currentCurrency: "USD" - readonly property var flatNetworks: NetworksModel.flatNetworks - } - - // globalUtilsInst mock - QtObject { - function getColorHashAsJson(publicKey) { - return JSON.stringify([{"segmentLength":1,"colorId":12},{"segmentLength":5,"colorId":18}, - {"segmentLength":3,"colorId":25},{"segmentLength":3,"colorId":23}, - {"segmentLength":1,"colorId":10},{"segmentLength":3,"colorId":26}, - {"segmentLength":2,"colorId":30},{"segmentLength":1,"colorId":18}, - {"segmentLength":4,"colorId":28},{"segmentLength":1,"colorId":17}, - {"segmentLength":2,"colorId":2}]) - } - function getColorId(publicKey) { return Math.floor(Math.random() * 10) } - - Component.onCompleted: { - Utils.globalUtilsInst = this - root.globalUtilsReady = true - } - Component.onDestruction: { - root.globalUtilsReady = false - Utils.globalUtilsInst = {} - } - } - - // mainModuleInst mock - QtObject { - function getContactDetailsAsJson(publicKey, getVerification) { - return JSON.stringify({ - displayName: "ArianaP", - displayIcon: "", - publicKey: publicKey, - compressedPublicKey: "compressed", - name: "", - alias: "", - localNickname: "", - isContact: true - }) - } - function isEnsVerified(publicKey) { return false } - - Component.onCompleted: { - Utils.mainModuleInst = this - root.mainModuleReady = true - } - Component.onDestruction: { - root.mainModuleReady = false - Utils.mainModuleInst = {} - } - } - - QtObject { - id: contactsStoreMockup - readonly property var myContactsModel: QtObject { - signal itemChanged(address: string) - } - - function getContactPublicKeyByAddress(address) { - return "" - } - } - - QtObject { - id: historyMockup - - signal txDecoded(txHash: string, dataDecoded: string) - - function fetchDecodedTxData(txHash, input) { - decodeTimer.txHash = txHash - decodeTimer.start() - } - - readonly property Timer decodeTimer: Timer { - id: decodeTimer - property string txHash: "" - interval: 2000 - onTriggered: { - const data = JSON.stringify({ - name: "processDepositQueue", - signature: "processDepositQueue(address,uint256)", - id: "0xf94d2", - inputs: { - "0": "0x3030303030303030303030303637306463613632", - "1": "0x40e8d703000000000000000", - "2": "0x60d8f57dh0bcdd0da0a00ad000000", - "3": "0xd8ff5ba7fhfaafbf0fdfa0afaf1d000000" - } - }) - historyMockup.txDecoded(txHash, data) - } - } - } - - QtObject { - id: transactionData - - property int chainId: 1 - property int timestamp: Date.now() / 1000 - property int txStatus: 0 - property string type: "eth" - property string from: "eth:arb1:oeth:0xb38e8c17e38363af6ebdcb3dae12e0243582891d" - property string to: "0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8" - property bool isNFT: false - property string tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337" - property string nftName: "Happy Meow" - property string nftImageUrl: Theme.png("collectibles/HappyMeow") - property string symbol: "ETH" - property int txType: Constants.TransactionType.Send - - readonly property var value: QtObject { - property real amount: amountSpinbox.realValue - property string symbol: "ETH" - property int displayDecimals: 5 - property bool stripTrailingZeroes: true - } - } - - QtObject { - id: transactionDetails - - property string nonce: "0x123" - property string blockNumber: "0x124" - property string txHash: "0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35" - property string txHashOut: "0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35" - property string input: "0x40e8d703000000000000000000000000670dca62b3418bddd08cbc69cb4490a5a3382a9f0000000000000000000000000000000000000000000000000000000000000064ddd08cbc69cb4490a5a3382a9f0000000000" - property string contract: "0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35" - - readonly property var totalFees: QtObject { - property real amount: (transactionData.value / 15) * Math.pow(10, 9) - property string symbol: "Gwei" - property int displayDecimals: 8 - property bool stripTrailingZeroes: true - } - - } - - QtObject { - id: overviewMockup - - property var mixedcaseAddress: root.isIncoming ? transactionData.to : transactionData.from - } - - QtObject { - id: networkConnectionStoreMockup - - property bool sendBuyBridgeEnabled: true - } - - QtObject { - id: controllerMockup - - property var activityEntry: transactionData - property var activityDetails - - function fetchExtraTxDetails() { - extraDetailsTimer.start() - } - - readonly property Timer extraDetailsTimer: Timer { - id: extraDetailsTimer - interval: 1000 - onTriggered: { - controllerMockup.activityDetails = transactionDetails - } - } - } - - SplitView { - orientation: Qt.Vertical - SplitView.fillWidth: true - Item { - SplitView.fillWidth: true - SplitView.fillHeight: true - - Rectangle { - anchors.fill: viewLoader - anchors.margins: -1 - color: "transparent" - border.width: 1 - border.color: "#808080" - } - - Loader { - id: viewLoader - anchors.centerIn: parent - width: 800 - height: 500 - - active: root.globalUtilsReady && root.mainModuleReady - sourceComponent: TransactionDetailView { - rootStore: rootStoreMock - currenciesStore: CurrenciesStore {} - contactsStore: contactsStoreMockup - controller: controllerMockup - overview: overviewMockup - networkConnectionStore: networkConnectionStoreMockup - } - } - } - - LogsAndControlsPanel { - SplitView.minimumHeight: 100 - SplitView.preferredHeight: 150 - - SplitView.fillWidth: true - } - } - - Pane { - SplitView.minimumWidth: 300 - SplitView.preferredWidth: 300 - - ColumnLayout { - Label { - text: "Amount:" - } - SpinBox { - id: amountSpinbox - from: 0 - to: 999999999 - value: 12345 - stepSize: 1 - editable: true - - readonly property int multiplier: Math.pow(10, decimals) - property int decimals: 5 - property real realValue: value / multiplier - validator: DoubleValidator { bottom: 0.0 } - textFromValue: function(value, locale) { return Number(value / amountSpinbox.multiplier).toLocaleString(locale, 'f', amountSpinbox.decimals) } - valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text) * amountSpinbox.multiplier } - } - CheckBox { - text: "is NFT" - checked: transactionData.isNFT - onCheckedChanged: transactionData.isNFT = checked - } - CheckBox { - text: "is incoming" - checked: root.isIncoming - onCheckedChanged: root.isIncoming = checked - } - } - } -} - -// category: Wallet diff --git a/ui/app/AppLayouts/Wallet/WalletLayout.qml b/ui/app/AppLayouts/Wallet/WalletLayout.qml index d547d8a525..d5496c4d61 100644 --- a/ui/app/AppLayouts/Wallet/WalletLayout.qml +++ b/ui/app/AppLayouts/Wallet/WalletLayout.qml @@ -126,14 +126,10 @@ Item { rightPanelStackView.currentItem.resetView() rightPanelStackView.currentItem.currentTabIndex = rightPanelSelection - let txHash = data.txHash?? "" let savedAddress = data.savedAddress?? "" if (!!savedAddress) { RootStore.currentActivityFiltersStore.resetAllFilters() RootStore.currentActivityFiltersStore.toggleSavedAddress(savedAddress) - } else if (!!txHash) { - RootStore.currentActivityFiltersStore.resetAllFilters() - RootStore.currentActivityFiltersStore.displayTxDetails(txHash) } } } diff --git a/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml b/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml index 2a527b27f0..ced78c9565 100644 --- a/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml @@ -20,8 +20,6 @@ QtObject { recentsFilters.length !== 0 || savedAddressFilters.length !== 0 - signal displayTxDetails(string txHash) - readonly property QtObject _d: QtObject { id: d diff --git a/ui/app/AppLayouts/Wallet/views/RightTabView.qml b/ui/app/AppLayouts/Wallet/views/RightTabView.qml index afa80232f6..04cbc239a5 100644 --- a/ui/app/AppLayouts/Wallet/views/RightTabView.qml +++ b/ui/app/AppLayouts/Wallet/views/RightTabView.qml @@ -431,10 +431,6 @@ RightTabBaseView { showAllAccounts: RootStore.showAllAccounts sendModal: root.sendModal filterVisible: filterButton.checked - onLaunchTransactionDetail: function (txID) { - RootStore.activityController.fetchTxDetails(txID) - stack.currentIndex = 3 - } } } } @@ -458,14 +454,6 @@ RightTabBaseView { RootStore.collectiblesStore.resetDetailedCollectible() } } - - onLaunchTransactionDetail: function (txID) { - d.detailedCollectibleActivityController.fetchTxDetails(txID) - stack.currentIndex = 3 - - // Take user to the activity view when they press the "Back" button - walletTabBar.currentIndex = 2 - } } AssetsDetailView { id: assetDetailView @@ -485,33 +473,5 @@ RightTabBaseView { RootStore.resetCurrentViewedHolding(Constants.TokenType.ERC20) } } - - Loader { - active: stack.currentIndex === 3 - - sourceComponent: TransactionDetailView { - controller: RootStore.activityDetailsController - onVisibleChanged: { - if (visible) { - if (!!transaction) { - RootStore.addressWasShown(transaction.sender) - if (transaction.sender !== transaction.recipient) { - RootStore.addressWasShown(transaction.recipient) - } - } - } else { - controller.resetActivityEntry() - } - } - showAllAccounts: RootStore.showAllAccounts - communitiesStore: root.communitiesStore - sendModal: root.sendModal - rootStore: root.sharedRootStore - currenciesStore: root.sharedRootStore.currencyStore - contactsStore: root.contactsStore - networkConnectionStore: root.networkConnectionStore - visible: (stack.currentIndex === 3) - } - } } } diff --git a/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml b/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml deleted file mode 100644 index 6f03a70ea6..0000000000 --- a/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml +++ /dev/null @@ -1,884 +0,0 @@ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 -import QtGraphicalEffects 1.15 - -import StatusQ 0.1 -import StatusQ.Components 0.1 -import StatusQ.Core.Theme 0.1 -import StatusQ.Core 0.1 -import StatusQ.Core.Utils 0.1 -import StatusQ.Controls 0.1 -import StatusQ.Popups 0.1 - -import shared.controls 1.0 -import shared.panels 1.0 -import shared.stores 1.0 -import utils 1.0 -import shared.popups.send 1.0 - -import AppLayouts.Communities.stores 1.0 -import AppLayouts.Profile.stores 1.0 as ProfileStores - -import "../controls" -import "../popups" -import "../stores" as WalletStores -import ".." -import "../panels" - -Item { - id: root - - property var overview: WalletStores.RootStore.overview - property RootStore rootStore - property CurrenciesStore currenciesStore - property ProfileStores.ContactsStore contactsStore - property CommunitiesStore communitiesStore - property NetworkConnectionStore networkConnectionStore - property var controller - property var sendModal - property bool showAllAccounts: false - - readonly property alias transaction: d.transaction - - Component.onCompleted: d.updateTransactionDetails() - - QtObject { - id: d - - readonly property var transaction: root.controller.activityEntry - readonly property bool isTransactionValid: transaction !== undefined && !!transaction - - onTransactionChanged: { - d.reEvaluateSender = !d.reEvaluateSender - d.reEvaluateRecipient = !d.reEvaluateRecipient - d.reEvaluateSender = !d.reEvaluateSender - d.reEvaluateRecipient = !d.reEvaluateRecipient - - d.updateTransactionDetails() - } - - property bool reEvaluateSender: true - property bool reEvaluateRecipient: true - - property var details: root.controller.activityDetails - readonly property bool isDetailsValid: details !== undefined && !!details - - onDetailsChanged: { - if (!!d.details && !!d.details.input && d.details.input !== "0x") { - d.loadingInputDate = true - WalletStores.RootStore.fetchDecodedTxData(d.details.txHashOut, d.details.input) - } - } - - readonly property bool isIncoming: transactionType === Constants.TransactionType.Received || transactionType === Constants.TransactionType.ContractDeployment - readonly property string networkShortName: d.isTransactionValid ? ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", transaction.chainId, "shortName") : "" - readonly property string networkIcon: isTransactionValid ? ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", transaction.chainId, "iconUrl") : "network/Network=Custom" - readonly property int blockNumber: isDetailsValid ? details.blockNumber : 0 - readonly property int blockNumberIn: isDetailsValid ? details.blockNumberIn : 0 - readonly property int blockNumberOut: isDetailsValid ? details.blockNumberOut : 0 - readonly property string networkShortNameOut: networkShortName - readonly property string networkShortNameIn: transactionHeader.isMultiTransaction ? ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", transaction.chainIdIn, "shortName") : "" - readonly property string symbol: isTransactionValid ? transaction.symbol : "" - readonly property string inSymbol: isTransactionValid ? transaction.inSymbol : "" - readonly property string outSymbol: isTransactionValid ? transaction.outSymbol : "" - readonly property var multichainNetworks: [] // TODO fill icon for networks for multichain - readonly property string fiatValueFormatted: { - if (!d.isTransactionValid || transactionHeader.isMultiTransaction || !symbol) - return "" - return root.currenciesStore.formatCurrencyAmount(transactionHeader.fiatValue, root.currenciesStore.currentCurrency) - } - readonly property string cryptoValueFormatted: { - if (!d.isTransactionValid || transactionHeader.isMultiTransaction) - return "" - const formatted = root.currenciesStore.formatCurrencyAmount(transaction.amount, transaction.symbol) - return symbol || (!d.isDetailsValid || !d.details.contract) ? formatted : "%1 (%2)".arg(formatted).arg(Utils.compactAddress(transaction.tokenAddress, 4)) - } - readonly property string outFiatValueFormatted: { - if (!d.isTransactionValid || !transactionHeader.isMultiTransaction || !outSymbol) - return "" - return root.currenciesStore.formatCurrencyAmount(transactionHeader.outFiatValue, root.currenciesStore.currentCurrency) - } - readonly property string outCryptoValueFormatted: { - if (!d.isTransactionValid || !transactionHeader.isMultiTransaction) - return "" - const formatted = root.currenciesStore.formatCurrencyAmount(transaction.outAmount, transaction.outSymbol) - return outSymbol || !transaction.tokenOutAddress ? formatted : "%1 (%2)".arg(formatted).arg(Utils.compactAddress(transaction.tokenOutAddress, 4)) - } - readonly property real feeEthValue: d.details ? root.currenciesStore.getFeeEthValue(d.details.totalFees) : 0 - readonly property real feeFiatValue: root.currenciesStore.getFiatValue(d.feeEthValue, Constants.ethToken) - readonly property int transactionType: d.isTransactionValid ? WalletStores.RootStore.transactionType(transaction) : Constants.TransactionType.Send - readonly property bool isBridge: d.transactionType === Constants.TransactionType.Bridge - - property string decodedInputData: "" - property bool loadingInputDate: false - - function retryTransaction() { - // TODO handle failed transaction retry - } - - function updateTransactionDetails() { - d.decodedInputData = "" - if (!d.transaction) - return - - root.controller.fetchExtraTxDetails() - } - } - - Connections { - target: WalletStores.RootStore.walletSectionInst - function onTxDecoded(txHash: string, dataDecoded: string) { - if (!d.isTransactionValid || (d.isDetailsValid && txHash !== d.details.txHashOut)) - return - if (!dataDecoded) { - d.loadingInputDate = false - return - } - - try { - const decodedObject = JSON.parse(dataDecoded) - let text = qsTr("Function: %1").arg(decodedObject.signature) - text += "\n" + qsTr("MethodID: %1").arg(decodedObject.id) - for (const [key, value] of Object.entries(decodedObject.inputs)) { - text += "\n[%1]: %2".arg(key).arg(value) - } - d.decodedInputData = text - } catch(e) { - console.error("Failed to parse decoded tx data. Data:", dataDecoded) - } - d.loadingInputDate = false - } - } - - StatusScrollView { - id: scrollView - anchors.fill: parent - contentWidth: availableWidth - - Column { - id: column - width: scrollView.availableWidth - spacing: Theme.xlPadding + Theme.halfPadding - - Column { - width: parent.width - spacing: Theme.bigPadding - - TransactionDelegate { - id: transactionHeader - objectName: "transactionDetailHeader" - width: parent.width - leftPadding: 0 - sensor.enabled: false - color: Theme.palette.transparent - state: "header" - - showAllAccounts: root.showAllAccounts - modelData: transaction - timeStampText: d.isTransactionValid ? qsTr("Signed at %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)): "" - flatNetworks: root.rootStore.flatNetworks - currenciesStore: root.currenciesStore - walletRootStore: WalletStores.RootStore - community: isModelDataValid && communityId && communitiesStore ? communitiesStore.getCommunityDetailsAsJson(communityId) : null - - onRetryClicked: d.retryTransaction() - } - - Separator { } - } - - WalletTxProgressBlock { - id: progressBlock - width: Math.min(513, root.width) - readonly property int latestBlockNumber: d.isTransactionValid && !pending && !error ? WalletStores.RootStore.getEstimatedLatestBlockNumber(d.transaction.chainId) : 0 - readonly property int latestBlockNumberIn: d.isTransactionValid && !pending && !error && transactionHeader.isMultiTransaction && d.isBridge ? WalletStores.RootStore.getEstimatedLatestBlockNumber(d.transaction.chainIdIn) : 0 - error: transactionHeader.transactionStatus === Constants.TransactionStatus.Failed - pending: transactionHeader.transactionStatus === Constants.TransactionStatus.Pending - outNetworkLayer: d.isTransactionValid ? Number(ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", transactionHeader.isMultiTransaction ? d.transaction.chainIdOut : d.transaction.chainId, "layer")) : 0 - inNetworkLayer: d.isTransactionValid && transactionHeader.isMultiTransaction && d.isBridge ? - ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", d.transaction.chainIdIn, "layer") : 0 - outNetworkTimestamp: d.isTransactionValid ? d.transaction.timestamp : 0 - inNetworkTimestamp: d.isTransactionValid ? d.transaction.timestamp : 0 - outChainName: transactionHeader.isMultiTransaction ? transactionHeader.networkNameOut : transactionHeader.networkName - inChainName: transactionHeader.isMultiTransaction && d.isBridge ? transactionHeader.networkNameIn : "" - outNetworkConfirmations: d.isTransactionValid && latestBlockNumber > 0 ? latestBlockNumber - d.blockNumberOut : 0 - inNetworkConfirmations: d.isTransactionValid && latestBlockNumberIn > 0 ? latestBlockNumberIn - d.blockNumberIn : 0 - } - - Separator { - width: progressBlock.width - } - - WalletNftPreview { - visible: d.isTransactionValid && transactionHeader.isNFT && !!transaction.nftImageUrl - width: Math.min(304, progressBlock.width) - nftName: d.isTransactionValid ? transaction.nftName : "" - nftUrl: d.isTransactionValid && !!transaction.nftImageUrl ? transaction.nftImageUrl : "" - strikethrough: d.transactionType === Constants.TransactionType.Destroy - tokenId: d.isTransactionValid ? transaction.tokenID : "" - tokenAddress: d.isTransactionValid ? transaction.tokenAddress : "" - areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled - } - - Column { - width: progressBlock.width - spacing: 0 - - StatusBaseText { - width: parent.width - font.pixelSize: 15 - color: Theme.palette.directColor5 - text: qsTr("Transaction summary") - elide: Text.ElideRight - } - - Item { - width: parent.width - height: Theme.smallPadding - } - - DetailsPanel { - RowLayout { - spacing: 0 - width: parent.width - height: fromNetworkTile.visible || toNetworkTile.visible ? 85 : 0 - TransactionDataTile { - id: fromNetworkTile - Layout.fillWidth: true - Layout.fillHeight: true - title: qsTr("From") - subTitle: { - if (!d.isTransactionValid) - return "" - switch(d.transactionType) { - case Constants.TransactionType.Swap: - return !!d.outSymbol ? d.outSymbol : " " - case Constants.TransactionType.Bridge: - return transactionHeader.networkNameOut - default: - return "" - } - } - asset.name: { - if (!d.isTransactionValid) - return "" - switch(d.transactionType) { - case Constants.TransactionType.Swap: - return Constants.tokenIcon(d.outSymbol) - case Constants.TransactionType.Bridge: - return Theme.svg(ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", d.transaction.chainIdOut, "iconUrl")) ?? Theme.svg("network/Network=Custom") - default: - return "" - } - } - visible: !!subTitle - } - TransactionDataTile { - id: toNetworkTile - Layout.fillWidth: true - Layout.fillHeight: true - title: qsTr("To") - subTitle: { - switch(d.transactionType) { - case Constants.TransactionType.Swap: - return !!d.inSymbol ? d.inSymbol : " " - case Constants.TransactionType.Bridge: - return transactionHeader.networkNameIn ?? " " - default: - return "" - } - } - asset.name: { - switch(d.transactionType) { - case Constants.TransactionType.Swap: - return Constants.tokenIcon(d.inSymbol) - case Constants.TransactionType.Bridge: - return Theme.svg(ModelUtils.getByKey(root.rootStore.flatNetworks, "chainId", d.transaction.chainIdIn, "iconUrl")) ?? Theme.svg("network/Network=Custom") - default: - return "" - } - } - visible: !!subTitle - } - } - TransactionAddressTile { - width: parent.width - title: d.transactionType === Constants.TransactionType.Swap || d.transactionType === Constants.TransactionType.Bridge ? - qsTr("In") : qsTr("From") - addresses: d.isTransactionValid && d.reEvaluateSender? [d.transaction.sender] : [] - contactsStore: root.contactsStore - rootStore: WalletStores.RootStore - onButtonClicked: { - if (d.transactionType === Constants.TransactionType.Swap || d.transactionType === Constants.TransactionType.Bridge) { - addressMenu.openEthAddressMenu(this, addresses[0], [d.networkShortNameIn, d.networkShortNameOut]) - } else { - addressMenu.openSenderMenu(this, addresses[0], [d.networkShortName]) - } - } - } - TransactionDataTile { - id: contractDeploymentTile - readonly property bool hasValue: d.isDetailsValid && !!d.details.contractOut - && transactionHeader.transactionStatus !== Constants.TransactionStatus.Pending - && transactionHeader.transactionStatus !== Constants.TransactionStatus.Failed - width: parent.width - title: qsTr("To") - visible: d.transactionType === Constants.TransactionType.ContractDeployment - subTitle: { - if (transactionHeader.transactionStatus === Constants.TransactionStatus.Failed) { - return qsTr("Contract address not created") - } else if (!hasValue) { - return qsTr("Awaiting contract address...") - } - return qsTr("Contract created") + "\n" + d.details.contract - } - buttonIconName: hasValue ? "more" : "" - statusListItemSubTitle.customColor: hasValue ? Theme.palette.directColor1 : Theme.palette.directColor5 - onButtonClicked: addressMenu.openContractMenu(this, d.details.contract, [d.networkShortName], d.symbol) - components: [ - Loader { - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: Theme.halfPadding - active: transactionHeader.transactionStatus === Constants.TransactionStatus.Pending - width: active ? implicitWidth : 0 - sourceComponent: StatusLoadingIndicator { } - } - ] - } - TransactionAddressTile { - width: parent.width - title: qsTr("To") - addresses: d.isTransactionValid && visible && d.reEvaluateRecipient? [d.transaction.recipient] : [] - contactsStore: root.contactsStore - rootStore: WalletStores.RootStore - onButtonClicked: addressMenu.openReceiverMenu(this, addresses[0], [d.networkShortName]) - visible: d.transactionType !== Constants.TransactionType.ContractDeployment && d.transactionType !== Constants.TransactionType.Swap && d.transactionType !== Constants.TransactionType.Bridge && d.transactionType !== Constants.TransactionType.Destroy - } - TransactionDataTile { - width: parent.width - title: qsTr("Using") - subTitle: d.isDetailsValid ? d.details.protocol : "" - asset.name: d.isDetailsValid && d.details.protocol ? Theme.svg("protocol/Protocol=%1".arg(d.details.protocol)) : Theme.svg("network/Network=Custom") - iconSettings.bgRadius: iconSettings.bgWidth / 2 -// buttonIconName: "external" // TODO handle external link #11982 - visible: !!subTitle - } - TransactionDataTile { - width: parent.width - title: qsTr("%1 Tx hash").arg(transactionHeader.networkName) - subTitle: d.isDetailsValid ? d.details.txHash : "" - visible: !!subTitle && !transactionHeader.isMultiTransaction - buttonIconName: "more" - onButtonClicked: addressMenu.openTxMenu(this, subTitle, [d.networkShortName]) - } - TransactionDataTile { - width: parent.width - title: qsTr("%1 Tx hash").arg(transactionHeader.networkNameOut) - subTitle: d.isDetailsValid ? d.details.txHashOut : "" - visible: !!subTitle && transactionHeader.isMultiTransaction - buttonIconName: "more" - onButtonClicked: addressMenu.openTxMenu(this, subTitle, [d.networkShortNameOut]) - } - TransactionDataTile { - width: parent.width - title: qsTr("%1 Tx hash").arg(transactionHeader.networkNameIn) - subTitle: d.isDetailsValid ? d.details.txHashIn : "" - visible: !!subTitle && transactionHeader.isMultiTransaction - buttonIconName: "more" - onButtonClicked: addressMenu.openTxMenu(this, subTitle, [d.networkShortNameIn]) - } -// TransactionContractTile { -// // Used for Bridge and Swap to display 'From' network Protocol contract address -// address: "" // TODO fill protocol contract address for 'from' network for Bridge and Swap -// symbol: "" // TODO fill protocol name for Bridge and Swap -// networkName: transactionHeader.networkName -// shortNetworkName: d.networkShortName -// visible: !!subTitle && (d.transactionType === Constants.TransactionType.Bridge || d.transactionType === Constants.TransactionType.Swap) -// } - TransactionContractTile { - // Used to display contract address for any network - address: d.isDetailsValid ? d.details.contractIn : "" - symbol: { - if (!d.isTransactionValid) - return "" - return d.symbol ? d.symbol : "(%1)".arg(Utils.compactAddress(transaction.tokenAddress, 4)) - } - networkName: transactionHeader.networkName - shortNetworkName: d.networkShortName - visible: !!subTitle && d.transactionType !== Constants.TransactionType.ContractDeployment - } -// TransactionContractTile { -// // Used for Bridge to display 'To' network Protocol contract address -// address: "" // TODO fill protocol contract address for 'to' network for Bridge -// symbol: "" // TODO fill protocol name for Bridge -// networkName: transactionHeader.networkNameOut -// shortNetworkName: d.networkShortNameOut -// visible: !!subTitle && d.transactionType === Constants.TransactionType.Bridge -// } - TransactionContractTile { - // Used for Bridge and Swap to display 'To' network token contract address - address: { - if (!d.isTransactionValid) - return "" - switch(d.transactionType) { - case Constants.TransactionType.Swap: - case Constants.TransactionType.Bridge: - return d.isDetailsValid ? d.details.contractOut : "" - default: - return "" - } - } - symbol: { - if (!d.isTransactionValid) - return "" - switch(d.transactionType) { - case Constants.TransactionType.Swap: - return d.inSymbol - case Constants.TransactionType.Bridge: - return d.outSymbol - default: - return "" - } - } - networkName: transactionHeader.networkNameIn - shortNetworkName: d.networkShortNameIn - visible: d.isTransactionValid && !!subTitle - } - } - - Item { - width: parent.width - height: Theme.bigPadding - } - - DetailsPanel { - width: progressBlock.width - RowLayout { - width: parent.width - height: networkNameTile.statusListItemSubTitle.lineCount > 1 ? 85 : 70 - spacing: 0 - TransactionDataTile { - id: multichainNetworksTile - Layout.fillHeight: true - Layout.fillWidth: true - title: qsTr("Networks") - visible: d.multichainNetworks.length > 0 - Row { - anchors { - top: parent.top - topMargin: multichainNetworksTile.statusListItemTitleArea.height + multichainNetworksTile.topPadding - left: parent.left - leftMargin: multichainNetworksTile.leftPadding - } - spacing: -4 - Repeater { - model: d.multichainNetworks - delegate: StatusRoundedImage { - width: 20 - height: 20 - visible: image.source !== "" - border.width: index === 0 ? 0 : 1 - border.color: Theme.palette.white - image.source: Theme.svg("tiny/" + modelData) - z: index + 1 - } - } - } - } - TransactionDataTile { - id: networkNameTile - Layout.fillHeight: true - Layout.fillWidth: true - title: qsTr("Network") - subTitle: transactionHeader.networkName - asset.name: !!d.networkIcon ? Theme.svg(d.networkIcon) : "" - subTitleBadgeLoaderAlignment: Qt.AlignTop - smallIcon: true - visible: !!subTitle && d.transactionType !== Constants.TransactionType.Bridge - } - TransactionDataTile { - Layout.fillHeight: true - Layout.fillWidth: true - title: qsTr("Token format") - subTitle: d.isDetailsValid ? d.details.tokenType.toUpperCase() : "" - visible: !!subTitle - } - TransactionDataTile { - Layout.fillHeight: true - Layout.fillWidth: true - title: qsTr("Nonce") - subTitle: d.isDetailsValid ? d.details.nonce : "" - visible: !!subTitle - } - } - TransactionDataTile { - width: parent.width - height: d.loadingInputDate ? 112 : Math.min(implicitHeight + bottomPadding, 112) - title: qsTr("Input data") - // Input string can be really long. Getting substring just for 3+ lines to speedup formatting. - subTitle: { - if (d.loadingInputDate) { - return "" - } else if (!!d.decodedInputData) { - return d.decodedInputData.substring(0, 200) - } else if (d.isDetailsValid) { - return String(d.details.input).substring(0, 200) - } - return "" - } - visible: !!subTitle || d.loadingInputDate - buttonIconName: d.loadingInputDate ? "" : "more" - statusListItemSubTitle.maximumLineCount: 4 - statusListItemSubTitle.lineHeight: 1.21 - statusListItemSubTitle.layer.enabled: statusListItemSubTitle.lineCount > 3 - statusListItemSubTitle.layer.effect: OpacityMask { - maskSource: Rectangle { - width: 10 - height: 10 - gradient: Gradient { - GradientStop { position: 0.0; color: "#f00" } - GradientStop { position: 0.4; color: "#a0ff0000" } - GradientStop { position: 0.75; color: "#00ff0000" } - } - } - } - tertiaryTitle: !d.loadingInputDate && !d.decodedInputData ? qsTr("Data could not be decoded") : "" - statusListItemTertiaryTitle.anchors.top: undefined - statusListItemTertiaryTitle.anchors.baseline: statusListItemTitle.baseline - statusListItemTertiaryTitle.font: statusListItemTitle.font - onButtonClicked: addressMenu.openInputDataMenu(this, !!d.decodedInputData ? d.decodedInputData : d.details.input) - - Loader { - anchors { - left: parent.left - bottom: parent.bottom - right: parent.right - margins: 12 - } - active: d.loadingInputDate - sourceComponent: Column { - spacing: 10 - Repeater { - model: 3 - LoadingComponent { - anchors { - left: parent.left - right: index === 2 ? parent.horizontalCenter : parent.right - } - height: 11 - radius: 4 - enabled: false - } - } - } - } - } - TransactionDataTile { - // Tile used only for multiTx - width: parent.width - title: !!transactionHeader.networkNameOut ? qsTr("Included in Block on %1").arg(transactionHeader.networkNameOut) : qsTr("Included on Block") - subTitle: d.blockNumberOut - tertiaryTitle: d.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : "" - visible: d.blockNumberOut > 0 && transactionHeader.isMultiTransaction - } - TransactionDataTile { - // Tile used for multiTx and normal tx - width: parent.width - readonly property int blockNumber: transactionHeader.isMultiTransaction ? d.blockNumberIn : d.blockNumber - readonly property string networkName: transactionHeader.isMultiTransaction ? transactionHeader.networkNameIn : transactionHeader.networkName - title: !!networkName ? qsTr("Included in Block on %1").arg(networkName) : qsTr("Included on Block") - subTitle: blockNumber - tertiaryTitle: d.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : "" - visible: blockNumber > 0 - } - } - } - - Column { - width: progressBlock.width - spacing: Theme.smallPadding - visible: !(transactionHeader.isNFT && d.isIncoming) - - RowLayout { - width: parent.width - visible: amountSentTile.visible || amountReceiveTile.visible || feesTile.visible || totalTile.visible - StatusBaseText { - Layout.alignment: Qt.AlignLeft - font.pixelSize: 15 - color: Theme.palette.directColor5 - text: qsTr("Values") - elide: Text.ElideRight - } - - StatusBaseText { - Layout.alignment: Qt.AlignRight - font.pixelSize: 15 - color: Theme.palette.directColor5 - text: d.isTransactionValid ? qsTr("as of %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)) : "" - elide: Text.ElideRight - } - } - - DetailsPanel { - TransactionDataTile { - id: amountSentTile - width: parent.width - title: qsTr("Amount sent") - subTitle: transactionHeader.isMultiTransaction ? d.outCryptoValueFormatted : d.cryptoValueFormatted - tertiaryTitle: transactionHeader.isMultiTransaction ? d.outFiatValueFormatted : d.fiatValueFormatted - visible: { - if (transactionHeader.isNFT) - return false - switch(d.transactionType) { - case Constants.TransactionType.Send: - case Constants.TransactionType.Swap: - case Constants.TransactionType.Bridge: - return true - default: - return false - } - } - } - TransactionDataTile { - id: amountReceiveTile - width: parent.width - title: transactionHeader.transactionStatus === Constants.TransactionStatus.Pending ? qsTr("Amount to receive") : qsTr("Amount received") - subTitle: { - if (!d.isTransactionValid || transactionHeader.isNFT) - return "" - const type = d.transactionType - if (type === Constants.TransactionType.Swap) { - return root.currenciesStore.formatCurrencyAmount(transactionHeader.inCryptoValue, d.inSymbol) - } else if (type === Constants.TransactionType.Bridge) { - // Reduce crypto value by fee value - const valueInCrypto = root.currenciesStore.getCryptoValue(transactionHeader.outFiatValue - d.feeFiatValue, d.inSymbol) - return root.currenciesStore.formatCurrencyAmount(valueInCrypto, d.inSymbol) - } - return "" - } - tertiaryTitle: { - const type = d.transactionType - if (type === Constants.TransactionType.Swap) { - return root.currenciesStore.formatCurrencyAmount(transactionHeader.inFiatValue, root.currenciesStore.currentCurrency) - } else if (type === Constants.TransactionType.Bridge) { - return root.currenciesStore.formatCurrencyAmount(transactionHeader.outFiatValue - d.feeFiatValue, root.currenciesStore.currentCurrency) - } - return "" - } - visible: !!subTitle - } - TransactionDataTile { - id: feesTile - width: parent.width - title: d.symbol ? qsTr("Fees") : qsTr("Estimated max fee") - subTitle: { - if (!d.isTransactionValid || transactionHeader.isNFT || !d.isDetailsValid) - return "" - if (!d.symbol) { - const maxFeeEth = root.currenciesStore.getFeeEthValue(d.details.maxTotalFees) - return root.currenciesStore.formatCurrencyAmount(maxFeeEth, Constants.ethToken) - } - - switch(d.transactionType) { - case Constants.TransactionType.Send: - case Constants.TransactionType.Swap: - case Constants.TransactionType.Bridge: - return LocaleUtils.currencyAmountToLocaleString(d.details.totalFees) - default: - return "" - } - } - tertiaryTitle: { - if (!subTitle) - return "" - let fiatValue - if (!d.symbol) { - const maxFeeEth = root.currenciesStore.getFeeEthValue(d.details.maxTotalFees) - fiatValue = root.currenciesStore.getFiatValue(maxFeeEth, Constants.ethToken) - } else { - fiatValue = d.feeFiatValue - } - return root.currenciesStore.formatCurrencyAmount(fiatValue, root.currenciesStore.currentCurrency) - } - visible: !!subTitle - } - TransactionDataTile { - id: totalTile - width: parent.width - readonly property bool fieldIsHidden: (transactionHeader.isNFT && d.isIncoming) || !d.symbol - readonly property bool showMaxFee: d.transactionType === Constants.TransactionType.ContractDeployment && transactionHeader.transactionStatus === Constants.TransactionStatus.Pending - readonly property bool showFee: d.transactionType === Constants.TransactionType.Destroy || transactionHeader.isNFT || d.transactionType === Constants.TransactionType.ContractDeployment - readonly property bool showValue: d.transactionType === Constants.TransactionType.Receive || (d.transactionType === Constants.TransactionType.Buy && progressBlock.isLayer1) - // NOTE Using fees in this tile because of same higlight and color settings as Total - title: { - if (showMaxFee) { - return qsTr("Estimated max fee") - } else if (showFee) { - return qsTr("Fees") - } - return qsTr("Total") - } - subTitle: { - if (fieldIsHidden) - return "" - if (showMaxFee) { - const maxFeeEth = root.currenciesStore.getFeeEthValue(d.details.maxTotalFees) - return root.currenciesStore.formatCurrencyAmount(maxFeeEth, Constants.ethToken) - } else if (showFee) { - return root.currenciesStore.formatCurrencyAmount(d.feeEthValue, Constants.ethToken) - } else if (showValue) { - return d.cryptoValueFormatted - } - const cryptoValue = transactionHeader.isMultiTransaction ? d.outCryptoValueFormatted : d.cryptoValueFormatted - return "%1 + %2".arg(cryptoValue).arg(root.currenciesStore.formatCurrencyAmount(d.feeEthValue, Constants.ethToken)) - } - tertiaryTitle: { - if (fieldIsHidden) - return "" - if (showMaxFee) { - const maxFeeEth = root.currenciesStore.getFeeEthValue(d.details.maxTotalFees) - const maxFeeFiat = root.currenciesStore.getFiatValue(d.feeEthValue, Constants.ethToken) - return root.currenciesStore.formatCurrencyAmount(maxFeeFiat, root.currenciesStore.currentCurrency) - } else if (showFee) { - return root.currenciesStore.formatCurrencyAmount(d.feeFiatValue, root.currenciesStore.currentCurrency) - } else if (showValue) { - return d.fiatValueFormatted - } - const fiatValue = transactionHeader.isMultiTransaction ? transactionHeader.outFiatValue : transactionHeader.fiatValue - return root.currenciesStore.formatCurrencyAmount(fiatValue + d.feeFiatValue, root.currenciesStore.currentCurrency) - } - visible: !!subTitle - highlighted: true - statusListItemTertiaryTitle.customColor: Theme.palette.directColor1 - } - } - } - - Separator { - width: progressBlock.width - } - - RowLayout { - width: progressBlock.width - visible: d.isTransactionValid - spacing: 8 - StatusButton { - Layout.fillWidth: true - Layout.preferredHeight: copyDetailsButton.height - text: qsTr("Repeat transaction") - size: StatusButton.Small - - property alias tx: d.transaction - - visible: { - if (!d.isTransactionValid || root.overview.isWatchOnlyAccount || root.overview.isAllAccounts) - return false - - return WalletStores.RootStore.isTxRepeatable(tx) - } - onClicked: { - let asset = WalletStores.RootStore.getAssetForSendTx(tx) - const req = Helpers.lookupAddressesForSendModal(WalletStores.RootStore.accounts, - WalletStores.RootStore.savedAddresses, - tx.sender, - tx.recipient, - asset, - tx.isNFT, - tx.amount, - tx.chainId) - - root.sendModal.preSelectedAccountAddress = req.preSelectedAccount.address - root.sendModal.preSelectedRecipient = req.preSelectedRecipient - root.sendModal.preSelectedRecipientType = req.preSelectedRecipientType - root.sendModal.preSelectedHoldingID = req.preSelectedHoldingID - root.sendModal.preSelectedHoldingType = req.preSelectedHoldingType - root.sendModal.preSelectedSendType = req.preSelectedSendType - root.sendModal.preDefinedAmountToSend = req.preDefinedAmountToSend - root.sendModal.preSelectedChainId = req.preSelectedChainId - root.sendModal.onlyAssets = false - root.sendModal.open() - } - } - StatusButton { - id: copyDetailsButton - Layout.fillWidth: true - text: qsTr("Copy details") - icon.name: "copy" - icon.width: 20 - icon.height: 20 - size: StatusButton.Small - onClicked: ClipboardUtils.setText(transactionHeader.getDetailsString(d.details)) - } - } - } - } - - TransactionAddressMenu { - id: addressMenu - - areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled - contactsStore: root.contactsStore - networkConnectionStore: root.networkConnectionStore - onOpenSendModal: (address) => root.sendModal.open(address) - } - - component DetailsPanel: Item { - width: parent.width - height: { - // Using childrenRect and transactionvalid properties to refresh this binding - if (!d.isTransactionValid || detailsColumn.childrenRect.height === 0) - return 0 - - // Height is calculated from visible children because Column doesn't handle - // visibility change properly and childrenRect.height gives different values - // comparing to manual check - var visibleHeight = 0 - for (var i = 0 ; i < detailsColumn.children.length ; i++) { - if (detailsColumn.children[i].visible) - visibleHeight += detailsColumn.children[i].height - } - return visibleHeight - } - - default property alias content: detailsColumn.children - - Rectangle { - id: tileBackground - anchors.fill: parent - color: Theme.palette.transparent - radius: 8 - border.width: 1 - border.color: Theme.palette.separator - } - - Column { - id: detailsColumn - anchors.fill: parent - anchors.margins: 1 - spacing: 0 - layer.enabled: true - layer.effect: OpacityMask { - // Separate rectangle is used as mask because background rectangle must be transaprent - maskSource: Rectangle { - width: tileBackground.width - height: tileBackground.height - radius: tileBackground.radius - } - } - } - } - - component TransactionContractTile: TransactionDataTile { - property string networkName: "" - property string symbol: "" - property string address: "" - property string shortNetworkName: "" - width: parent.width - title: visible ? qsTr("%1 %2 contract address").arg(networkName).arg(symbol) : "" - subTitle: !!address && !/0x0+$/.test(address) ? address : "" - buttonIconName: "more" - visible: !!subTitle - onButtonClicked: addressMenu.openContractMenu(this, address, shortNetworkName, symbol) - } -} diff --git a/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml b/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml index a1611ef935..e49b7cd5a2 100644 --- a/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml +++ b/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml @@ -25,8 +25,6 @@ import "../../controls" Item { id: root - signal launchTransactionDetail(string txID) - required property SharedStores.RootStore rootStore required property RootStore walletRootStore required property CommunitiesStore communitiesStore @@ -309,8 +307,6 @@ Item { onClicked: { if (mouse.button === Qt.RightButton) { // TODO: Implement context menu - } else { - root.launchTransactionDetail(modelData.id) } } } diff --git a/ui/imports/shared/views/HistoryView.qml b/ui/imports/shared/views/HistoryView.qml index e4b7c04f20..f3503ee6f0 100644 --- a/ui/imports/shared/views/HistoryView.qml +++ b/ui/imports/shared/views/HistoryView.qml @@ -45,18 +45,12 @@ ColumnLayout { property real yPosition: transactionListRoot.visibleArea.yPosition * transactionListRoot.contentHeight - signal launchTransactionDetail(string txID) - function resetView() { if (!!filterPanelLoader.item) { filterPanelLoader.item.resetView() } } - onVisibleChanged: { - d.openTxDetailsHash = "" - } - Component.onCompleted: { if (root.walletRootStore.transactionActivityStatus.isFilterDirty) { root.walletRootStore.currentActivityFiltersStore.applyAllFilters() @@ -78,16 +72,6 @@ ColumnLayout { } } - Connections { - target: root.walletRootStore.currentActivityFiltersStore - enabled: root.visible - function onDisplayTxDetails(txHash) { - if (!d.openTxDetails(txHash)) { - d.openTxDetailsHash = txHash - } - } - } - QtObject { id: d readonly property bool isInitialLoading: root.walletRootStore.loadingHistoryTransactions && transactionListRoot.count === 0 @@ -97,18 +81,6 @@ ColumnLayout { property bool firstSectionHeaderLoaded: false readonly property int maxSecondsBetweenRefresh: 3 - - property string openTxDetailsHash - - function openTxDetails(txID) { - // Prevent opening details when loading, that will invalidate the model data - if (root.walletRootStore.loadingHistoryTransactions) { - return false - } - - root.launchTransactionDetail(txID) - return true - } } InformationTag { @@ -200,16 +172,6 @@ ColumnLayout { objectName: "walletAccountTransactionList" anchors.fill: parent - onCountChanged: { - if (!!d.openTxDetailsHash && root.visible) { - if (d.openTxDetails(d.openTxDetailsHash)) { - d.openTxDetailsHash = "" - } else { - root.walletRootStore.fetchMoreTransactions() - } - } - } - model: SortFilterProxyModel { id: txModel @@ -499,8 +461,6 @@ ColumnLayout { onClicked: { if (mouse.button === Qt.RightButton) { delegateMenu.openMenu(this, mouse, modelData) - } else { - launchTransactionDetail(modelData.id) } } }