bash: q: command not found

feat(@desktop/wallet): New design for Transaction History

fixes #7213
This commit is contained in:
Khushboo Mehta 2022-09-01 17:34:27 +02:00 committed by Khushboo-dev-cpp
parent b2485603de
commit e9d3d7a0b0
18 changed files with 358 additions and 217 deletions

View File

@ -127,6 +127,12 @@ QtObject:
return item.getIconURL()
return ""
proc getNetworkShortName*(self: Model, chainId: int): string {.slot.} =
for item in self.items:
if(item.getChainId() == chainId):
return item.getShortName()
return ""
proc getNetworkIconUrl*(self: Model, shortName: string): string {.slot.} =
for item in self.items:
if(item.getShortName() == toLowerAscii(shortName)):

View File

@ -62,3 +62,6 @@ proc removeCustomToken*(self: Controller, chainId: int, address: string) =
proc getTokenDetails*(self: Controller, address: string) =
self.tokenService.getTokenDetails(address)
method findTokenSymbolByAddress*(self: Controller, address: string): string =
return self.walletAccountService.findTokenSymbolByAddress(address)

View File

@ -29,6 +29,9 @@ method getTokenDetails*(self: AccessInterface, address: string) {.base.} =
method tokenDetailsWereResolved*(self: AccessInterface, tokenDetails: string) {.base.} =
raise newException(ValueError, "No implementation available")
method findTokenSymbolByAddress*(self: AccessInterface, address: string): string {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim.

View File

@ -88,3 +88,6 @@ method getTokenDetails*(self: Module, address: string) =
method tokenDetailsWereResolved*(self: Module, tokenDetails: string) =
self.view.tokenDetailsWereResolved(tokenDetails)
method findTokenSymbolByAddress*(self: Module, address: string): string =
return self.controller.findTokenSymbolByAddress(address)

View File

@ -74,3 +74,6 @@ QtObject:
proc getTokenDetails*(self: View, address: string) {.slot.} =
self.delegate.getTokenDetails(address)
proc findTokenSymbolByAddress*(self: View, address: string): string {.slot.} =
return self.delegate.findTokenSymbolByAddress(address)

View File

@ -74,3 +74,9 @@ QtObject:
self.items = items
self.endResetModel()
self.countChanged()
proc getNameByAddress*(self: Model, address: string): string =
for item in self.items:
if(item.getAddress() == address):
return item.getName()
return ""

View File

@ -42,3 +42,6 @@ QtObject:
proc deleteSavedAddress*(self: View, address: string): string {.slot.} =
return self.delegate.deleteSavedAddress(address)
proc getNameByAddress*(self: View, address: string): string {.slot.} =
return self.model.getNameByAddress(address)

View File

@ -55,6 +55,10 @@ proc init*(self: Controller) =
let addresses = accounts.map(account => account.address)
self.delegate.setHistoryFetchState(addresses, false)
self.delegate.setIsNonArchivalNode(true)
of "fetching-history-error":
let accounts = self.getWalletAccounts()
let addresses = accounts.map(account => account.address)
self.delegate.setHistoryFetchState(addresses, false)
else:
echo "Unhandled wallet signal: ", data.eventType

View File

@ -1,4 +1,4 @@
import strformat, stint
import strformat
type
Item* = object
@ -7,7 +7,7 @@ type
address: string
blockNumber: string
blockHash: string
timestamp: UInt256
timestamp: int
gasPrice: string
gasLimit: string
gasUsed: string
@ -17,23 +17,37 @@ type
fro: string
to: string
contract: string
chainId: int
maxFeePerGas: string
maxPriorityFeePerGas: string
input: string
txHash: string
multiTransactionID: int
isTimeStamp: bool
proc initItem*(
id,
typ,
address,
blockNumber,
id: string,
typ: string,
address: string,
blockNumber: string,
blockHash: string,
timestamp: UInt256,
gasPrice,
gasLimit,
gasUsed,
nonce,
txStatus,
value,
fro,
to,
contract: string
timestamp: int,
gasPrice: string,
gasLimit: string,
gasUsed: string,
nonce: string,
txStatus: string,
value: string,
fro: string,
to: string,
contract: string,
chainId: int,
maxFeePerGas: string,
maxPriorityFeePerGas: string,
input: string,
txHash: string,
multiTransactionID: int,
isTimeStamp: bool
): Item =
result.id = id
result.typ = typ
@ -50,6 +64,13 @@ proc initItem*(
result.fro = fro
result.to = to
result.contract = contract
result.chainId = chainId
result.maxFeePerGas = maxFeePerGas
result.maxPriorityFeePerGas = maxPriorityFeePerGas
result.input = input
result.txHash = txHash
result.multiTransactionID = multiTransactionID
result.isTimeStamp = isTimeStamp
proc `$`*(self: Item): string =
result = fmt"""AllTokensItem(
@ -68,6 +89,13 @@ proc `$`*(self: Item): string =
fro: {self.fro},
to: {self.to},
contract: {self.contract},
chainId: {self.chainId},
maxFeePerGas: {self.maxFeePerGas},
maxPriorityFeePerGas: {self.maxPriorityFeePerGas},
input: {self.input},
txHash: {self.txHash},
multiTransactionID: {self.multiTransactionID},
isTimeStamp: {self.isTimeStamp},
]"""
proc getId*(self: Item): string =
@ -85,8 +113,8 @@ proc getBlockNumber*(self: Item): string =
proc getBlockHash*(self: Item): string =
return self.blockHash
proc getTimestamp*(self: Item): string =
return $self.timestamp
proc getTimestamp*(self: Item): int =
return self.timestamp
proc getGasPrice*(self: Item): string =
return self.gasPrice
@ -114,3 +142,24 @@ proc getTo*(self: Item): string =
proc getContract*(self: Item): string =
return self.contract
proc getChainId*(self: Item): int =
return self.chainId
proc getMaxFeePerGas*(self: Item): string =
return self.maxFeePerGas
proc getMaxPriorityFeePerGas*(self: Item): string =
return self.maxPriorityFeePerGas
proc getInput*(self: Item): string =
return self.input
proc getTxHash*(self: Item): string =
return self.txHash
proc getMultiTransactionID*(self: Item): int =
return self.multiTransactionID
proc getIsTimeStamp*(self: Item): bool =
return self.isTimeStamp

View File

@ -1,4 +1,4 @@
import NimQml, Tables, strutils, strformat, sequtils, tables, sugar, algorithm
import NimQml, Tables, strutils, strformat, sequtils, tables, sugar, algorithm, std/[times, os], stint
import ./item
import ../../../../../app_service/service/eth/utils as eth_service_utils
@ -21,15 +21,24 @@ type
From
To
Contract
ChainID
MaxFeePerGas
MaxPriorityFeePerGas
Input
TxHash
MultiTransactionID
IsTimeStamp
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[Item]
itemsWithDateHeaders: seq[Item]
hasMore: bool
proc delete(self: Model) =
self.items = @[]
self.itemsWithDateHeaders = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
@ -41,20 +50,20 @@ QtObject:
result.hasMore = true
proc `$`*(self: Model): string =
for i in 0 ..< self.items.len:
result &= fmt"""[{i}]:({$self.items[i]})"""
for i in 0 ..< self.itemsWithDateHeaders.len:
result &= fmt"""[{i}]:({$self.itemsWithDateHeaders[i]})"""
proc countChanged(self: Model) {.signal.}
proc getCount*(self: Model): int {.slot.} =
self.items.len
self.itemsWithDateHeaders.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: Model, index: QModelIndex = nil): int =
return self.items.len
return self.itemsWithDateHeaders.len
method roleNames(self: Model): Table[int, string] =
{
@ -73,16 +82,23 @@ QtObject:
ModelRole.From.int:"from",
ModelRole.To.int:"to",
ModelRole.Contract.int:"contract",
ModelRole.ChainID.int:"chainId",
ModelRole.MaxFeePerGas.int:"maxFeePerGas",
ModelRole.MaxPriorityFeePerGas.int:"maxPriorityFeePerGas",
ModelRole.Input.int:"input",
ModelRole.TxHash.int:"txHash",
ModelRole.MultiTransactionID.int:"multiTransactionID",
ModelRole.IsTimeStamp.int: "isTimeStamp"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
if (index.row < 0 or index.row >= self.itemsWithDateHeaders.len):
return
let item = self.items[index.row]
let item = self.itemsWithDateHeaders[index.row]
let enumRole = role.ModelRole
case enumRole:
@ -116,17 +132,31 @@ QtObject:
result = newQVariant(item.getTo())
of ModelRole.Contract:
result = newQVariant(item.getContract())
of ModelRole.ChainID:
result = newQVariant(item.getChainId())
of ModelRole.MaxFeePerGas:
result = newQVariant(item.getMaxFeePerGas())
of ModelRole.MaxPriorityFeePerGas:
result = newQVariant(item.getMaxPriorityFeePerGas())
of ModelRole.Input:
result = newQVariant(item.getInput())
of ModelRole.TxHash:
result = newQVariant(item.getTxHash())
of ModelRole.MultiTransactionID:
result = newQVariant(item.getMultiTransactionID())
of ModelRole.IsTimeStamp:
result = newQVariant(item.getIsTimeStamp())
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
self.items = items
self.itemsWithDateHeaders = items
self.endResetModel()
self.countChanged()
proc getLastTxBlockNumber*(self: Model): string {.slot.} =
if (self.items.len == 0):
if (self.itemsWithDateHeaders.len == 0):
return "0x0"
return self.items[^1].getBlockNumber()
return self.itemsWithDateHeaders[^1].getBlockNumber()
proc hasMoreChanged*(self: Model) {.signal.}
@ -160,7 +190,7 @@ QtObject:
t.address,
t.blockNumber,
t.blockHash,
t.timestamp,
toInt(t.timestamp),
t.gasPrice,
t.gasLimit,
t.gasUsed,
@ -169,14 +199,32 @@ QtObject:
t.value,
t.fromAddress,
t.to,
t.contract
t.contract,
t.chainId,
t.maxFeePerGas,
t.maxPriorityFeePerGas,
t.input,
t.txHash,
t.multiTransactionID,
false
))
var allTxs = self.items.concat(newTxItems)
allTxs.sort(cmpTransactions, SortOrder.Descending)
eth_service_utils.deduplicate(allTxs, tx => tx.getId())
self.setItems(allTxs)
# add day headers to the transaction list
var itemsWithDateHeaders: seq[Item] = @[]
var tempTimeStamp: Time
for tx in allTxs:
let duration = fromUnix(tx.getTimestamp()) - tempTimeStamp
if(duration.inDays != 0):
itemsWithDateHeaders.add(initItem("", "", "", "", "", tx.getTimestamp(), "", "", "", "", "", "", "", "", "", 0, "", "", "", "", 0, true))
itemsWithDateHeaders.add(tx)
tempTimeStamp = fromUnix(tx.getTimestamp())
self.items = allTxs
self.setItems(itemsWithDateHeaders)
self.setHasMore(true)
else:
self.setHasMore(false)

