feat(@desktop/wallet): Extended activity progress block (#12013)

This commit is contained in:
Cuteivist 2023-09-04 12:19:02 +02:00 committed by GitHub
parent bc4a150afa
commit 722a9022e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 158 additions and 136 deletions

View File

@ -33,4 +33,18 @@ QtObject {
return prefixStr return prefixStr
} }
function calculateConfirmationTimestamp(chainLayer, timestamp) {
if (chainLayer === 1) {
return timestamp + 12 * 4 // A block on layer1 is every 12s
}
return timestamp
}
function calculateFinalisationTimestamp(chainLayer, timestamp) {
if (chainLayer === 1) {
return timestamp + 12 * 64 // A block on layer1 is every 12s
}
return timestamp + Constants.time.secondsIn7Days
}
} }

View File

@ -5,16 +5,20 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import utils 1.0
import AppLayouts.Wallet 1.0
ColumnLayout { ColumnLayout {
id: root id: root
property bool isLayer1: true property int networkLayer: 0
property bool error: false property bool error: false
property bool pending: false property bool pending: false
property int steps: isLayer1 ? 64 : 1 property int steps: isLayer1 ? 64 : 1
property int confirmations: 0 property int confirmations: 0
property int confirmationBlocks: isLayer1 ? 4 : 1 property int confirmationBlocks: isLayer1 ? 4 : 1
property string chainName property string chainName
property int timestamp: 0
property color fillColor: Theme.palette.blockProgressBarColor property color fillColor: Theme.palette.blockProgressBarColor
property color confirmationColor: Theme.palette.successColor1 property color confirmationColor: Theme.palette.successColor1
@ -23,18 +27,21 @@ ColumnLayout {
property alias titleText: title.text property alias titleText: title.text
property alias subText: subText.text property alias subText: subText.text
// Below properties only needed when not a mainnet tx readonly property bool isValid: root.networkLayer > 0 && !!root.chainName
property alias progress: progressBar.value readonly property double confirmationTimeStamp: WalletUtils.calculateConfirmationTimestamp(root.networkLayer, root.timestamp)
property alias duration: progressBar.to readonly property double finalisationTimeStamp: WalletUtils.calculateFinalisationTimestamp(root.networkLayer, root.timestamp)
QtObject { readonly property bool finalized: (isLayer1 ? confirmations >= steps : progress >= duration) && !error && !pending
id: d readonly property bool confirmed: confirmations >= confirmationBlocks && !error && !pending
readonly property bool finalized: isLayer1 ? confirmations >= steps : progress === duration
readonly property bool confirmed: confirmations >= confirmationBlocks readonly property bool isLayer1: networkLayer === 1
readonly property int hoursInADay: 24
} // Below properties only needed when not a mainnet tx
property int duration: Constants.time.hoursIn7Days
property alias progress: progressBar.value
spacing: 8 spacing: 8
visible: isValid
StatusBaseText { StatusBaseText {
id: title id: title
@ -49,9 +56,9 @@ ColumnLayout {
return qsTr("Failed on %1").arg(root.chainName) return qsTr("Failed on %1").arg(root.chainName)
} else if (pending) { } else if (pending) {
return qsTr("Confirmation in progress on %1...").arg(root.chainName) return qsTr("Confirmation in progress on %1...").arg(root.chainName)
} else if (d.finalized) { } else if (root.finalized) {
return qsTr("Finalised on %1").arg(root.chainName) return qsTr("Finalised on %1").arg(root.chainName)
} else if (d.confirmed) { } else if (root.confirmed) {
return qsTr("Confirmed on %1, finalisation in progress...").arg(root.chainName) return qsTr("Confirmed on %1, finalisation in progress...").arg(root.chainName)
} }
return qsTr("Pending on %1...").arg(root.chainName) return qsTr("Pending on %1...").arg(root.chainName)
@ -87,7 +94,8 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
from: 0 from: 0
to: duration to: root.duration
value: root.pending || root.error ? 0 : (Math.floor(Date.now() / 1000) - root.timestamp) / Constants.time.secondsInHour
backgroundColor: root.fillColor backgroundColor: root.fillColor
backgroundBorderColor: "transparent" backgroundBorderColor: "transparent"
fillColor: error ? "transparent": Theme.palette.primaryColor1 fillColor: error ? "transparent": Theme.palette.primaryColor1
@ -105,10 +113,10 @@ ColumnLayout {
lineHeight: 18 lineHeight: 18
lineHeightMode: Text.FixedHeight lineHeightMode: Text.FixedHeight
text: { text: {
if (d.finalized && !root.error) { if (root.finalized) {
return qsTr("In epoch %1").arg(root.confirmations) return qsTr("In epoch %1").arg(root.confirmations)
} else if (d.confirmed && !root.isLayer1) { } else if (root.confirmed && !root.isLayer1) {
return qsTr("%n day(s) until finality", "", Math.ceil((root.duration - root.progress)/d.hoursInADay)) return qsTr("%n day(s) until finality", "", Math.ceil((root.duration - root.progress) / Constants.time.hoursInDay))
} }
return qsTr("%1 / %2 confirmations").arg(root.confirmations).arg(root.steps) return qsTr("%1 / %2 confirmations").arg(root.confirmations).arg(root.steps)
} }

View File

@ -116,7 +116,7 @@ Column {
return qsTr("Pending") return qsTr("Pending")
case Constants.TransactionStatus.Complete: case Constants.TransactionStatus.Complete:
return qsTr("Complete") return qsTr("Complete")
case Constants.TransactionStatus.Finished: case Constants.TransactionStatus.Finalised:
return qsTr("Finalised") return qsTr("Finalised")
default: default:
console.warn("Unhandled status :: ",activityFilterStore.statusFilters[index]) console.warn("Unhandled status :: ",activityFilterStore.statusFilters[index])

View File

@ -12,121 +12,105 @@ import "../controls"
ColumnLayout { ColumnLayout {
id: root id: root
// To-do adapt this for multi-tx, not sure how the data will look for that yet
property bool isLayer1: true
property bool error: false property bool error: false
property bool pending: false property bool pending: false
property int confirmations: 0
property string chainName property int outNetworkLayer: 0
property double timeStamp property int inNetworkLayer: 0
property int outNetworkTimestamp: 0
property int inNetworkTimestamp: 0
property string outChainName
property string inChainName
property int outNetworkConfirmations: 0
property int inNetworkConfirmations: 0
spacing: 32 spacing: 32
QtObject {
id: d
readonly property bool finalized: (isLayer1 ? confirmations >= progressBar.steps : progress >= duration) && !error && !pending
readonly property bool confirmed: confirmations >= progressBar.confirmationBlocks && !error && !pending
readonly property double confirmationTimeStamp: {
if (root.isLayer1) {
return root.timeStamp + 12 * 4 // A block on layer1 is every 12s
}
return root.timeStamp
}
readonly property double finalisationTimeStamp: {
if (root.isLayer1) {
return root.timeStamp + 12 * 64 // A block on layer1 is every 12s
}
return root.timeStamp + 604800 // 7 days in seconds
}
readonly property int duration: 168 // 7 days in hours
readonly property int progress: pending || error ? 0 : (Math.floor(Date.now() / 1000) - root.timeStamp) / 3600
}
StatusTxProgressBar { StatusTxProgressBar {
id: progressBar id: progressBarOut
Layout.topMargin: 8 Layout.topMargin: 8
Layout.fillWidth: true Layout.fillWidth: true
error: root.error error: root.error
isLayer1: root.isLayer1 networkLayer: root.outNetworkLayer
confirmations: root.confirmations confirmations: root.outNetworkConfirmations
duration: d.duration timestamp: root.outNetworkTimestamp
progress: d.progress chainName: root.outChainName
chainName: root.chainName
} }
Column { TextColumn {
spacing: 20 visible: progressBarOut.isValid && progressBarOut.error
Column { text: qsTr("Failed on %1").arg(progressBarOut.chainName)
spacing: 4 timestamp: progressBarOut.timestamp
visible: d.confirmed }
StatusBaseText {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.baseColor1
lineHeight: 18
lineHeightMode: Text.FixedHeight
text: qsTr("Confirmed on %1").arg(root.chainName)
}
StatusBaseText {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.directColor1
lineHeight: 18
lineHeightMode: Text.FixedHeight
text: LocaleUtils.formatDateTime(d.confirmationTimeStamp * 1000, Locale.LongFormat)
}
}
Column { StatusTxProgressBar {
spacing: 4 id: progressBarIn
visible: d.finalized Layout.topMargin: 8
StatusBaseText { Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter error: root.error
verticalAlignment: Text.AlignVCenter networkLayer: root.inNetworkLayer
font.pixelSize: 13 confirmations: root.inNetworkConfirmations
color: Theme.palette.baseColor1 timestamp: root.inNetworkTimestamp
lineHeight: 18 chainName: root.inChainName
lineHeightMode: Text.FixedHeight }
text: qsTr("Finalised on %1").arg(root.chainName)
}
StatusBaseText {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.directColor1
lineHeight: 18
lineHeightMode: Text.FixedHeight
text: LocaleUtils.formatDateTime(d.finalisationTimeStamp * 1000, Locale.LongFormat)
}
}
Column { TextColumn {
spacing: 4 visible: progressBarOut.isValid && progressBarOut.confirmed
visible: root.error text: qsTr("Confirmed on %1").arg(progressBarOut.chainName)
StatusBaseText { timestamp: progressBarOut.confirmationTimeStamp
horizontalAlignment: Text.AlignHCenter }
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13 TextColumn {
color: Theme.palette.baseColor1 visible: progressBarIn.isValid && progressBarIn.confirmed
lineHeight: 18 text: qsTr("Confirmed on %1").arg(progressBarIn.chainName)
lineHeightMode: Text.FixedHeight timestamp: progressBarIn.confirmationTimeStamp
text: qsTr("Failed on %1").arg(root.chainName) }
}
StatusBaseText { TextColumn {
horizontalAlignment: Text.AlignHCenter visible: progressBarOut.isValid && progressBarOut.finalized
verticalAlignment: Text.AlignVCenter text: qsTr("Finalised on %1").arg(progressBarOut.chainName)
font.pixelSize: 13 timestamp: progressBarOut.finalisationTimeStamp
color: Theme.palette.directColor1 }
lineHeight: 18
lineHeightMode: Text.FixedHeight TextColumn {
text: LocaleUtils.formatDateTime(root.timeStamp * 1000, Locale.LongFormat) visible: progressBarIn.isValid && progressBarIn.finalized
} text: qsTr("Finalised on %1").arg(progressBarIn.chainName)
timestamp: progressBarIn.finalisationTimeStamp
}
TextColumn {
visible: progressBarIn.isValid && progressBarIn.error
text: qsTr("Failed on %1").arg(progressBarIn.chainName)
timestamp: progressBarIn.timestamp
}
component TextColumn: Column {
id: textColumn
property string text
property int timestamp
spacing: 4
StatusBaseText {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.baseColor1
lineHeight: 18
lineHeightMode: Text.FixedHeight
text: textColumn.text
}
StatusBaseText {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.directColor1
lineHeight: 18
lineHeightMode: Text.FixedHeight
text: textColumn.timestamp > 0 ? LocaleUtils.formatDateTime(textColumn.timestamp * 1000, Locale.LongFormat) : ""
} }
} }
} }

View File

@ -73,7 +73,7 @@ StatusMenu {
assetSettings.color: "transparent" assetSettings.color: "transparent"
buttonGroup: typeButtonGroup buttonGroup: typeButtonGroup
allChecked: root.allChecked allChecked: root.allChecked
type: Constants.TransactionStatus.Finished type: Constants.TransactionStatus.Finalised
checked: root.allChecked || statusFilters.includes(type) checked: root.allChecked || statusFilters.includes(type)
onActionTriggered: root.actionTriggered(type) onActionTriggered: root.actionTriggered(type)
} }

View File

@ -86,6 +86,7 @@ Item {
readonly property real feeEthValue: root.isTransactionValid ? RootStore.getFeeEthValue(transaction.totalFees) : 0 readonly property real feeEthValue: root.isTransactionValid ? RootStore.getFeeEthValue(transaction.totalFees) : 0
readonly property real feeFiatValue: root.isTransactionValid ? RootStore.getFiatValue(d.feeEthValue, Constants.ethToken, RootStore.currentCurrency) : 0 // TODO use directly? readonly property real feeFiatValue: root.isTransactionValid ? RootStore.getFiatValue(d.feeEthValue, Constants.ethToken, RootStore.currentCurrency) : 0 // TODO use directly?
readonly property int transactionType: root.isTransactionValid ? transaction.txType : Constants.TransactionType.Send readonly property int transactionType: root.isTransactionValid ? transaction.txType : Constants.TransactionType.Send
readonly property bool isBridge: d.transactionType === Constants.TransactionType.Bridge
property string decodedInputData: "" property string decodedInputData: ""
property bool loadingInputDate: false property bool loadingInputDate: false
@ -158,12 +159,17 @@ Item {
WalletTxProgressBlock { WalletTxProgressBlock {
id: progressBlock id: progressBlock
width: Math.min(513, root.width) width: Math.min(513, root.width)
readonly property int latestBlockNumber: root.isTransactionValid && !pending && !error ? RootStore.hex2Dec(WalletStores.RootStore.getLatestBlockNumber(root.transaction.chainId)) : 0
error: transactionHeader.transactionStatus === Constants.TransactionStatus.Failed error: transactionHeader.transactionStatus === Constants.TransactionStatus.Failed
pending: transactionHeader.transactionStatus === Constants.TransactionStatus.Pending pending: transactionHeader.transactionStatus === Constants.TransactionStatus.Pending
isLayer1: root.isTransactionValid && RootStore.getNetworkLayer(root.transaction.chainId) == 1 outNetworkLayer: root.isTransactionValid ? Number(RootStore.getNetworkLayer(transactionHeader.isMultiTransaction ? root.transaction.chainIdOut : root.transaction.chainId)) : 0
confirmations: root.isTransactionValid && !pending && !error ? Math.abs(WalletStores.RootStore.getLatestBlockNumber(root.transaction.chainId) - d.blockNumber): 0 inNetworkLayer: root.isTransactionValid && transactionHeader.isMultiTransaction && d.isBridge ? Number(RootStore.getNetworkLayer(root.transaction.chainIdIn)) : 0
chainName: transactionHeader.networkName outNetworkTimestamp: root.isTransactionValid ? root.transaction.timestamp : 0
timeStamp: root.isTransactionValid ? transaction.timestamp: "" inNetworkTimestamp: root.isTransactionValid ? root.transaction.timestamp : 0
outChainName: transactionHeader.isMultiTransaction ? transactionHeader.networkNameOut : transactionHeader.networkName
inChainName: transactionHeader.isMultiTransaction && d.isBridge ? transactionHeader.networkNameIn : ""
outNetworkConfirmations: root.isTransactionValid && latestBlockNumber > 0 ? latestBlockNumber - d.blockNumber : 0
inNetworkConfirmations: root.isTransactionValid && latestBlockNumber > 0 ? latestBlockNumber - d.blockNumber : 0
} }
Separator { Separator {

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -7,6 +7,8 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import AppLayouts.Wallet 1.0
import utils 1.0 import utils 1.0
import shared 1.0 import shared 1.0
@ -131,8 +133,8 @@ StatusListItem {
case Constants.TransactionStatus.Pending: case Constants.TransactionStatus.Pending:
return Style.svg("transaction/pending") return Style.svg("transaction/pending")
case Constants.TransactionStatus.Complete: case Constants.TransactionStatus.Complete:
return Style.svg("transaction/verified") return Style.svg("transaction/confirmed")
case Constants.TransactionStatus.Finished: case Constants.TransactionStatus.Finalised:
return Style.svg("transaction/finished") return Style.svg("transaction/finished")
case Constants.TransactionStatus.Failed: case Constants.TransactionStatus.Failed:
return Style.svg("transaction/failed") return Style.svg("transaction/failed")
@ -232,15 +234,16 @@ StatusListItem {
if (root.isNFT) { if (root.isNFT) {
details += qsTr("Token ID") + endl + modelData.tokenID + endl2 details += qsTr("Token ID") + endl + modelData.tokenID + endl2
details += qsTr("Token name") + endl + modelData.nftName + endl2 if (!!modelData.nftName) {
details += qsTr("Token name") + endl + modelData.nftName + endl2
}
} }
// PROGRESS // PROGRESS
const isLayer1 = rootStore.getNetworkLayer(modelData.chainId) === 1 const networkLayer = rootStore.getNetworkLayer(modelData.chainId) === 1
// A block on layer1 is every 12s // A block on layer1 is every 12s
const confirmationTimeStamp = isLayer1 ? modelData.timestamp + 12 * 4 : modelData.timestamp const confirmationTimeStamp = WalletUtils.calculateConfirmationTimestamp(networkLayer, modelData.timestamp)
// A block on layer1 is every 12s const finalisationTimeStamp = WalletUtils.calculateFinalisationTimestamp(networkLayer, modelData.timestamp)
const finalisationTimeStamp = isLayer1 ? modelData.timestamp + 12 * 64 : modelData.timestamp + 604800 // 7 days in seconds
switch(transactionStatus) { switch(transactionStatus) {
case Constants.TransactionStatus.Pending: case Constants.TransactionStatus.Pending:
details += qsTr("Status") + endl details += qsTr("Status") + endl
@ -250,17 +253,17 @@ StatusListItem {
details += qsTr("Status") + endl details += qsTr("Status") + endl
details += qsTr("Failed on %1").arg(root.networkName) + endl2 details += qsTr("Failed on %1").arg(root.networkName) + endl2
break break
case Constants.TransactionStatus.Verified: { case Constants.TransactionStatus.Complete: {
const timestampString = LocaleUtils.formatDateTime(modelData.timestamp * 1000, Locale.LongFormat) const timestampString = LocaleUtils.formatDateTime(modelData.timestamp * 1000, Locale.LongFormat)
details += qsTr("Status") + endl details += qsTr("Status") + endl
const epoch = parseFloat(Math.abs(walletRootStore.getLatestBlockNumber(modelData.chainId) - detailsObj.blockNumber).toFixed(0)).toLocaleString() const epoch = parseFloat(Math.abs(walletRootStore.getLatestBlockNumber(modelData.chainId) - detailsObj.blockNumber).toFixed(0)).toLocaleString()
details += qsTr("Finalised in epoch %1").arg(epoch.toFixed(0)) + endl2
details += qsTr("Signed") + endl + root.timestampString + endl2 details += qsTr("Signed") + endl + root.timestampString + endl2
details += qsTr("Signed") + endl + timestampString + endl2
details += qsTr("Confirmed") + endl details += qsTr("Confirmed") + endl
details += LocaleUtils.formatDateTime(confirmationTimeStamp * 1000, Locale.LongFormat) + endl2 details += LocaleUtils.formatDateTime(confirmationTimeStamp * 1000, Locale.LongFormat) + endl2
break break
} }
case Constants.TransactionStatus.Finished: { case Constants.TransactionStatus.Finalised: {
const timestampString = LocaleUtils.formatDateTime(modelData.timestamp * 1000, Locale.LongFormat) const timestampString = LocaleUtils.formatDateTime(modelData.timestamp * 1000, Locale.LongFormat)
details += qsTr("Status") + endl details += qsTr("Status") + endl
const epoch = Math.abs(walletRootStore.getLatestBlockNumber(modelData.chainId) - detailsObj.blockNumber) const epoch = Math.abs(walletRootStore.getLatestBlockNumber(modelData.chainId) - detailsObj.blockNumber)
@ -412,7 +415,7 @@ StatusListItem {
const feeCrypto = rootStore.formatCurrencyAmount(feeEthValue, "ETH") const feeCrypto = rootStore.formatCurrencyAmount(feeEthValue, "ETH")
const feeFiat = rootStore.formatCurrencyAmount(feeFiatValue, root.currentCurrency) const feeFiat = rootStore.formatCurrencyAmount(feeFiatValue, root.currentCurrency)
valuesString += qsTr("Fees %1 (%2)").arg(feeCrypto).arg(feeFiat) + endl2 valuesString += qsTr("Fees %1 (%2)").arg(feeCrypto).arg(feeFiat) + endl2
} else if (type === Constants.TransactionType.Receive || (type === Constants.TransactionType.Buy && isLayer1)) { } else if (type === Constants.TransactionType.Receive || (type === Constants.TransactionType.Buy && networkLayer === 1)) {
valuesString += qsTr("Total %1 (%2)").arg(root.transactionValue).arg(fiatTransactionValue) + endl2 valuesString += qsTr("Total %1 (%2)").arg(root.transactionValue).arg(fiatTransactionValue) + endl2
} else if (type === Constants.TransactionType.ContractDeployment) { } else if (type === Constants.TransactionType.ContractDeployment) {
const isPending = root.transactionStatus === Constants.TransactionStatus.Pending const isPending = root.transactionStatus === Constants.TransactionStatus.Pending

View File

@ -1047,7 +1047,7 @@ QtObject {
Failed, Failed,
Pending, Pending,
Complete, Complete,
Finished Finalised
} }
// Mirrors src/backend/activity.nim ActivityType // Mirrors src/backend/activity.nim ActivityType
@ -1075,6 +1075,13 @@ QtObject {
Custom Custom
} }
readonly property QtObject time: QtObject {
readonly property int hoursIn7Days: 168
readonly property int hoursInDay: 24
readonly property int secondsIn7Days: 604800
readonly property int secondsInHour: 3600
}
readonly property QtObject walletSection: QtObject { readonly property QtObject walletSection: QtObject {
readonly property string cancelledMessage: "cancelled" readonly property string cancelledMessage: "cancelled"
} }