2024-10-15 19:26:12 +00:00
|
|
|
|
import QtQuick 2.15
|
|
|
|
|
import QtQuick.Layouts 1.15
|
2022-07-01 11:24:32 +00:00
|
|
|
|
|
|
|
|
|
import utils 1.0
|
|
|
|
|
|
|
|
|
|
import StatusQ.Controls 0.1
|
|
|
|
|
import StatusQ.Popups 0.1
|
|
|
|
|
import StatusQ.Components 0.1
|
|
|
|
|
import StatusQ.Core 0.1
|
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
|
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
|
|
|
|
|
2024-05-22 08:13:39 +00:00
|
|
|
|
import shared.stores 1.0 as SharedStores
|
|
|
|
|
import shared.stores.send 1.0 as SharedSendStores
|
|
|
|
|
|
2022-12-19 13:02:56 +00:00
|
|
|
|
import "../controls"
|
|
|
|
|
|
2022-07-01 11:24:32 +00:00
|
|
|
|
Item {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
id: root
|
2022-07-01 11:24:32 +00:00
|
|
|
|
|
2024-05-22 08:13:39 +00:00
|
|
|
|
property SharedSendStores.TransactionStore store
|
|
|
|
|
readonly property SharedStores.CurrenciesStore currencyStore: store.currencyStore
|
2023-08-15 18:21:51 +00:00
|
|
|
|
property string receiverIdentityText
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property var selectedAsset
|
|
|
|
|
property bool customMode: false
|
2023-02-17 12:56:31 +00:00
|
|
|
|
property double amountToSend
|
2023-02-17 14:09:15 +00:00
|
|
|
|
property int minSendCryptoDecimals: 0
|
|
|
|
|
property int minReceiveCryptoDecimals: 0
|
2023-02-17 12:56:31 +00:00
|
|
|
|
property bool errorMode: d.customAmountToSend > root.amountToSend
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property bool interactive: true
|
|
|
|
|
property var weiToEth: function(wei) {}
|
2022-11-15 11:22:03 +00:00
|
|
|
|
property var reCalculateSuggestedRoute: function() {}
|
2024-07-03 08:51:15 +00:00
|
|
|
|
property var fromNetworksList
|
|
|
|
|
property var toNetworksList
|
2022-12-19 13:02:56 +00:00
|
|
|
|
property int errorType: Constants.NoError
|
|
|
|
|
property bool isLoading
|
2022-07-01 11:24:32 +00:00
|
|
|
|
|
|
|
|
|
QtObject {
|
|
|
|
|
id: d
|
|
|
|
|
property double customAmountToSend: 0
|
2024-03-28 17:47:49 +00:00
|
|
|
|
// Collectibles don't have a symbol
|
|
|
|
|
readonly property string selectedSymbol: !!selectedAsset && !!selectedAsset.symbol ? selectedAsset.symbol : ""
|
2022-07-01 11:24:32 +00:00
|
|
|
|
|
2022-10-17 10:17:25 +00:00
|
|
|
|
function resetAllSetValues() {
|
|
|
|
|
for(var i = 0; i<fromNetworksRepeater.count; i++) {
|
2022-11-29 21:47:26 +00:00
|
|
|
|
fromNetworksRepeater.itemAt(i).routeOnNetwork = 0
|
2024-07-03 08:51:15 +00:00
|
|
|
|
}
|
|
|
|
|
for(var i = 0; i<toNetworksRepeater.count; i++) {
|
2022-11-29 21:47:26 +00:00
|
|
|
|
toNetworksRepeater.itemAt(i).routeOnNetwork = 0
|
2022-12-19 13:02:56 +00:00
|
|
|
|
toNetworksRepeater.itemAt(i).bentLine = 0
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-01 15:48:44 +00:00
|
|
|
|
|
2022-11-25 09:13:02 +00:00
|
|
|
|
function calculateCustomAmounts() {
|
|
|
|
|
d.customAmountToSend = 0
|
|
|
|
|
for(var i = 0; i<fromNetworksRepeater.count; i++) {
|
|
|
|
|
if(fromNetworksRepeater.itemAt(i).locked) {
|
2023-02-17 12:56:31 +00:00
|
|
|
|
let amountEntered = fromNetworksRepeater.itemAt(i).advancedInputCurrencyAmount
|
2022-11-25 09:13:02 +00:00
|
|
|
|
d.customAmountToSend += isNaN(amountEntered) ? 0 : amountEntered
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-01 15:48:44 +00:00
|
|
|
|
function draw() {
|
|
|
|
|
canvas.clear()
|
|
|
|
|
canvas.requestPaint()
|
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-01 15:48:44 +00:00
|
|
|
|
onVisibleChanged: if(visible) d.draw()
|
2022-11-25 09:13:02 +00:00
|
|
|
|
onErrorModeChanged: if(errorMode) d.draw()
|
2022-12-01 15:48:44 +00:00
|
|
|
|
|
2022-10-17 10:17:25 +00:00
|
|
|
|
height: visible ? networkCardsLayout.height : 0
|
|
|
|
|
|
2022-07-01 11:24:32 +00:00
|
|
|
|
RowLayout {
|
|
|
|
|
id: networkCardsLayout
|
|
|
|
|
width: parent.width
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
id: fromNetworksLayout
|
|
|
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
|
|
|
spacing: 12
|
|
|
|
|
StatusBaseText {
|
2022-12-19 13:02:56 +00:00
|
|
|
|
Layout.maximumWidth: 100
|
|
|
|
|
elide: Text.ElideRight
|
2022-07-01 11:24:32 +00:00
|
|
|
|
font.pixelSize: 10
|
|
|
|
|
color: Theme.palette.baseColor1
|
2024-10-15 19:26:12 +00:00
|
|
|
|
text: qsTr("Your Balances")
|
|
|
|
|
font.capitalization: Font.AllUppercase
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
Repeater {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
id: fromNetworksRepeater
|
2024-07-03 08:51:15 +00:00
|
|
|
|
model: root.fromNetworksList
|
2022-07-01 11:24:32 +00:00
|
|
|
|
StatusCard {
|
|
|
|
|
id: fromNetwork
|
2023-04-04 16:13:33 +00:00
|
|
|
|
locale: LocaleUtils.userInputLocale
|
2022-10-17 10:17:25 +00:00
|
|
|
|
objectName: model.chainId
|
2023-08-15 18:21:51 +00:00
|
|
|
|
property double advancedInputCurrencyAmount: selectedAsset !== undefined && advancedInput.valid ? LocaleUtils.numberFromLocaleString(advancedInput.text, LocaleUtils.userInputLocale) : 0.0
|
|
|
|
|
property var tokenBalance: model.tokenBalance
|
|
|
|
|
onTokenBalanceChanged: maxAdvancedValue = model.tokenBalance.amount
|
|
|
|
|
property var toNetworks: model.toNetworks
|
2022-11-29 21:47:26 +00:00
|
|
|
|
property int routeOnNetwork: 0
|
2024-07-27 16:21:14 +00:00
|
|
|
|
readonly property bool hasGas: model.hasGas
|
2023-08-15 18:21:51 +00:00
|
|
|
|
onToNetworksChanged: d.draw()
|
2022-11-25 09:13:02 +00:00
|
|
|
|
|
2022-07-01 11:24:32 +00:00
|
|
|
|
primaryText: model.chainName
|
2023-08-15 18:21:51 +00:00
|
|
|
|
secondaryText: (model.tokenBalance.amount === 0 && root.amountToSend > 0) ?
|
|
|
|
|
qsTr("No Balance") : !model.hasGas ? qsTr("No Gas") : root.currencyStore.formatCurrencyAmount(advancedInputCurrencyAmount, d.selectedSymbol, {"minDecimals": root.minSendCryptoDecimals})
|
2024-10-15 19:26:12 +00:00
|
|
|
|
tertiaryText: root.errorMode && advancedInputCurrencyAmount > 0 ? qsTr("EXCEEDS SEND AMOUNT"): qsTr("BALANCE: %1").arg(root.currencyStore.formatCurrencyAmount(model.tokenBalance.amount, d.selectedSymbol))
|
2023-08-15 18:21:51 +00:00
|
|
|
|
locked: model.locked
|
2022-11-25 09:13:02 +00:00
|
|
|
|
preCalculatedAdvancedText: {
|
2023-08-15 18:21:51 +00:00
|
|
|
|
if(locked && model.lockedAmount) {
|
|
|
|
|
let amount = root.weiToEth(parseInt(model.lockedAmount, 16))
|
2023-04-04 16:13:33 +00:00
|
|
|
|
return LocaleUtils.numberToLocaleString(amount, -1, LocaleUtils.userInputLocale)
|
2022-11-25 09:13:02 +00:00
|
|
|
|
}
|
2023-08-15 18:21:51 +00:00
|
|
|
|
else return LocaleUtils.numberToLocaleString(root.weiToEth(model.amountIn), -1, LocaleUtils.userInputLocale)
|
2022-11-25 09:13:02 +00:00
|
|
|
|
}
|
2023-08-15 18:21:51 +00:00
|
|
|
|
maxAdvancedValue: tokenBalance.amount
|
|
|
|
|
state: (model.tokenBalance.amount === 0 && root.amountToSend > 0) || !model.hasGas ? "unavailable" :
|
|
|
|
|
(root.errorMode || !advancedInput.valid) && advancedInputCurrencyAmount > 0 ? "error" : "default"
|
2024-10-15 19:26:12 +00:00
|
|
|
|
cardIcon.source: Theme.svg(model.iconUrl)
|
2022-07-01 11:24:32 +00:00
|
|
|
|
disabledText: qsTr("Disabled")
|
2023-09-15 08:51:06 +00:00
|
|
|
|
disableText: qsTr("Disable")
|
2022-12-19 13:02:56 +00:00
|
|
|
|
enableText: qsTr("Enable")
|
2022-10-17 10:17:25 +00:00
|
|
|
|
advancedMode: root.customMode
|
2024-07-03 08:51:15 +00:00
|
|
|
|
disabled: !model.isRouteEnabled
|
2022-10-17 10:17:25 +00:00
|
|
|
|
clickable: root.interactive
|
2022-07-01 11:24:32 +00:00
|
|
|
|
onClicked: {
|
2023-08-15 18:21:51 +00:00
|
|
|
|
store.toggleFromDisabledChains(model.chainId)
|
2024-07-10 09:02:24 +00:00
|
|
|
|
store.lockCard(model.chainId, 0, false)
|
2023-09-25 12:39:54 +00:00
|
|
|
|
root.reCalculateSuggestedRoute()
|
2022-11-23 17:58:22 +00:00
|
|
|
|
}
|
2023-08-15 18:21:51 +00:00
|
|
|
|
onLockCard: {
|
|
|
|
|
let amount = lock ? (advancedInputCurrencyAmount * Math.pow(10, root.selectedAsset.decimals)).toString(16) : ""
|
|
|
|
|
store.lockCard(model.chainId, amount, lock)
|
2022-11-25 09:13:02 +00:00
|
|
|
|
d.calculateCustomAmounts()
|
2023-09-25 12:39:54 +00:00
|
|
|
|
root.reCalculateSuggestedRoute()
|
2022-11-25 09:13:02 +00:00
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-19 13:02:56 +00:00
|
|
|
|
BalanceExceeded {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
|
errorType: root.errorType
|
2023-01-27 13:16:42 +00:00
|
|
|
|
visible: root.errorType === Constants.NoRoute
|
2022-12-19 13:02:56 +00:00
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
ColumnLayout {
|
2022-12-19 13:02:56 +00:00
|
|
|
|
id: toNetworksLayout
|
2022-07-01 11:24:32 +00:00
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
|
|
|
|
spacing: 12
|
2023-02-01 10:44:22 +00:00
|
|
|
|
|
|
|
|
|
RowLayout {
|
2022-11-25 09:13:02 +00:00
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
2023-02-01 10:44:22 +00:00
|
|
|
|
Layout.maximumWidth: 160
|
|
|
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
|
id: receiverIdentityText
|
|
|
|
|
|
2023-08-15 18:21:51 +00:00
|
|
|
|
text: root.receiverIdentityText
|
2023-02-01 10:44:22 +00:00
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
|
|
font.pixelSize: 10
|
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
|
elide: Text.ElideMiddle
|
|
|
|
|
horizontalAlignment: Text.AlignRight
|
|
|
|
|
}
|
|
|
|
|
StatusBaseText {
|
|
|
|
|
font.pixelSize: receiverIdentityText.font.pixelSize
|
|
|
|
|
color: receiverIdentityText.color
|
|
|
|
|
text: qsTr("WILL RECEIVE")
|
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
2023-02-01 10:44:22 +00:00
|
|
|
|
|
2022-12-19 13:02:56 +00:00
|
|
|
|
Repeater {
|
|
|
|
|
id: toNetworksRepeater
|
2024-07-03 08:51:15 +00:00
|
|
|
|
model: root.toNetworksList
|
2022-12-19 13:02:56 +00:00
|
|
|
|
StatusCard {
|
|
|
|
|
id: toCard
|
2023-04-04 16:13:33 +00:00
|
|
|
|
locale: LocaleUtils.userInputLocale
|
2022-12-19 13:02:56 +00:00
|
|
|
|
objectName: model.chainId
|
2024-07-03 08:51:15 +00:00
|
|
|
|
property bool preferred: model.isRoutePreferred
|
2022-12-19 13:02:56 +00:00
|
|
|
|
property int bentLine: 0
|
2023-08-15 18:21:51 +00:00
|
|
|
|
property int routeOnNetwork: 0
|
2022-12-19 13:02:56 +00:00
|
|
|
|
primaryText: model.chainName
|
2023-08-15 18:21:51 +00:00
|
|
|
|
secondaryText: root.currencyStore.formatCurrencyAmount(root.weiToEth(model.amountOut), d.selectedSymbol, {"minDecimals": root.minReceiveCryptoDecimals})
|
2022-12-19 13:02:56 +00:00
|
|
|
|
tertiaryText: state === "unpreferred" ? qsTr("UNPREFERRED") : ""
|
|
|
|
|
state: !preferred ? "unpreferred" : "default"
|
2023-08-15 18:21:51 +00:00
|
|
|
|
opacity: preferred || store.showUnPreferredChains ? 1 : 0
|
2024-10-15 19:26:12 +00:00
|
|
|
|
cardIcon.source: Theme.svg(model.iconUrl)
|
2022-12-19 13:02:56 +00:00
|
|
|
|
disabledText: qsTr("Disabled")
|
|
|
|
|
disableText: qsTr("Disable")
|
|
|
|
|
enableText: qsTr("Enable")
|
2024-07-03 08:51:15 +00:00
|
|
|
|
disabled: !model.isRouteEnabled
|
2022-12-19 13:02:56 +00:00
|
|
|
|
clickable: root.interactive
|
2023-01-27 13:16:42 +00:00
|
|
|
|
loading: root.isLoading
|
2022-12-19 13:02:56 +00:00
|
|
|
|
onClicked: {
|
2023-08-15 18:21:51 +00:00
|
|
|
|
store.toggleToDisabledChains(model.chainId)
|
2023-09-25 12:39:54 +00:00
|
|
|
|
root.reCalculateSuggestedRoute()
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas {
|
|
|
|
|
id: canvas
|
|
|
|
|
x: networkCardsLayout.x + fromNetworksLayout.x
|
|
|
|
|
y: networkCardsLayout.y
|
|
|
|
|
width: networkCardsLayout.width
|
|
|
|
|
height: networkCardsLayout.height
|
|
|
|
|
|
|
|
|
|
function clear() {
|
|
|
|
|
if(available) {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
var ctx = getContext("2d");
|
|
|
|
|
if(ctx)
|
|
|
|
|
ctx.reset()
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onPaint: {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
d.resetAllSetValues()
|
|
|
|
|
|
2022-11-25 09:13:02 +00:00
|
|
|
|
// in case you are drawing multiple routes we need an offset so that the lines dont overlap
|
2022-11-29 21:47:26 +00:00
|
|
|
|
let yOffsetFrom = 0
|
|
|
|
|
let yOffsetTo = 0
|
|
|
|
|
let xOffset = 0
|
|
|
|
|
|
2022-10-17 10:17:25 +00:00
|
|
|
|
// Get the canvas context
|
|
|
|
|
var ctx = getContext("2d");
|
2023-08-15 18:21:51 +00:00
|
|
|
|
for(var j = 0; j<fromNetworksRepeater.count; j++) {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
var fromN, toN = null
|
2023-08-15 18:21:51 +00:00
|
|
|
|
fromN = fromNetworksRepeater.itemAt(j)
|
|
|
|
|
const toNetworks = fromN.toNetworks.split(":")
|
|
|
|
|
for(var i = 0; i<toNetworks.length; i++) {
|
|
|
|
|
for(var k = 0; k<toNetworksRepeater.count; k++) {
|
|
|
|
|
if(toNetworks[i] === toNetworksRepeater.itemAt(k).objectName && !toNetworksRepeater.itemAt(k).disabled) {
|
|
|
|
|
toN = toNetworksRepeater.itemAt(k)
|
|
|
|
|
yOffsetFrom = toN.objectName === fromN.objectName && toN.routeOnNetwork !== 0 ? toN.routeOnNetwork * 16 : 0
|
|
|
|
|
yOffsetTo = toN.routeOnNetwork * 16
|
|
|
|
|
xOffset = (fromN.y - toN.y > 0 ? -1 : 1) * toN.bentLine * 16
|
|
|
|
|
fromN.routeOnNetwork += 1
|
|
|
|
|
toN.routeOnNetwork += 1
|
|
|
|
|
toN.bentLine = toN.objectName !== fromN.objectName
|
2024-07-27 16:21:14 +00:00
|
|
|
|
let routeColor = root.errorMode || !fromN.hasGas ? Theme.palette.dangerColor1 : toN.preferred ? '#627EEA' : Theme.palette.pinColor1
|
2023-08-15 18:21:51 +00:00
|
|
|
|
StatusQUtils.Utils.drawArrow(ctx, fromN.x + fromN.width,
|
|
|
|
|
fromN.y + fromN.cardIconPosition + yOffsetFrom,
|
|
|
|
|
toNetworksLayout.x + toN.x,
|
|
|
|
|
toNetworksLayout.y + toN.y + toN.cardIconPosition + yOffsetTo,
|
|
|
|
|
routeColor, xOffset)
|
|
|
|
|
break
|
|
|
|
|
}
|
2022-10-17 10:17:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
2022-11-25 09:13:02 +00:00
|
|
|
|
d.calculateCustomAmounts()
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|