feat(@deaktop/wallet): Add bridge view

fixes #8236
This commit is contained in:
Khushboo Mehta 2022-11-23 18:58:22 +01:00 committed by Khushboo-dev-cpp
parent 75b5a583dd
commit 9ded9d4ffa
20 changed files with 485 additions and 194 deletions

View File

@ -194,14 +194,13 @@ class StatusWalletScreen:
time.sleep(1)
type(SendPopup.AMOUNT_INPUT.value, amount)
if token != Tokens.ETH.value:
click_obj_by_name(SendPopup.ASSET_SELECTOR.value)
asset_list = get_obj(SendPopup.ASSET_LIST.value)
for index in range(asset_list.count):
tokenObj = asset_list.itemAtIndex(index)
if(not squish.isNull(tokenObj) and tokenObj.objectName == "AssetSelector_ItemDelegate_" + token):
click_obj(asset_list.itemAtIndex(index))
break
click_obj_by_name(SendPopup.ASSET_SELECTOR.value)
asset_list = get_obj(SendPopup.ASSET_LIST.value)
for index in range(asset_list.count):
tokenObj = asset_list.itemAtIndex(index)
if(not squish.isNull(tokenObj) and tokenObj.objectName == "AssetSelector_ItemDelegate_" + token):
click_obj(asset_list.itemAtIndex(index))
break
click_obj_by_name(SendPopup.MY_ACCOUNTS_TAB.value)

View File

@ -10380,5 +10380,6 @@
<file>assets/img/icons/unfavourite.svg</file>
<file>assets/img/icons/youtube.svg</file>
<file>assets/twemoji/LICENSE</file>
<file>assets/img/icons/bridge.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,3 @@
<svg width="21" height="14" viewBox="0 0 21 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.5 0.999984H6.72C5.61 -0.230016 3.71 -0.320016 2.5 0.799984C1.86 1.35998 1.5 2.15998 1.5 2.99998V12C1.23478 12 0.98043 12.1053 0.792893 12.2929C0.605357 12.4804 0.5 12.7348 0.5 13V14H8.5V13C8.5 12.7348 8.39464 12.4804 8.20711 12.2929C8.01957 12.1053 7.76522 12 7.5 12V4.99998H18.5C19.0304 4.99998 19.5391 4.78927 19.9142 4.4142C20.2893 4.03912 20.5 3.53042 20.5 2.99998C20.5 2.46955 20.2893 1.96084 19.9142 1.58577C19.5391 1.2107 19.0304 0.999984 18.5 0.999984ZM6 12H3V5.59998C3.93 6.13998 5.07 6.13998 6 5.59998V12ZM4.5 4.49998C4.10218 4.49998 3.72064 4.34195 3.43934 4.06064C3.15804 3.77934 3 3.39781 3 2.99998C3 2.60216 3.15804 2.22063 3.43934 1.93932C3.72064 1.65802 4.10218 1.49998 4.5 1.49998C4.89782 1.49998 5.27936 1.65802 5.56066 1.93932C5.84196 2.22063 6 2.60216 6 2.99998C6 3.39781 5.84196 3.77934 5.56066 4.06064C5.27936 4.34195 4.89782 4.49998 4.5 4.49998ZM9 3.99998L7.5 1.99998H9L10.5 3.99998H9ZM13 3.99998L11.5 1.99998H13L14.5 3.99998H13ZM17 3.99998L15.5 1.99998H17L18.5 3.99998H17Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -54,6 +54,16 @@ Rectangle {
Global.openPopup(buySellModal);
}
}
StatusFlatButton {
id: bridgeBtn
icon.name: "bridge"
text: qsTr("Bridge")
onClicked: function () {
sendModal.isBridgeTx = true
sendModal.open()
}
}
}
Component {

View File

@ -1093,15 +1093,19 @@ Item {
this.active = false
}
property var selectedAccount
property bool isBridgeTx
sourceComponent: SendModal {
onClosed: {
sendModal.closed()
sendModal.isBridgeTx = false
}
}
onLoaded: {
if (!!sendModal.selectedAccount) {
item.selectedAccount = sendModal.selectedAccount
}
if(isBridgeTx)
item.isBridgeTx = sendModal.isBridgeTx
}
}

View File

@ -0,0 +1,54 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Popups 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import utils 1.0
StatusListItem {
property string currentCurrencySymbol
title: name
subTitle: `${enabledNetworkBalance} ${symbol}`
asset.name: symbol ? Style.png("tokens/" + symbol) : ""
asset.isImage: true
components: [
Column {
id: valueColumn
property string textColor: Math.sign(Number(changePct24hour)) === 0 ? Theme.palette.baseColor1 :
Math.sign(Number(changePct24hour)) === -1 ? Theme.palette.dangerColor1 :
Theme.palette.successColor1
StatusBaseText {
anchors.right: parent.right
font.pixelSize: 15
font.strikeout: false
text: enabledNetworkCurrencyBalance.toLocaleCurrencyString(Qt.locale(), currentCurrencySymbol)
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 8
StatusBaseText {
id: change24HourText
font.pixelSize: 15
font.strikeout: false
color: valueColumn.textColor
text: currencyPrice.toLocaleCurrencyString(Qt.locale(), currentCurrencySymbol)
}
Rectangle {
width: 1
height: change24HourText.implicitHeight
color: Theme.palette.directColor9
}
StatusBaseText {
font.pixelSize: 15
font.strikeout: false
color: valueColumn.textColor
text: changePct24hour !== "" ? "%1%".arg(changePct24hour) : "---"
}
}
}
]
}

