2022-09-05 09:15:47 +00:00
import QtQuick 2.13
import QtQuick . Layouts 1.13
import QtQuick . Controls 2.14
import QtQuick . Window 2.12
2023-05-31 09:25:16 +00:00
import QtGraphicalEffects 1.15
2022-09-05 09:15:47 +00:00
import StatusQ . Components 0.1
import StatusQ . Core . Theme 0.1
import StatusQ . Core 0.1
import StatusQ . Controls 0.1
import StatusQ . Popups 0.1
import shared . controls 1.0
2023-05-31 09:25:16 +00:00
import shared . panels 1.0
2022-09-05 09:15:47 +00:00
import utils 1.0
2023-01-19 21:14:23 +00:00
import shared . stores 1.0
2022-09-05 09:15:47 +00:00
import "../controls"
2023-05-23 08:44:35 +00:00
import "../popups"
2023-02-20 10:57:45 +00:00
import "../stores" as WalletStores
import ".."
2023-05-16 08:25:40 +00:00
import "../panels"
2022-09-05 09:15:47 +00:00
Item {
id: root
2023-04-25 16:54:50 +00:00
property var overview: WalletStores . RootStore . overview
2022-09-05 09:15:47 +00:00
property var contactsStore
property var transaction
2023-08-29 18:57:38 +00:00
property int transactionIndex
2022-09-05 09:15:47 +00:00
property var sendModal
2023-07-26 11:50:27 +00:00
property bool showAllAccounts: false
2023-01-17 20:05:21 +00:00
readonly property bool isTransactionValid: transaction !== undefined && ! ! transaction
2022-09-05 09:15:47 +00:00
2023-08-29 18:57:38 +00:00
onTransactionChanged: d . updateTransactionDetails ( )
Component.onCompleted: d . updateTransactionDetails ( )
2023-06-07 14:16:23 +00:00
2022-09-05 09:15:47 +00:00
QtObject {
id: d
2023-08-30 12:10:59 +00:00
property var details: null
readonly property bool isDetailsValid: details !== undefined && ! ! details
2023-06-30 15:07:53 +00:00
readonly property bool isIncoming: transactionType === Constants . TransactionType . Received
2023-05-31 09:25:16 +00:00
readonly property string networkShortName: root . isTransactionValid ? RootStore . getNetworkShortName ( transaction . chainId ) : ""
2023-08-18 08:56:57 +00:00
readonly property string networkIcon: isTransactionValid ? RootStore . getNetworkIcon ( transaction . chainId ) : "network/Network=Custom"
2023-08-30 12:10:59 +00:00
readonly property int blockNumber: isDetailsValid ? details.blockNumber : 0
2023-06-30 15:07:53 +00:00
readonly property int toBlockNumber: 0 // TODO fill when bridge data is implemented
2023-08-18 08:56:57 +00:00
readonly property string networkShortNameOut: networkShortName
readonly property string networkShortNameIn: transactionHeader . isMultiTransaction ? RootStore . getNetworkShortName ( transaction . chainIdOut ) : ""
2023-06-30 15:07:53 +00:00
readonly property string symbol: isTransactionValid ? transaction.symbol : ""
readonly property string inSymbol: isTransactionValid ? transaction.inSymbol : ""
readonly property string outSymbol: isTransactionValid ? transaction.outSymbol : ""
2023-05-31 09:25:16 +00:00
readonly property var multichainNetworks: [ ] // TODO fill icon for networks for multichain
2023-07-18 14:05:22 +00:00
readonly property string fiatValueFormatted: {
if ( ! root . isTransactionValid || transactionHeader . isMultiTransaction || ! symbol )
return ""
return RootStore . formatCurrencyAmount ( transactionHeader . fiatValue , RootStore . currentCurrency )
}
readonly property string cryptoValueFormatted: {
if ( ! root . isTransactionValid || transactionHeader . isMultiTransaction )
return ""
const formatted = RootStore . formatCurrencyAmount ( transaction . amount , transaction . symbol )
2023-08-30 12:10:59 +00:00
return symbol || ( ! d . isDetailsValid || ! d . details . contract ) ? formatted : "%1 (%2)" . arg ( formatted ) . arg ( Utils . compactAddress ( transaction . tokenAddress , 4 ) )
2023-07-18 14:05:22 +00:00
}
readonly property string outFiatValueFormatted: {
if ( ! root . isTransactionValid || ! transactionHeader . isMultiTransaction || ! outSymbol )
return ""
return RootStore . formatCurrencyAmount ( transactionHeader . outFiatValue , RootStore . currentCurrency )
}
readonly property string outCryptoValueFormatted: {
if ( ! root . isTransactionValid || ! transactionHeader . isMultiTransaction )
return ""
const formatted = RootStore . formatCurrencyAmount ( transaction . outAmount , transaction . outSymbol )
2023-08-02 04:36:54 +00:00
return outSymbol || ! transaction . tokenOutAddress ? formatted : "%1 (%2)" . arg ( formatted ) . arg ( Utils . compactAddress ( transaction . tokenOutAddress , 4 ) )
2023-07-18 14:05:22 +00:00
}
2023-08-29 18:57:38 +00:00
readonly property real feeEthValue: d . details ? RootStore . getFeeEthValue ( d . details . totalFees ) : 0
2023-07-18 14:05:22 +00:00
readonly property real feeFiatValue: root . isTransactionValid ? RootStore . getFiatValue ( d . feeEthValue , Constants . ethToken , RootStore . currentCurrency ) : 0 // TODO use directly?
2023-06-15 13:09:35 +00:00
readonly property int transactionType: root . isTransactionValid ? transaction.txType : Constants . TransactionType . Send
2023-09-04 10:19:02 +00:00
readonly property bool isBridge: d . transactionType === Constants . TransactionType . Bridge
2022-09-05 09:15:47 +00:00
2023-06-07 14:16:23 +00:00
property string decodedInputData: ""
2023-07-10 13:36:29 +00:00
property bool loadingInputDate: false
2023-06-07 14:16:23 +00:00
2023-05-31 09:25:16 +00:00
function retryTransaction ( ) {
// TODO handle failed transaction retry
}
2023-08-29 18:57:38 +00:00
function updateTransactionDetails ( ) {
d . decodedInputData = ""
if ( ! transaction )
return
RootStore . fetchTxDetails ( transactionIndex )
d . details = RootStore . getTxDetails ( )
if ( ! ! d . details && ! ! d . details . input ) {
d . loadingInputDate = true
RootStore . fetchDecodedTxData ( d . details . txHash , d . details . input )
}
}
2023-05-31 09:25:16 +00:00
}
2022-09-05 09:15:47 +00:00
2023-06-07 14:16:23 +00:00
Connections {
2023-06-29 17:35:18 +00:00
target: RootStore . walletSectionInst
2023-06-07 14:16:23 +00:00
function onTxDecoded ( txHash: string , dataDecoded: string ) {
2023-08-30 12:10:59 +00:00
if ( ! root . isTransactionValid || ( d . isDetailsValid && txHash !== d . details . txHash ) )
2023-06-07 14:16:23 +00:00
return
2023-07-10 13:36:29 +00:00
if ( ! dataDecoded ) {
d . loadingInputDate = false
return
}
2023-06-07 14:16:23 +00:00
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 )
}
2023-07-10 13:36:29 +00:00
d . loadingInputDate = false
2023-06-07 14:16:23 +00:00
}
}
2022-09-05 09:15:47 +00:00
StatusScrollView {
2023-05-31 09:25:16 +00:00
id: scrollView
2023-05-31 20:58:23 +00:00
anchors.fill: parent
contentWidth: availableWidth
2022-09-05 09:15:47 +00:00
Column {
id: column
2023-05-31 20:58:23 +00:00
width: scrollView . availableWidth
2023-05-31 09:25:16 +00:00
spacing: Style . current . xlPadding + Style . current . halfPadding
2022-09-05 09:15:47 +00:00
2023-05-31 09:25:16 +00:00
Column {
2022-09-05 09:15:47 +00:00
width: parent . width
2023-05-31 09:25:16 +00:00
spacing: Style . current . bigPadding
TransactionDelegate {
id: transactionHeader
objectName: "transactionDetailHeader"
width: parent . width
leftPadding: 0
2023-06-30 15:07:53 +00:00
sensor.enabled: false
color: Theme . palette . transparent
state: "header"
2023-05-31 09:25:16 +00:00
2023-07-26 11:50:27 +00:00
showAllAccounts: root . showAllAccounts
2023-05-31 09:25:16 +00:00
modelData: transaction
timeStampText: root . isTransactionValid ? qsTr ( "Signed at %1" ) . arg ( LocaleUtils . formatDateTime ( transaction . timestamp * 1000 , Locale . LongFormat ) ) : ""
2023-06-13 08:18:53 +00:00
rootStore: RootStore
walletRootStore: WalletStores . RootStore
2023-06-30 15:07:53 +00:00
2023-05-31 09:25:16 +00:00
onRetryClicked: d . retryTransaction ( )
2023-05-10 11:54:06 +00:00
}
2023-05-31 09:25:16 +00:00
Separator { }
2022-09-05 09:15:47 +00:00
}
2023-05-16 08:25:40 +00:00
WalletTxProgressBlock {
2023-05-31 09:25:16 +00:00
id: progressBlock
2023-05-16 08:25:40 +00:00
width: Math . min ( 513 , root . width )
2023-09-11 08:08:53 +00:00
readonly property int latestBlockNumber: root . isTransactionValid && ! pending && ! error ? WalletStores . RootStore . getEstimatedLatestBlockNumber ( root . transaction . chainId ) : 0
readonly property int latestBlockNumberIn: root . isTransactionValid && ! pending && ! error && transactionHeader . isMultiTransaction && d . isBridge ? WalletStores . RootStore . getEstimatedLatestBlockNumber ( root . transaction . chainIdIn ) : 0
2023-06-12 13:04:39 +00:00
error: transactionHeader . transactionStatus === Constants . TransactionStatus . Failed
2023-08-02 04:36:54 +00:00
pending: transactionHeader . transactionStatus === Constants . TransactionStatus . Pending
2023-09-04 10:19:02 +00:00
outNetworkLayer: root . isTransactionValid ? Number ( RootStore . getNetworkLayer ( transactionHeader . isMultiTransaction ? root.transaction.chainIdOut : root . transaction . chainId ) ) : 0
inNetworkLayer: root . isTransactionValid && transactionHeader . isMultiTransaction && d . isBridge ? Number ( RootStore . getNetworkLayer ( root . transaction . chainIdIn ) ) : 0
outNetworkTimestamp: root . isTransactionValid ? root.transaction.timestamp : 0
inNetworkTimestamp: root . isTransactionValid ? root.transaction.timestamp : 0
outChainName: transactionHeader . isMultiTransaction ? transactionHeader.networkNameOut : transactionHeader . networkName
inChainName: transactionHeader . isMultiTransaction && d . isBridge ? transactionHeader.networkNameIn : ""
outNetworkConfirmations: root . isTransactionValid && latestBlockNumber > 0 ? latestBlockNumber - d.blockNumber : 0
2023-09-11 08:08:53 +00:00
inNetworkConfirmations: root . isTransactionValid && latestBlockNumberIn > 0 ? latestBlockNumberIn - d.blockNumber : 0
2023-05-16 08:25:40 +00:00
}
2023-05-31 09:25:16 +00:00
Separator {
width: progressBlock . width
}
2022-09-05 09:15:47 +00:00
2023-06-02 08:29:40 +00:00
WalletNftPreview {
2023-06-30 15:07:53 +00:00
visible: root . isTransactionValid && transactionHeader . isNFT && ! ! transaction . nftImageUrl
2023-06-02 08:29:40 +00:00
width: Math . min ( 304 , progressBlock . width )
nftName: root . isTransactionValid ? transaction.nftName : ""
nftUrl: root . isTransactionValid && ! ! transaction . nftImageUrl ? transaction.nftImageUrl : ""
2023-06-15 13:09:35 +00:00
strikethrough: d . transactionType === Constants . TransactionType . Destroy
2023-06-02 08:29:40 +00:00
tokenId: root . isTransactionValid ? transaction.tokenID : ""
2023-08-30 12:10:59 +00:00
contractAddress: d . isDetailsValid ? d.details.contract : ""
2023-06-02 08:29:40 +00:00
}
2023-05-31 09:25:16 +00:00
Column {
width: progressBlock . width
spacing: 0
StatusBaseText {
width: parent . width
font.pixelSize: 15
color: Theme . palette . directColor5
text: qsTr ( "Transaction summary" )
elide: Text . ElideRight
2022-09-05 09:15:47 +00:00
}
2023-05-31 09:25:16 +00:00
Item {
width: parent . width
height: Style . current . smallPadding
2022-09-05 09:15:47 +00:00
}
2023-05-31 09:25:16 +00:00
DetailsPanel {
RowLayout {
spacing: 0
width: parent . width
2023-06-30 15:07:53 +00:00
height: fromNetworkTile . visible || toNetworkTile . visible ? 85 : 0
2023-05-31 09:25:16 +00:00
TransactionDataTile {
id: fromNetworkTile
Layout.fillWidth: true
Layout.fillHeight: true
title: qsTr ( "From" )
subTitle: {
2023-08-18 08:56:57 +00:00
if ( ! root . isTransactionValid )
return ""
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Swap:
2023-08-02 04:36:54 +00:00
return ! ! d . outSymbol ? d.outSymbol : " "
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Bridge:
2023-08-18 08:56:57 +00:00
return transactionHeader . networkNameOut
2023-05-31 09:25:16 +00:00
default:
return ""
}
}
asset.name: {
2023-08-18 08:56:57 +00:00
if ( ! root . isTransactionValid )
return ""
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Swap:
2023-08-02 04:36:54 +00:00
return Constants . tokenIcon ( d . outSymbol )
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Bridge:
2023-08-18 08:56:57 +00:00
return Style . svg ( RootStore . getNetworkIcon ( root . transaction . chainIdOut ) ) ? ? Style . svg ( "network/Network=Custom" )
2023-05-31 09:25:16 +00:00
default:
return ""
}
}
visible: ! ! subTitle
}
TransactionDataTile {
id: toNetworkTile
Layout.fillWidth: true
Layout.fillHeight: true
title: qsTr ( "To" )
subTitle: {
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Swap:
2023-08-02 04:36:54 +00:00
return ! ! d . inSymbol ? d.inSymbol : " "
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Bridge:
2023-08-18 08:56:57 +00:00
return transactionHeader . networkNameIn ? ? " "
2023-05-31 09:25:16 +00:00
default:
return ""
}
}
asset.name: {
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Swap:
2023-08-02 04:36:54 +00:00
return Constants . tokenIcon ( d . inSymbol )
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Bridge:
2023-08-18 08:56:57 +00:00
return Style . svg ( RootStore . getNetworkIcon ( root . transaction . chainIdIn ) ) ? ? Style . svg ( "network/Network=Custom" )
2023-05-31 09:25:16 +00:00
default:
return ""
}
}
visible: ! ! subTitle
}
}
TransactionAddressTile {
width: parent . width
2023-06-15 13:09:35 +00:00
title: d . transactionType === Constants . TransactionType . Swap || d . transactionType === Constants . TransactionType . Bridge ?
2023-05-31 09:25:16 +00:00
qsTr ( "In" ) : qsTr ( "From" )
2023-06-15 13:09:35 +00:00
addresses: root . isTransactionValid ? [ root . transaction . sender ] : [ ]
2023-05-31 09:25:16 +00:00
contactsStore: root . contactsStore
rootStore: WalletStores . RootStore
onButtonClicked: {
2023-06-15 13:09:35 +00:00
if ( d . transactionType === Constants . TransactionType . Swap || d . transactionType === Constants . TransactionType . Bridge ) {
2023-08-18 08:56:57 +00:00
addressMenu . openEthAddressMenu ( this , addresses [ 0 ] , d . networkShortNameOut )
2023-05-31 09:25:16 +00:00
} else {
2023-06-12 08:39:59 +00:00
addressMenu . openSenderMenu ( this , addresses [ 0 ] , d . networkShortName )
2023-05-31 09:25:16 +00:00
}
}
}
2023-07-24 11:18:42 +00:00
TransactionDataTile {
id: contractDeploymentTile
2023-08-30 12:10:59 +00:00
readonly property bool hasValue: d . isDetailsValid && ! ! d . details . contract
2023-07-24 11:18:42 +00:00
&& 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..." )
}
2023-08-30 12:10:59 +00:00
return qsTr ( "Contract created" ) + "\n" + d . details . contract
2023-07-24 11:18:42 +00:00
}
buttonIconName: hasValue ? "more" : ""
statusListItemSubTitle.customColor: hasValue ? Theme.palette.directColor1 : Theme . palette . directColor5
2023-08-30 12:10:59 +00:00
onButtonClicked: addressMenu . openContractMenu ( this , d . details . contract , transactionHeader . networkName , d . symbol )
2023-07-24 11:18:42 +00:00
components: [
Loader {
anchors.verticalCenter: parent . verticalCenter
anchors.verticalCenterOffset: Style . current . halfPadding
active: transactionHeader . transactionStatus === Constants . TransactionStatus . Pending
width: active ? implicitWidth : 0
sourceComponent: StatusLoadingIndicator { }
}
]
}
2023-05-31 09:25:16 +00:00
TransactionAddressTile {
width: parent . width
title: qsTr ( "To" )
2023-06-30 15:07:53 +00:00
addresses: root . isTransactionValid && visible ? [ root . transaction . recipient ] : [ ]
2023-05-31 09:25:16 +00:00
contactsStore: root . contactsStore
rootStore: WalletStores . RootStore
2023-06-12 08:39:59 +00:00
onButtonClicked: addressMenu . openReceiverMenu ( this , addresses [ 0 ] , d . networkShortName )
2023-07-24 11:18:42 +00:00
visible: d . transactionType !== Constants . TransactionType . ContractDeployment && d . transactionType !== Constants . TransactionType . Swap && d . transactionType !== Constants . TransactionType . Bridge && d . transactionType !== Constants . TransactionType . Destroy
2023-05-31 09:25:16 +00:00
}
TransactionDataTile {
width: parent . width
title: qsTr ( "Using" )
2023-08-30 12:10:59 +00:00
subTitle: d . isDetailsValid ? d.details.protocol : ""
asset.name: d . isDetailsValid && d . details . protocol ? Style . svg ( "protocol/Protocol=%1" . arg ( d . details . protocol ) ) : Style . svg ( "network/Network=Custom" )
iconSettings.bgRadius: iconSettings . bgWidth / 2
// buttonIconName: "external" // TODO handle external link #11982
2023-05-31 09:25:16 +00:00
visible: ! ! subTitle
}
TransactionDataTile {
width: parent . width
2023-06-30 15:07:53 +00:00
title: qsTr ( "%1 Tx hash" ) . arg ( transactionHeader . networkName )
2023-08-30 12:10:59 +00:00
subTitle: d . isDetailsValid ? d.details.txHash : ""
2023-05-31 09:25:16 +00:00
visible: ! ! subTitle
buttonIconName: "more"
onButtonClicked: addressMenu . openTxMenu ( this , subTitle , d . networkShortName )
}
TransactionDataTile {
width: parent . width
2023-08-18 08:56:57 +00:00
title: qsTr ( "%1 Tx hash" ) . arg ( transactionHeader . networkNameIn )
2023-05-31 09:25:16 +00:00
subTitle: "" // TODO fill tx hash for Bridge
visible: ! ! subTitle
buttonIconName: "more"
2023-08-18 08:56:57 +00:00
onButtonClicked: addressMenu . openTxMenu ( this , subTitle , d . networkShortNameIn )
2023-05-31 09:25:16 +00:00
}
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
2023-06-30 15:07:53 +00:00
networkName: transactionHeader . networkName
2023-05-31 09:25:16 +00:00
shortNetworkName: d . networkShortName
2023-06-15 13:09:35 +00:00
visible: ! ! subTitle && ( d . transactionType === Constants . TransactionType . Bridge || d . transactionType === Constants . TransactionType . Swap )
2023-05-31 09:25:16 +00:00
}
TransactionContractTile {
// Used to display contract address for any network
2023-08-30 12:10:59 +00:00
address: d . isDetailsValid ? d.details.contract : ""
2023-07-18 14:05:22 +00:00
symbol: {
if ( ! root . isTransactionValid )
return ""
2023-08-02 04:36:54 +00:00
return d . symbol ? d.symbol : "(%1)" . arg ( Utils . compactAddress ( transaction . tokenAddress , 4 ) )
2023-07-18 14:05:22 +00:00
}
2023-06-30 15:07:53 +00:00
networkName: transactionHeader . networkName
2023-05-31 09:25:16 +00:00
shortNetworkName: d . networkShortName
2023-07-24 11:18:42 +00:00
visible: ! ! subTitle && d . transactionType !== Constants . TransactionType . ContractDeployment
2023-05-31 09:25:16 +00:00
}
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
2023-08-29 15:28:41 +00:00
networkName: transactionHeader . networkNameOut
2023-08-18 08:56:57 +00:00
shortNetworkName: d . networkShortNameOut
2023-06-15 13:09:35 +00:00
visible: ! ! subTitle && d . transactionType === Constants . TransactionType . Bridge
2023-05-31 09:25:16 +00:00
}
TransactionContractTile {
// Used for Bridge and Swap to display 'To' network token contract address
address: {
if ( ! root . isTransactionValid )
return ""
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Swap:
2023-06-13 08:18:53 +00:00
return "" // TODO fill swap contract address for Swap
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Bridge:
2023-05-31 09:25:16 +00:00
return "" // TODO fill swap token's contract address for 'to' network for Bridge
default:
return ""
}
}
symbol: {
if ( ! root . isTransactionValid )
return ""
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Swap:
2023-06-30 15:07:53 +00:00
return d . inSymbol
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Bridge:
2023-06-30 15:07:53 +00:00
return d . outSymbol
2023-05-31 09:25:16 +00:00
default:
return ""
}
}
2023-08-18 08:56:57 +00:00
networkName: transactionHeader . networkNameIn
shortNetworkName: d . networkShortNameIn
2023-06-13 08:18:53 +00:00
visible: root . isTransactionValid && ! ! subTitle
2023-05-31 09:25:16 +00:00
}
}
2022-09-05 09:15:47 +00:00
2023-05-31 09:25:16 +00:00
Item {
width: parent . width
height: Style . current . bigPadding
}
DetailsPanel {
width: progressBlock . width
RowLayout {
width: parent . width
2023-07-10 13:36:29 +00:00
height: networkNameTile . statusListItemSubTitle . lineCount > 1 ? 85 : 70
2023-05-31 09:25:16 +00:00
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: Style . svg ( "tiny/" + modelData )
z: index + 1
}
}
}
}
TransactionDataTile {
2023-07-10 13:36:29 +00:00
id: networkNameTile
2023-05-31 09:25:16 +00:00
Layout.fillHeight: true
Layout.fillWidth: true
title: qsTr ( "Network" )
2023-06-30 15:07:53 +00:00
subTitle: transactionHeader . networkName
2023-07-10 13:36:29 +00:00
asset.name: ! ! d . networkIcon ? Style . svg ( d . networkIcon ) : ""
subTitleBadgeLoaderAlignment: Qt . AlignTop
2023-05-31 09:25:16 +00:00
smallIcon: true
2023-08-02 04:36:54 +00:00
visible: ! ! subTitle && d . transactionType !== Constants . TransactionType . Bridge
2023-05-31 09:25:16 +00:00
}
TransactionDataTile {
Layout.fillHeight: true
Layout.fillWidth: true
title: qsTr ( "Token format" )
2023-08-29 18:57:38 +00:00
subTitle: root . isTransactionValid ? d . details . tokenType . toUpperCase ( ) : ""
2023-05-31 09:25:16 +00:00
visible: ! ! subTitle
}
TransactionDataTile {
Layout.fillHeight: true
Layout.fillWidth: true
title: qsTr ( "Nonce" )
2023-08-30 12:10:59 +00:00
subTitle: d . isDetailsValid ? d.details.nonce : ""
2023-05-31 09:25:16 +00:00
visible: ! ! subTitle
}
}
TransactionDataTile {
width: parent . width
2023-07-10 13:36:29 +00:00
height: d . loadingInputDate ? 112 : Math . min ( implicitHeight + bottomPadding , 112 )
2023-05-31 09:25:16 +00:00
title: qsTr ( "Input data" )
2023-07-10 13:36:29 +00:00
// Input string can be really long. Getting substring just for 3+ lines to speedup formatting.
2023-06-07 14:16:23 +00:00
subTitle: {
2023-07-10 13:36:29 +00:00
if ( d . loadingInputDate ) {
return ""
} else if ( ! ! d . decodedInputData ) {
2023-07-19 14:16:45 +00:00
return d . decodedInputData . substring ( 0 , 200 )
2023-08-30 12:10:59 +00:00
} else if ( d . isDetailsValid ) {
return String ( d . details . input ) . substring ( 0 , 200 )
2023-06-07 14:16:23 +00:00
}
return ""
}
2023-07-10 13:36:29 +00:00
visible: ! ! subTitle || d . loadingInputDate
buttonIconName: d . loadingInputDate ? "" : "more"
2023-06-07 14:16:23 +00:00
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" }
}
}
}
2023-07-10 13:36:29 +00:00
tertiaryTitle: ! d . loadingInputDate && ! d . decodedInputData ? qsTr ( "Data could not be decoded" ) : ""
2023-08-16 14:06:56 +00:00
statusListItemTertiaryTitle.anchors.top: undefined
2023-07-10 13:36:29 +00:00
statusListItemTertiaryTitle.anchors.baseline: statusListItemTitle . baseline
statusListItemTertiaryTitle.font: statusListItemTitle . font
2023-08-30 12:10:59 +00:00
onButtonClicked: addressMenu . openInputDataMenu ( this , ! ! d . decodedInputData ? d.decodedInputData : d . details . input )
2023-07-10 13:36:29 +00:00
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
}
}
}
}
2023-05-31 09:25:16 +00:00
}
TransactionDataTile {
width: parent . width
2023-06-30 15:07:53 +00:00
title: ! ! transactionHeader . networkName ? qsTr ( "Included in Block on %1" ) . arg ( transactionHeader . networkName ) : qsTr ( "Included on Block" )
2023-05-31 09:25:16 +00:00
subTitle: d . blockNumber
tertiaryTitle: root . isTransactionValid ? LocaleUtils . formatDateTime ( transaction . timestamp * 1000 , Locale . LongFormat ) : ""
visible: d . blockNumber > 0
}
TransactionDataTile {
width: parent . width
2023-06-30 15:07:53 +00:00
title: ! ! d . toNetworkName ? qsTr ( "Included in Block on %1" ) . arg ( d . toNetworkName ) : qsTr ( "Included on Block" )
subTitle: d . toBlockNumber
2023-05-31 09:25:16 +00:00
tertiaryTitle: root . isTransactionValid ? LocaleUtils . formatDateTime ( transaction . timestamp * 1000 , Locale . LongFormat ) : ""
2023-06-30 15:07:53 +00:00
visible: d . toBlockNumber > 0
2023-05-31 09:25:16 +00:00
}
}
2022-09-05 09:15:47 +00:00
}
2023-06-05 06:22:30 +00:00
Column {
width: progressBlock . width
spacing: Style . current . smallPadding
2023-06-30 15:07:53 +00:00
visible: ! ( transactionHeader . isNFT && d . isIncoming )
2022-09-05 09:15:47 +00:00
2023-06-05 06:22:30 +00:00
RowLayout {
width: parent . width
StatusBaseText {
Layout.alignment: Qt . AlignLeft
font.pixelSize: 15
color: Theme . palette . directColor5
text: qsTr ( "Values" )
elide: Text . ElideRight
}
2022-09-05 09:15:47 +00:00
2023-06-05 06:22:30 +00:00
StatusBaseText {
Layout.alignment: Qt . AlignRight
font.pixelSize: 15
color: Theme . palette . directColor5
text: root . isTransactionValid ? qsTr ( "as of %1" ) . arg ( LocaleUtils . formatDateTime ( transaction . timestamp * 1000 , Locale . LongFormat ) ) : ""
elide: Text . ElideRight
}
2022-09-05 09:15:47 +00:00
}
2023-06-05 06:22:30 +00:00
DetailsPanel {
TransactionDataTile {
width: parent . width
title: qsTr ( "Amount sent" )
2023-06-30 15:07:53 +00:00
subTitle: transactionHeader . isMultiTransaction ? d.outCryptoValueFormatted : d . cryptoValueFormatted
tertiaryTitle: transactionHeader . isMultiTransaction ? d.outFiatValueFormatted : d . fiatValueFormatted
2023-06-05 06:22:30 +00:00
visible: {
2023-06-30 15:07:53 +00:00
if ( transactionHeader . isNFT )
2023-06-05 06:22:30 +00:00
return false
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Send:
case Constants.TransactionType.Swap:
case Constants.TransactionType.Bridge:
2023-06-05 06:22:30 +00:00
return true
default:
return false
}
}
}
TransactionDataTile {
width: parent . width
2023-07-24 11:18:42 +00:00
title: transactionHeader . transactionStatus === Constants . TransactionStatus . Pending ? qsTr ( "Amount to receive" ) : qsTr ( "Amount received" )
2023-06-05 06:22:30 +00:00
subTitle: {
2023-06-30 15:07:53 +00:00
if ( ! root . isTransactionValid || transactionHeader . isNFT )
2023-06-05 06:22:30 +00:00
return ""
2023-06-15 13:09:35 +00:00
const type = d . transactionType
2023-06-12 13:04:39 +00:00
if ( type === Constants . TransactionType . Swap ) {
2023-06-30 15:07:53 +00:00
return RootStore . formatCurrencyAmount ( transactionHeader . inCryptoValue , d . inSymbol )
2023-06-12 13:04:39 +00:00
} else if ( type === Constants . TransactionType . Bridge ) {
2023-06-05 06:22:30 +00:00
// Reduce crypto value by fee value
2023-06-30 15:07:53 +00:00
const valueInCrypto = RootStore . getCryptoValue ( transactionHeader . fiatValue - d . feeFiatValue , d . inSymbol , RootStore . currentCurrency )
return RootStore . formatCurrencyAmount ( valueInCrypto , d . inSymbol )
2023-06-05 06:22:30 +00:00
}
return ""
}
tertiaryTitle: {
2023-06-15 13:09:35 +00:00
const type = d . transactionType
2023-06-12 13:04:39 +00:00
if ( type === Constants . TransactionType . Swap ) {
2023-06-30 15:07:53 +00:00
return RootStore . formatCurrencyAmount ( transactionHeader . inFiatValue , RootStore . currentCurrency )
2023-06-12 13:04:39 +00:00
} else if ( type === Constants . TransactionType . Bridge ) {
2023-06-30 15:07:53 +00:00
return RootStore . formatCurrencyAmount ( transactionHeader . fiatValue - d . feeFiatValue , RootStore . currentCurrency )
2023-06-05 06:22:30 +00:00
}
return ""
}
visible: ! ! subTitle
}
TransactionDataTile {
width: parent . width
2023-07-18 14:05:22 +00:00
title: d . symbol ? qsTr ( "Fees" ) : qsTr ( "Estimated max fee" )
2023-06-05 06:22:30 +00:00
subTitle: {
2023-09-11 10:08:21 +00:00
if ( ! root . isTransactionValid || transactionHeader . isNFT || ! d . isDetailsValid )
2023-06-05 06:22:30 +00:00
return ""
2023-07-18 14:05:22 +00:00
if ( ! d . symbol ) {
2023-08-30 12:10:59 +00:00
const maxFeeEth = RootStore . getFeeEthValue ( d . details . maxTotalFees )
2023-07-18 14:05:22 +00:00
return RootStore . formatCurrencyAmount ( maxFeeEth , Constants . ethToken )
}
2023-06-15 13:09:35 +00:00
switch ( d . transactionType ) {
2023-06-12 13:04:39 +00:00
case Constants.TransactionType.Send:
case Constants.TransactionType.Swap:
case Constants.TransactionType.Bridge:
2023-09-11 10:08:21 +00:00
return LocaleUtils . currencyAmountToLocaleString ( d . details . totalFees )
2023-06-05 06:22:30 +00:00
default:
return ""
}
}
2023-07-18 14:05:22 +00:00
tertiaryTitle: {
if ( ! subTitle )
return ""
let fiatValue
if ( ! d . symbol ) {
2023-08-30 12:10:59 +00:00
const maxFeeEth = RootStore . getFeeEthValue ( d . details . maxTotalFees )
2023-07-18 14:05:22 +00:00
fiatValue = RootStore . getFiatValue ( maxFeeEth , Constants . ethToken , RootStore . currentCurrency )
} else {
fiatValue = d . feeFiatValue
}
return RootStore . formatCurrencyAmount ( fiatValue , RootStore . currentCurrency )
}
2023-06-05 06:22:30 +00:00
visible: ! ! subTitle
}
TransactionDataTile {
width: parent . width
2023-07-24 11:18:42 +00:00
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" )
}
2023-06-05 06:22:30 +00:00
subTitle: {
2023-07-24 11:18:42 +00:00
if ( fieldIsHidden )
2023-06-05 06:22:30 +00:00
return ""
2023-07-24 11:18:42 +00:00
if ( showMaxFee ) {
2023-08-30 12:10:59 +00:00
const maxFeeEth = RootStore . getFeeEthValue ( d . details . maxTotalFees )
2023-07-24 11:18:42 +00:00
return RootStore . formatCurrencyAmount ( maxFeeEth , Constants . ethToken )
} else if ( showFee ) {
2023-07-18 14:05:22 +00:00
return RootStore . formatCurrencyAmount ( d . feeEthValue , Constants . ethToken )
2023-07-24 11:18:42 +00:00
} else if ( showValue ) {
2023-06-05 06:22:30 +00:00
return d . cryptoValueFormatted
}
2023-06-30 15:07:53 +00:00
const cryptoValue = transactionHeader . isMultiTransaction ? d.outCryptoValueFormatted : d . cryptoValueFormatted
2023-07-18 14:05:22 +00:00
return "%1 + %2" . arg ( cryptoValue ) . arg ( RootStore . formatCurrencyAmount ( d . feeEthValue , Constants . ethToken ) )
2023-06-05 06:22:30 +00:00
}
tertiaryTitle: {
2023-07-24 11:18:42 +00:00
if ( fieldIsHidden )
2023-06-05 06:22:30 +00:00
return ""
2023-07-24 11:18:42 +00:00
if ( showMaxFee ) {
2023-08-30 12:10:59 +00:00
const maxFeeEth = RootStore . getFeeEthValue ( d . details . maxTotalFees )
2023-07-24 11:18:42 +00:00
const maxFeeFiat = RootStore . getFiatValue ( d . feeEthValue , "ETH" , RootStore . currentCurrency )
return RootStore . formatCurrencyAmount ( maxFeeFiat , RootStore . currentCurrency )
} else if ( showFee ) {
2023-06-05 06:22:30 +00:00
return RootStore . formatCurrencyAmount ( d . feeFiatValue , RootStore . currentCurrency )
2023-07-24 11:18:42 +00:00
} else if ( showValue ) {
2023-06-05 06:22:30 +00:00
return d . fiatValueFormatted
}
2023-06-30 15:07:53 +00:00
const fiatValue = transactionHeader . isMultiTransaction ? transactionHeader.outFiatValue : transactionHeader . fiatValue
return RootStore . formatCurrencyAmount ( fiatValue + d . feeFiatValue , RootStore . currentCurrency )
2023-06-05 06:22:30 +00:00
}
visible: ! ! subTitle
highlighted: true
statusListItemTertiaryTitle.customColor: Theme . palette . directColor1
}
2022-09-05 09:15:47 +00:00
}
}
2023-06-13 08:18:53 +00:00
Separator {
width: progressBlock . width
}
RowLayout {
width: progressBlock . width
visible: root . isTransactionValid
spacing: 8
StatusButton {
Layout.fillWidth: true
Layout.preferredHeight: copyDetailsButton . height
text: qsTr ( "Repeat transaction" )
size: StatusButton . Small
2023-06-15 13:09:35 +00:00
visible: root . isTransactionValid && ! root . overview . isWatchOnlyAccount && d . transactionType === TransactionDelegate . Send
2023-06-13 08:18:53 +00:00
onClicked: {
root . sendModal . open ( root . transaction . to )
// TODO handle other types
}
}
StatusButton {
id: copyDetailsButton
Layout.fillWidth: true
text: qsTr ( "Copy details" )
icon.name: "copy"
icon.width: 20
icon.height: 20
size: StatusButton . Small
2023-08-30 12:10:59 +00:00
onClicked: RootStore . copyToClipboard ( transactionHeader . getDetailsString ( d . details ) )
2023-06-13 08:18:53 +00:00
}
}
2022-09-05 09:15:47 +00:00
}
}
2023-05-23 08:44:35 +00:00
TransactionAddressMenu {
id: addressMenu
2023-07-21 10:55:36 +00:00
areTestNetworksEnabled: WalletStores . RootStore . areTestNetworksEnabled
2023-05-23 08:44:35 +00:00
contactsStore: root . contactsStore
onOpenSendModal: ( address ) = > root . sendModal . open ( address )
}
2023-05-31 09:25:16 +00:00
component DetailsPanel: Item {
width: parent . width
2023-06-30 15:07:53 +00:00
height: {
// Using childrenRect and transactionvalid properties to refresh this binding
if ( ! 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
}
2023-05-31 09:25:16 +00:00
default property alias content: detailsColumn . children
2023-06-16 09:37:17 +00:00
2023-05-31 09:25:16 +00:00
Rectangle {
id: tileBackground
anchors.fill: parent
2023-06-16 09:37:17 +00:00
color: Style . current . transparent
2023-05-31 09:25:16 +00:00
radius: 8
border.width: 1
border.color: Style . current . separator
}
Column {
id: detailsColumn
anchors.fill: parent
anchors.margins: 1
spacing: 0
layer.enabled: true
layer.effect: OpacityMask {
2023-06-16 09:37:17 +00:00
// Separate rectangle is used as mask because background rectangle must be transaprent
maskSource: Rectangle {
width: tileBackground . width
height: tileBackground . height
radius: tileBackground . radius
}
2023-05-31 09:25:16 +00:00
}
}
}
component TransactionContractTile: TransactionDataTile {
property string networkName: ""
property string symbol: ""
property string address: ""
property string shortNetworkName: ""
width: parent . width
2023-06-30 15:07:53 +00:00
title: visible ? qsTr ( "%1 %2 contract address" ) . arg ( networkName ) . arg ( symbol ) : ""
2023-05-31 09:25:16 +00:00
subTitle: ! ! address && ! /0x0+$/ . test ( address ) ? address : ""
buttonIconName: "more"
visible: ! ! subTitle
onButtonClicked: addressMenu . openContractMenu ( this , address , shortNetworkName , symbol )
}
2022-09-05 09:15:47 +00:00
}