From 56568f68c87c9f067c457a6021198cd3d9bc229e Mon Sep 17 00:00:00 2001 From: Pascal Precht Date: Tue, 4 Aug 2020 13:10:09 +0200 Subject: [PATCH] feat: introduce AssetAndAmountInput component Closes #673 --- src/app/wallet/view.nim | 7 + src/app/wallet/views/account_item.nim | 11 +- src/app/wallet/views/asset_list.nim | 6 +- src/status/wallet.nim | 3 + src/status/wallet/account.nim | 2 +- src/status/wallet/balance_manager.nim | 1 + .../Wallet/components/SendModalContent.qml | 31 ++-- ui/shared/AssetAndAmountInput.qml | 161 ++++++++++++++++++ ui/shared/AssetSelector.qml | 8 +- 9 files changed, 203 insertions(+), 27 deletions(-) create mode 100644 ui/shared/AssetAndAmountInput.qml diff --git a/src/app/wallet/view.nim b/src/app/wallet/view.nim index 48760f0331..ce2e0ebbed 100644 --- a/src/app/wallet/view.nim +++ b/src/app/wallet/view.nim @@ -149,6 +149,13 @@ QtObject: self.setCurrentAccountByIndex(0) self.accountListChanged() + proc getFiatValue*(self: WalletView, cryptoBalance: string, cryptoSymbol: string, fiatSymbol: string): string {.slot.} = + let val = self.status.wallet.getFiatValue(cryptoBalance, cryptoSymbol, fiatSymbol) + result = fmt"{val:.2f}" + + proc getCryptoValue*(self: WalletView, fiatBalance: string, fiatSymbol: string, cryptoSymbol: string): string {.slot.} = + result = fmt"{self.status.wallet.getFiatValue(fiatBalance, fiatSymbol, cryptoSymbol)}" + proc generateNewAccount*(self: WalletView, password: string, accountName: string, color: string): string {.slot.} = result = self.status.wallet.generateNewAccount(password, accountName, color) diff --git a/src/app/wallet/views/account_item.nim b/src/app/wallet/views/account_item.nim index ad39182963..4800489318 100644 --- a/src/app/wallet/views/account_item.nim +++ b/src/app/wallet/views/account_item.nim @@ -1,9 +1,11 @@ import NimQml, std/wrapnils from ../../../status/wallet import WalletAccount +import ./asset_list QtObject: type AccountItemView* = ref object of QObject account*: WalletAccount + assetList*: AssetList proc setup(self: AccountItemView) = self.QObject.setup @@ -13,11 +15,14 @@ QtObject: proc newAccountItemView*(): AccountItemView = new(result, delete) - result = AccountItemView() + let accountItemView = AccountItemView() + accountItemView.assetList = newAssetList() + result = accountItemView result.setup proc setAccountItem*(self: AccountItemView, account: WalletAccount) = self.account = account + self.assetList.setNewData(account.assetList) proc name*(self: AccountItemView): string {.slot.} = result = ?.self.account.name QtProperty[string] name: @@ -42,3 +47,7 @@ QtObject: proc walletType*(self: AccountItemView): string {.slot.} = result = ?.self.account.walletType QtProperty[string] walletType: read = walletType + + proc assets*(self: AccountItemView): QVariant {.slot.} = result = newQVariant(?.self.assetList) + QtProperty[QVariant] assets: + read = assets diff --git a/src/app/wallet/views/asset_list.nim b/src/app/wallet/views/asset_list.nim index 80ea51e53b..00fd1560b5 100644 --- a/src/app/wallet/views/asset_list.nim +++ b/src/app/wallet/views/asset_list.nim @@ -8,6 +8,7 @@ type Value = UserRole + 3, FiatBalanceDisplay = UserRole + 4 Address = UserRole + 5 + FiatBalance = UserRole + 6 QtObject: type AssetList* = ref object of QAbstractListModel @@ -34,6 +35,7 @@ QtObject: of "value": result = asset.value of "fiatBalanceDisplay": result = asset.fiatBalanceDisplay of "address": result = asset.address + of "fiatBalance": result = asset.fiatBalance method rowCount(self: AssetList, index: QModelIndex = nil): int = return self.assets.len @@ -51,13 +53,15 @@ QtObject: of AssetRoles.Value: result = newQVariant(asset.value) of AssetRoles.FiatBalanceDisplay: result = newQVariant(asset.fiatBalanceDisplay) of AssetRoles.Address: result = newQVariant(asset.address) + of AssetRoles.FiatBalance: result = newQVariant(asset.fiatBalance) method roleNames(self: AssetList): Table[int, string] = { AssetRoles.Name.int:"name", AssetRoles.Symbol.int:"symbol", AssetRoles.Value.int:"value", AssetRoles.FiatBalanceDisplay.int:"fiatBalanceDisplay", - AssetRoles.Address.int:"address" }.toTable + AssetRoles.Address.int:"address", + AssetRoles.FiatBalance.int:"fiatBalance"}.toTable proc addAssetToList*(self: AssetList, asset: Asset) = self.beginInsertRows(newQModelIndex(), self.assets.len, self.assets.len) diff --git a/src/status/wallet.nim b/src/status/wallet.nim index f61dc52b3a..0df61a4293 100644 --- a/src/status/wallet.nim +++ b/src/status/wallet.nim @@ -95,6 +95,9 @@ proc getTotalFiatBalance*(self: WalletModel): string = var newBalance = 0.0 fmt"{self.totalBalance:.2f} {self.defaultCurrency}" +proc getFiatValue*(self: WalletModel, cryptoBalance: string, cryptoSymbol: string, fiatSymbol: string): float = + result = getFiatValue(cryptoBalance, cryptoSymbol, fiatSymbol) + proc calculateTotalFiatBalance*(self: WalletModel) = self.totalBalance = 0.0 for account in self.accounts: diff --git a/src/status/wallet/account.nim b/src/status/wallet/account.nim index 6b1653e4b9..bfb21e0305 100644 --- a/src/status/wallet/account.nim +++ b/src/status/wallet/account.nim @@ -8,7 +8,7 @@ type CurrencyArgs* = ref object of Args currency*: string type Asset* = ref object - name*, symbol*, value*, fiatBalanceDisplay*, accountAddress*, address*: string + name*, symbol*, value*, fiatBalanceDisplay*, fiatBalance*, accountAddress*, address*: string type WalletAccount* = ref object name*, address*, iconColor*, balance*, path*, walletType*, publicKey*: string diff --git a/src/status/wallet/balance_manager.nim b/src/status/wallet/balance_manager.nim index 188275907b..c1b997197e 100644 --- a/src/status/wallet/balance_manager.nim +++ b/src/status/wallet/balance_manager.nim @@ -64,6 +64,7 @@ proc updateBalance*(asset: Asset, currency: string) = let fiat_balance = getFiatValue(token_balance, asset.symbol, currency) asset.value = token_balance asset.fiatBalanceDisplay = fmt"{fiat_balance:.2f} {currency}" + asset.fiatBalance = fmt"{fiat_balance:.2f}" proc updateBalance*(account: WalletAccount, currency: string) = try: diff --git a/ui/app/AppLayouts/Wallet/components/SendModalContent.qml b/ui/app/AppLayouts/Wallet/components/SendModalContent.qml index d3b26837de..bb53e7653e 100644 --- a/ui/app/AppLayouts/Wallet/components/SendModalContent.qml +++ b/ui/app/AppLayouts/Wallet/components/SendModalContent.qml @@ -91,34 +91,27 @@ Item { } } - Input { - id: txtAmount - //% "Amount" - label: qsTrId("amount") - anchors.top: parent.top - //% "Enter amount..." - placeholderText: qsTrId("enter-amount...") - validationError: amountValidationError - } - - AssetSelector { - id: selectAsset - assets: walletModel.assets - anchors.top: txtAmount.bottom - anchors.topMargin: Style.current.padding - anchors.right: parent.right - width: 86 - height: 28 + AssetAndAmountInput { + id: txtAmount + selectedAccount: walletModel.currentAccount + defaultCurrency: walletModel.defaultCurrency + errorMessage: amountValidationError + anchors.top: parent.top + getFiatValue: walletModel.getFiatValue + getCryptoValue: walletModel.getCryptoValue } AccountSelector { id: selectFromAccount accounts: walletModel.accounts currency: walletModel.defaultCurrency - anchors.top: selectAsset.bottom + anchors.top: txtAmount.bottom anchors.topMargin: Style.current.padding anchors.left: parent.left anchors.right: parent.right + onAccountSelected: function (selectedAccount, index) { + txtAmount.selectedAccount = selectedAccount + } } Input { diff --git a/ui/shared/AssetAndAmountInput.qml b/ui/shared/AssetAndAmountInput.qml new file mode 100644 index 0000000000..965747c4b4 --- /dev/null +++ b/ui/shared/AssetAndAmountInput.qml @@ -0,0 +1,161 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.13 +import QtGraphicalEffects 1.13 +import "../imports" + +Item { + property string errorMessage: "" + property string defaultCurrency: "USD" + property string fiatBalance: "0.00" + property alias text: inputAmount.text + property var selectedAccount + property var getFiatValue: function () {} + property var getCryptoValue: function () {} + + id: root + + height: inputAmount.height + txtFiatBalance.height + txtFiatBalance.anchors.topMargin + anchors.right: parent.right + anchors.left: parent.left + + onSelectedAccountChanged: { + txtBalance.text = selectAsset.selectedAsset.value + } + + Item { + anchors.right: parent.right + anchors.left: parent.left + anchors.top: parent.top + height: txtBalanceDesc.height + + StyledText { + id: txtBalanceDesc + text: qsTr("Balance: ") + anchors.right: txtBalance.left + font.weight: Font.Medium + font.pixelSize: 13 + color: parseFloat(inputAmount.text) > parseFloat(txtBalance.text) ? Style.current.red : Style.current.secondaryText + } + + StyledText { + id: txtBalance + property bool hovered: false + text: selectAsset.selectedAsset.value + anchors.right: parent.right + font.weight: Font.Medium + font.pixelSize: 13 + color: { + if (txtBalance.hovered) { + return Style.current.textColor + } + return parseFloat(inputAmount.text) > parseFloat(txtBalance.text) ? Style.current.red : Style.current.secondaryText + } + + MouseArea { + cursorShape: Qt.PointingHandCursor + anchors.fill: parent + hoverEnabled: true + onExited: { + txtBalance.hovered = false + } + onEntered: { + txtBalance.hovered = true + } + onClicked: { + inputAmount.text = selectAsset.selectedAsset.value + txtFiatBalance.text = root.getFiatValue(inputAmount.text, selectAsset.selectedAsset.symbol, root.defaultCurrency) + } + } + } + } + + Input { + id: inputAmount + label: qsTr("Asset & Amount") + placeholderText: "0.00" + validationError: root.errorMessage + anchors.top: parent.top + customHeight: 56 + Keys.onReleased: { + let amount = inputAmount.text.trim() + + if (isNaN(amount)) { + return + } + if (amount === "") { + txtFiatBalance.text = "0.00" + } else { + txtFiatBalance.text = root.getFiatValue(amount, selectAsset.selectedAsset.symbol, root.defaultCurrency) + } + } + } + + AssetSelector { + id: selectAsset + assets: root.selectedAccount.assets + width: 86 + height: 28 + anchors.top: inputAmount.top + anchors.topMargin: Style.current.bigPadding + 14 + anchors.right: parent.right + anchors.rightMargin: Style.current.smallPadding + onSelectedAssetChanged: { + inputAmount.text = selectAsset.selectedAsset.value + txtBalance.text = selectAsset.selectedAsset.value + txtFiatBalance.text = root.getFiatValue(inputAmount.text, selectAsset.selectedAsset.symbol, root.defaultCurrency) + } + } + + Item { + height: txtFiatBalance.height + anchors.left: parent.left + anchors.top: inputAmount.bottom + anchors.topMargin: inputAmount.labelMargin + + StyledTextField { + id: txtFiatBalance + anchors.left: parent.left + anchors.top: parent.top + color: txtFiatBalance.activeFocus ? Style.current.textColor : Style.current.secondaryText + font.weight: Font.Medium + font.pixelSize: 12 + inputMethodHints: Qt.ImhFormattedNumbersOnly + text: root.fiatBalance + selectByMouse: true + background: Rectangle { + color: Style.current.transparent + } + padding: 0 + Keys.onReleased: { + let balance = txtFiatBalance.text.trim() + if (balance === "" || isNaN(balance)) { + return + } + inputAmount.text = root.getCryptoValue(balance, root.defaultCurrency, selectAsset.selectedAsset.symbol) + } + } + + StyledText { + id: txtFiatSymbol + text: root.defaultCurrency.toUpperCase() + font.weight: Font.Medium + font.pixelSize: 12 + color: Style.current.secondaryText + anchors.top: parent.top + anchors.left: txtFiatBalance.right + anchors.leftMargin: 2 + } + } + + StyledText { + text: root.errorMessage != "" ? root.errorMessage : qsTr("Insufficient balance") + anchors.right: parent.right + anchors.top: inputAmount.bottom + anchors.topMargin: inputAmount.labelMargin + font.weight: Font.Medium + font.pixelSize: 12 + color: Style.current.red + visible: parseFloat(inputAmount.text) > parseFloat(txtBalance.text) || root.errorMessage != "" + } +} diff --git a/ui/shared/AssetSelector.qml b/ui/shared/AssetSelector.qml index 6eada97215..3e592455b7 100644 --- a/ui/shared/AssetSelector.qml +++ b/ui/shared/AssetSelector.qml @@ -7,9 +7,7 @@ import "../imports" Item { id: root property var assets - property var selectedAsset: { - "symbol": "snt", "name": "", "value": "", "fiatBalanceDisplay": "", "address": "" - } + property var selectedAsset width: 86 height: 24 @@ -61,7 +59,7 @@ Item { Component.onCompleted: { if (isFirstItem) { - root.selectedAsset = { address, name, value, symbol, fiatBalanceDisplay } + root.selectedAsset = { address, name, value, symbol, fiatBalanceDisplay, fiatBalance } } } width: parent.width @@ -141,7 +139,7 @@ Item { cursorShape: Qt.PointingHandCursor anchors.fill: itemContainer onClicked: { - root.selectedAsset = { address, name, value, symbol, fiatBalanceDisplay } + root.selectedAsset = { address, name, value, symbol, fiatBalance, fiatBalanceDisplay } select.menu.close() } }