mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-28 22:41:09 +00:00
feat:[UI - Swap] Create swap approve dialog
- create a new UI component - add it to StoryBook - add QML tests - integration will be done as part of https://github.com/status-im/status-desktop/issues/15443 Fixes #15442
This commit is contained in:
parent
7b8361ec0f
commit
5665602451
181
storybook/pages/SwapApproveCapModalPage.qml
Normal file
181
storybook/pages/SwapApproveCapModalPage.qml
Normal file
@ -0,0 +1,181 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ 0.1
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
import AppLayouts.Wallet 1.0
|
||||
import AppLayouts.Wallet.popups.swap 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
property var dialog
|
||||
|
||||
function createAndOpenDialog() {
|
||||
dialog = dlgComponent.createObject(popupBg)
|
||||
dialog.open()
|
||||
}
|
||||
|
||||
Component.onCompleted: createAndOpenDialog()
|
||||
|
||||
QtObject {
|
||||
id: priv
|
||||
|
||||
readonly property var accountsModel: WalletAccountsModel {}
|
||||
readonly property var selectedAccount: selectedAccountEntry.item
|
||||
|
||||
readonly property var networksModel: NetworksModel.flatNetworks
|
||||
readonly property var selectedNetwork: selectedNetworkEntry.item
|
||||
}
|
||||
|
||||
ModelEntry {
|
||||
id: selectedAccountEntry
|
||||
sourceModel: priv.accountsModel
|
||||
key: "address"
|
||||
value: ctrlAccount.currentValue
|
||||
}
|
||||
|
||||
ModelEntry {
|
||||
id: selectedNetworkEntry
|
||||
sourceModel: priv.networksModel
|
||||
key: "chainId"
|
||||
value: ctrlNetwork.currentValue
|
||||
}
|
||||
|
||||
Item {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
PopupBackground {
|
||||
id: popupBg
|
||||
anchors.fill: parent
|
||||
|
||||
Button {
|
||||
anchors.centerIn: parent
|
||||
text: "Reopen"
|
||||
|
||||
onClicked: createAndOpenDialog()
|
||||
}
|
||||
|
||||
Component {
|
||||
id: dlgComponent
|
||||
SwapApproveCapModal {
|
||||
anchors.centerIn: parent
|
||||
destroyOnClose: true
|
||||
modal: false
|
||||
closePolicy: Popup.NoAutoClose
|
||||
|
||||
fromTokenSymbol: ctrlFromSymbol.text
|
||||
fromTokenAmount: ctrlFromAmount.text
|
||||
fromTokenContractAddress: "0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
||||
|
||||
accountName: priv.selectedAccount.name
|
||||
accountAddress: priv.selectedAccount.address
|
||||
accountEmoji: priv.selectedAccount.emoji
|
||||
accountColor: Utils.getColorForId(priv.selectedAccount.colorId)
|
||||
accountBalanceAmount: "120.55489"
|
||||
|
||||
networkShortName: priv.selectedNetwork.shortName
|
||||
networkName: priv.selectedNetwork.chainName
|
||||
networkIconPath: Style.svg(priv.selectedNetwork.iconUrl)
|
||||
networkBlockExplorerUrl: priv.selectedNetwork.blockExplorerUrl
|
||||
|
||||
currentCurrency: "EUR"
|
||||
fiatFees: "1.54"
|
||||
cryptoFees: "0.001"
|
||||
estimatedTime: ctrlEstimatedTime.currentValue
|
||||
|
||||
loginType: ctrlLoginType.currentIndex
|
||||
|
||||
feesLoading: ctrlLoading.checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
SplitView.minimumWidth: 250
|
||||
SplitView.preferredWidth: 250
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlFromSymbol
|
||||
text: "DAI"
|
||||
placeholderText: "From symbol"
|
||||
}
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlFromAmount
|
||||
text: "115.478"
|
||||
placeholderText: "From amount"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Selected Account"
|
||||
}
|
||||
ComboBox {
|
||||
id: ctrlAccount
|
||||
textRole: "name"
|
||||
valueRole: "address"
|
||||
model: priv.accountsModel
|
||||
currentIndex: 0
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Selected Network"
|
||||
}
|
||||
ComboBox {
|
||||
id: ctrlNetwork
|
||||
textRole: "chainName"
|
||||
valueRole: "chainId"
|
||||
model: priv.networksModel
|
||||
currentIndex: 2
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: ctrlLoading
|
||||
text: "Fees loading"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Login Type"
|
||||
}
|
||||
ComboBox {
|
||||
id: ctrlLoginType
|
||||
model: Constants.authenticationIconByType
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Estimated time"
|
||||
}
|
||||
ComboBox {
|
||||
id: ctrlEstimatedTime
|
||||
model: [Constants.TransactionEstimatedTime.Unknown,
|
||||
Constants.TransactionEstimatedTime.LessThanOneMin,
|
||||
Constants.TransactionEstimatedTime.LessThanThreeMins,
|
||||
Constants.TransactionEstimatedTime.LessThanFiveMins,
|
||||
Constants.TransactionEstimatedTime.MoreThanFiveMins
|
||||
]
|
||||
displayText: WalletUtils.getLabelForEstimatedTxTime(currentValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Popups
|
||||
|
||||
// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3517-435657&t=sRX8mAj4irR1bOuT-0
|
279
storybook/qmlTests/tests/tst_SwapApproveCapModal.qml
Normal file
279
storybook/qmlTests/tests/tst_SwapApproveCapModal.qml
Normal file
@ -0,0 +1,279 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtTest 1.15
|
||||
import QtQml 2.15
|
||||
|
||||
import Models 1.0
|
||||
|
||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||
|
||||
import AppLayouts.Wallet 1.0
|
||||
import AppLayouts.Wallet.popups.swap 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
Component {
|
||||
id: componentUnderTest
|
||||
SwapApproveCapModal {
|
||||
anchors.centerIn: parent
|
||||
|
||||
fromTokenSymbol: "DAI"
|
||||
fromTokenAmount: "100.07"
|
||||
fromTokenContractAddress: "0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
||||
|
||||
accountName: "Hot wallet (generated)"
|
||||
accountAddress: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881"
|
||||
accountEmoji: "🚗"
|
||||
accountColor: Utils.getColorForId(Constants.walletAccountColors.primary)
|
||||
accountBalanceAmount: "120.55489"
|
||||
|
||||
networkShortName: Constants.networkShortChainNames.mainnet
|
||||
networkName: "Mainnet"
|
||||
networkIconPath: Style.svg("network/Network=Ethereum")
|
||||
networkBlockExplorerUrl: "https://etherscan.io/"
|
||||
|
||||
currentCurrency: "EUR"
|
||||
fiatFees: "1.54"
|
||||
cryptoFees: "0.001"
|
||||
estimatedTime: Constants.TransactionEstimatedTime.Unknown
|
||||
|
||||
loginType: Constants.LoginType.Password
|
||||
}
|
||||
}
|
||||
|
||||
SignalSpy {
|
||||
id: signalSpyAccepted
|
||||
target: controlUnderTest
|
||||
signalName: "accepted"
|
||||
}
|
||||
|
||||
SignalSpy {
|
||||
id: signalSpyRejected
|
||||
target: controlUnderTest
|
||||
signalName: "rejected"
|
||||
}
|
||||
|
||||
property SwapApproveCapModal controlUnderTest: null
|
||||
|
||||
TestCase {
|
||||
name: "SwapApproveCapModal"
|
||||
when: windowShown
|
||||
|
||||
function init() {
|
||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||
signalSpyAccepted.clear()
|
||||
signalSpyRejected.clear()
|
||||
}
|
||||
|
||||
function test_basicGeometry() {
|
||||
verify(!!controlUnderTest)
|
||||
verify(controlUnderTest.width > 0)
|
||||
verify(controlUnderTest.height > 0)
|
||||
}
|
||||
|
||||
function test_fromToProps() {
|
||||
verify(!!controlUnderTest)
|
||||
controlUnderTest.fromTokenSymbol = "SNT"
|
||||
controlUnderTest.fromTokenAmount = "1000.123456789"
|
||||
controlUnderTest.fromTokenContractAddress = "Oxdeadbeef"
|
||||
|
||||
// title & subtitle
|
||||
compare(controlUnderTest.title, qsTr("Approve spending cap"))
|
||||
compare(controlUnderTest.subtitle, controlUnderTest.serviceProviderURL)
|
||||
|
||||
// info box
|
||||
const headerText = findChild(controlUnderTest.contentItem, "headerText")
|
||||
verify(!!headerText)
|
||||
compare(headerText.text, qsTr("Set %1 %2 spending cap in %3 for %4 on %5")
|
||||
.arg(controlUnderTest.formatBigNumber(controlUnderTest.fromTokenAmount)).arg(controlUnderTest.fromTokenSymbol)
|
||||
.arg(controlUnderTest.accountName).arg(controlUnderTest.serviceProviderURL).arg(controlUnderTest.networkName))
|
||||
|
||||
const fromImageHidden = findChild(controlUnderTest.contentItem, "fromImage")
|
||||
compare(fromImageHidden.visible, false)
|
||||
|
||||
const fromImage = findChild(controlUnderTest.contentItem, "fromImageIdenticon")
|
||||
verify(!!fromImage)
|
||||
compare(fromImage.asset.emoji, controlUnderTest.accountEmoji)
|
||||
compare(fromImage.asset.color, controlUnderTest.accountColor)
|
||||
const toImage = findChild(controlUnderTest.contentItem, "toImage")
|
||||
verify(!!toImage)
|
||||
compare(toImage.image.source, Constants.tokenIcon(controlUnderTest.fromTokenSymbol))
|
||||
|
||||
// spending cap box
|
||||
const spendingCapBox = findChild(controlUnderTest.contentItem, "spendingCapBox")
|
||||
verify(!!spendingCapBox)
|
||||
compare(spendingCapBox.caption, qsTr("Set spending cap"))
|
||||
compare(spendingCapBox.primaryText, controlUnderTest.formatBigNumber(controlUnderTest.fromTokenAmount))
|
||||
}
|
||||
|
||||
function test_accountInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
// account box
|
||||
const accountBox = findChild(controlUnderTest.contentItem, "accountBox")
|
||||
verify(!!accountBox)
|
||||
|
||||
compare(accountBox.caption, qsTr("Account"))
|
||||
compare(accountBox.primaryText, controlUnderTest.accountName)
|
||||
compare(accountBox.secondaryText, SQUtils.Utils.elideAndFormatWalletAddress(controlUnderTest.accountAddress))
|
||||
compare(accountBox.asset.emoji, controlUnderTest.accountEmoji)
|
||||
compare(accountBox.asset.color, controlUnderTest.accountColor)
|
||||
}
|
||||
|
||||
function test_tokenInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
// token box
|
||||
const tokenBox = findChild(controlUnderTest.contentItem, "tokenBox")
|
||||
verify(!!tokenBox)
|
||||
|
||||
compare(tokenBox.caption, qsTr("Token"))
|
||||
compare(tokenBox.primaryText, controlUnderTest.fromTokenSymbol)
|
||||
compare(tokenBox.secondaryText, SQUtils.Utils.elideAndFormatWalletAddress(controlUnderTest.fromTokenContractAddress))
|
||||
compare(tokenBox.icon, Constants.tokenIcon(controlUnderTest.fromTokenSymbol))
|
||||
compare(tokenBox.badge, controlUnderTest.networkIconPath)
|
||||
}
|
||||
|
||||
function test_smartContractInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
// smart contract box
|
||||
const smartContractBox = findChild(controlUnderTest.contentItem, "smartContractBox")
|
||||
verify(!!smartContractBox)
|
||||
|
||||
compare(smartContractBox.caption, qsTr("Via smart contract"))
|
||||
compare(smartContractBox.primaryText, controlUnderTest.serviceProviderName)
|
||||
compare(smartContractBox.secondaryText, SQUtils.Utils.elideAndFormatWalletAddress(controlUnderTest.serviceProviderContractAddress))
|
||||
compare(smartContractBox.icon, Style.png("swap/paraswap"))
|
||||
}
|
||||
|
||||
function test_networkInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
// network box
|
||||
const networkBox = findChild(controlUnderTest.contentItem, "networkBox")
|
||||
verify(!!networkBox)
|
||||
|
||||
compare(networkBox.caption, qsTr("Network"))
|
||||
compare(networkBox.primaryText, controlUnderTest.networkName)
|
||||
compare(networkBox.icon, controlUnderTest.networkIconPath)
|
||||
}
|
||||
|
||||
function test_feesInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
// fees box
|
||||
const feesBox = findChild(controlUnderTest.contentItem, "feesBox")
|
||||
verify(!!feesBox)
|
||||
|
||||
compare(feesBox.caption, qsTr("Fees"))
|
||||
compare(feesBox.primaryText, qsTr("Max. fees on %1").arg(controlUnderTest.networkName))
|
||||
|
||||
const fiatFeesText = findChild(feesBox, "fiatFeesText")
|
||||
verify(!!fiatFeesText)
|
||||
compare(fiatFeesText.text, "%1 %2".arg(controlUnderTest.fiatFees).arg(controlUnderTest.currentCurrency))
|
||||
|
||||
const cryptoFeesText = findChild(feesBox, "cryptoFeesText")
|
||||
verify(!!cryptoFeesText)
|
||||
compare(cryptoFeesText.text, "%1 ETH".arg(controlUnderTest.cryptoFees))
|
||||
}
|
||||
|
||||
function test_loginType_data() {
|
||||
return [
|
||||
{ tag: "password", loginType: Constants.LoginType.Password, iconName: "password" },
|
||||
{ tag: "touchId", loginType: Constants.LoginType.Biometrics, iconName: "touch-id" },
|
||||
{ tag: "keycard", loginType: Constants.LoginType.Keycard, iconName: "keycard" }
|
||||
]
|
||||
}
|
||||
|
||||
function test_loginType(data) {
|
||||
const loginType = data.loginType
|
||||
const iconName = data.iconName
|
||||
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
controlUnderTest.loginType = loginType
|
||||
|
||||
const signButton = findChild(controlUnderTest.footer, "signButton")
|
||||
verify(!!signButton)
|
||||
compare(signButton.icon.name, iconName)
|
||||
}
|
||||
|
||||
function test_loading() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
compare(controlUnderTest.feesLoading, false)
|
||||
|
||||
const signButton = findChild(controlUnderTest.footer, "signButton")
|
||||
verify(!!signButton)
|
||||
compare(signButton.interactive, true)
|
||||
|
||||
const footerFiatFeesText = findChild(controlUnderTest.footer, "footerFiatFeesText")
|
||||
verify(!!footerFiatFeesText)
|
||||
compare(footerFiatFeesText.loading, false)
|
||||
|
||||
const footerEstimatedTime = findChild(controlUnderTest.footer, "footerEstimatedTime")
|
||||
verify(!!footerEstimatedTime)
|
||||
compare(footerEstimatedTime.loading, false)
|
||||
|
||||
const fiatFeesText = findChild(controlUnderTest.contentItem, "fiatFeesText")
|
||||
verify(!!fiatFeesText)
|
||||
compare(fiatFeesText.loading, false)
|
||||
|
||||
const cryptoFeesText = findChild(controlUnderTest.contentItem, "cryptoFeesText")
|
||||
verify(!!cryptoFeesText)
|
||||
compare(cryptoFeesText.loading, false)
|
||||
|
||||
controlUnderTest.feesLoading = true
|
||||
|
||||
compare(signButton.interactive, false)
|
||||
compare(footerFiatFeesText.loading, true)
|
||||
compare(footerEstimatedTime.loading, true)
|
||||
compare(fiatFeesText.loading, true)
|
||||
compare(cryptoFeesText.loading, true)
|
||||
}
|
||||
|
||||
function test_footerInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const fiatFeesText = findChild(controlUnderTest.footer, "footerFiatFeesText")
|
||||
verify(!!fiatFeesText)
|
||||
compare(fiatFeesText.text, "%1 %2".arg(controlUnderTest.fiatFees).arg(controlUnderTest.currentCurrency))
|
||||
|
||||
const footerEstimatedTime = findChild(controlUnderTest.footer, "footerEstimatedTime")
|
||||
verify(!!footerEstimatedTime)
|
||||
compare(footerEstimatedTime.text, WalletUtils.getLabelForEstimatedTxTime(controlUnderTest.estimatedTime))
|
||||
}
|
||||
|
||||
function test_signButton() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const signButton = findChild(controlUnderTest.footer, "signButton")
|
||||
verify(!!signButton)
|
||||
compare(signButton.interactive, true)
|
||||
|
||||
signButton.clicked()
|
||||
compare(signalSpyAccepted.count, 1)
|
||||
compare(controlUnderTest.opened, false)
|
||||
compare(controlUnderTest.result, Dialog.Accepted)
|
||||
}
|
||||
|
||||
function test_rejectButton() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const rejectButton = findChild(controlUnderTest.footer, "rejectButton")
|
||||
verify(!!rejectButton)
|
||||
compare(rejectButton.interactive, true)
|
||||
|
||||
rejectButton.clicked()
|
||||
compare(signalSpyRejected.count, 1)
|
||||
compare(controlUnderTest.opened, false)
|
||||
compare(controlUnderTest.result, Dialog.Rejected)
|
||||
}
|
||||
}
|
||||
}
|
@ -146,7 +146,7 @@ Item {
|
||||
function test_feesInfo() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
// network box
|
||||
// fees box
|
||||
const feesBox = findChild(controlUnderTest.contentItem, "feesBox")
|
||||
verify(!!feesBox)
|
||||
|
||||
@ -192,14 +192,24 @@ Item {
|
||||
verify(!!signButton)
|
||||
compare(signButton.interactive, true)
|
||||
|
||||
const fiatFeesText = findChild(controlUnderTest.footer, "footerFiatFeesText")
|
||||
const footerFiatFeesText = findChild(controlUnderTest.footer, "footerFiatFeesText")
|
||||
verify(!!footerFiatFeesText)
|
||||
compare(footerFiatFeesText.loading, false)
|
||||
|
||||
const fiatFeesText = findChild(controlUnderTest.contentItem, "fiatFeesText")
|
||||
verify(!!fiatFeesText)
|
||||
compare(fiatFeesText.loading, false)
|
||||
|
||||
const cryptoFeesText = findChild(controlUnderTest.contentItem, "cryptoFeesText")
|
||||
verify(!!cryptoFeesText)
|
||||
compare(cryptoFeesText.loading, false)
|
||||
|
||||
controlUnderTest.feesLoading = true
|
||||
|
||||
compare(signButton.interactive, false)
|
||||
compare(footerFiatFeesText.loading, true)
|
||||
compare(fiatFeesText.loading, true)
|
||||
compare(cryptoFeesText.loading, true)
|
||||
}
|
||||
|
||||
function test_footerInfo() {
|
||||
|
@ -96,7 +96,6 @@ QtObject {
|
||||
locale = locale || Qt.locale()
|
||||
const numberOfDigits = integralPartLength(num)
|
||||
let oneArgStrFormat = "%1"
|
||||
let formattedNumber = num
|
||||
let multiplier = 1
|
||||
if(numberOfDigits >=4 && numberOfDigits < 7) { // 1K - 999K
|
||||
multiplier = 1 / 1000
|
||||
|
@ -16,7 +16,7 @@ StatusFlatButton {
|
||||
required property string symbol
|
||||
required property string contractAddress
|
||||
required property string networkName
|
||||
required property string explorerName
|
||||
required property string networkShortName
|
||||
required property string networkBlockExplorerUrl
|
||||
|
||||
signal openLink(string link)
|
||||
@ -27,12 +27,23 @@ StatusFlatButton {
|
||||
highlighted: moreMenu.opened
|
||||
onClicked: moreMenu.popup(-moreMenu.width + width, height + 4)
|
||||
|
||||
function getExplorerName() {
|
||||
if (root.networkShortName === Constants.networkShortChainNames.arbitrum) {
|
||||
return qsTr("Arbiscan")
|
||||
}
|
||||
if (root.networkShortName === Constants.networkShortChainNames.optimism) {
|
||||
return qsTr("Optimistic")
|
||||
}
|
||||
return qsTr("Etherscan")
|
||||
}
|
||||
|
||||
StatusMenu {
|
||||
id: moreMenu
|
||||
|
||||
StatusAction {
|
||||
//: e.g. "View Optimism DAI contract address on Optimistic"
|
||||
text: qsTr("View %1 %2 contract address on %3").arg(root.networkName).arg(root.symbol).arg(root.explorerName)
|
||||
//: e.g. "View Optimism (DAI) contract address on Optimistic"
|
||||
text: !!root.symbol ? qsTr("View %1 %2 contract address on %3").arg(root.networkName).arg(root.symbol).arg(getExplorerName())
|
||||
: qsTr("View %1 contract address on %2").arg(root.networkName).arg(getExplorerName())
|
||||
icon.name: "external-link"
|
||||
onTriggered: {
|
||||
var link = "%1/%2/%3".arg(root.networkBlockExplorerUrl).arg(Constants.networkExplorerLinks.addressPath).arg(root.contractAddress)
|
||||
|
@ -18,6 +18,7 @@ ColumnLayout {
|
||||
property string badge
|
||||
property alias asset: listItem.asset
|
||||
property alias components: listItem.components
|
||||
property int listItemHeight: 76
|
||||
|
||||
StatusBaseText {
|
||||
text: root.caption
|
||||
@ -26,7 +27,7 @@ ColumnLayout {
|
||||
StatusListItem {
|
||||
id: listItem
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 76
|
||||
Layout.preferredHeight: root.listItemHeight
|
||||
title: root.primaryText
|
||||
statusListItemTitle.font.pixelSize: Style.current.additionalTextSize
|
||||
statusListItemTitle.elide: Text.ElideMiddle
|
||||
@ -34,6 +35,8 @@ ColumnLayout {
|
||||
statusListItemSubTitle.font.pixelSize: Style.current.additionalTextSize
|
||||
asset.name: root.icon
|
||||
asset.isImage: true
|
||||
asset.bgWidth: 40
|
||||
asset.bgHeight: 40
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
|
||||
|
@ -49,6 +49,7 @@ StatusDialog {
|
||||
|
||||
property color gradientColor: backgroundColor
|
||||
property url fromImageSource
|
||||
property alias fromImageSmartIdenticon: fromImageSmartIdenticon
|
||||
property url toImageSource
|
||||
property alias headerMainText: headerMainText.text
|
||||
property alias headerSubTextLayout: headerSubTextLayout.children
|
||||
@ -67,6 +68,10 @@ StatusDialog {
|
||||
return resultNum.replace('.', Qt.locale().decimalPoint)
|
||||
}
|
||||
|
||||
function openLinkWithConfirmation(linkUrl) {
|
||||
Global.openLinkWithConfirmation(linkUrl, SQUtils.StringUtils.extractDomainFromLink(linkUrl))
|
||||
}
|
||||
|
||||
header: StatusDialogHeader {
|
||||
visible: root.title || root.subtitle
|
||||
headline.title: root.title
|
||||
@ -102,7 +107,7 @@ StatusDialog {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: -parent.anchors.leftMargin - scrollView.leftPadding
|
||||
Layout.rightMargin: -parent.anchors.rightMargin - scrollView.rightPadding
|
||||
Layout.preferredHeight: 266 // design
|
||||
Layout.preferredHeight: childrenRect.height + 80 // 40 + 40 top/bottomMargin
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: root.gradientColor }
|
||||
GradientStop { position: 1.0; color: root.backgroundColor }
|
||||
@ -117,6 +122,15 @@ StatusDialog {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 4
|
||||
spacing: -10
|
||||
StatusSmartIdenticon {
|
||||
objectName: "fromImageIdenticon"
|
||||
id: fromImageSmartIdenticon
|
||||
width: 40
|
||||
height: 40
|
||||
asset.bgWidth: 40
|
||||
asset.bgHeight: 40
|
||||
visible: !!asset.name
|
||||
}
|
||||
StatusRoundedImage {
|
||||
objectName: "fromImage"
|
||||
width: 42
|
||||
@ -124,6 +138,7 @@ StatusDialog {
|
||||
border.width: 2
|
||||
border.color: "transparent"
|
||||
image.source: root.fromImageSource
|
||||
visible: root.fromImageSource.toString() !== ""
|
||||
}
|
||||
StatusRoundedImage {
|
||||
objectName: "toImage"
|
||||
|
240
ui/app/AppLayouts/Wallet/popups/swap/SwapApproveCapModal.qml
Normal file
240
ui/app/AppLayouts/Wallet/popups/swap/SwapApproveCapModal.qml
Normal file
@ -0,0 +1,240 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
import AppLayouts.Wallet 1.0
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
import AppLayouts.Wallet.popups 1.0
|
||||
|
||||
import shared.controls 1.0
|
||||
import utils 1.0
|
||||
|
||||
SignTransactionModalBase {
|
||||
id: root
|
||||
|
||||
required property string fromTokenSymbol
|
||||
required property string fromTokenAmount
|
||||
required property string fromTokenContractAddress
|
||||
|
||||
required property string accountName
|
||||
required property string accountAddress
|
||||
required property string accountEmoji
|
||||
required property color accountColor
|
||||
required property string accountBalanceAmount
|
||||
|
||||
required property string networkShortName // e.g. "oeth"
|
||||
required property string networkName // e.g. "Optimism"
|
||||
required property string networkIconPath // e.g. `Style.svg("network/Network=Optimism")`
|
||||
required property string networkBlockExplorerUrl
|
||||
|
||||
required property string currentCurrency
|
||||
required property string fiatFees
|
||||
required property string cryptoFees
|
||||
// need to check how this is done in new router, right now it is Enum type
|
||||
required property int estimatedTime // Constants.TransactionEstimatedTime.XXX enum
|
||||
|
||||
property string serviceProviderName: "Paraswap"
|
||||
property string serviceProviderURL: Constants.swap.paraswapUrl // TODO https://github.com/status-im/status-desktop/issues/15329
|
||||
property string serviceProviderContractAddress: "0x1bD435F3C054b6e901B7b108a0ab7617C808677b"
|
||||
|
||||
title: qsTr("Approve spending cap")
|
||||
subtitle: serviceProviderURL
|
||||
|
||||
gradientColor: Utils.setColorAlpha(root.accountColor, 0.05) // 5% of wallet color
|
||||
fromImageSmartIdenticon.asset.name: "filled-account"
|
||||
fromImageSmartIdenticon.asset.emoji: root.accountEmoji
|
||||
fromImageSmartIdenticon.asset.color: root.accountColor
|
||||
fromImageSmartIdenticon.asset.isLetterIdenticon: !!root.accountEmoji
|
||||
toImageSource: Constants.tokenIcon(root.fromTokenSymbol)
|
||||
|
||||
//: e.g. "Set 100 DAI spending cap in <account name> for <service> on <network name>"
|
||||
headerMainText: qsTr("Set %1 %2 spending cap in %3 for %4 on %5").arg(formatBigNumber(root.fromTokenAmount)).arg(root.fromTokenSymbol)
|
||||
.arg(root.accountName).arg(root.serviceProviderURL).arg(root.networkName)
|
||||
headerSubTextLayout: [
|
||||
StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
text: qsTr("The smart contract specified will be able to spend up to %1 %2 of your current or future balance.").arg(formatBigNumber(root.fromTokenAmount)).arg(root.fromTokenSymbol)
|
||||
}
|
||||
]
|
||||
|
||||
headerIconComponent: StatusSmartIdenticon {
|
||||
asset.name: Style.png("swap/paraswap") // FIXME svg
|
||||
asset.isImage: true
|
||||
asset.bgWidth: 40
|
||||
asset.bgHeight: 40
|
||||
}
|
||||
|
||||
leftFooterContents: ObjectModel {
|
||||
RowLayout {
|
||||
Layout.leftMargin: 4
|
||||
spacing: Style.current.bigPadding
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
StatusBaseText {
|
||||
text: qsTr("Max fees:")
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "footerFiatFeesText"
|
||||
text: "%1 %2".arg(formatBigNumber(root.fiatFees)).arg(root.currentCurrency)
|
||||
loading: root.feesLoading
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
StatusBaseText {
|
||||
text: qsTr("Est. time:")
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "footerEstimatedTime"
|
||||
text: WalletUtils.getLabelForEstimatedTxTime(root.estimatedTime)
|
||||
loading: root.feesLoading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spending cap
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "spendingCapBox"
|
||||
caption: qsTr("Set spending cap")
|
||||
primaryText: formatBigNumber(root.fromTokenAmount)
|
||||
listItemHeight: 44
|
||||
components: [
|
||||
StatusSmartIdenticon {
|
||||
asset.name: Constants.tokenIcon(root.fromTokenSymbol)
|
||||
asset.isImage: true
|
||||
asset.width: 20
|
||||
asset.height: 20
|
||||
},
|
||||
StatusBaseText {
|
||||
text: root.fromTokenSymbol
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Account
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "accountBox"
|
||||
caption: qsTr("Account")
|
||||
primaryText: root.accountName
|
||||
secondaryText: SQUtils.Utils.elideAndFormatWalletAddress(root.accountAddress)
|
||||
asset.name: "filled-account"
|
||||
asset.emoji: root.accountEmoji
|
||||
asset.color: root.accountColor
|
||||
asset.isLetterIdenticon: !!root.accountEmoji
|
||||
components: [
|
||||
InformationTag {
|
||||
tagPrimaryLabel.text: "%1 %2".arg(formatBigNumber(root.accountBalanceAmount, 2)).arg(root.fromTokenSymbol)
|
||||
rightComponent: StatusRoundedImage {
|
||||
width: 16
|
||||
height: 16
|
||||
image.source: root.networkIconPath
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Token
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "tokenBox"
|
||||
caption: qsTr("Token")
|
||||
primaryText: root.fromTokenSymbol
|
||||
secondaryText: SQUtils.Utils.elideAndFormatWalletAddress(root.fromTokenContractAddress)
|
||||
icon: Constants.tokenIcon(root.fromTokenSymbol)
|
||||
badge: root.networkIconPath
|
||||
components: [
|
||||
ContractInfoButtonWithMenu {
|
||||
symbol: root.fromTokenSymbol
|
||||
contractAddress: root.fromTokenContractAddress
|
||||
networkName: root.networkName
|
||||
networkShortName: root.networkShortName
|
||||
networkBlockExplorerUrl: root.networkBlockExplorerUrl
|
||||
onOpenLink: (link) => root.openLinkWithConfirmation(link)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Smart contract
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "smartContractBox"
|
||||
caption: qsTr("Via smart contract")
|
||||
primaryText: root.serviceProviderName
|
||||
secondaryText: SQUtils.Utils.elideAndFormatWalletAddress(root.serviceProviderContractAddress)
|
||||
icon: Style.png("swap/paraswap") // FIXME svg
|
||||
components: [
|
||||
ContractInfoButtonWithMenu {
|
||||
symbol: ""
|
||||
contractAddress: root.serviceProviderContractAddress
|
||||
networkName: root.serviceProviderName
|
||||
networkShortName: root.networkShortName
|
||||
networkBlockExplorerUrl: root.networkBlockExplorerUrl
|
||||
onOpenLink: (link) => root.openLinkWithConfirmation(link)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Network
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "networkBox"
|
||||
caption: qsTr("Network")
|
||||
primaryText: root.networkName
|
||||
icon: root.networkIconPath
|
||||
}
|
||||
|
||||
// Fees
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "feesBox"
|
||||
caption: qsTr("Fees")
|
||||
primaryText: qsTr("Max. fees on %1").arg(root.networkName)
|
||||
secondaryText: " "
|
||||
components: [
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "fiatFeesText"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "%1 %2".arg(formatBigNumber(root.fiatFees)).arg(root.currentCurrency)
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
loading: root.feesLoading
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "cryptoFeesText"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "%1 ETH".arg(formatBigNumber(root.cryptoFees))
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
customColor: Theme.palette.baseColor1
|
||||
loading: root.feesLoading
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ SignTransactionModalBase {
|
||||
normalColor: Theme.palette.directColor1
|
||||
linkColor: Theme.palette.directColor1
|
||||
font.weight: Font.Normal
|
||||
onClicked: d.openLinkWithConfirmation(root.serviceProviderURL)
|
||||
onClicked: root.openLinkWithConfirmation(root.serviceProviderURL)
|
||||
},
|
||||
StatusIcon {
|
||||
Layout.leftMargin: -2
|
||||
@ -79,24 +79,6 @@ SignTransactionModalBase {
|
||||
]
|
||||
infoTagText: qsTr("Review all details before signing")
|
||||
|
||||
readonly property var d: QtObject {
|
||||
id: d
|
||||
|
||||
function openLinkWithConfirmation(linkUrl) {
|
||||
Global.openLinkWithConfirmation(linkUrl, SQUtils.StringUtils.extractDomainFromLink(linkUrl))
|
||||
}
|
||||
|
||||
function getExplorerName() {
|
||||
if (root.networkShortName === Constants.networkShortChainNames.arbitrum) {
|
||||
return qsTr("Arbiscan")
|
||||
}
|
||||
if (root.networkShortName === Constants.networkShortChainNames.optimism) {
|
||||
return qsTr("Optimistic")
|
||||
}
|
||||
return qsTr("Etherscan")
|
||||
}
|
||||
}
|
||||
|
||||
headerIconComponent: StatusSmartIdenticon {
|
||||
asset.name: "filled-account"
|
||||
asset.emoji: root.accountEmoji
|
||||
@ -158,9 +140,9 @@ SignTransactionModalBase {
|
||||
symbol: root.fromTokenSymbol
|
||||
contractAddress: root.fromTokenContractAddress
|
||||
networkName: root.networkName
|
||||
explorerName: d.getExplorerName()
|
||||
networkShortName: root.networkShortName
|
||||
networkBlockExplorerUrl: root.networkBlockExplorerUrl
|
||||
onOpenLink: (link) => d.openLinkWithConfirmation(link)
|
||||
onOpenLink: (link) => root.openLinkWithConfirmation(link)
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -180,9 +162,9 @@ SignTransactionModalBase {
|
||||
symbol: root.toTokenSymbol
|
||||
contractAddress: root.toTokenContractAddress
|
||||
networkName: root.networkName
|
||||
explorerName: d.getExplorerName()
|
||||
networkShortName: root.networkShortName
|
||||
networkBlockExplorerUrl: root.networkBlockExplorerUrl
|
||||
onOpenLink: (link) => d.openLinkWithConfirmation(link)
|
||||
onOpenLink: (link) => root.openLinkWithConfirmation(link)
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -195,12 +177,10 @@ SignTransactionModalBase {
|
||||
caption: qsTr("In account")
|
||||
primaryText: root.accountName
|
||||
secondaryText: SQUtils.Utils.elideAndFormatWalletAddress(root.accountAddress)
|
||||
asset.name: !!root.accountEmoji ? "" : "filled-account"
|
||||
asset.name: "filled-account"
|
||||
asset.emoji: root.accountEmoji
|
||||
asset.color: root.accountColor
|
||||
asset.isLetterIdenticon: !!root.accountEmoji
|
||||
asset.bgWidth: 40
|
||||
asset.bgHeight: 40
|
||||
}
|
||||
|
||||
// Network
|
||||
@ -224,20 +204,22 @@ SignTransactionModalBase {
|
||||
components: [
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
StatusBaseText {
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "fiatFeesText"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "%1 %2".arg(formatBigNumber(root.fiatFees)).arg(root.currentCurrency)
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
loading: root.feesLoading
|
||||
}
|
||||
StatusBaseText {
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "cryptoFeesText"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "%1 ETH".arg(formatBigNumber(root.cryptoFees))
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
color: Theme.palette.baseColor1
|
||||
customColor: Theme.palette.baseColor1
|
||||
loading: root.feesLoading
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -5,4 +5,6 @@ SwapOutputData 1.0 SwapOutputData.qml
|
||||
SwapSignApprovePopup 1.0 SwapSignApprovePopup.qml
|
||||
SwapSignApproveInputForm 1.0 SwapSignApproveInputForm.qml
|
||||
SwapSignApproveAdaptor 1.0 SwapSignApproveAdaptor.qml
|
||||
|
||||
SwapApproveCapModal 1.0 SwapApproveCapModal.qml
|
||||
SwapSignModal 1.0 SwapSignModal.qml
|
||||
|
Loading…
x
Reference in New Issue
Block a user