2022-07-01 11:24:32 +00:00
|
|
|
|
import QtQuick 2.13
|
|
|
|
|
import QtQuick.Layouts 1.13
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
property var store
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property var bestRoutes
|
2022-07-01 11:24:32 +00:00
|
|
|
|
property var selectedAccount
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property var selectedAsset
|
2022-07-01 11:24:32 +00:00
|
|
|
|
property var allNetworks
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property bool customMode: false
|
2022-07-01 11:24:32 +00:00
|
|
|
|
property double amountToSend: 0
|
|
|
|
|
property double requiredGasInEth: 0
|
2022-12-19 13:02:56 +00:00
|
|
|
|
property bool errorMode: d.customAmountToSend > root.amountToSend
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property bool interactive: true
|
2022-12-01 15:48:44 +00:00
|
|
|
|
property bool showPreferredChains: false
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property var weiToEth: function(wei) {}
|
2022-11-15 11:22:03 +00:00
|
|
|
|
property var reCalculateSuggestedRoute: function() {}
|
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
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property bool thereIsApossibleRoute: false
|
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++) {
|
|
|
|
|
fromNetworksRepeater.itemAt(i).amountToSend = 0
|
2022-11-29 21:47:26 +00:00
|
|
|
|
fromNetworksRepeater.itemAt(i).routeOnNetwork = 0
|
2022-10-17 10:17:25 +00:00
|
|
|
|
toNetworksRepeater.itemAt(i).amountToReceive = 0
|
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) {
|
|
|
|
|
let amountEntered = parseFloat(fromNetworksRepeater.itemAt(i).advancedInputText)
|
|
|
|
|
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()
|
|
|
|
|
onBestRoutesChanged: d.draw()
|
2022-11-25 09:13:02 +00:00
|
|
|
|
onErrorModeChanged: if(errorMode) d.draw()
|
2022-12-01 15:48:44 +00:00
|
|
|
|
|
2022-07-01 11:24:32 +00:00
|
|
|
|
width: 410
|
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
|
|
|
|
|
text: qsTr("Your Balances").toUpperCase()
|
|
|
|
|
}
|
|
|
|
|
Repeater {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
id: fromNetworksRepeater
|
|
|
|
|
model: root.allNetworks
|
2022-07-01 11:24:32 +00:00
|
|
|
|
StatusCard {
|
|
|
|
|
id: fromNetwork
|
2022-10-17 10:17:25 +00:00
|
|
|
|
objectName: model.chainId
|
|
|
|
|
property double amountToSend: 0
|
2022-11-29 21:47:26 +00:00
|
|
|
|
property int routeOnNetwork: 0
|
2022-12-29 16:44:51 +00:00
|
|
|
|
property bool tokenBalanceOnChainValid: selectedAccount && selectedAccount !== undefined && selectedAsset !== undefined
|
|
|
|
|
property var tokenBalanceOnChain: tokenBalanceOnChainValid ? root.store.getTokenBalanceOnChain(selectedAccount, model.chainId, selectedAsset.symbol) : undefined
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property var hasGas: selectedAccount.hasGas(model.chainId, model.nativeCurrencySymbol, requiredGasInEth)
|
2022-11-25 09:13:02 +00:00
|
|
|
|
|
2022-07-01 11:24:32 +00:00
|
|
|
|
primaryText: model.chainName
|
2022-12-29 16:44:51 +00:00
|
|
|
|
secondaryText: (tokenBalanceOnChain.amount === 0) && root.amountToSend !== 0 ?
|
2022-11-25 09:13:02 +00:00
|
|
|
|
qsTr("No Balance") : !hasGas ? qsTr("No Gas") : advancedInputText
|
2022-12-29 16:44:51 +00:00
|
|
|
|
tertiaryText: root.errorMode && parseFloat(advancedInputText) !== 0 && advancedInput.valid ? qsTr("EXCEEDS SEND AMOUNT"): qsTr("BALANCE: ") + LocaleUtils.currencyAmountToLocaleString(tokenBalanceOnChain, root.store.locale)
|
2022-11-25 09:13:02 +00:00
|
|
|
|
locked: store.lockedInAmounts.findIndex(lockedItem => lockedItem !== undefined && lockedItem.chainID === model.chainId) !== -1
|
|
|
|
|
preCalculatedAdvancedText: {
|
|
|
|
|
let index = store.lockedInAmounts.findIndex(lockedItem => lockedItem!== undefined && lockedItem.chainID === model.chainId)
|
|
|
|
|
if(locked && index !== -1) {
|
|
|
|
|
return root.weiToEth(parseInt(store.lockedInAmounts[index].value, 16))
|
|
|
|
|
}
|
|
|
|
|
else return LocaleUtils.numberToLocaleString(fromNetwork.amountToSend)
|
|
|
|
|
}
|
2022-12-29 16:44:51 +00:00
|
|
|
|
maxAdvancedValue: tokenBalanceOnChain.amount
|
|
|
|
|
state: tokenBalanceOnChain.amount === 0 || !hasGas ?
|
2022-12-19 13:02:56 +00:00
|
|
|
|
"unavailable" :
|
|
|
|
|
(root.errorMode || !advancedInput.valid) && (parseFloat(advancedInputText) !== 0) ? "error" : "default"
|
2022-10-17 10:17:25 +00:00
|
|
|
|
cardIcon.source: Style.svg(model.iconUrl)
|
2022-07-01 11:24:32 +00:00
|
|
|
|
disabledText: qsTr("Disabled")
|
2022-12-19 13:02:56 +00:00
|
|
|
|
disableText: qsTr("Disable")
|
|
|
|
|
enableText: qsTr("Enable")
|
2022-10-17 10:17:25 +00:00
|
|
|
|
advancedMode: root.customMode
|
|
|
|
|
disabled: store.disabledChainIdsFromList.includes(model.chainId)
|
|
|
|
|
clickable: root.interactive
|
2022-07-01 11:24:32 +00:00
|
|
|
|
onClicked: {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
store.addRemoveDisabledFromChain(model.chainId, disabled)
|
2022-11-23 17:58:22 +00:00
|
|
|
|
// only recalculate if the a best route was disabled
|
2022-11-29 21:47:26 +00:00
|
|
|
|
if(root.bestRoutes.length === 0 || routeOnNetwork !== 0 || !disabled)
|
2022-11-23 17:58:22 +00:00
|
|
|
|
root.reCalculateSuggestedRoute()
|
|
|
|
|
}
|
|
|
|
|
onVisibleChanged: {
|
|
|
|
|
if(visible)
|
|
|
|
|
disabled = store.disabledChainIdsFromList.includes(model.chainId)
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
2022-11-25 09:13:02 +00:00
|
|
|
|
onCardLocked: {
|
2022-12-19 13:02:56 +00:00
|
|
|
|
|
2022-11-25 09:13:02 +00:00
|
|
|
|
store.addLockedInAmount(model.chainId, advancedInputText, root.selectedAsset.decimals, isLocked)
|
|
|
|
|
d.calculateCustomAmounts()
|
2022-12-19 13:02:56 +00:00
|
|
|
|
if(!locked || (d.customAmountToSend <= root.amountToSend && advancedInput.valid))
|
2022-11-25 09:13:02 +00:00
|
|
|
|
root.reCalculateSuggestedRoute()
|
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-19 13:02:56 +00:00
|
|
|
|
BalanceExceeded {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
|
amountToSend: root.amountToSend
|
|
|
|
|
isLoading: root.isLoading
|
|
|
|
|
errorType: root.errorType
|
|
|
|
|
}
|
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
|
|
|
|
|
StatusBaseText {
|
2022-11-25 09:13:02 +00:00
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
2022-11-30 18:57:00 +00:00
|
|
|
|
Layout.maximumWidth: 100
|
2022-07-01 11:24:32 +00:00
|
|
|
|
font.pixelSize: 10
|
|
|
|
|
color: Theme.palette.baseColor1
|
2022-11-30 18:57:00 +00:00
|
|
|
|
text: StatusQUtils.Utils.elideText(selectedAccount.address, 6, 4).toUpperCase()
|
2022-07-01 11:24:32 +00:00
|
|
|
|
elide: Text.ElideMiddle
|
|
|
|
|
}
|
2022-12-19 13:02:56 +00:00
|
|
|
|
Repeater {
|
|
|
|
|
id: toNetworksRepeater
|
|
|
|
|
model: root.allNetworks
|
|
|
|
|
StatusCard {
|
|
|
|
|
id: toCard
|
|
|
|
|
objectName: model.chainId
|
|
|
|
|
property int routeOnNetwork: 0
|
|
|
|
|
property int bentLine: 0
|
|
|
|
|
property double amountToReceive: 0
|
|
|
|
|
property bool preferred: store.preferredChainIds.includes(model.chainId)
|
|
|
|
|
primaryText: model.chainName
|
|
|
|
|
secondaryText: LocaleUtils.numberToLocaleString(amountToReceive)
|
|
|
|
|
tertiaryText: state === "unpreferred" ? qsTr("UNPREFERRED") : ""
|
|
|
|
|
state: !preferred ? "unpreferred" : "default"
|
|
|
|
|
opacity: preferred || showPreferredChains ? 1 : 0
|
|
|
|
|
cardIcon.source: Style.svg(model.iconUrl)
|
|
|
|
|
disabledText: qsTr("Disabled")
|
|
|
|
|
disableText: qsTr("Disable")
|
|
|
|
|
enableText: qsTr("Enable")
|
|
|
|
|
disabled: store.disabledChainIdsToList.includes(model.chainId)
|
|
|
|
|
clickable: root.interactive
|
|
|
|
|
onClicked: {
|
|
|
|
|
store.addRemoveDisabledToChain(model.chainId, disabled)
|
|
|
|
|
// only recalculate if the a best route was disabled
|
|
|
|
|
if((root.bestRoutes !== undefined && root.bestRoutes.length === 0) || routeOnNetwork !== 0 || !disabled)
|
|
|
|
|
root.reCalculateSuggestedRoute()
|
|
|
|
|
}
|
|
|
|
|
onVisibleChanged: {
|
|
|
|
|
if(visible) {
|
|
|
|
|
disabled = store.disabledChainIdsToList.includes(model.chainId)
|
|
|
|
|
preferred = store.preferredChainIds.includes(model.chainId)
|
2022-11-25 09:13:02 +00:00
|
|
|
|
}
|
2022-12-19 13:02:56 +00:00
|
|
|
|
}
|
|
|
|
|
onOpacityChanged: {
|
|
|
|
|
if(opacity === 1) {
|
|
|
|
|
disabled = store.disabledChainIdsToList.includes(model.chainId)
|
|
|
|
|
} else {
|
|
|
|
|
if(opacity === 0 && routeOnNetwork > 0)
|
|
|
|
|
root.reCalculateSuggestedRoute()
|
2022-11-25 09:13:02 +00:00
|
|
|
|
}
|
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()
|
|
|
|
|
d.thereIsApossibleRoute = false
|
|
|
|
|
|
|
|
|
|
if(bestRoutes === undefined)
|
|
|
|
|
return
|
|
|
|
|
|
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");
|
|
|
|
|
for(var i = 0; i< bestRoutes.length; i++) {
|
|
|
|
|
var fromN, toN = null
|
|
|
|
|
for(var j = 0; j<fromNetworksRepeater.count; j++) {
|
|
|
|
|
if(bestRoutes[i].fromNetwork.chainId === parseInt(fromNetworksRepeater.itemAt(j).objectName) &&
|
|
|
|
|
!store.disabledChainIdsFromList.includes(bestRoutes[i].fromNetwork.chainId)) {
|
|
|
|
|
fromN = fromNetworksRepeater.itemAt(j)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(var k = 0; k<toNetworksRepeater.count; k++) {
|
|
|
|
|
if(bestRoutes[i].toNetwork.chainId === parseInt(toNetworksRepeater.itemAt(k).objectName) &&
|
|
|
|
|
!store.disabledChainIdsToList.includes(bestRoutes[i].toNetwork.chainId)) {
|
|
|
|
|
toN = toNetworksRepeater.itemAt(k)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(toN !== null && fromN !== null) {
|
2022-12-19 13:02:56 +00:00
|
|
|
|
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
|
2022-10-17 10:17:25 +00:00
|
|
|
|
let amountToSend = weiToEth(bestRoutes[i].amountIn)
|
|
|
|
|
let amountToReceive = weiToEth(bestRoutes[i].amountOut)
|
|
|
|
|
fromN.amountToSend = amountToSend
|
|
|
|
|
toN.amountToReceive += amountToReceive
|
2022-11-29 21:47:26 +00:00
|
|
|
|
fromN.routeOnNetwork += 1
|
|
|
|
|
toN.routeOnNetwork += 1
|
2022-12-19 13:02:56 +00:00
|
|
|
|
toN.bentLine = toN.objectName !== fromN.objectName
|
2022-10-17 10:17:25 +00:00
|
|
|
|
d.thereIsApossibleRoute = true
|
2022-11-25 09:13:02 +00:00
|
|
|
|
let routeColor = root.errorMode ? Theme.palette.dangerColor1 : toN.preferred ? '#627EEA' : Theme.palette.pinColor1
|
2022-10-17 10:17:25 +00:00
|
|
|
|
StatusQUtils.Utils.drawArrow(ctx, fromN.x + fromN.width,
|
2022-11-29 21:47:26 +00:00
|
|
|
|
fromN.y + fromN.cardIconPosition + yOffsetFrom,
|
2022-12-19 13:02:56 +00:00
|
|
|
|
toNetworksLayout.x + toN.x,
|
2022-11-25 09:13:02 +00:00
|
|
|
|
toNetworksLayout.y + toN.y + toN.cardIconPosition + yOffsetTo,
|
2022-12-01 15:48:44 +00:00
|
|
|
|
routeColor, xOffset)
|
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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|