feat(@desktop/wallet): Transaction activity summary (#10809)
closes #10751
This commit is contained in:
parent
367640af6c
commit
7caa89b050
|
@ -1,4 +1,4 @@
|
||||||
import NimQml, strutils, uri, strformat, strutils, stint
|
import NimQml, strutils, uri, strformat, strutils, stint, re
|
||||||
import stew/byteutils
|
import stew/byteutils
|
||||||
import ./utils/qrcodegen
|
import ./utils/qrcodegen
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ QtObject:
|
||||||
|
|
||||||
proc hex2Dec*(self: Utils, value: string): string {.slot.} =
|
proc hex2Dec*(self: Utils, value: string): string {.slot.} =
|
||||||
# somehow this value crashes the app
|
# somehow this value crashes the app
|
||||||
if value == "0x0":
|
if value.find(re("0x0+$")) >= 0:
|
||||||
return "0"
|
return "0"
|
||||||
return $stint.fromHex(StUint[256], value)
|
return $stint.fromHex(StUint[256], value)
|
||||||
|
|
||||||
|
|
|
@ -281,22 +281,10 @@ ListModel {
|
||||||
title: "TokenItem"
|
title: "TokenItem"
|
||||||
section: "Components"
|
section: "Components"
|
||||||
}
|
}
|
||||||
ListElement {
|
|
||||||
title: "TransactionDelegate"
|
|
||||||
section: "Components"
|
|
||||||
}
|
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "CommunityPermissionsRow"
|
title: "CommunityPermissionsRow"
|
||||||
section: "Components"
|
section: "Components"
|
||||||
}
|
}
|
||||||
ListElement {
|
|
||||||
title: "TransactionAddress"
|
|
||||||
section: "Components"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
title: "TransactionAddressTile"
|
|
||||||
section: "Components"
|
|
||||||
}
|
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "StatusImageCropPanel"
|
title: "StatusImageCropPanel"
|
||||||
section: "Components"
|
section: "Components"
|
||||||
|
@ -321,6 +309,22 @@ ListModel {
|
||||||
title: "PopupSizing"
|
title: "PopupSizing"
|
||||||
section: "Research / Examples"
|
section: "Research / Examples"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "TransactionDelegate"
|
||||||
|
section: "Wallet"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "TransactionAddress"
|
||||||
|
section: "Wallet"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "TransactionAddressTile"
|
||||||
|
section: "Wallet"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "TransactionDetailView"
|
||||||
|
section: "Wallet"
|
||||||
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "WalletHeader"
|
title: "WalletHeader"
|
||||||
section: "Wallet"
|
section: "Wallet"
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool globalUtilsReady: false
|
||||||
|
property bool mainModuleReady: false
|
||||||
|
property bool rootStoreReady: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
RootStore.getFiatValue = (cryptoValue, symbol, currentCurrency) => { return 123 }
|
||||||
|
RootStore.getNetworkIcon = (chainId) => { return "tiny/network/Network=Ethereum" }
|
||||||
|
RootStore.getLatestBlockNumber = () => { return 4 }
|
||||||
|
RootStore.hex2Dec = (number) => { return 10 }
|
||||||
|
RootStore.getNetworkColor = (number) => { return "blue" }
|
||||||
|
RootStore.getNetworkFullName = (chainId) => { return "Ethereum Mainnet" }
|
||||||
|
RootStore.getNetworkShortName = (chainId) => { return "eth" }
|
||||||
|
RootStore.formatCurrencyAmount = (value, symbol) => { return value + " " + symbol }
|
||||||
|
RootStore.getNameForSavedWalletAddress = (address) => { return "Saved Wallet Name" }
|
||||||
|
RootStore.getNameForAddress = (address) => { return "Address Name" }
|
||||||
|
RootStore.getEnsForSavedWalletAddress = (address) => { return "123" }
|
||||||
|
RootStore.getChainShortNamesForSavedWalletAddress = (address) => { return "" }
|
||||||
|
RootStore.currentCurrency = "USD"
|
||||||
|
|
||||||
|
root.rootStoreReady = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// globalUtilsInst mock
|
||||||
|
QtObject {
|
||||||
|
function getCompressedPk(publicKey) { return "zx3sh" + publicKey }
|
||||||
|
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 isCompressedPubKey(publicKey) { return true }
|
||||||
|
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,
|
||||||
|
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: 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: "0xdasdja214i12r0uf0jh013rfj01rfj12-09fuj12f012fuj0-129fuj012ujf1209u120912er902iue30912e"
|
||||||
|
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
|
||||||
|
property string symbol: "eth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 && root.rootStoreReady
|
||||||
|
sourceComponent: TransactionDetailView {
|
||||||
|
contactsStore: contactsStoreMockup
|
||||||
|
transaction: transactionData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,20 @@ QtObject {
|
||||||
property bool isWalletEnabled
|
property bool isWalletEnabled
|
||||||
property var getSelectedTextWithFormationChars
|
property var getSelectedTextWithFormationChars
|
||||||
property var gifColumnA
|
property var gifColumnA
|
||||||
|
property var currentCurrency
|
||||||
|
|
||||||
property var currencyStore
|
property var currencyStore
|
||||||
|
|
||||||
property var getNetworkIcon
|
property var getNetworkIcon
|
||||||
|
property var getFiatValue
|
||||||
|
property var getLatestBlockNumber
|
||||||
|
property var hex2Dec
|
||||||
|
property var getNetworkColor
|
||||||
|
property var getNetworkFullName
|
||||||
|
property var getNetworkShortName
|
||||||
|
property var formatCurrencyAmount
|
||||||
|
property var getNameForSavedWalletAddress
|
||||||
|
property var getNameForAddress
|
||||||
|
property var getEnsForSavedWalletAddress
|
||||||
|
property var getChainShortNamesForSavedWalletAddress
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,6 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: sensor
|
id: sensor
|
||||||
|
|
||||||
z: 1 // Gives ability to hide siblings under the MouseArea
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
acceptedButtons: Qt.NoButton
|
acceptedButtons: Qt.NoButton
|
||||||
|
@ -289,7 +288,7 @@ Rectangle {
|
||||||
objectName: "statusListItemSubTitle"
|
objectName: "statusListItemSubTitle"
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.preferredWidth: inlineTagModelRepeater.count > 0 ? contentWidth : parent.width
|
Layout.preferredWidth: inlineTagModelRepeater.count > 0 ? contentWidth : parent.width - subTitleBadgeLoader.width
|
||||||
|
|
||||||
text: root.subTitle
|
text: root.subTitle
|
||||||
font.pixelSize: 15
|
font.pixelSize: 15
|
||||||
|
|
|
@ -45,11 +45,6 @@ ColumnLayout {
|
||||||
readonly property int progress: (Math.floor(Date.now() / 1000) - root.timeStamp) / 3600
|
readonly property int progress: (Math.floor(Date.now() / 1000) - root.timeStamp) / 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusTxProgressBar {
|
StatusTxProgressBar {
|
||||||
id: progressBar
|
id: progressBar
|
||||||
Layout.topMargin: 8
|
Layout.topMargin: 8
|
||||||
|
@ -133,10 +128,4 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
implicitHeight: 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ StatusMenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
function openMenu(delegate) {
|
function openMenu(delegate) {
|
||||||
const x = delegate.width - root.contentWidth / 2
|
const x = delegate.width - 40
|
||||||
const y = delegate.height / 2 + 20
|
const y = delegate.height / 2 + 20
|
||||||
root.popup(delegate, x, y)
|
root.popup(delegate, x, y)
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,7 @@ StatusMenu {
|
||||||
function openEthAddressMenu(delegate, address) {
|
function openEthAddressMenu(delegate, address) {
|
||||||
d.selectedAddress = address
|
d.selectedAddress = address
|
||||||
|
|
||||||
|
address = address.toLowerCase()
|
||||||
const contactPubKey = "" // TODO retrive contact public key or contact data directly from address
|
const contactPubKey = "" // TODO retrive contact public key or contact data directly from address
|
||||||
let contactData = Utils.getContactDetailsAsJson(contactPubKey)
|
let contactData = Utils.getContactDetailsAsJson(contactPubKey)
|
||||||
let isWalletAccount = false
|
let isWalletAccount = false
|
||||||
|
@ -135,6 +136,7 @@ StatusMenu {
|
||||||
function openTxMenu(delegate, address, chainShortName="") {
|
function openTxMenu(delegate, address, chainShortName="") {
|
||||||
d.addressType = TransactionAddressMenu.AddressType.Tx
|
d.addressType = TransactionAddressMenu.AddressType.Tx
|
||||||
d.selectedAddress = address
|
d.selectedAddress = address
|
||||||
|
chainShortName = chainShortName.toLowerCase()
|
||||||
if (chainShortName === root.arbiscanShortChainName) {
|
if (chainShortName === root.arbiscanShortChainName) {
|
||||||
showOnArbiscanAction.enabled = true
|
showOnArbiscanAction.enabled = true
|
||||||
} else if (chainShortName === root.optimismShortChainName) {
|
} else if (chainShortName === root.optimismShortChainName) {
|
||||||
|
@ -149,6 +151,7 @@ StatusMenu {
|
||||||
d.addressType = TransactionAddressMenu.AddressType.Contract
|
d.addressType = TransactionAddressMenu.AddressType.Contract
|
||||||
d.contractName = name
|
d.contractName = name
|
||||||
d.selectedAddress = address
|
d.selectedAddress = address
|
||||||
|
chainShortName = chainShortName.toLowerCase()
|
||||||
if (chainShortName === root.arbiscanShortChainName) {
|
if (chainShortName === root.arbiscanShortChainName) {
|
||||||
showOnArbiscanAction.enabled = true
|
showOnArbiscanAction.enabled = true
|
||||||
} else if (chainShortName === root.optimismShortChainName) {
|
} else if (chainShortName === root.optimismShortChainName) {
|
||||||
|
@ -232,8 +235,6 @@ StatusMenu {
|
||||||
successText: {
|
successText: {
|
||||||
switch(d.addressType) {
|
switch(d.addressType) {
|
||||||
case TransactionAddressMenu.AddressType.Contract:
|
case TransactionAddressMenu.AddressType.Contract:
|
||||||
if (d.contractName.length > 0)
|
|
||||||
return qsTr("%1 contract address copied").arg(d.contractName)
|
|
||||||
return qsTr("Contract address copied")
|
return qsTr("Contract address copied")
|
||||||
case TransactionAddressMenu.AddressType.InputData:
|
case TransactionAddressMenu.AddressType.InputData:
|
||||||
return qsTr("Input data copied")
|
return qsTr("Input data copied")
|
||||||
|
@ -250,8 +251,6 @@ StatusMenu {
|
||||||
defaultText: {
|
defaultText: {
|
||||||
switch(d.addressType) {
|
switch(d.addressType) {
|
||||||
case TransactionAddressMenu.AddressType.Contract:
|
case TransactionAddressMenu.AddressType.Contract:
|
||||||
if (d.contractName.length > 0)
|
|
||||||
return qsTr("Copy %1 contract address").arg(d.contractName)
|
|
||||||
return qsTr("Copy contract address")
|
return qsTr("Copy contract address")
|
||||||
case TransactionAddressMenu.AddressType.InputData:
|
case TransactionAddressMenu.AddressType.InputData:
|
||||||
return qsTr("Copy input data")
|
return qsTr("Copy input data")
|
||||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.13
|
||||||
import QtQuick.Layouts 1.13
|
import QtQuick.Layouts 1.13
|
||||||
import QtQuick.Controls 2.14
|
import QtQuick.Controls 2.14
|
||||||
import QtQuick.Window 2.12
|
import QtQuick.Window 2.12
|
||||||
|
import QtGraphicalEffects 1.15
|
||||||
|
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
|
@ -10,6 +11,7 @@ import StatusQ.Controls 0.1
|
||||||
import StatusQ.Popups 0.1
|
import StatusQ.Popups 0.1
|
||||||
|
|
||||||
import shared.controls 1.0
|
import shared.controls 1.0
|
||||||
|
import shared.panels 1.0
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
import shared.stores 1.0
|
import shared.stores 1.0
|
||||||
|
|
||||||
|
@ -38,96 +40,360 @@ Item {
|
||||||
readonly property string to: root.isTransactionValid ? !!savedAddressNameTo ? savedAddressNameTo : Utils.compactAddress(transaction.to, 4): ""
|
readonly property string to: root.isTransactionValid ? !!savedAddressNameTo ? savedAddressNameTo : Utils.compactAddress(transaction.to, 4): ""
|
||||||
readonly property string savedAddressEns: root.isTransactionValid ? RootStore.getEnsForSavedWalletAddress(isIncoming ? transaction.from : transaction.to) : ""
|
readonly property string savedAddressEns: root.isTransactionValid ? RootStore.getEnsForSavedWalletAddress(isIncoming ? transaction.from : transaction.to) : ""
|
||||||
readonly property string savedAddressChains: root.isTransactionValid ? RootStore.getChainShortNamesForSavedWalletAddress(isIncoming ? transaction.from : transaction.to) : ""
|
readonly property string savedAddressChains: root.isTransactionValid ? RootStore.getChainShortNamesForSavedWalletAddress(isIncoming ? transaction.from : transaction.to) : ""
|
||||||
|
readonly property string networkShortName: root.isTransactionValid ? RootStore.getNetworkShortName(transaction.chainId) : ""
|
||||||
|
readonly property string networkFullName: root.isTransactionValid ? RootStore.getNetworkFullName(transaction.chainId): ""
|
||||||
|
readonly property string networkIcon: root.isTransactionValid ? RootStore.getNetworkIcon(transaction.chainId): ""
|
||||||
|
readonly property int blockNumber: root.isTransactionValid ? RootStore.hex2Dec(root.transaction.blockNumber) : 0
|
||||||
|
readonly property string bridgeNetworkIcon: "" // TODO fill when bridge data is implemented
|
||||||
|
readonly property string bridgeNetworkFullname: "" // TODO fill when bridge data is implemented
|
||||||
|
readonly property string bridgeNetworkShortName: "" // TODO fill when bridge data is implemented
|
||||||
|
readonly property int bridgeBlockNumber: 0 // TODO fill when bridge data is implemented
|
||||||
|
readonly property string swapSymbol: "" // TODO fill when swap data is implemented
|
||||||
|
readonly property string symbol: root.isTransactionValid ? transaction.symbol : ""
|
||||||
|
readonly property var multichainNetworks: [] // TODO fill icon for networks for multichain
|
||||||
|
|
||||||
function getNameForSavedWalletAddress(address) {
|
function getNameForSavedWalletAddress(address) {
|
||||||
return RootStore.getNameForSavedWalletAddress(address)
|
return RootStore.getNameForSavedWalletAddress(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function retryTransaction() {
|
||||||
|
// TODO handle failed transaction retry
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StatusScrollView {
|
StatusScrollView {
|
||||||
|
id: scrollView
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
contentHeight: column.height
|
contentHeight: column.height
|
||||||
contentWidth: parent.width
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: column
|
id: column
|
||||||
width: parent.width - Style.current.xlPadding
|
width: scrollView.availableWidth - Style.current.xlPadding
|
||||||
|
|
||||||
spacing: Style.current.bigPadding
|
spacing: Style.current.xlPadding + Style.current.halfPadding
|
||||||
|
|
||||||
TransactionDelegate {
|
Column {
|
||||||
id: transactionHeader
|
|
||||||
objectName: "transactionDetailHeader"
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
leftPadding: 0
|
spacing: Style.current.bigPadding
|
||||||
|
|
||||||
modelData: transaction
|
TransactionDelegate {
|
||||||
transactionType: d.isIncoming ? TransactionDelegate.Receive : TransactionDelegate.Send
|
id: transactionHeader
|
||||||
currentCurrency: RootStore.currentCurrency
|
objectName: "transactionDetailHeader"
|
||||||
cryptoValue: root.isTransactionValid ? transaction.value.amount: 0.0
|
width: parent.width
|
||||||
fiatValue: root.isTransactionValid ? RootStore.getFiatValue(cryptoValue, symbol, currentCurrency): 0.0
|
leftPadding: 0
|
||||||
networkIcon: root.isTransactionValid ? RootStore.getNetworkIcon(transaction.chainId): ""
|
|
||||||
networkColor: root.isTransactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
|
||||||
networkName: root.isTransactionValid ? RootStore.getNetworkFullName(transaction.chainId): ""
|
|
||||||
symbol: root.isTransactionValid ? transaction.symbol : ""
|
|
||||||
transferStatus: root.isTransactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
|
||||||
timeStampText: root.isTransactionValid ? qsTr("Signed at %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)): ""
|
|
||||||
addressNameTo: root.isTransactionValid ? WalletStores.RootStore.getNameForAddress(transaction.to): ""
|
|
||||||
addressNameFrom: root.isTransactionValid ? WalletStores.RootStore.getNameForAddress(transaction.from): ""
|
|
||||||
sensor.enabled: false
|
|
||||||
formatCurrencyAmount: RootStore.formatCurrencyAmount
|
|
||||||
color: Theme.palette.transparent
|
|
||||||
state: "header"
|
|
||||||
|
|
||||||
onRetryClicked: {
|
modelData: transaction
|
||||||
// TODO handle failed transaction retry
|
transactionType: d.isIncoming ? TransactionDelegate.Receive : TransactionDelegate.Send
|
||||||
|
currentCurrency: RootStore.currentCurrency
|
||||||
|
cryptoValue: root.isTransactionValid ? transaction.value.amount: 0.0
|
||||||
|
fiatValue: root.isTransactionValid ? RootStore.getFiatValue(cryptoValue, symbol, currentCurrency): 0.0
|
||||||
|
networkIcon: d.networkIcon
|
||||||
|
networkColor: root.isTransactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
||||||
|
networkName: d.networkFullName
|
||||||
|
swapSymbol: d.swapSymbol
|
||||||
|
bridgeNetworkName: d.bridgeNetworkFullname
|
||||||
|
symbol: d.symbol
|
||||||
|
transferStatus: root.isTransactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
||||||
|
timeStampText: root.isTransactionValid ? qsTr("Signed at %1").arg(LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat)): ""
|
||||||
|
addressNameTo: root.isTransactionValid ? WalletStores.RootStore.getNameForAddress(transaction.to): ""
|
||||||
|
addressNameFrom: root.isTransactionValid ? WalletStores.RootStore.getNameForAddress(transaction.from): ""
|
||||||
|
sensor.enabled: false
|
||||||
|
formatCurrencyAmount: RootStore.formatCurrencyAmount
|
||||||
|
color: Theme.palette.transparent
|
||||||
|
state: "header"
|
||||||
|
onRetryClicked: d.retryTransaction()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Separator { }
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletTxProgressBlock {
|
WalletTxProgressBlock {
|
||||||
|
id: progressBlock
|
||||||
width: Math.min(513, root.width)
|
width: Math.min(513, root.width)
|
||||||
error: transactionHeader.transactionStatus === TransactionDelegate.TransactionStatus.Failed
|
error: transactionHeader.transactionStatus === TransactionDelegate.TransactionStatus.Failed
|
||||||
isLayer1: RootStore.getNetworkLayer(root.transaction.chainId) == 1
|
isLayer1: RootStore.getNetworkLayer(root.transaction.chainId) == 1
|
||||||
confirmations: root.isTransactionValid ? Math.abs(WalletStores.RootStore.getLatestBlockNumber(root.transaction.chainId) - RootStore.hex2Dec(root.transaction.blockNumber)): 0
|
confirmations: root.isTransactionValid ? Math.abs(WalletStores.RootStore.getLatestBlockNumber(root.transaction.chainId) - d.blockNumber): 0
|
||||||
chainName: root.isTransactionValid ? RootStore.getNetworkFullName(root.transaction.chainId): ""
|
chainName: d.networkFullName
|
||||||
timeStamp: root.isTransactionValid ? transaction.timestamp: ""
|
timeStamp: root.isTransactionValid ? transaction.timestamp: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
SavedAddressesDelegate {
|
Separator {
|
||||||
width: parent.width
|
width: progressBlock.width
|
||||||
|
|
||||||
name: d.isIncoming ? d.savedAddressNameFrom : d.savedAddressNameTo
|
|
||||||
address: root.isTransactionValid ? d.isIncoming ? transaction.from : transaction.to : ""
|
|
||||||
ens: d.savedAddressEns
|
|
||||||
chainShortNames: d.savedAddressChains
|
|
||||||
title: d.isIncoming ? d.from : d.to
|
|
||||||
subTitle: root.isTransactionValid ? d.isIncoming ? !!d.savedAddressNameFrom ? Utils.compactAddress(transaction.from, 4) : "" : !!d.savedAddressNameTo ? Utils.compactAddress(transaction.to, 4) : "": ""
|
|
||||||
store: WalletStores.RootStore
|
|
||||||
contactsStore: root.contactsStore
|
|
||||||
onOpenSendModal: root.sendModal.open(address);
|
|
||||||
saveAddress: function(name, address, favourite, chainShortNames, ens) {
|
|
||||||
RootStore.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens)
|
|
||||||
}
|
|
||||||
deleteSavedAddress: function(address, ens) {
|
|
||||||
RootStore.deleteSavedAddress(address, ens)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusExpandableItem {
|
Column {
|
||||||
width: parent.width
|
width: progressBlock.width
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
spacing: 0
|
||||||
|
|
||||||
type: StatusExpandableItem.Type.Tertiary
|
StatusBaseText {
|
||||||
expandable: true
|
width: parent.width
|
||||||
primaryText: qsTr("Transaction summary")
|
font.pixelSize: 15
|
||||||
expandableComponent: transactionSummary
|
color: Theme.palette.directColor5
|
||||||
separatorVisible: false
|
text: qsTr("Transaction summary")
|
||||||
expanded: true
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: Style.current.smallPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
DetailsPanel {
|
||||||
|
RowLayout {
|
||||||
|
spacing: 0
|
||||||
|
width: parent.width
|
||||||
|
height: opacity > 0 ? Math.max(implicitHeight, 85) : 0
|
||||||
|
opacity: fromNetworkTile.visible || toNetworkTile.visible ? 1 : 0
|
||||||
|
TransactionDataTile {
|
||||||
|
id: fromNetworkTile
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
title: qsTr("From")
|
||||||
|
subTitle: {
|
||||||
|
switch(transactionHeader.transactionType) {
|
||||||
|
case TransactionDelegate.Swap:
|
||||||
|
return d.symbol
|
||||||
|
case TransactionDelegate.Bridge:
|
||||||
|
return d.networkFullName
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
asset.name: {
|
||||||
|
switch(transactionHeader.transactionType) {
|
||||||
|
case TransactionDelegate.Swap:
|
||||||
|
return !!d.symbol ? Style.png("tokens/%1".arg(d.symbol)) : ""
|
||||||
|
case TransactionDelegate.Bridge:
|
||||||
|
return !!d.networkIcon ? Style.svg(d.networkIcon) : ""
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visible: !!subTitle
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
id: toNetworkTile
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
title: qsTr("To")
|
||||||
|
subTitle: {
|
||||||
|
switch(transactionHeader.transactionType) {
|
||||||
|
case TransactionDelegate.Swap:
|
||||||
|
return d.swapSymbol
|
||||||
|
case TransactionDelegate.Bridge:
|
||||||
|
return d.bridgeNetworkFullname
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
asset.name: {
|
||||||
|
switch(transactionHeader.transactionType) {
|
||||||
|
case TransactionDelegate.Swap:
|
||||||
|
return !!d.swapSymbol ? Style.png("tokens/%1".arg(d.swapSymbol)) : ""
|
||||||
|
case TransactionDelegate.Bridge:
|
||||||
|
return !!d.bridgeNetworkIcon ? Style.svg(d.bridgeNetworkIcon) : ""
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visible: !!subTitle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TransactionAddressTile {
|
||||||
|
width: parent.width
|
||||||
|
title: transactionHeader.transactionType === TransactionDelegate.Swap || transactionHeader.transactionType === TransactionDelegate.Bridge ?
|
||||||
|
qsTr("In") : qsTr("From")
|
||||||
|
addresses: root.isTransactionValid ? [root.transaction.from] : []
|
||||||
|
contactsStore: root.contactsStore
|
||||||
|
rootStore: WalletStores.RootStore
|
||||||
|
onButtonClicked: {
|
||||||
|
if (transactionHeader.transactionType === TransactionDelegate.Swap || transactionHeader.transactionType === TransactionDelegate.Bridge) {
|
||||||
|
addressMenu.openEthAddressMenu(this, addresses[0])
|
||||||
|
} else {
|
||||||
|
addressMenu.openSenderMenu(this, addresses[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TransactionAddressTile {
|
||||||
|
width: parent.width
|
||||||
|
title: qsTr("To")
|
||||||
|
addresses: root.isTransactionValid ? [root.transaction.to] : []
|
||||||
|
contactsStore: root.contactsStore
|
||||||
|
rootStore: WalletStores.RootStore
|
||||||
|
onButtonClicked: addressMenu.openReceiverMenu(this, addresses[0])
|
||||||
|
visible: transactionHeader.transactionType !== TransactionDelegate.Swap && transactionHeader.transactionType !== TransactionDelegate.Bridge && transactionHeader.transactionType !== TransactionDelegate.Destroy
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: qsTr("Using")
|
||||||
|
buttonIconName: "external"
|
||||||
|
subTitle: "" // TODO fill protocol name for Swap and Bridge
|
||||||
|
asset.name: "" // TODO fill protocol icon for Bridge and Swap e.g. Style.svg("network/Network=Arbitrum")
|
||||||
|
onButtonClicked: {
|
||||||
|
// TODO handle
|
||||||
|
}
|
||||||
|
visible: !!subTitle
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: qsTr("%1 Tx hash").arg(d.networkFullName)
|
||||||
|
subTitle: root.isTransactionValid ? root.transaction.txHash : ""
|
||||||
|
visible: !!subTitle
|
||||||
|
buttonIconName: "more"
|
||||||
|
onButtonClicked: addressMenu.openTxMenu(this, subTitle, d.networkShortName)
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: qsTr("%1 Tx hash").arg(d.bridgeNetworkFullname)
|
||||||
|
subTitle: "" // TODO fill tx hash for Bridge
|
||||||
|
visible: !!subTitle
|
||||||
|
buttonIconName: "more"
|
||||||
|
onButtonClicked: addressMenu.openTxMenu(this, subTitle, d.bridgeNetworkShortName)
|
||||||
|
}
|
||||||
|
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: d.networkFullName
|
||||||
|
shortNetworkName: d.networkShortName
|
||||||
|
visible: !!subTitle && (transactionHeader.transactionType === TransactionDelegate.Bridge || transactionHeader.transactionType === TransactionDelegate.Swap)
|
||||||
|
}
|
||||||
|
TransactionContractTile {
|
||||||
|
// Used to display contract address for any network
|
||||||
|
address: root.isTransactionValid ? transaction.contract : ""
|
||||||
|
symbol: root.isTransactionValid ? transaction.value.symbol.toUpperCase() : ""
|
||||||
|
networkName: d.networkFullName
|
||||||
|
shortNetworkName: d.networkShortName
|
||||||
|
}
|
||||||
|
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: d.bridgeNetworkFullname
|
||||||
|
shortNetworkName: d.bridgeNetworkShortName
|
||||||
|
visible: !!subTitle && transactionHeader.transactionType === TransactionDelegate.Bridge
|
||||||
|
}
|
||||||
|
TransactionContractTile {
|
||||||
|
// Used for Bridge and Swap to display 'To' network token contract address
|
||||||
|
address: {
|
||||||
|
if (!root.isTransactionValid)
|
||||||
|
return ""
|
||||||
|
switch(transactionHeader.transactionType) {
|
||||||
|
case TransactionDelegate.Swap:
|
||||||
|
return transaction.contract
|
||||||
|
case TransactionDelegate.Bridge:
|
||||||
|
return "" // TODO fill swap token's contract address for 'to' network for Bridge
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symbol: {
|
||||||
|
if (!root.isTransactionValid)
|
||||||
|
return ""
|
||||||
|
switch(transactionHeader.transactionType) {
|
||||||
|
case TransactionDelegate.Swap:
|
||||||
|
return d.swapSymbol
|
||||||
|
case TransactionDelegate.Bridge:
|
||||||
|
return transaction.value.symbol.toUpperCase()
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
networkName: d.bridgeNetworkFullname
|
||||||
|
shortNetworkName: d.bridgeNetworkShortName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: Style.current.bigPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
DetailsPanel {
|
||||||
|
width: progressBlock.width
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
height: Math.max(implicitHeight, 85)
|
||||||
|
spacing: 0
|
||||||
|
TransactionDataTile {
|
||||||
|
id: multichainNetworksTile
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
title: qsTr("Networks")
|
||||||
|
visible: d.multichainNetworks.length > 0
|
||||||
|
Row {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: multichainNetworksTile.statusListItemTitleArea.height + multichainNetworksTile.topPadding
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: multichainNetworksTile.leftPadding
|
||||||
|
}
|
||||||
|
spacing: -4
|
||||||
|
Repeater {
|
||||||
|
model: d.multichainNetworks
|
||||||
|
delegate: StatusRoundedImage {
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
visible: image.source !== ""
|
||||||
|
border.width: index === 0 ? 0 : 1
|
||||||
|
border.color: Theme.palette.white
|
||||||
|
image.source: Style.svg("tiny/" + modelData)
|
||||||
|
z: index + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
title: qsTr("Network")
|
||||||
|
subTitle: d.networkFullName
|
||||||
|
asset.name: !!d.networkIcon ? Style.svg("%1".arg(d.networkIcon)) : ""
|
||||||
|
smallIcon: true
|
||||||
|
visible: transactionHeader.transactionType !== TransactionDelegate.Bridge
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
title: qsTr("Token format")
|
||||||
|
subTitle: root.isTransactionValid ? transaction.type.toUpperCase() : ""
|
||||||
|
visible: !!subTitle
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
title: qsTr("Nonce")
|
||||||
|
subTitle: root.isTransactionValid ? RootStore.hex2Dec(root.transaction.nonce) : ""
|
||||||
|
visible: !!subTitle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: qsTr("Input data")
|
||||||
|
subTitle: root.isTransactionValid ? root.transaction.input : ""
|
||||||
|
visible: !!subTitle
|
||||||
|
buttonIconName: "more"
|
||||||
|
onButtonClicked: addressMenu.openInputDataMenu(this, subTitle)
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: !!d.networkFullName ? qsTr("Included in Block on %1").arg(d.networkFullName) : qsTr("Included on Block")
|
||||||
|
subTitle: d.blockNumber
|
||||||
|
tertiaryTitle: root.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : ""
|
||||||
|
visible: d.blockNumber > 0
|
||||||
|
}
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: !!d.bridgeNetworkFullname ? qsTr("Included in Block on %1").arg(d.bridgeNetworkFullname) : qsTr("Included on Block")
|
||||||
|
subTitle: d.bridgeBlockNumber
|
||||||
|
tertiaryTitle: root.isTransactionValid ? LocaleUtils.formatDateTime(transaction.timestamp * 1000, Locale.LongFormat) : ""
|
||||||
|
visible: d.bridgeBlockNumber > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusExpandableItem {
|
StatusExpandableItem {
|
||||||
|
@ -140,76 +406,6 @@ Item {
|
||||||
expandableComponent: fees
|
expandableComponent: fees
|
||||||
expanded: true
|
expanded: true
|
||||||
}
|
}
|
||||||
|
|
||||||
InformationTile {
|
|
||||||
maxWidth: parent.width
|
|
||||||
primaryText: qsTr("Data")
|
|
||||||
secondaryText: root.isTransactionValid ? root.transaction.input : ""
|
|
||||||
copy: true
|
|
||||||
onCopyClicked: RootStore.copyToClipboard(textToCopy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: transactionSummary
|
|
||||||
Column {
|
|
||||||
id: column
|
|
||||||
width: parent.width
|
|
||||||
spacing: 8
|
|
||||||
TransactionDelegate {
|
|
||||||
width: parent.width
|
|
||||||
modelData: transaction
|
|
||||||
transactionType: d.isIncoming ? TransactionDelegate.Receive : TransactionDelegate.Send
|
|
||||||
currentCurrency: RootStore.currentCurrency
|
|
||||||
cryptoValue: root.isTransactionValid ? transaction.value.amount: 0.0
|
|
||||||
fiatValue: root.isTransactionValid ? RootStore.getFiatValue(cryptoValue, symbol, currentCurrency): 0.0
|
|
||||||
networkIcon: root.isTransactionValid ? RootStore.getNetworkIcon(transaction.chainId) : ""
|
|
||||||
networkColor: root.isTransactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
|
||||||
networkName: root.isTransactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
|
|
||||||
symbol: root.isTransactionValid ? transaction.symbol : ""
|
|
||||||
transferStatus: root.isTransactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
|
||||||
timeStampText: root.isTransactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
|
|
||||||
addressNameTo: root.isTransactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
|
|
||||||
addressNameFrom: root.isTransactionValid ? RootStore.getNameForSavedWalletAddress(transaction.from): ""
|
|
||||||
formatCurrencyAmount: RootStore.formatCurrencyAmount
|
|
||||||
sensor.enabled: false
|
|
||||||
color: Theme.palette.statusListItem.backgroundColor
|
|
||||||
border.width: 1
|
|
||||||
border.color: Theme.palette.directColor8
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
spacing: 8
|
|
||||||
InformationTile {
|
|
||||||
maxWidth: parent.width
|
|
||||||
primaryText: qsTr("Time")
|
|
||||||
secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 <font color=\"#939BA1\">on</font> %2").
|
|
||||||
arg(LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat)).
|
|
||||||
arg(LocaleUtils.formatDate(transaction.timestamp * 1000, Locale.ShortFormat)): ""
|
|
||||||
}
|
|
||||||
InformationTile {
|
|
||||||
maxWidth: parent.width
|
|
||||||
primaryText: qsTr("Confirmations")
|
|
||||||
secondaryText: {
|
|
||||||
if(root.isTransactionValid)
|
|
||||||
return Math.abs(WalletStores.RootStore.getLatestBlockNumber(root.transaction.chainId) - RootStore.hex2Dec(root.transaction.blockNumber))
|
|
||||||
else
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InformationTile {
|
|
||||||
maxWidth: parent.width
|
|
||||||
primaryText: qsTr("Nonce")
|
|
||||||
secondaryText: root.isTransactionValid ? RootStore.hex2Dec(root.transaction.nonce) : ""
|
|
||||||
}
|
|
||||||
InformationTile {
|
|
||||||
maxWidth: parent.width
|
|
||||||
primaryText: qsTr("TokenID")
|
|
||||||
secondaryText: root.isTransactionValid ? root.transaction.tokenID : ""
|
|
||||||
visible: root.isTransactionValid && d.isNFT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,4 +454,41 @@ Item {
|
||||||
contactsStore: root.contactsStore
|
contactsStore: root.contactsStore
|
||||||
onOpenSendModal: (address) => root.sendModal.open(address)
|
onOpenSendModal: (address) => root.sendModal.open(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component DetailsPanel: Item {
|
||||||
|
width: parent.width
|
||||||
|
height: detailsColumn.childrenRect.height
|
||||||
|
default property alias content: detailsColumn.children
|
||||||
|
Rectangle {
|
||||||
|
id: tileBackground
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 8
|
||||||
|
border.width: 1
|
||||||
|
border.color: Style.current.separator
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: detailsColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 1
|
||||||
|
spacing: 0
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
maskSource: tileBackground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component TransactionContractTile: TransactionDataTile {
|
||||||
|
property string networkName: ""
|
||||||
|
property string symbol: ""
|
||||||
|
property string address: ""
|
||||||
|
property string shortNetworkName: ""
|
||||||
|
width: parent.width
|
||||||
|
title: 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,7 @@ Item {
|
||||||
font.pixelSize: 15
|
font.pixelSize: 15
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
wrapMode: Text.WrapAnywhere
|
wrapMode: Text.WrapAnywhere
|
||||||
|
enabled: false // Set to false to disable hover for rich text
|
||||||
text: {
|
text: {
|
||||||
if(!!root.address == false)
|
if(!!root.address == false)
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -9,7 +9,7 @@ import StatusQ.Core.Theme 0.1
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype TransactionAddressTile
|
\qmltype TransactionAddressTile
|
||||||
\inherits StatusListItem
|
\inherits TransactionDataTile
|
||||||
\inqmlmodule shared.controls
|
\inqmlmodule shared.controls
|
||||||
\since shared.controls 1.0
|
\since shared.controls 1.0
|
||||||
\brief It displays list of addresses for wallet activity.
|
\brief It displays list of addresses for wallet activity.
|
||||||
|
@ -21,7 +21,6 @@ import StatusQ.Core.Theme 0.1
|
||||||
title: qsTr("From")
|
title: qsTr("From")
|
||||||
width: parent.width
|
width: parent.width
|
||||||
rootStore: WalletStores.RootStore
|
rootStore: WalletStores.RootStore
|
||||||
roundedCornersBottom: false
|
|
||||||
addresses: [
|
addresses: [
|
||||||
"eth:arb:opt:0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35",
|
"eth:arb:opt:0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35",
|
||||||
"0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35",
|
"0x4de3f6278C0DdFd3F29df9DcD979038F5c7bbc35",
|
||||||
|
@ -30,7 +29,7 @@ import StatusQ.Core.Theme 0.1
|
||||||
\endqml
|
\endqml
|
||||||
*/
|
*/
|
||||||
|
|
||||||
StatusListItem {
|
TransactionDataTile {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -44,48 +43,11 @@ StatusListItem {
|
||||||
*/
|
*/
|
||||||
property var rootStore
|
property var rootStore
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlproperty int TransactionAddressTile::topPadding
|
|
||||||
This property holds spacing between top and content item in tile.
|
|
||||||
*/
|
|
||||||
property int topPadding: 12
|
|
||||||
/*!
|
|
||||||
\qmlproperty int TransactionAddressTile::bottomPadding
|
|
||||||
This property holds spacing between bottom and content item in tile.
|
|
||||||
*/
|
|
||||||
property int bottomPadding: 12
|
|
||||||
|
|
||||||
/* /internal Property hold reference to contacts store to refresh contact data on any change. */
|
/* /internal Property hold reference to contacts store to refresh contact data on any change. */
|
||||||
property var contactsStore
|
property var contactsStore
|
||||||
|
|
||||||
signal showContextMenu()
|
implicitHeight: transactionColumn.height + transactionColumn.spacing + root.topPadding + root.bottomPadding
|
||||||
|
buttonIconName: "more"
|
||||||
leftPadding: 12
|
|
||||||
rightPadding: 12
|
|
||||||
radius: 0
|
|
||||||
|
|
||||||
implicitHeight: transactionColumn.height + statusListItemTitleArea.height + root.topPadding + root.bottomPadding
|
|
||||||
statusListItemTitle.customColor: Theme.palette.directColor5
|
|
||||||
statusListItemTitleArea.anchors {
|
|
||||||
top: statusListItemTitleArea.parent.top
|
|
||||||
topMargin: root.topPadding
|
|
||||||
right: statusListItemTitleArea.parent.right
|
|
||||||
verticalCenter: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
components: [
|
|
||||||
StatusRoundButton {
|
|
||||||
id: button
|
|
||||||
width: 32
|
|
||||||
height: 32
|
|
||||||
icon.color: hovered ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
|
||||||
icon.name: "more"
|
|
||||||
type: StatusRoundButton.Type.Quinary
|
|
||||||
radius: 8
|
|
||||||
visible: root.sensor.containsMouse
|
|
||||||
onClicked: root.showContextMenu()
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: transactionColumn
|
id: transactionColumn
|
||||||
|
@ -93,14 +55,12 @@ StatusListItem {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
leftMargin: root.leftPadding
|
leftMargin: root.leftPadding
|
||||||
right: parent.right
|
right: parent.right
|
||||||
rightMargin: button.width + root.rightPadding * 2
|
rightMargin: root.statusListItemComponentsSlot.width + root.rightPadding * 2
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
bottomMargin: root.bottomPadding
|
bottomMargin: root.bottomPadding
|
||||||
}
|
}
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
spacing: 4
|
spacing: 4
|
||||||
// Moving it under sensor, because Rich Text steals hovering
|
|
||||||
z: root.sensor.z - 1
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.addresses
|
model: root.addresses
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import QtQuick 2.13
|
||||||
|
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import shared.panels 1.0
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype TransactionDataTile
|
||||||
|
\inherits StatusListItem
|
||||||
|
\inqmlmodule shared.controls
|
||||||
|
\since shared.controls 1.0
|
||||||
|
\brief It displays data for wallet activity.
|
||||||
|
|
||||||
|
The \c TransactionDataTile can display wallet activity data as a tile.
|
||||||
|
To show button fill \l{buttonIcon} property.
|
||||||
|
|
||||||
|
\qml
|
||||||
|
TransactionDataTile {
|
||||||
|
width: parent.width
|
||||||
|
title: qsTr("From")
|
||||||
|
buttonIcon: "more"
|
||||||
|
}
|
||||||
|
\endqml
|
||||||
|
*/
|
||||||
|
|
||||||
|
StatusListItem {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty int TransactionDataTile::topPadding
|
||||||
|
This property holds spacing between top and content item in tile.
|
||||||
|
*/
|
||||||
|
property int topPadding: 12
|
||||||
|
/*!
|
||||||
|
\qmlproperty int TransactionDataTile::bottomPadding
|
||||||
|
This property holds spacing between bottom and content item in tile.
|
||||||
|
*/
|
||||||
|
property int bottomPadding: 12
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty bool TransactionDataTile::smallIcon
|
||||||
|
This property holds information about icon state. Setting it to true will display small icon before subtitle.
|
||||||
|
|
||||||
|
Default value is false.
|
||||||
|
*/
|
||||||
|
property bool smallIcon: false
|
||||||
|
/*!
|
||||||
|
\qmlproperty string TransactionDataTile::buttonIconName
|
||||||
|
This property holds button icon source string.
|
||||||
|
To show button icon source must be filled
|
||||||
|
*/
|
||||||
|
property string buttonIconName
|
||||||
|
|
||||||
|
signal buttonClicked()
|
||||||
|
|
||||||
|
leftPadding: 12
|
||||||
|
rightPadding: 12
|
||||||
|
height: implicitHeight + bottomPadding
|
||||||
|
radius: 0
|
||||||
|
sensor.cursorShape: Qt.ArrowCursor
|
||||||
|
|
||||||
|
// Title
|
||||||
|
statusListItemTitle.customColor: Theme.palette.directColor5
|
||||||
|
statusListItemTitle.enabled: false
|
||||||
|
statusListItemTitleArea.anchors {
|
||||||
|
left: statusListItemTitleArea.parent.left
|
||||||
|
top: statusListItemTitleArea.parent.top
|
||||||
|
topMargin: topPadding
|
||||||
|
right: statusListItemTitleArea.parent.right
|
||||||
|
verticalCenter: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtitle
|
||||||
|
statusListItemTagsRowLayout.anchors.topMargin: 8
|
||||||
|
statusListItemTagsRowLayout.width: statusListItemTagsRowLayout.parent.width - (!!root.buttonIconName ? 36 : 0)
|
||||||
|
statusListItemSubTitle.customColor: Theme.palette.directColor1
|
||||||
|
|
||||||
|
// Tertiary title
|
||||||
|
statusListItemTertiaryTitle.anchors.topMargin: -statusListItemTertiaryTitle.height
|
||||||
|
statusListItemTertiaryTitle.horizontalAlignment: Qt.AlignRight
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
asset.isImage: false
|
||||||
|
statusListItemTagsRowLayout.spacing: 8
|
||||||
|
subTitleBadgeComponent: !!asset.name ? iconComponent : null
|
||||||
|
statusListItemIcon.asset: StatusAssetSettings {}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: iconComponent
|
||||||
|
StatusRoundIcon {
|
||||||
|
asset: StatusAssetSettings {
|
||||||
|
name: root.asset.name
|
||||||
|
color: "transparent"
|
||||||
|
width: root.smallIcon ? 20 : 36
|
||||||
|
height: root.smallIcon ? 20 : 36
|
||||||
|
bgWidth: width
|
||||||
|
bgHeight: height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
components: Loader {
|
||||||
|
active: !!root.buttonIconName
|
||||||
|
sourceComponent: StatusRoundButton {
|
||||||
|
width: 32
|
||||||
|
height: 32
|
||||||
|
icon.color: hovered ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||||
|
icon.name: root.buttonIconName
|
||||||
|
type: StatusRoundButton.Type.Quinary
|
||||||
|
radius: 8
|
||||||
|
visible: root.sensor.containsMouse
|
||||||
|
onClicked: root.buttonClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,7 +55,7 @@ StatusListItem {
|
||||||
property string symbol
|
property string symbol
|
||||||
property string swapSymbol // TODO fill when swap data is implemented
|
property string swapSymbol // TODO fill when swap data is implemented
|
||||||
property int transactionType
|
property int transactionType
|
||||||
property int transactionStatus: transferStatus === 0 ? TransactionDelegate.TransactionStatus.Failed : TransactionDelegate.TransactionStatus.Finished
|
property int transactionStatus: transferStatus === 0 ? TransactionDelegate.TransactionStatus.Pending : TransactionDelegate.TransactionStatus.Finished
|
||||||
property string currentCurrency
|
property string currentCurrency
|
||||||
property int transferStatus
|
property int transferStatus
|
||||||
property double cryptoValue
|
property double cryptoValue
|
||||||
|
|
|
@ -26,6 +26,7 @@ Timer 1.0 Timer.qml
|
||||||
TransactionDelegate 1.0 TransactionDelegate.qml
|
TransactionDelegate 1.0 TransactionDelegate.qml
|
||||||
TransactionAddress 1.0 TransactionAddress.qml
|
TransactionAddress 1.0 TransactionAddress.qml
|
||||||
TransactionAddressTile 1.0 TransactionAddressTile.qml
|
TransactionAddressTile 1.0 TransactionAddressTile.qml
|
||||||
|
TransactionDataTile 1.0 TransactionDataTile.qml
|
||||||
TransactionFormGroup 1.0 TransactionFormGroup.qml
|
TransactionFormGroup 1.0 TransactionFormGroup.qml
|
||||||
EmojiHash 1.0 EmojiHash.qml
|
EmojiHash 1.0 EmojiHash.qml
|
||||||
InformationTile 1.0 InformationTile.qml
|
InformationTile 1.0 InformationTile.qml
|
||||||
|
|
Loading…
Reference in New Issue