feat(activity): remove activity details screen
This commit is contained in:
parent
9eaf4cc4ea
commit
a53eb6001f
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ QtObject {
|
|||
recentsFilters.length !== 0 ||
|
||||
savedAddressFilters.length !== 0
|
||||
|
||||
signal displayTxDetails(string txHash)
|
||||
|
||||
readonly property QtObject _d: QtObject {
|
||||
id: d
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue