feat(@desktop/wallet): implement jump to activity details screen from collectible details activity tab

Fixes #13721
This commit is contained in:
Dario Gabriel Lipicar 2024-02-29 11:53:08 -03:00 committed by dlipicar
parent f3bf194187
commit 96d9acf1f0
12 changed files with 264 additions and 128 deletions

View File

@ -3,7 +3,6 @@ import tables, stint, sets
import model
import entry
import entry_details
import recipients_model
import collectibles_model
import collectibles_item
@ -11,6 +10,8 @@ import events_handler
import status
import utils
import details_controller as details_controller
import web3/conversions
import app/core/eventemitter
@ -48,7 +49,8 @@ QtObject:
currencyService: currency_service.Service
tokenService: token_service.Service
savedAddressService: saved_address_service.Service
activityDetails: ActivityDetails
detailsController: details_controller.Controller
eventsHandler: EventsHandler
status: Status
@ -114,30 +116,17 @@ QtObject:
ae = entry.newTransactionActivityEntry(backendEntry, self.addresses, extraData, amountToCurrencyConvertor)
result.add(ae)
proc fetchTxDetails*(self: Controller, entryIndex: int) {.slot.} =
let amountToCurrencyConvertor = proc(amount: UInt256, symbol: string): CurrencyAmount =
return currencyAmountToItem(self.currencyService.parseCurrencyValue(symbol, amount),
self.currencyService.getCurrencyFormat(symbol))
self.activityDetails = nil
let entry = self.model.getEntry(entryIndex)
proc fetchTxDetails*(self: Controller, txID: string) {.slot.} =
let index = self.model.getIndex(txID)
if index == -1:
error "entry index not found"
return
let entry = self.model.getEntry(index)
if entry == nil:
error "failed to find entry with index: ", entryIndex
error "entry not found"
return
try:
self.activityDetails = newActivityDetails(entry.getMetadata(), amountToCurrencyConvertor)
except Exception as e:
error "error: ", e.msg
return
proc getActivityDetails(self: Controller): QVariant {.slot.} =
if self.activityDetails == nil:
return newQVariant()
return newQVariant(self.activityDetails)
QtProperty[QVariant] activityDetails:
read = getActivityDetails
self.detailsController.setActivityEntry(entry)
proc processResponse(self: Controller, response: JsonNode) =
defer: self.status.setLoadingData(false)
@ -307,6 +296,7 @@ QtObject:
)
proc newController*(requestId: int32,
detailsController: details_controller.Controller,
currencyService: currency_service.Service,
tokenService: token_service.Service,
savedAddressService: saved_address_service.Service,
@ -325,6 +315,7 @@ QtObject:
result.status = newStatus()
result.currencyService = currencyService
result.detailsController = detailsController
result.filterTokenCodes = initHashSet[string]()

View File

@ -0,0 +1,75 @@
import NimQml, logging, stint
import entry
import entry_details
import app_service/service/currency/service as currency_service
import app/modules/shared/wallet_utils
import app/modules/shared_models/currency_amount
QtObject:
type
Controller* = ref object of QObject
activityEntry: ActivityEntry
activityDetails: ActivityDetails
currencyService: currency_service.Service
proc setup(self: Controller) =
self.QObject.setup
proc delete*(self: Controller) =
self.QObject.delete
proc newController*(currencyService: currency_service.Service): Controller =
new(result, delete)
result.currencyService = currencyService
result.setup()
proc activityEntryChanged*(self: Controller) {.signal.}
proc getActivityEntry(self: Controller): QVariant {.slot.} =
if self.activityEntry == nil:
return newQVariant()
return newQVariant(self.activityEntry)
QtProperty[QVariant] activityEntry:
read = getActivityEntry
notify = activityEntryChanged
proc activityDetailsChanged*(self: Controller) {.signal.}
proc getActivityDetails(self: Controller): QVariant {.slot.} =
if self.activityDetails == nil:
return newQVariant()
return newQVariant(self.activityDetails)
QtProperty[QVariant] activityDetails:
read = getActivityDetails
notify = activityDetailsChanged
proc setActivityEntry*(self: Controller, entry: ActivityEntry) =
self.activityEntry = entry
self.activityEntryChanged()
if self.activityDetails != nil:
self.activityDetails = nil
self.activityDetailsChanged()
proc resetActivityEntry*(self: Controller) {.slot.} =
self.setActivityEntry(nil)
proc fetchExtraTxDetails*(self: Controller) {.slot.} =
let amountToCurrencyConvertor = proc(amount: UInt256, symbol: string): CurrencyAmount =
return currencyAmountToItem(self.currencyService.parseCurrencyValue(symbol, amount),
self.currencyService.getCurrencyFormat(symbol))
if self.activityEntry == nil:
error "activity entry is not set"
return
try:
self.activityDetails = newActivityDetails(self.activityEntry.getMetadata(), amountToCurrencyConvertor)
self.activityDetailsChanged()
except Exception as e:
error "error: ", e.msg
return

View File

@ -15,6 +15,7 @@ import ./overview/module as overview_module
import ./send/module as send_module
import ./activity/controller as activityc
import ./activity/details_controller as activity_detailsc
import ./wallet_connect/controller as wcc
import app/modules/shared_models/collectibles_model as collectiblesm
@ -90,6 +91,7 @@ type
# We need one for each app "layer" that simultaneously needs to show a different list of activity
# entries (e.g. send popup is one "layer" above the collectible details activity tab)
tmpActivityControllers: ActivityControllerArray
activityDetailsController: activity_detailsc.Controller
wcController: wcc.Controller
@ -141,20 +143,36 @@ proc newModule*(
result.networksService = networkService
result.transactionService = transactionService
result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService,
savedAddressService, events)
result.activityDetailsController = activity_detailsc.newController(currencyService)
result.activityController = activityc.newController(
int32(ActivityID.History),
result.activityDetailsController,
currencyService,
tokenService,
savedAddressService,
events)
result.tmpActivityControllers = [
activityc.newController(int32(ActivityID.Temporary0), currencyService, tokenService,
savedAddressService, events),
activityc.newController(int32(ActivityID.Temporary1), currencyService, tokenService,
savedAddressService, events)
activityc.newController(
int32(ActivityID.Temporary0),
result.activityDetailsController,
currencyService,
tokenService,
savedAddressService,
events),
activityc.newController(
int32(ActivityID.Temporary1),
result.activityDetailsController,
currencyService,
tokenService,
savedAddressService,
events)
]
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
result.filter = initFilter(result.controller)
result.wcController = wcc.newController(events, walletAccountService)
result.view = newView(result, result.activityController, result.tmpActivityControllers, result.collectibleDetailsController, result.wcController)
result.view = newView(result, result.activityController, result.tmpActivityControllers, result.activityDetailsController, result.collectibleDetailsController, result.wcController)
method delete*(self: Module) =
self.accountsModule.delete
@ -169,6 +187,7 @@ method delete*(self: Module) =
self.activityController.delete
for i in 0..self.tmpActivityControllers.len-1:
self.tmpActivityControllers[i].delete
self.activityDetailsController.delete
self.collectibleDetailsController.delete
self.wcController.delete

View File

@ -1,6 +1,7 @@
import NimQml, json
import ./activity/controller as activityc
import ./activity/details_controller as activity_detailsc
import app/modules/shared_modules/collectible_details/controller as collectible_detailsc
import ./io_interface
import ../../shared_models/currency_amount
@ -20,6 +21,7 @@ QtObject:
tmpSymbol: string # shouldn't be used anywhere except in prepare*/getPrepared* procs
activityController: activityc.Controller
tmpActivityControllers: ActivityControllerArray
activityDetailsController: activity_detailsc.Controller
collectibleDetailsController: collectible_detailsc.Controller
isNonArchivalNode: bool
keypairOperabilityForObservedAccount: string
@ -34,11 +36,17 @@ QtObject:
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface, activityController: activityc.Controller, tmpActivityControllers: ActivityControllerArray, collectibleDetailsController: collectible_detailsc.Controller, wcController: wcc.Controller): View =
proc newView*(delegate: io_interface.AccessInterface,
activityController: activityc.Controller,
tmpActivityControllers: ActivityControllerArray,
activityDetailsController: activity_detailsc.Controller,
collectibleDetailsController: collectible_detailsc.Controller,
wcController: wcc.Controller): View =
new(result, delete)
result.delegate = delegate
result.activityController = activityController
result.tmpActivityControllers = tmpActivityControllers
result.activityDetailsController = activityDetailsController
result.collectibleDetailsController = collectibleDetailsController
result.wcController = wcController
@ -164,6 +172,11 @@ QtObject:
QtProperty[QVariant] tmpActivityController1:
read = getTmpActivityController1
proc getActivityDetailsController(self: View): QVariant {.slot.} =
return newQVariant(self.activityDetailsController)
QtProperty[QVariant] activityDetailsController:
read = getActivityDetailsController
proc getLatestBlockNumber*(self: View, chainId: int): string {.slot.} =
return self.delegate.getLatestBlockNumber(chainId)