View File

@ -43,7 +43,12 @@ type
value*: string
fromAddress*: string
to*: string
chainId*: int
chainId*: int
maxFeePerGas*: string
maxPriorityFeePerGas*: string
input*: string
txHash*: string
multiTransactionID*: int
proc toTransactionDto*(jsonObj: JsonNode): TransactionDto =
result = TransactionDto()
@ -63,7 +68,11 @@ proc toTransactionDto*(jsonObj: JsonNode): TransactionDto =
discard jsonObj.getProp("from", result.fromAddress)
discard jsonObj.getProp("to", result.to)
discard jsonObj.getProp("networkId", result.chainId)
discard jsonObj.getProp("maxFeePerGas", result.maxFeePerGas)
discard jsonObj.getProp("maxPriorityFeePerGas", result.maxPriorityFeePerGas)
discard jsonObj.getProp("input", result.input)
discard jsonObj.getProp("txHash", result.txHash)
discard jsonObj.getProp("multiTransactionID", result.multiTransactionID)
proc cmpTransactions*(x, y: TransactionDto): int =
# Sort proc to compare transactions from a single account.

@ -1 +1 @@
Subproject commit f6424328d87a4cac571f3b1c424f2dc125ced7b3
Subproject commit 7108ac87cffe529d011ec1c14473630e52980282

