feat(activity): remove activity details screen

This commit is contained in:
Dario Gabriel Lipicar 2024-11-07 00:58:55 -03:00 committed by dlipicar
parent 9eaf4cc4ea
commit a53eb6001f
7 changed files with 0 additions and 1259 deletions

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -20,8 +20,6 @@ QtObject {
recentsFilters.length !== 0 ||
savedAddressFilters.length !== 0
signal displayTxDetails(string txHash)
readonly property QtObject _d: QtObject {
id: d

View File

@ -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)
}
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}