View File

@ -137,21 +137,16 @@ SplitView {
id: transactionData
property int chainId: 1
property string blockNumber: "0x124"
property int timestamp: Date.now() / 1000
property int txStatus: 0
property string type: "eth"
property string nonce: "0x123"
property string from: "0x29D7d1dd5B6f9C864d9db560D72a247c178aE86B"
property string to: "0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35"
property string contract: "0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35"
property bool isNFT: false
property string input: "0x40e8d703000000000000000000000000670dca62b3418bddd08cbc69cb4490a5a3382a9f0000000000000000000000000000000000000000000000000000000000000064ddd08cbc69cb4490a5a3382a9f0000000000"
property string tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337"
property string nftName: "Happy Meow"
property string nftImageUrl: Style.png("collectibles/HappyMeow")
property string symbol: "ETH"
property string txHash: "0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35"
readonly property var value: QtObject {
property real amount: amountSpinbox.realValue
@ -159,6 +154,17 @@ SplitView {
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)
@ -167,10 +173,6 @@ SplitView {
property bool stripTrailingZeroes: true
}
readonly property var gasPrice: QtObject {
property real amount: 0.0000005
property string symbol: "ETH"
}
}
QtObject {
@ -179,6 +181,25 @@ SplitView {
property var mixedcaseAddress: root.isIncoming ? transactionData.to : transactionData.from
}
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
@ -203,7 +224,7 @@ SplitView {
active: root.globalUtilsReady && root.mainModuleReady && root.rootStoreReady
sourceComponent: TransactionDetailView {
contactsStore: contactsStoreMockup
transaction: transactionData
controller: controllerMockup
overview: overviewMockup
}
}

View File

@ -52,6 +52,7 @@ QtObject {
property var activityController: walletSectionInst.activityController
property var tmpActivityController0: walletSectionInst.tmpActivityController0
property var tmpActivityController1: walletSectionInst.tmpActivityController1
property var activityDetailsController: walletSectionInst.activityDetailsController
property string signingPhrase: walletSectionInst.signingPhrase
property string mnemonicBackedUp: walletSectionInst.isMnemonicBackedUp
property var walletConnectController: walletSectionInst.walletConnectController

View File

@ -208,9 +208,8 @@ RightTabBaseView {
showAllAccounts: RootStore.showAllAccounts
sendModal: root.sendModal
filterVisible: filterButton.checked
onLaunchTransactionDetail: function (entryIndex) {
transactionDetailView.transactionIndex = entryIndex
transactionDetailView.transaction = Qt.binding(() => selectedTransaction)
onLaunchTransactionDetail: function (txID) {
RootStore.activityController.fetchTxDetails(txID)
stack.currentIndex = 3
}
}
@ -218,6 +217,10 @@ RightTabBaseView {
}
}
CollectibleDetailView {
id: collectibleDetailView
visible : (stack.currentIndex === 1)
collectible: RootStore.collectiblesStore.detailedCollectible
isCollectibleLoading: RootStore.collectiblesStore.isDetailedCollectibleLoading
activityModel: d.detailedCollectibleActivityController.model
@ -230,6 +233,14 @@ RightTabBaseView {
RootStore.resetCurrentViewedHolding(Constants.TokenType.ERC721)
}
}
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
@ -252,6 +263,7 @@ RightTabBaseView {
TransactionDetailView {
id: transactionDetailView
controller: RootStore.activityDetailsController
onVisibleChanged: {
if (visible) {
if (!!transaction) {
@ -261,7 +273,7 @@ RightTabBaseView {
}
}
} else {
transaction = null
controller.resetActivityEntry()
}
}
showAllAccounts: RootStore.showAllAccounts

View File

@ -29,10 +29,18 @@ Item {
property var contactsStore
property var communitiesStore
property var networkConnectionStore
property var transaction
property int transactionIndex
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: {
@ -44,18 +52,21 @@ Item {
d.updateTransactionDetails()
}
Component.onCompleted: d.updateTransactionDetails()
QtObject {
id: d
property bool reEvaluateSender: true
property bool reEvaluateRecipient: true
property var details: null
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
RootStore.fetchDecodedTxData(d.details.txHashOut, d.details.input)
}
}
readonly property bool isIncoming: transactionType === Constants.TransactionType.Received || transactionType === Constants.TransactionType.ContractDeployment
readonly property string networkShortName: root.isTransactionValid ? RootStore.getNetworkShortName(transaction.chainId) : ""
readonly property string networkShortName: d.isTransactionValid ? RootStore.getNetworkShortName(transaction.chainId) : ""
readonly property string networkIcon: isTransactionValid ? RootStore.getNetworkIcon(transaction.chainId) : "network/Network=Custom"
readonly property int blockNumber: isDetailsValid ? details.blockNumber : 0
readonly property int blockNumberIn: isDetailsValid ? details.blockNumberIn : 0
@ -67,30 +78,30 @@ Item {
readonly property string outSymbol: isTransactionValid ? transaction.outSymbol : ""
readonly property var multichainNetworks: [] // TODO fill icon for networks for multichain
readonly property string fiatValueFormatted: {
if (!root.isTransactionValid || transactionHeader.isMultiTransaction || !symbol)
if (!d.isTransactionValid || transactionHeader.isMultiTransaction || !symbol)
return ""
return RootStore.formatCurrencyAmount(transactionHeader.fiatValue, RootStore.currentCurrency)
}
readonly property string cryptoValueFormatted: {
if (!root.isTransactionValid || transactionHeader.isMultiTransaction)
if (!d.isTransactionValid || transactionHeader.isMultiTransaction)
return ""
const formatted = RootStore.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 (!root.isTransactionValid || !transactionHeader.isMultiTransaction || !outSymbol)
if (!d.isTransactionValid || !transactionHeader.isMultiTransaction || !outSymbol)
return ""
return RootStore.formatCurrencyAmount(transactionHeader.outFiatValue, RootStore.currentCurrency)
}
readonly property string outCryptoValueFormatted: {
if (!root.isTransactionValid || !transactionHeader.isMultiTransaction)
if (!d.isTransactionValid || !transactionHeader.isMultiTransaction)
return ""
const formatted = RootStore.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 ? RootStore.getFeeEthValue(d.details.totalFees) : 0
readonly property real feeFiatValue: root.isTransactionValid ? RootStore.getFiatValue(d.feeEthValue, Constants.ethToken) : 0
readonly property int transactionType: root.isTransactionValid ? transaction.txType : Constants.TransactionType.Send
readonly property real feeFiatValue: d.isTransactionValid ? RootStore.getFiatValue(d.feeEthValue, Constants.ethToken) : 0
readonly property int transactionType: d.isTransactionValid ? transaction.txType : Constants.TransactionType.Send
readonly property bool isBridge: d.transactionType === Constants.TransactionType.Bridge
property string decodedInputData: ""
@ -102,23 +113,17 @@ Item {
function updateTransactionDetails() {
d.decodedInputData = ""
if (!transaction)
if (!d.transaction)
return
RootStore.fetchTxDetails(transactionIndex)
d.details = RootStore.getTxDetails()
if (!!d.details && !!d.details.input) {
d.loadingInputDate = true
RootStore.fetchDecodedTxData(d.details.txHashOut, d.details.input)
}
root.controller.fetchExtraTxDetails()
}
}
Connections {
target: RootStore.walletSectionInst
function onTxDecoded(txHash: string, dataDecoded: string) {
if (!root.isTransactionValid || (d.isDetailsValid && txHash !== d.details.txHashOut))
if (!d.isTransactionValid || (d.isDetailsValid && txHash !== d.details.txHashOut))
return
if (!dataDecoded) {
d.loadingInputDate = false
@ -165,7 +170,7 @@ Item {
showAllAccounts: root.showAllAccounts
modelData: transaction
timeStampText: root.isTransactionValid ? qsTr("Signed at %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)): ""
timeStampText: d.isTransactionValid ? qsTr("Signed at %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)): ""
rootStore: RootStore
walletRootStore: WalletStores.RootStore
community: isModelDataValid && communityId && communitiesStore ? communitiesStore.getCommunityDetailsAsJson(communityId) : null
@ -179,18 +184,18 @@ Item {
WalletTxProgressBlock {
id: progressBlock
width: Math.min(513, root.width)
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
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: 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
outNetworkLayer: d.isTransactionValid ? Number(RootStore.getNetworkLayer(transactionHeader.isMultiTransaction ? d.transaction.chainIdOut : d.transaction.chainId)) : 0
inNetworkLayer: d.isTransactionValid && transactionHeader.isMultiTransaction && d.isBridge ? Number(RootStore.getNetworkLayer(d.transaction.chainIdIn)) : 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: root.isTransactionValid && latestBlockNumber > 0 ? latestBlockNumber - d.blockNumberOut : 0
inNetworkConfirmations: root.isTransactionValid && latestBlockNumberIn > 0 ? latestBlockNumberIn - d.blockNumberIn : 0
outNetworkConfirmations: d.isTransactionValid && latestBlockNumber > 0 ? latestBlockNumber - d.blockNumberOut : 0
inNetworkConfirmations: d.isTransactionValid && latestBlockNumberIn > 0 ? latestBlockNumberIn - d.blockNumberIn : 0
}
Separator {
@ -198,13 +203,13 @@ Item {
}
WalletNftPreview {
visible: root.isTransactionValid && transactionHeader.isNFT && !!transaction.nftImageUrl
visible: d.isTransactionValid && transactionHeader.isNFT && !!transaction.nftImageUrl
width: Math.min(304, progressBlock.width)
nftName: root.isTransactionValid ? transaction.nftName : ""
nftUrl: root.isTransactionValid && !!transaction.nftImageUrl ? transaction.nftImageUrl : ""
nftName: d.isTransactionValid ? transaction.nftName : ""
nftUrl: d.isTransactionValid && !!transaction.nftImageUrl ? transaction.nftImageUrl : ""
strikethrough: d.transactionType === Constants.TransactionType.Destroy
tokenId: root.isTransactionValid ? transaction.tokenID : ""
tokenAddress: root.isTransactionValid ? transaction.tokenAddress : ""
tokenId: d.isTransactionValid ? transaction.tokenID : ""
tokenAddress: d.isTransactionValid ? transaction.tokenAddress : ""
areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled
isGoerliEnabled: WalletStores.RootStore.isGoerliEnabled
}
@ -237,7 +242,7 @@ Item {
Layout.fillHeight: true
title: qsTr("From")
subTitle: {
if (!root.isTransactionValid)
if (!d.isTransactionValid)
return ""
switch(d.transactionType) {
case Constants.TransactionType.Swap:
@ -249,13 +254,13 @@ Item {
}
}
asset.name: {
if (!root.isTransactionValid)
if (!d.isTransactionValid)
return ""
switch(d.transactionType) {
case Constants.TransactionType.Swap:
return Constants.tokenIcon(d.outSymbol)
case Constants.TransactionType.Bridge:
return Style.svg(RootStore.getNetworkIcon(root.transaction.chainIdOut)) ?? Style.svg("network/Network=Custom")
return Style.svg(RootStore.getNetworkIcon(d.transaction.chainIdOut)) ?? Style.svg("network/Network=Custom")
default:
return ""
}
@ -282,7 +287,7 @@ Item {
case Constants.TransactionType.Swap:
return Constants.tokenIcon(d.inSymbol)
case Constants.TransactionType.Bridge:
return Style.svg(RootStore.getNetworkIcon(root.transaction.chainIdIn)) ?? Style.svg("network/Network=Custom")
return Style.svg(RootStore.getNetworkIcon(d.transaction.chainIdIn)) ?? Style.svg("network/Network=Custom")
default:
return ""
}
@ -294,7 +299,7 @@ Item {
width: parent.width
title: d.transactionType === Constants.TransactionType.Swap || d.transactionType === Constants.TransactionType.Bridge ?
qsTr("In") : qsTr("From")
addresses: root.isTransactionValid && d.reEvaluateSender? [root.transaction.sender] : []
addresses: d.isTransactionValid && d.reEvaluateSender? [d.transaction.sender] : []
contactsStore: root.contactsStore
rootStore: WalletStores.RootStore
onButtonClicked: {
@ -337,7 +342,7 @@ Item {
TransactionAddressTile {
width: parent.width
title: qsTr("To")
addresses: root.isTransactionValid && visible && d.reEvaluateRecipient? [root.transaction.recipient] : []
addresses: d.isTransactionValid && visible && d.reEvaluateRecipient? [d.transaction.recipient] : []
contactsStore: root.contactsStore
rootStore: WalletStores.RootStore
onButtonClicked: addressMenu.openReceiverMenu(this, addresses[0], [d.networkShortName])
@ -388,7 +393,7 @@ Item {
// Used to display contract address for any network
address: d.isDetailsValid ? d.details.contractIn : ""
symbol: {
if (!root.isTransactionValid)
if (!d.isTransactionValid)
return ""
return d.symbol ? d.symbol : "(%1)".arg(Utils.compactAddress(transaction.tokenAddress, 4))
}
@ -407,7 +412,7 @@ Item {
TransactionContractTile {
// Used for Bridge and Swap to display 'To' network token contract address
address: {
if (!root.isTransactionValid)
if (!d.isTransactionValid)
return ""
switch(d.transactionType) {
case Constants.TransactionType.Swap:
@ -418,7 +423,7 @@ Item {
}
}
symbol: {
if (!root.isTransactionValid)
if (!d.isTransactionValid)
return ""
switch(d.transactionType) {
case Constants.TransactionType.Swap:
@ -431,7 +436,7 @@ Item {
}
networkName: transactionHeader.networkNameIn
shortNetworkName: d.networkShortNameIn
visible: root.isTransactionValid && !!subTitle
visible: d.isTransactionValid && !!subTitle
}
}
@ -567,7 +572,7 @@ Item {
width: parent.width
title: !!transactionHeader.networkNameOut ? qsTr("Included in Block on %1").arg(transactionHeader.networkNameOut) : qsTr("Included on Block")
subTitle: d.blockNumberOut
tertiaryTitle: root.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : ""
tertiaryTitle: d.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : ""
visible: d.blockNumberOut > 0 && transactionHeader.isMultiTransaction
}
TransactionDataTile {
@ -577,7 +582,7 @@ Item {
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: root.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : ""
tertiaryTitle: d.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : ""
visible: blockNumber > 0
}
}
@ -603,7 +608,7 @@ Item {
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)) : ""
text: d.isTransactionValid ? qsTr("as of %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)) : ""
elide: Text.ElideRight
}
}
@ -633,7 +638,7 @@ Item {
width: parent.width
title: transactionHeader.transactionStatus === Constants.TransactionStatus.Pending ? qsTr("Amount to receive") : qsTr("Amount received")
subTitle: {
if (!root.isTransactionValid || transactionHeader.isNFT)
if (!d.isTransactionValid || transactionHeader.isNFT)
return ""
const type = d.transactionType
if (type === Constants.TransactionType.Swap) {
@ -661,7 +666,7 @@ Item {
width: parent.width
title: d.symbol ? qsTr("Fees") : qsTr("Estimated max fee")
subTitle: {
if (!root.isTransactionValid || transactionHeader.isNFT || !d.isDetailsValid)
if (!d.isTransactionValid || transactionHeader.isNFT || !d.isDetailsValid)
return ""
if (!d.symbol) {
const maxFeeEth = RootStore.getFeeEthValue(d.details.maxTotalFees)
@ -749,7 +754,7 @@ Item {
RowLayout {
width: progressBlock.width
visible: root.isTransactionValid
visible: d.isTransactionValid
spacing: 8
StatusButton {
Layout.fillWidth: true
@ -757,10 +762,10 @@ Item {
text: qsTr("Repeat transaction")
size: StatusButton.Small
property alias tx: root.transaction
property alias tx: d.transaction
visible: {
if (!root.isTransactionValid || root.overview.isWatchOnlyAccount)
if (!d.isTransactionValid || root.overview.isWatchOnlyAccount)
return false
return WalletStores.RootStore.isTxRepeatable(tx)
@ -809,7 +814,7 @@ Item {
width: parent.width
height: {
// Using childrenRect and transactionvalid properties to refresh this binding
if (!isTransactionValid || detailsColumn.childrenRect.height === 0)
if (!d.isTransactionValid || detailsColumn.childrenRect.height === 0)
return 0
// Height is calculated from visible children because Column doesn't handle

View File

@ -19,6 +19,8 @@ import "../../controls"
Item {
id: root
signal launchTransactionDetail(string txID)
required property var rootStore
required property var walletRootStore
required property var communitiesStore
@ -212,7 +214,11 @@ Item {
community: isModelDataValid && !!communityId && !!root.communitiesStore ? root.communitiesStore.getCommunityDetailsAsJson(communityId) : null
loading: false
onClicked: {
// TODO: Implement switch to transaction details screen
if (mouse.button === Qt.RightButton) {
// TODO: Implement context menu
} else {
root.launchTransactionDetail(modelData.id)
}
}
}
}

View File

@ -50,6 +50,7 @@ StatusListItem {
readonly property bool isModelDataValid: modelData !== undefined && !!modelData
readonly property string txID: isModelDataValid ? modelData.id : "INVALID"
readonly property int transactionStatus: isModelDataValid ? modelData.status : Constants.TransactionStatus.Pending
readonly property bool isMultiTransaction: isModelDataValid && modelData.isMultiTransaction
readonly property string currentCurrency: rootStore.currentCurrency
@ -176,11 +177,6 @@ StatusListItem {
}
function getDetailsString(detailsObj) {
if (!detailsObj) {
rootStore.fetchTxDetails(index)
detailsObj = rootStore.getTxDetails()
}
let details = ""
const endl = "\n"
const endl2 = endl + endl

View File

@ -208,12 +208,13 @@ QtObject {
walletSectionInst.fetchDecodedTxData(txHash, input)
}
function fetchTxDetails(modelIndex) {
walletSectionInst.activityController.fetchTxDetails(modelIndex)
function fetchTxDetails(txID) {
walletSectionInst.activityController.fetchTxDetails(txID)
walletSectionInst.activityDetailsController.fetchExtraTxDetails()
}
function getTxDetails() {
return walletSectionInst.activityController.activityDetails
return walletSectionInst.activityDetailsController.activityDetails
}
property bool marketHistoryIsLoading: Global.appIsReady? walletSectionAllTokens.marketHistoryIsLoading : false

View File

@ -37,11 +37,9 @@ ColumnLayout {
property bool hideVerticalScrollbar: false
property int firstItemOffset: 0
property var selectedTransaction
property real yPosition: transactionListRoot.visibleArea.yPosition * transactionListRoot.contentHeight
signal launchTransactionDetail(int entryIndex)
signal launchTransactionDetail(string txID)
function resetView() {
if (!!filterPanelLoader.item) {
@ -102,18 +100,13 @@ ColumnLayout {
property string openTxDetailsHash
function openTxDetails(txHash) {
function openTxDetails(txID) {
// Prevent opening details when loading, that will invalidate the model data
if (RootStore.loadingHistoryTransactions) {
return false
}
const index = WalletStores.RootStore.currentActivityFiltersStore.transactionsList.getIndex(txHash)
if (index < 0)
return false
const entry = transactionListRoot.itemAtIndex(index)
root.selectedTransaction = Qt.binding(() => entry.modelData)
root.launchTransactionDetail(index)
root.launchTransactionDetail(txID)
return true
}
}
@ -391,7 +384,11 @@ ColumnLayout {
if (delegateMenu.transaction.sender !== delegateMenu.transaction.recipient) {
WalletStores.RootStore.addressWasShown(delegateMenu.transaction.recipient)
}
RootStore.copyToClipboard(delegateMenu.transactionDelegate.getDetailsString())
RootStore.fetchTxDetails(delegateMenu.transaction.id)
let detailsObj = RootStore.getTxDetails()
let detailsString = delegateMenu.transactionDelegate.getDetailsString(detailsObj)
RootStore.copyToClipboard(detailsString)
}
}
StatusMenuSeparator {
@ -496,8 +493,7 @@ ColumnLayout {
if (mouse.button === Qt.RightButton) {
delegateMenu.openMenu(this, mouse, modelData)
} else {
root.selectedTransaction = Qt.binding(() => transactionDelegate.model.activityEntry)
launchTransactionDetail(transactionDelegate.index)
launchTransactionDetail(modelData.id)
}
}
}