View File

@ -30,3 +30,4 @@ AssetsDetailsHeader 1.0 AssetsDetailsHeader.qml
InformationTag 1.0 InformationTag.qml
TransactionDetailsHeader.qml 1.0 TransactionDetailsHeader.qml
SavedAddressesDelegate 1.0 SavedAddressesDelegate.qml
TokenDelegate 1.0 TokenDelegate.qml

View File

@ -29,13 +29,14 @@ Item {
// Define this in the usage to get balance in currency selected by user
property var getCurrencyBalanceString: function (currencyBalance) { return "" }
property string placeholderText
function resetInternal() {
assets = null
selectedAsset = null
}
implicitWidth: 106
implicitWidth: comboBox.width
implicitHeight: comboBox.implicitHeight
onSelectedAssetChanged: {
@ -59,7 +60,7 @@ Item {
StatusComboBox {
id: comboBox
objectName: "assetSelectorButton"
width: parent.width
width: control.width
height: parent.height
control.padding: 4
@ -86,25 +87,28 @@ Item {
border.width: 1
border.color: comboBox.control.hovered ? Theme.palette.primaryColor2 : Theme.palette.directColor8
radius: 16
width: rowLayout.width
implicitHeight: 48
}
contentItem: RowLayout {
id: rowLayout
spacing: 8
StatusBaseText {
Layout.maximumWidth: 50
Layout.leftMargin: 8
Layout.alignment: Qt.AlignVCenter
font.pixelSize: 15
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
color: !!root.selectedAsset ? Theme.palette.directColor1: Theme.palette.baseColor1
font.weight: Font.Medium
text: d.text
text: !!root.selectedAsset ? d.text : placeholderText
}
StatusRoundedImage {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignVCenter
visible: !!d.iconSource
image.source: d.iconSource
image.onStatusChanged: {
if (image.status === Image.Error) {
@ -112,6 +116,10 @@ Item {
}
}
}
Item {
width: 8
height: 0
}
}
control.indicator: null
@ -122,16 +130,14 @@ Item {
padding: 16
objectName: "AssetSelector_ItemDelegate_" + symbol
onClicked: {
// TODO: move this out of StatusQ, this involves dependency on BE code
// WARNING: Wrong ComboBox value processing. Check `StatusAccountSelector` for more info.
root.userSelectedToken = symbol
root.selectedAsset = {name: name, symbol: symbol, totalBalance: totalBalance, totalCurrencyBalance: totalCurrencyBalance, balances: balances, decimals: decimals}
}
// TODO: move this out of StatusQ, this involves dependency on BE code
// WARNING: Wrong ComboBox value processing. Check `StatusAccountSelector` for more info.
Component.onCompleted: {
if ((userSelectedToken === "" && index === 0) || symbol === userSelectedToken)
if (symbol === userSelectedToken)
root.selectedAsset = { name: name, symbol: symbol, totalBalance: totalBalance, totalCurrencyBalance: totalCurrencyBalance, balances: balances, decimals: decimals}
}

View File

@ -22,6 +22,8 @@ import "../views"
StatusDialog {
id: popup
property bool isBridgeTx: false
property string preSelectedRecipient
property string preDefinedAmountToSend
property var preSelectedAsset
@ -29,14 +31,14 @@ StatusDialog {
property alias modalHeader: modalHeader.text
property alias selectedPriority: gasSelector.selectedPriority
property alias selectedPriority: fees.selectedPriority
property var store: TransactionStore{}
property var contactsStore: store.contactStore
property var selectedAccount: store.currentAccount
property var bestRoutes
property string addressText
property bool isLoading: false
property int sendType: Constants.SendType.Transfer
property int sendType: isBridgeTx ? Constants.SendType.Bridge : Constants.SendType.Transfer
property MessageDialog sendingError: MessageDialog {
id: sendingError
title: qsTr("Error sending the transaction")
@ -61,19 +63,19 @@ StatusDialog {
assetSelector.selectedAsset.symbol,
amountToSendInput.text,
d.uuid,
gasSelector.selectedPriority,
fees.selectedPriority,
JSON.stringify(popup.bestRoutes)
)
}
property var recalculateRoutesAndFees: Backpressure.debounce(popup, 600, function() {
d.sendTxError = false
if(popup.selectedAccount && assetSelector.selectedAsset) {
if(!!popup.selectedAccount && !!assetSelector.selectedAsset) {
popup.isLoading = true
let amount = parseFloat(amountToSendInput.text) * Math.pow(10, assetSelector.selectedAsset.decimals)
popup.store.suggestedRoutes(popup.selectedAccount.address, amount.toString(16), assetSelector.selectedAsset.symbol,
store.disabledChainIdsFromList, store.disabledChainIdsToList,
d.preferredChainIds, gasSelector.selectedPriority, popup.sendType)
d.preferredChainIds, fees.selectedPriority, popup.sendType)
}
})
@ -85,6 +87,10 @@ StatusDialog {
QtObject {
id: d
readonly property double maxFiatBalance: assetSelector.selectedAsset ? assetSelector.selectedAsset.totalBalance: 0
onMaxFiatBalanceChanged: {
floatValidator.top = maxFiatBalance
amountToSendInput.validate()
}
readonly property bool isReady: amountToSendInput.valid && !amountToSendInput.pending && recipientReady
readonly property bool errorMode: (networkSelector.bestRoutes && networkSelector.bestRoutes.length <= 0) || networkSelector.errorMode || isNaN(amountToSendInput.text)
readonly property bool recipientReady: (isAddressValid || isENSValid) && !recipientSelector.isPending
@ -147,8 +153,6 @@ StatusDialog {
onSelectedAccountChanged: popup.recalculateRoutesAndFees()
onOpened: {
popup.store.disabledChainIdsFromList = []
popup.store.disabledChainIdsToList = []
amountToSendInput.input.edit.forceActiveFocus()
if(!!popup.preSelectedAsset) {
@ -163,6 +167,16 @@ StatusDialog {
recipientSelector.input.text = popup.preSelectedRecipient
d.waitTimer.restart()
}
if(popup.isBridgeTx) {
recipientSelector.input.text = popup.selectedAccount.address
d.waitTimer.restart()
}
}
onClosed: {
popup.store.disabledChainIdsFromList = []
popup.store.disabledChainIdsToList = []
}
header: AccountsModalHeader {
@ -186,14 +200,13 @@ StatusDialog {
ColumnLayout {
id: group1
Layout.preferredWidth: parent.width
spacing: Style.current.padding
Rectangle {
Layout.preferredWidth: parent.width
Layout.preferredHeight: assetAndAmmountSelector.height + Style.current.padding
color: Theme.palette.baseColor3
layer.enabled: scrollView.contentY > -8
layer.enabled: scrollView.contentY > 0
layer.effect: DropShadow {
verticalOffset: 2
radius: 16
@ -214,7 +227,7 @@ StatusDialog {
StatusBaseText {
id: modalHeader
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Send")
text: popup.isBridgeTx ? qsTr("Bridge") : qsTr("Send")
font.pixelSize: 15
color: Theme.palette.directColor1
}
@ -237,14 +250,14 @@ StatusDialog {
anchors.left: parent.left
anchors.leftMargin: -Style.current.padding
width: parent.width - assetSelector.width
placeholderText: assetSelector.selectedAsset ? "%1 %2".arg(LocaleUtils.numberToLocaleString(0, 2)).arg(assetSelector.selectedAsset.symbol) : ""
placeholderText: assetSelector.selectedAsset ? "%1 %2".arg(LocaleUtils.numberToLocaleString(0, 2)).arg(assetSelector.selectedAsset.symbol) : LocaleUtils.numberToLocaleString(0, 2)
input.edit.color: d.errorMode ? Theme.palette.dangerColor1 : Theme.palette.directColor1
input.edit.readOnly: !popup.interactive
validators: [
StatusFloatValidator{
id: floatValidator
bottom: 0
top: assetSelector.selectedAsset ? assetSelector.selectedAsset.totalBalance: 0
top: d.maxFiatBalance
errorMessage: ""
}
]
@ -264,6 +277,7 @@ StatusDialog {
enabled: popup.interactive
assets: popup.selectedAccount && popup.selectedAccount.assets ? popup.selectedAccount.assets : []
defaultToken: Style.png("tokens/DEFAULT-TOKEN@3x")
placeholderText: popup.isBridgeTx ? qsTr("Select token to bridge") : qsTr("Select token to send")
getCurrencyBalanceString: function (currencyBalance) {
return "%1 %2".arg(Utils.toLocaleString(currencyBalance.toFixed(2), popup.store.locale, {"currency": true})).arg(popup.store.currentCurrency.toUpperCase())
}
@ -306,10 +320,13 @@ StatusDialog {
input.edit.color: txtFiatBalance.input.edit.activeFocus ? Theme.palette.directColor1 : Theme.palette.baseColor1
input.edit.readOnly: true
text: {
let fiatValue = popup.store.getFiatValue(amountToSendInput.text, assetSelector.selectedAsset.symbol, popup.store.currentCurrency)
return parseFloat(fiatValue) === 0 ? LocaleUtils.numberToLocaleString(parseFloat(fiatValue), 2) : LocaleUtils.numberToLocaleString(parseFloat(fiatValue))
if(!!assetSelector.selectedAsset) {
let fiatValue = popup.store.getFiatValue(amountToSendInput.text, assetSelector.selectedAsset.symbol, popup.store.currentCurrency)
return parseFloat(fiatValue) === 0 ? LocaleUtils.numberToLocaleString(parseFloat(fiatValue), 2) : LocaleUtils.numberToLocaleString(parseFloat(fiatValue))
}
return LocaleUtils.numberToLocaleString(0, 2)
}
input.implicitHeight: 15
input.implicitHeight: Style.current.bigPadding
implicitWidth: txtFiatBalance.input.edit.contentWidth + 50
input.rightComponent: StatusBaseText {
id: currencyText
@ -326,14 +343,34 @@ StatusDialog {
// amountToSendInput.text = root.getCryptoValue(balance, popup.store.currentCurrency, assetSelector.selectedAsset.symbol)
}
}
TokenListView {
id: tokenListRect
anchors.left: parent.left
anchors.right: parent.right
visible: !assetSelector.selectedAsset
assets: popup.selectedAccount && popup.selectedAccount.assets ? popup.selectedAccount.assets : []
currentCurrencySymbol: RootStore.currencyStore.currentCurrencySymbol
searchTokenSymbolByAddressFn: function (address) {
if(popup.selectedAccount) {
return popup.selectedAccount.findTokenSymbolByAddress(address)
}
return ""
}
onTokenSelected: {
assetSelector.userSelectedToken = selectedToken.symbol
assetSelector.selectedAsset = selectedToken
}
}
}
}
StatusScrollView {
id: scrollView
topPadding: 0
Layout.fillHeight: true
Layout.preferredWidth: parent.width
contentHeight: layout.height
contentHeight: layout.height + Style.current.padding
contentWidth: parent.width
z: 0
objectName: "sendModalScroll"
@ -341,13 +378,16 @@ StatusDialog {
Column {
id: layout
width: scrollView.availableWidth
spacing: Style.current.halfPadding
spacing: Style.current.bigPadding
anchors.left: parent.left
StatusInput {
id: recipientSelector
property bool isPending: false
height: visible ? implicitHeight: 0
visible: !isBridgeTx && !!assetSelector.selectedAsset
width: parent.width
anchors.left: parent.left
anchors.right: parent.right
@ -419,7 +459,7 @@ StatusDialog {
recipientSelector.input.text = address
d.waitTimer.restart()
}
visible: !d.recipientReady
visible: !d.recipientReady && !isBridgeTx && !!assetSelector.selectedAsset
}
NetworkSelector {
@ -433,86 +473,30 @@ StatusDialog {
interactive: popup.interactive
selectedAccount: popup.selectedAccount
amountToSend: isNaN(parseFloat(amountToSendInput.text)) ? 0 : parseFloat(amountToSendInput.text)
requiredGasInEth: gasSelector.selectedGasEthValue
requiredGasInEth: fees.selectedGasEthValue
selectedAsset: assetSelector.selectedAsset
onReCalculateSuggestedRoute: popup.recalculateRoutesAndFees()
visible: d.recipientReady
visible: d.recipientReady && !!assetSelector.selectedAsset
isLoading: popup.isLoading
bestRoutes: popup.bestRoutes
isBridgeTx: popup.isBridgeTx
}
Rectangle {
FeesView {
id: fees
radius: 13
color: Theme.palette.indirectColor1
height: text.height + gasSelector.height + gasValidator.height + Style.current.xlPadding
width: parent.width
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.bigPadding
anchors.rightMargin: Style.current.bigPadding
visible: d.recipientReady
RowLayout {
id: feesLayout
spacing: 10
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: Style.current.padding
StatusRoundIcon {
id: feesIcon
Layout.alignment: Qt.AlignTop
radius: 8
asset.name: "fees"
}
Column {
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.preferredWidth: fees.width - feesIcon.width - Style.current.xlPadding
Item {
width: parent.width
height: childrenRect.height
StatusBaseText {
id: text
anchors.left: parent.left
font.pixelSize: 15
font.weight: Font.Medium
color: Theme.palette.directColor1
text: qsTr("Fees")
wrapMode: Text.WordWrap
}
StatusBaseText {
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
id: totalFeesAdvanced
text: popup.isLoading ? "..." : gasSelector.selectedGasFiatValue
font.pixelSize: 15
color: Theme.palette.directColor1
visible: networkSelector.advancedOrCustomMode && popup.bestRoutes.length > 0
}
}
GasSelector {
id: gasSelector
width: parent.width
getGasEthValue: popup.store.getGasEthValue
getFiatValue: popup.store.getFiatValue
currentCurrency: popup.store.currencyStore.currentCurrency
currentCurrencySymbol: popup.store.currencyStore.currentCurrencySymbol
visible: gasValidator.isValid && !popup.isLoading
advancedOrCustomMode: networkSelector.advancedOrCustomMode
bestRoutes: popup.bestRoutes
selectedTokenSymbol: assetSelector.selectedAsset ? assetSelector.selectedAsset.symbol: ""
onSelectedPriorityChanged: popup.recalculateRoutesAndFees()
}
GasValidator {
id: gasValidator
width: parent.width
isLoading: popup.isLoading
isValid: popup.bestRoutes ? popup.bestRoutes.length > 0 : true
}
}
}
visible: d.recipientReady && !!assetSelector.selectedAsset
selectedTokenSymbol: assetSelector.selectedAsset ? assetSelector.selectedAsset.symbol: ""
advancedOrCustomMode: networkSelector.advancedOrCustomMode
isLoading: popup.isLoading
bestRoutes: popup.bestRoutes
store: popup.store
onPriorityChanged: popup.recalculateRoutesAndFees()
}
}
}
@ -520,10 +504,11 @@ StatusDialog {
}
footer: SendModalFooter {
maxFiatFees: popup.isLoading ? "..." : gasSelector.selectedGasFiatValue
selectedTimeEstimate: popup.isLoading? "..." : gasSelector.selectedTimeEstimate
nextButtonText: popup.isBridgeTx ? qsTr("Bridge") : qsTr("Send")
maxFiatFees: popup.isLoading ? "..." : fees.selectedGasFiatValue
selectedTimeEstimate: popup.isLoading? "..." : fees.selectedTimeEstimate
pending: d.isPendingTx || popup.isLoading
visible: d.isReady && !isNaN(amountToSendInput.text) && gasValidator.isValid && !d.errorMode
visible: d.isReady && !isNaN(amountToSendInput.text) && fees.isValid && !d.errorMode
onNextButtonClicked: popup.sendTransaction()
}
@ -541,7 +526,7 @@ StatusDialog {
return
}
popup.bestRoutes = response.suggestedRoutes.best
gasSelector.estimatedGasFeesTime = response.suggestedRoutes.gasTimeEstimates
fees.estimatedGasFeesTime = response.suggestedRoutes.gasTimeEstimates
popup.isLoading = false
}
}

View File

@ -26,33 +26,29 @@ QtObject {
property var disabledChainIdsToList: []
function addRemoveDisabledFromChain(chainID, isDisabled) {
var tempList = disabledChainIdsFromList
if(isDisabled) {
tempList.push(chainID)
disabledChainIdsFromList.push(chainID)
}
else {
for(var i = 0; i < tempList.length;i++) {
if(tempList[i] === chainID) {
tempList.splice(i, 1)
for(var i = 0; i < disabledChainIdsFromList.length;i++) {
if(disabledChainIdsFromList[i] === chainID) {
disabledChainIdsFromList.splice(i, 1)
}
}
}
disabledChainIdsFromList = tempList
}
function addRemoveDisabledToChain(chainID, isDisabled) {
var tempList = disabledChainIdsToList
if(isDisabled) {
tempList.push(chainID)
root.disabledChainIdsToList.push(chainID)
}
else {
for(var i = 0; i < tempList.length;i++) {
if(tempList[i] === chainID) {
tempList.splice(i, 1)
for(var i = 0; i < root.disabledChainIdsToList.length;i++) {
if(root.disabledChainIdsToList[i] === chainID) {
root.disabledChainIdsToList.splice(i, 1)
}
}
}
disabledChainIdsToList = tempList
}
function getEtherscanLink() {

View File

@ -11,6 +11,7 @@ import SortFilterProxyModel 0.2
import utils 1.0
import "../stores"
import shared.controls 1.0
Item {
id: root
@ -41,50 +42,11 @@ Item {
]
}
delegate: StatusListItem {
readonly property string balance: enabledNetworkBalance // Needed for the tests
delegate: TokenDelegate {
objectName: "AssetView_TokenListItem_" + symbol
readonly property string balance: enabledNetworkBalance // Needed for the tests
currentCurrencySymbol: RootStore.currencyStore.currentCurrencySymbol
width: ListView.view.width
title: name
subTitle: `${enabledNetworkBalance} ${symbol}`
asset.name: symbol ? Style.png("tokens/" + symbol) : ""
asset.isImage: true
components: [
Column {
id: valueColumn
property string textColor: Math.sign(Number(changePct24hour)) === 0 ? Theme.palette.baseColor1 :
Math.sign(Number(changePct24hour)) === -1 ? Theme.palette.dangerColor1 :
Theme.palette.successColor1
StatusBaseText {
anchors.right: parent.right
font.pixelSize: 15
font.strikeout: false
text: enabledNetworkCurrencyBalance.toLocaleCurrencyString(Qt.locale(), RootStore.currencyStore.currentCurrencySymbol)
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 8
StatusBaseText {
id: change24HourText
font.pixelSize: 15
font.strikeout: false
color: valueColumn.textColor
text: currencyPrice.toLocaleCurrencyString(Qt.locale(), RootStore.currencyStore.currentCurrencySymbol)
}
Rectangle {
width: 1
height: change24HourText.implicitHeight
color: Theme.palette.directColor9
}
StatusBaseText {
font.pixelSize: 15
font.strikeout: false
color: valueColumn.textColor
text: changePct24hour !== "" ? "%1%".arg(changePct24hour) : "---"
}
}
}
]
onClicked: {
RootStore.getHistoricalDataForToken(symbol, RootStore.currencyStore.currentCurrency)
d.selectedAssetIndex = index

View File

@ -0,0 +1,92 @@
import QtQuick 2.13
import QtQuick.Layouts 1.13
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
import "../controls"
Rectangle {
id: root
property alias selectedPriority: gasSelector.selectedPriority
property alias selectedGasEthValue: gasSelector.selectedGasEthValue
property alias selectedGasFiatValue: gasSelector.selectedGasFiatValue
property alias selectedTimeEstimate: gasSelector.selectedTimeEstimate
property alias estimatedGasFeesTime: gasSelector.estimatedGasFeesTime
property alias isValid: gasValidator.isValid
property bool isLoading: false
property var bestRoutes
property var store
property var selectedTokenSymbol
property bool advancedOrCustomMode
signal priorityChanged()
radius: 13
color: Theme.palette.indirectColor1
height: text.height + gasSelector.height + gasValidator.height + Style.current.xlPadding
RowLayout {
id: feesLayout
spacing: 10
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: Style.current.padding
StatusRoundIcon {
id: feesIcon
Layout.alignment: Qt.AlignTop
radius: 8
asset.name: "fees"
}
Column {
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.preferredWidth: root.width - feesIcon.width - Style.current.xlPadding
Item {
width: parent.width
height: childrenRect.height
StatusBaseText {
id: text
anchors.left: parent.left
font.pixelSize: 15
font.weight: Font.Medium
color: Theme.palette.directColor1
text: qsTr("Fees")
wrapMode: Text.WordWrap
}
StatusBaseText {
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
id: totalFeesAdvanced
text: root.isLoading ? "..." : gasSelector.selectedGasFiatValue
font.pixelSize: 15
color: Theme.palette.directColor1
visible: root.advancedOrCustomMode && root.bestRoutes.length > 0
}
}
GasSelector {
id: gasSelector
width: parent.width
getGasEthValue: root.store.getGasEthValue
getFiatValue: root.store.getFiatValue
currentCurrency: root.store.currencyStore.currentCurrency
currentCurrencySymbol: root.store.currencyStore.currentCurrencySymbol
visible: gasValidator.isValid && !root.isLoading
advancedOrCustomMode: root.advancedOrCustomMode
bestRoutes: root.bestRoutes
selectedTokenSymbol: root.selectedTokenSymbol
onSelectedPriorityChanged: root.priorityChanged()
}
GasValidator {
id: gasValidator
width: parent.width
isLoading: root.isLoading
isValid: root.bestRoutes ? root.bestRoutes.length > 0 : true
}
}
}
}

View File

@ -44,7 +44,9 @@ Item {
function resetAllSetValues() {
for(var i = 0; i<fromNetworksRepeater.count; i++) {
fromNetworksRepeater.itemAt(i).amountToSend = 0
fromNetworksRepeater.itemAt(i).isOnBestRoute = false
toNetworksRepeater.itemAt(i).amountToReceive = 0
toNetworksRepeater.itemAt(i).isOnBestRoute = false
}
}
}
@ -76,6 +78,7 @@ Item {
id: fromNetwork
objectName: model.chainId
property double amountToSend: 0
property bool isOnBestRoute: false
property string tokenBalanceOnChain: selectedAccount && selectedAccount!== undefined && selectedAsset!== undefined ? selectedAccount.getTokenBalanceOnChain(model.chainId, selectedAsset.symbol) : ""
property var hasGas: selectedAccount.hasGas(model.chainId, model.nativeCurrencySymbol, requiredGasInEth)
primaryText: model.chainName
@ -91,7 +94,13 @@ Item {
clickable: root.interactive
onClicked: {
store.addRemoveDisabledFromChain(model.chainId, disabled)
root.reCalculateSuggestedRoute()
// only recalculate if the a best route was disabled
if(root.bestRoutes.length === 0 || isOnBestRoute)
root.reCalculateSuggestedRoute()
}
onVisibleChanged: {
if(visible)
disabled = store.disabledChainIdsFromList.includes(model.chainId)
}
// To-do needed for custom view
// onAdvancedInputTextChanged: {
@ -120,6 +129,7 @@ Item {
StatusCard {
id: toCard
objectName: model.chainId
property bool isOnBestRoute: false
property double amountToReceive: 0
primaryText: model.chainName
secondaryText: LocaleUtils.numberToLocaleString(amountToReceive)
@ -135,7 +145,13 @@ Item {
clickable: root.interactive
onClicked: {
store.addRemoveDisabledToChain(model.chainId, disabled)
root.reCalculateSuggestedRoute()
// only recalculate if the a best route was disabled
if(root.bestRoutes.length === 0 || isOnBestRoute)
root.reCalculateSuggestedRoute()
}
onVisibleChanged: {
if(visible)
disabled = store.disabledChainIdsToList.includes(model.chainId)
}
// To-do needed for custom view
// onAdvancedInputTextChanged: {
@ -190,6 +206,8 @@ Item {
let amountToReceive = weiToEth(bestRoutes[i].amountOut)
fromN.amountToSend = amountToSend
toN.amountToReceive += amountToReceive
fromN.isOnBestRoute = true
toN.isOnBestRoute = true
d.thereIsApossibleRoute = true
StatusQUtils.Utils.drawArrow(ctx, fromN.x + fromN.width,
fromN.y + fromN.height/2,

View File

@ -14,7 +14,7 @@ import "../controls"
Item {
id: root
implicitHeight: visible ? tabBar.height + stackLayout.height + 2* Style.current.xlPadding : 0
implicitHeight: visible ? tabBar.height + stackLayout.height + Style.current.xlPadding : 0
property var store
property var selectedAccount
@ -29,6 +29,7 @@ Item {
(tabBar.currentIndex === 2) ?
customNetworkRoutingPage.errorMode: false
property bool interactive: true
property bool isBridgeTx: false
signal reCalculateSuggestedRoute()
@ -41,7 +42,6 @@ Item {
StatusSwitchTabBar {
id: tabBar
anchors.top: parent.top
anchors.topMargin: Style.current.bigPadding
anchors.horizontalCenter: parent.horizontalCenter
StatusSwitchTabButton {
text: qsTr("Simple")
@ -76,10 +76,15 @@ Item {
anchors.margins: Style.current.padding
width: stackLayout.width - Style.current.bigPadding
bestRoutes: root.bestRoutes
isBridgeTx: root.isBridgeTx
amountToSend: root.amountToSend
isLoading: root.isLoading
store: root.store
weiToEth: function(wei) {
return "%1 %2".arg(LocaleUtils.numberToLocaleString(parseFloat(store.getWei2Eth(wei, selectedAsset.decimals)))).arg(selectedAsset.symbol)
return "%1 %2".arg(LocaleUtils.numberToLocaleString(parseFloat(store.getWei2Eth(wei, selectedAsset.decimals)))).arg(selectedAsset.symbol)
}
reCalculateSuggestedRoute: function() {
root.reCalculateSuggestedRoute()
}
}
}

View File

@ -15,10 +15,13 @@ import "../controls"
RowLayout {
id: root
property var store
property var bestRoutes
property double amountToSend: 0
property bool isLoading: false
property bool isBridgeTx: false
property var weiToEth: function(wei) {}
property var reCalculateSuggestedRoute: function() {}
spacing: 10
@ -42,17 +45,10 @@ RowLayout {
Layout.maximumWidth: 410
font.pixelSize: 15
color: Theme.palette.baseColor1
text: qsTr("The networks where the receipient will receive tokens. Amounts calculated automatically for the lowest cost.")
text: isBridgeTx ? qsTr("Choose the network to bridge token to") :
qsTr("The networks where the receipient will receive tokens. Amounts calculated automatically for the lowest cost.")
wrapMode: Text.WordWrap
}
BalanceExceeded {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Style.current.bigPadding
transferPossible: root.bestRoutes !== undefined ? root.bestRoutes.length > 0 : true
amountToSend: root.amountToSend
isLoading: root.isLoading
}
ScrollView {
Layout.fillWidth: true
Layout.preferredHeight: row.height + 10
@ -62,31 +58,91 @@ RowLayout {
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
clip: true
visible: !root.isLoading ? root.bestRoutes !== undefined ? root.bestRoutes.length > 0 : true : false
visible: !root.isLoading ? root.isBridgeTx ? true : root.bestRoutes !== undefined ? root.bestRoutes.length > 0 : true : false
Row {
id: row
spacing: Style.current.padding
Repeater {
id: repeater
objectName: "networksList"
model: root.bestRoutes
StatusListItem {
id: item
objectName: modelData.toNetwork.chainName
leftPadding: 5
rightPadding: 5
implicitWidth: 150
title: modelData.toNetwork.chainName
subTitle: root.weiToEth(modelData.amountIn)
statusListItemSubTitle.color: Theme.palette.primaryColor1
asset.width: 32
asset.height: 32
asset.name: Style.svg("tiny/" + modelData.toNetwork.iconUrl)
asset.isImage: true
color: "transparent"
}
model: isBridgeTx ? store.allNetworks : root.bestRoutes
delegate: isBridgeTx ? networkItem : routeItem
}
}
}
BalanceExceeded {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Style.current.bigPadding
transferPossible: root.bestRoutes !== undefined ? root.bestRoutes.length > 0 : true
amountToSend: root.amountToSend
isLoading: root.isLoading
}
}
ButtonGroup {
buttons: repeater.children
}
Component {
id: routeItem
StatusListItem {
objectName: modelData.toNetwork.chainName
leftPadding: 5
rightPadding: 5
implicitWidth: 126
title: modelData.toNetwork.chainName
subTitle: root.weiToEth(modelData.amountIn)
statusListItemSubTitle.color: Theme.palette.primaryColor1
asset.width: 32
asset.height: 32
asset.name: Style.svg("tiny/" + modelData.toNetwork.iconUrl)
asset.isImage: true
color: "transparent"
}
}
Component {
id: networkItem
StatusRadioButton {
id: gasRectangle
width: contentItem.implicitWidth
contentItem: StatusListItem {
id: card
objectName: chainName
leftPadding: 5
rightPadding: 5
implicitWidth: 150
title: chainName
subTitle: root.weiToEth(balance)
statusListItemSubTitle.color: Theme.palette.primaryColor1
asset.width: 32
asset.height: 32
asset.name: Style.svg("tiny/" + iconUrl)
asset.isImage: true
color: {
if (sensor.containsMouse || highlighted || gasRectangle.checked) {
return Theme.palette.baseColor2
}
return Theme.palette.statusListItem.backgroundColor
}
onClicked: gasRectangle.toggle()
}
onCheckedChanged: {
store.addRemoveDisabledToChain(chainId, !gasRectangle.checked)
if(checked)
root.reCalculateSuggestedRoute()
}
checked: index === 0
indicator: Item {
width: card.width
height: card.height
}
Component.onCompleted: {
store.addRemoveDisabledToChain(chainId, !gasRectangle.checked)
if(index === (repeater.count -1))
root.reCalculateSuggestedRoute()
}
}
}
}

View File

@ -16,6 +16,7 @@ Rectangle {
property string maxFiatFees: "..."
property alias selectedTimeEstimate: estimatedTime.text
property bool pending: true
property alias nextButtonText: nextButton.text
signal nextButtonClicked()
@ -80,6 +81,7 @@ Rectangle {
}
StatusFlatButton {
id: nextButton
text: qsTr("Send")
objectName: "sendModalFooterSendButton"
size: StatusBaseButton.Size.Large
@ -88,6 +90,7 @@ Rectangle {
enabled: !footer.pending
loading: footer.pending
onClicked: nextButtonClicked()
icon.name: "password"
}
}
}

View File

@ -19,7 +19,7 @@ import "../views"
Item {
id: root
clip: true
implicitHeight: accountSelectionTabBar.height + stackLayout.height + Style.current.bigPadding
implicitHeight: visible ? accountSelectionTabBar.height + stackLayout.height + Style.current.bigPadding: 0
property var store
@ -33,7 +33,6 @@ Item {
StatusTabBar {
id: accountSelectionTabBar
anchors.top: parent.top
anchors.topMargin: 20
anchors.left: parent.left
width: parent.width

View File

@ -0,0 +1,96 @@
import QtQuick 2.13
import SortFilterProxyModel 0.2
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
import "../controls"
Rectangle {
id: root
property var assets: []
property string currentCurrencySymbol
signal tokenSelected(var selectedToken)
property var searchTokenSymbolByAddressFn: function (address) {
return ""
}
QtObject {
id: d
property string searchString
readonly property var updateSearchText: Backpressure.debounce(root, 1000, function(inputText) {
d.searchString = inputText
})
}
height: visible ? tokenList.height: 0
color: Theme.palette.indirectColor1
radius: 8
StatusListView {
id: tokenList
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
width: parent.width
height: Math.min(433, tokenList.contentHeight)
model: SortFilterProxyModel {
sourceModel: root.assets
filters: [
ExpressionFilter {
expression: {
var tokenSymbolByAddress = searchTokenSymbolByAddressFn(d.searchString)
return symbol.startsWith(d.searchString.toUpperCase()) || name.toUpperCase().startsWith(d.searchString.toUpperCase()) || (tokenSymbolByAddress!=="" && symbol.startsWith(tokenSymbolByAddress))
}
}
]
}
delegate: TokenDelegate {
objectName: "SendModal_AssetView_TokenListItem_" + symbol
readonly property string balance: enabledNetworkBalance // Needed for the tests
currentCurrencySymbol: root.currentCurrencySymbol
width: ListView.view.width
onClicked: {
tokenSelected({name: name, symbol: symbol, totalBalance: totalBalance, totalCurrencyBalance: totalCurrencyBalance, balances: balances, decimals: decimals})
}
color: sensor.containsMouse || highlighted ? Theme.palette.baseColor3 : "transparent"
}
headerPositioning: ListView.OverlayHeader
header: Rectangle {
width: parent.width
height: childrenRect.height
color: Theme.palette.indirectColor1
radius: 8
z: 2
Column {
width: parent.width
Item {
height: 5
width: parent.width
}
StatusInput {
height: 50
width: parent.width
input.showBackground: false
placeholderText: qsTr("Search for token or enter token address")
input.rightComponent: StatusIcon {
icon: "search"
height: 17
color: Theme.palette.baseColor1
}
onTextChanged: Qt.callLater(d.updateSearchText, text)
}
Rectangle {
height: 1
width: parent.width
color: Theme.palette.baseColor3
}
}
}
}
}

View File

@ -695,6 +695,7 @@ QtObject {
ENSRegister,
ENSRelease,
ENSSetPubKey,
StickersBuy
StickersBuy,
Bridge
}
}

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 5b69985b189cae2a5e36153fa4be58afe075b446
Subproject commit 4c29c97591f5a68cb6c8f63290db8d1f1b778398