View File

@ -13,6 +13,7 @@ Control {
property alias tagPrimaryLabel: tagPrimaryLabel
property alias tagSecondaryLabel: tagSecondaryLabel
property alias controlBackground: controlBackground
property alias rightComponent: rightComponent.sourceComponent
horizontalPadding: Style.current.halfPadding
verticalPadding: 5
@ -62,5 +63,9 @@ Control {
visible: text !== ""
elide: Text.ElideMiddle
}
Loader {
id: rightComponent
Layout.alignment: Qt.AlignVCenter
}
}
}

View File

@ -1,148 +1,95 @@
import QtQuick 2.13
import QtQuick.Layouts 1.3
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
import utils 1.0
import shared 1.0
import shared.panels 1.0
import shared.stores 1.0
StatusListItem {
id: root
Rectangle {
id: transactionListItem
property var modelData
property string symbol
property bool isIncoming
property int transferStatus
property string currentCurrency
property string cryptoValue
property string fiatValue
property string networkIcon
property string networkColor
property string networkName
property string shortTimeStamp
property string resolvedSymbol: root.symbol != "" ? root.symbol : "ETH"
property string savedAddressName
property var tokens
property string currentAccountAddress: ""
property string ethValue: ""
property bool isHovered: false
property string symbol: ""
property string locale: ""
property bool isIncoming: to === currentAccountAddress
signal launchTransactionModal()
anchors.right: parent.right
anchors.left: parent.left
height: 64
color: isHovered ? Style.current.secondaryBackground : Style.current.transparent
radius: 8
Component.onCompleted: {
const count = transactionListItem.tokens.length
for (var i = 0; i < count; i++) {
let token = transactionListItem.tokens[i]
if (token.address === contract) {
transactionListItem.symbol = token.symbol
break
}
asset.isImage: true
asset.name: Style.png("tokens/%1".arg(resolvedSymbol))
statusListItemTitle.font.weight: Font.Medium
title: isIncoming ? qsTr("Receive %1").arg(resolvedSymbol) : !!savedAddressName ?
qsTr("Send %1 to %2").arg(resolvedSymbol).arg(savedAddressName) :
qsTr("Send %1 to %2").arg(resolvedSymbol).arg(Utils.compactAddress(modelData.to, 4))
subTitle: shortTimeStamp
inlineTagModel: 1
inlineTagDelegate: InformationTag {
tagPrimaryLabel.text: networkName
tagPrimaryLabel.color: networkColor
image.source: Style.svg("tiny/%1".arg(networkIcon))
background: Rectangle {
id: controlBackground
implicitWidth: 51
implicitHeight: 24
color: "transparent"
border.width: 1
border.color: Theme.palette.baseColor2
radius: 36
}
rightComponent: transferStatus === Constants.TransactionStatus.Success ? completedIcon : loadingIndicator
}
MouseArea {
anchors.fill: parent
onClicked: launchTransactionModal()
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: {
transactionListItem.isHovered = true
}
onExited: {
transactionListItem.isHovered = false
}
}
Row {
anchors.left: parent.left
anchors.leftMargin: Style.current.smallPadding
anchors.verticalCenter: parent.verticalCenter
spacing: 5
Image {
id: assetIcon
width: 40
height: 40
source: Style.png("tokens/"
+ (transactionListItem.symbol
!= "" ? transactionListItem.symbol : "ETH"))
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: {
if (assetIcon.status == Image.Error) {
assetIcon.source = Style.png("tokens/DEFAULT-TOKEN@3x")
components: [
ColumnLayout {
Row {
Layout.alignment: Qt.AlignRight
spacing: 4
StatusIcon {
color: isIncoming ? Theme.palette.successColor1 : Theme.palette.dangerColor1
icon: "arrow-up"
rotation: isIncoming ? 135 : 45
height: 18
}
StatusBaseText {
text: "%1 %2".arg(cryptoValue).arg(resolvedSymbol)
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
anchors.leftMargin: Style.current.padding
StatusBaseText {
Layout.alignment: Qt.AlignRight
text: "%1 %2".arg(fiatValue).arg(currentCurrency.toUpperCase())
font.pixelSize: 15
color: Theme.palette.baseColor1
}
}
]
StyledText {
id: transferIcon
anchors.verticalCenter: parent.verticalCenter
height: 15
width: 15
color: isIncoming ? Style.current.success : Style.current.danger
text: isIncoming ? "↓" : "↑"
}
StyledText {
id: transactionValue
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Style.current.primaryTextFontSize
text: ethValue + " " + transactionListItem.symbol
Component {
id: loadingIndicator
StatusLoadingIndicator {
height: 10
width: 10
}
}
Row {
anchors.right: timeInfo.left
anchors.rightMargin: Style.current.smallPadding
anchors.top: parent.top
anchors.topMargin: Style.current.bigPadding
spacing: 5
StyledText {
text: isIncoming ?
qsTr("From ") :
qsTr("To ")
color: Style.current.secondaryText
font.pixelSize: Style.current.primaryTextFontSize
font.strikeout: false
}
Address {
id: addressValue
text: isIncoming ? from : to
maxWidth: 120
width: 120
horizontalAlignment: Text.AlignRight
font.pixelSize: Style.current.primaryTextFontSize
color: Style.current.textColor
}
}
Row {
id: timeInfo
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
anchors.top: parent.top
anchors.topMargin: Style.current.bigPadding
spacing: 5
StyledText {
text: " • "
font.weight: Font.Bold
color: Style.current.secondaryText
font.pixelSize: Style.current.primaryTextFontSize
}
StyledText {
id: timeIndicator
text: qsTr("At ")
color: Style.current.secondaryText
font.pixelSize: Style.current.primaryTextFontSize
font.strikeout: false
}
StyledText {
id: timeValue
text: Utils.formatLongDateTime(timestamp * 1000, RootStore.accountSensitiveSettings.isDDMMYYDateFormat, RootStore.accountSensitiveSettings.is24hTimeFormat)
font.pixelSize: Style.current.primaryTextFontSize
anchors.rightMargin: Style.current.smallPadding
Component {
id: completedIcon
StatusIcon {
visible: icon !== ""
icon: "checkmark"
color: Theme.palette.baseColor1
width: 10
height: 10
}
}
}

View File

@ -50,6 +50,10 @@ QtObject {
return networksModule.all.getIconUrl(chainId)
}
function getNetworkShortName(chainId) {
return networksModule.all.getNetworkShortName(chainId)
}
function getNetworkIconUrl(symbol) {
return networksModule.all.getNetworkIconUrl(symbol)
}
@ -58,6 +62,14 @@ QtObject {
return networksModule.all.getNetworkName(symbol)
}
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
return profileSectionModule.ensUsernamesModule.getFiatValue(balance, cryptoSymbol, fiatSymbol)
}
function hex2Dec(value) {
return globalUtils.hex2Dec(value)
}
readonly property var formationChars: (["*", "`", "~"])
function getSelectedTextWithFormationChars(messageInputField) {
let i = 1
@ -157,4 +169,13 @@ QtObject {
function hex2Eth(value) {
return globalUtils.hex2Eth(value)
}
function findTokenSymbolByAddress(address) {
return walletSectionAllTokens.findTokenSymbolByAddress(address)
}
function getNameForSavedWalletAddress(address) {
return walletSectionSavedAddresses.getNameByAddress(address)
}
}

View File

@ -5,6 +5,7 @@ import QtQuick.Layouts 1.3
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
@ -13,48 +14,43 @@ import "../popups"
import "../stores"
import "../controls"
Item {
ColumnLayout {
id: historyView
property var account
property int pageSize: 20 // number of transactions per page
property bool isLoading: false
function fetchHistory() {
if (RootStore.isFetchingHistory(historyView.account.address)) {
loadingImg.active = true
isLoading = true
} else {
RootStore.loadTransactionsForAccount(historyView.account.address, pageSize)
}
}
Loader {
id: loadingImg
active: false
sourceComponent: loadingImageComponent
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
anchors.top: parent.top
}
Component {
id: loadingImageComponent
StatusLoadingIndicator {}
}
Connections {
target: RootStore.history
onLoadingTrxHistoryChanged: function(isLoading, address) {
if (historyView.account.address.toLowerCase() === address.toLowerCase()) {
loadingImg.active = isLoading
isLoading = isLoading
}
}
}
Loader {
id: loadingImg
active: isLoading
sourceComponent: loadingImageComponent
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.rightMargin: Style.current.padding
}
StyledText {
id: nonArchivalNodeError
Layout.alignment: Qt.AlignTop
visible: RootStore.isNonArchivalNode
height: visible ? implicitHeight : 0
anchors.top: parent.top
text: qsTr("Status Desktop is connected to a non-archival node. Transaction history may be incomplete.")
font.pixelSize: Style.current.primaryTextFontSize
color: Style.current.danger
@ -62,59 +58,80 @@ Item {
StyledText {
id: noTxs
anchors.top: nonArchivalNodeError.bottom
visible: transactionListRoot.count === 0
height: visible ? implicitHeight : 0
text: qsTr("No transactions found")
font.pixelSize: Style.current.primaryTextFontSize
}
StatusListView {
id: transactionListRoot
anchors.top: noTxs.bottom
anchors.topMargin: Style.current.padding
anchors.bottom: loadMoreButton.top
anchors.bottomMargin: Style.current.padding
width: parent.width
Layout.alignment: Qt.AlignTop
Layout.topMargin: nonArchivalNodeError.visible || noTxs.visible ? Style.current.padding : 0
Layout.bottomMargin: Style.current.padding
Layout.fillWidth: true
Layout.fillHeight: true
model: RootStore.historyTransactions
delegate: TransactionDelegate {
tokens: RootStore.tokens
locale: RootStore.locale
currentAccountAddress: account.address
ethValue: RootStore.hex2Eth(value)
onLaunchTransactionModal: {
transactionModal.transaction = model
transactionModal.open()
delegate: Loader {
width: parent.width
sourceComponent: isTimeStamp ? dateHeader : transactionDelegate
onLoaded: {
item.modelData = model
}
}
ScrollBar.vertical: ScrollBar {
id: scrollBar
}
ScrollBar.vertical: StatusScrollBar {}
onCountChanged: {
if (loadMoreButton.loadedMore)
transactionListRoot.positionViewAtEnd();
footer: StatusButton {
id: loadMoreButton
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Load More")
// TODO: handle case when requested limit === transaction count -- there
// is currently no way to know that there are no more results
enabled: !isLoading && RootStore.historyTransactions.hasMore
onClicked: fetchHistory()
}
}
StatusButton {
id: loadMoreButton
text: qsTr("Load More")
// TODO: handle case when requested limit === transaction count -- there
// is currently no way to know that there are no more results
enabled: !loadingImg.active && RootStore.historyTransactions.hasMore
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.padding
property bool loadedMore: false
onClicked: {
fetchHistory()
loadMoreButton.loadedMore = true
Component {
id: dateHeader
StatusListItem {
property var modelData
height: 40
title: Utils.formatShortDate(modelData.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat)
statusListItemTitle.color: Theme.palette.baseColor1
color: Theme.palette.statusListItem.backgroundColor
sensor.enabled: false
}
}
Component {
id: transactionDelegate
TransactionDelegate {
isIncoming: modelData !== undefined ? modelData.to === account.address: false
currentCurrency: RootStore.currentCurrency
cryptoValue: modelData !== undefined ? RootStore.hex2Eth(modelData.value) : ""
fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
networkIcon: modelData !== undefined ? RootStore.getNetworkIcon(modelData.chainId) : ""
networkColor: modelData !== undefined ? RootStore.getNetworkColor(modelData.chainId) : ""
networkName: modelData !== undefined ? RootStore.getNetworkShortName(modelData.chainId) : ""
symbol: modelData !== undefined ? RootStore.findTokenSymbolByAddress(modelData.contract) : ""
transferStatus: modelData !== undefined ? RootStore.hex2Dec(modelData.txStatus) : ""
shortTimeStamp: modelData !== undefined ? Utils.formatShortTime(modelData.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat) : ""
savedAddressName: modelData !== undefined ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
onClicked: {
transactionModal.transaction = modelData
transactionModal.open()
}
}
}
Component {
id: loadingImageComponent
StatusLoadingIndicator {}
}
TransactionModal {
id: transactionModal
}

View File

@ -546,4 +546,9 @@ QtObject {
readonly property bool isCppApp: typeof cppApp !== "undefined" ? cppApp : false
readonly property string existingAccountError: "account already exists"
enum TransactionStatus {
Failure = 0,
Success = 1
}
}

View File

@ -295,6 +295,15 @@ QtObject {
return qsTr("%1D").arg(diffDay)
}
function formatShortDate(value, isDDMMYYDateFormat) {
const formatDDMMYY = "d MMMM yyyy"
const formatMMDDYY = "MMMM d yyyy"
const currentFormat = isDDMMYYDateFormat ? formatDDMMYY : formatMMDDYY
var timeStamp = checkTimestamp(value, "formatLongDate") ? Qt.formatDate(new Date(value), currentFormat) :
Qt.formatDate(new Date(), currentFormat)
return formatShortDateStr(timeStamp)
}
// To-do move to Wallet Store, this should not be under Utils.
function findAssetByChainAndSymbol(chainIdToFind, assets, symbolToFind) {
for(var i=0; i<assets.rowCount(); i++) {