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
|
|
|
|
|
|
|
|
|
|
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-10-17 10:17:25 +00:00
|
|
|
|
property bool errorMode: {
|
|
|
|
|
if(customMode) {
|
|
|
|
|
return (d.customAmountToSend > amountToSend) || (d.customAmountToSend < amountToSend) ||
|
|
|
|
|
(d.customAmountToReceive > amountToSend) || (d.customAmountToReceive < amountToSend)
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return !d.thereIsApossibleRoute
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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-07-01 11:24:32 +00:00
|
|
|
|
|
2022-11-15 11:22:03 +00:00
|
|
|
|
property var reCalculateSuggestedRoute: function() {}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
|
|
|
|
|
QtObject {
|
|
|
|
|
id: d
|
|
|
|
|
property double customAmountToSend: 0
|
|
|
|
|
property double customAmountToReceive: 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-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
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-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 {
|
|
|
|
|
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-10-17 10:17:25 +00:00
|
|
|
|
property string tokenBalanceOnChain: selectedAccount && selectedAccount!== undefined && selectedAsset!== undefined ? selectedAccount.getTokenBalanceOnChain(model.chainId, selectedAsset.symbol) : ""
|
|
|
|
|
property var hasGas: selectedAccount.hasGas(model.chainId, model.nativeCurrencySymbol, requiredGasInEth)
|
2022-07-01 11:24:32 +00:00
|
|
|
|
primaryText: model.chainName
|
2022-10-17 10:17:25 +00:00
|
|
|
|
secondaryText: (parseFloat(tokenBalanceOnChain) === 0 && root.amountToSend !== 0) ?
|
|
|
|
|
qsTr("No Balance") : !hasGas ? qsTr("No Gas") : LocaleUtils.numberToLocaleString(fromNetwork.amountToSend)
|
|
|
|
|
tertiaryText: qsTr("BALANCE: ") + LocaleUtils.numberToLocaleString(parseFloat(tokenBalanceOnChain))
|
|
|
|
|
state: tokenBalanceOnChain === 0 || !hasGas ? "unavailable" : root.errorMode ? "error" : "default"
|
|
|
|
|
cardIcon.source: Style.svg(model.iconUrl)
|
2022-07-01 11:24:32 +00:00
|
|
|
|
disabledText: qsTr("Disabled")
|
2022-10-17 10:17:25 +00:00
|
|
|
|
advancedMode: root.customMode
|
|
|
|
|
advancedInputText: LocaleUtils.numberToLocaleString(fromNetwork.amountToSend)
|
|
|
|
|
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-10-17 10:17:25 +00:00
|
|
|
|
// To-do needed for custom view
|
|
|
|
|
// onAdvancedInputTextChanged: {
|
|
|
|
|
// if(selectedNetwork && selectedNetwork.chainName === model.chainName) {
|
|
|
|
|
// d.customAmountToSend = isNaN(parseFloat(advancedInputText)) ? 0 : parseFloat(advancedInputText)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
id: toNetworksLayout
|
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
|
|
|
|
spacing: 12
|
|
|
|
|
StatusBaseText {
|
|
|
|
|
Layout.alignment: Qt.AlignRight
|
|
|
|
|
Layout.maximumWidth: 70
|
|
|
|
|
font.pixelSize: 10
|
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
|
text: selectedAccount.address
|
|
|
|
|
elide: Text.ElideMiddle
|
|
|
|
|
}
|
|
|
|
|
Repeater {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
id: toNetworksRepeater
|
|
|
|
|
model: root.allNetworks
|
2022-07-01 11:24:32 +00:00
|
|
|
|
StatusCard {
|
|
|
|
|
id: toCard
|
2022-10-17 10:17:25 +00:00
|
|
|
|
objectName: model.chainId
|
2022-11-29 21:47:26 +00:00
|
|
|
|
property int routeOnNetwork: 0
|
2022-10-17 10:17:25 +00:00
|
|
|
|
property double amountToReceive: 0
|
2022-12-01 15:48:44 +00:00
|
|
|
|
property bool preferred: store.preferredChainIds.includes(model.chainId)
|
2022-07-01 11:24:32 +00:00
|
|
|
|
primaryText: model.chainName
|
2022-10-17 10:17:25 +00:00
|
|
|
|
secondaryText: LocaleUtils.numberToLocaleString(amountToReceive)
|
2022-12-01 15:48:44 +00:00
|
|
|
|
tertiaryText: state === "unpreferred" ? qsTr("UNPREFERRED") : ""
|
|
|
|
|
state: root.errorMode ? "error" : !preferred ? "unpreferred" : "default"
|
|
|
|
|
opacity: preferred || showPreferredChains ? 1 : 0
|
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-10-17 10:17:25 +00:00
|
|
|
|
advancedMode: root.customMode
|
|
|
|
|
advancedInputText: LocaleUtils.numberToLocaleString(amountToReceive)
|
|
|
|
|
disabled: store.disabledChainIdsToList.includes(model.chainId)
|
|
|
|
|
clickable: root.interactive
|
2022-07-01 11:24:32 +00:00
|
|
|
|
onClicked: {
|
2022-10-17 10:17:25 +00:00
|
|
|
|
store.addRemoveDisabledToChain(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: {
|
2022-12-01 15:48:44 +00:00
|
|
|
|
if(visible) {
|
|
|
|
|
disabled = store.disabledChainIdsToList.includes(model.chainId)
|
|
|
|
|
preferred = store.preferredChainIds.includes(model.chainId)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
onOpacityChanged: {
|
|
|
|
|
if(opacity === 1) {
|
2022-11-23 17:58:22 +00:00
|
|
|
|
disabled = store.disabledChainIdsToList.includes(model.chainId)
|
2022-12-01 15:48:44 +00:00
|
|
|
|
} else {
|
|
|
|
|
if(opacity === 0 && routeOnNetwork > 0)
|
|
|
|
|
root.reCalculateSuggestedRoute()
|
|
|
|
|
}
|
2022-07-01 11:24:32 +00:00
|
|
|
|
}
|
2022-12-01 15:48:44 +00:00
|
|
|
|
|
2022-10-17 10:17:25 +00:00
|
|
|
|
// To-do needed for custom view
|
|
|
|
|
// onAdvancedInputTextChanged: {
|
|
|
|
|
// if(selectedNetwork && selectedNetwork.chainName === model.chainName)
|
|
|
|
|
// d.customAmountToReceive = isNaN(parseFloat(advancedInputText)) ? 0 : parseFloat(advancedInputText)
|
|
|
|
|
// }
|
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-29 21:47:26 +00:00
|
|
|
|
// in case you are drwaing multiple routes we need an offset so that the lines dont overlap
|
|
|
|
|
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-11-29 21:47:26 +00:00
|
|
|
|
yOffsetFrom = toN.objectName === fromN.objectName && toN.routeOnNetwork !== 0 ? toN.routeOnNetwork * 10 : 0
|
|
|
|
|
yOffsetTo = toN.routeOnNetwork * 10
|
|
|
|
|
xOffset = toN.routeOnNetwork * 10
|
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-10-17 10:17:25 +00:00
|
|
|
|
d.thereIsApossibleRoute = true
|
2022-12-01 15:48:44 +00:00
|
|
|
|
let routeColor = 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-10-17 10:17:25 +00:00
|
|
|
|
toNetworksLayout.x + toN.x,
|
2022-11-29 21:47:26 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|