diff --git a/storybook/pages/SimpleSendModalPage.qml b/storybook/pages/SimpleSendModalPage.qml index d101c96802..cba06af5ea 100644 --- a/storybook/pages/SimpleSendModalPage.qml +++ b/storybook/pages/SimpleSendModalPage.qml @@ -5,6 +5,7 @@ import QtQuick.Controls 2.15 import SortFilterProxyModel 0.2 import StatusQ 0.1 +import StatusQ.Core 0.1 import Models 1.0 import Storybook 1.0 @@ -33,6 +34,15 @@ SplitView { } readonly property var walletAccountsModel: WalletAccountsModel{} + + function getCurrencyAmount(amount, symbol) { + return ({ + amount: amount, + symbol: symbol ? symbol.toUpperCase() : root.currentCurrency, + displayDecimals: 2, + stripTrailingZeroes: false + }) + } } PopupBackground { @@ -60,11 +70,22 @@ SplitView { modal: false closePolicy: Popup.CloseOnEscape + interactive: interactiveCheckbox.checked + accountsModel: d.walletAccountsModel assetsModel: assetsSelectorViewAdaptor.outputAssetsModel collectiblesModel: collectiblesSelectionAdaptor.model networksModel: d.filteredNetworksModel + currentCurrency: "USD" + fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) { + if (isNaN(amount)) { + return "N/A" + } + var currencyAmount = d.getCurrencyAmount(amount, symbol) + return LocaleUtils.currencyAmountToLocaleString(currencyAmount, options, locale) + } + Binding on selectedAccountAddress { value: accountsCombobox.currentValue ?? "" } @@ -123,7 +144,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "", communityName: "", - communityImage: Qt.resolvedUrl("") + communityImage: Qt.resolvedUrl(""), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_4", @@ -144,7 +166,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "", communityName: "", - communityImage: Qt.resolvedUrl("") + communityImage: Qt.resolvedUrl(""), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_5", @@ -165,7 +188,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "", communityName: "", - communityImage: Qt.resolvedUrl("") + communityImage: Qt.resolvedUrl(""), + tokenType: Constants.TokenType.ERC721 }, // collection 1 { @@ -192,7 +216,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "", communityName: "", - communityImage: Qt.resolvedUrl("") + communityImage: Qt.resolvedUrl(""), + tokenType: Constants.TokenType.ERC1155 }, { tokenId: "id_2", @@ -213,7 +238,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "", communityName: "", - communityImage: Qt.resolvedUrl("") + communityImage: Qt.resolvedUrl(""), + tokenType: Constants.TokenType.ERC1155 }, // collection 3, community token { @@ -235,7 +261,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_1", communityName: "My community", - communityImage: Constants.tokenIcon("KIN", false) + communityImage: Constants.tokenIcon("KIN", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_7", @@ -256,7 +283,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_1", communityName: "My community", - communityImage: Constants.tokenIcon("KIN", false) + communityImage: Constants.tokenIcon("KIN", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_8", @@ -277,7 +305,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_1", communityName: "My community", - communityImage: Constants.tokenIcon("KIN", false) + communityImage: Constants.tokenIcon("KIN", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_9", @@ -298,7 +327,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_1", communityName: "My community", - communityImage: Constants.tokenIcon("KIN", false) + communityImage: Constants.tokenIcon("KIN", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_10", @@ -319,7 +349,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_2", communityName: "My community 2", - communityImage: Constants.tokenIcon("ICOS", false) + communityImage: Constants.tokenIcon("ICOS", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_11", @@ -340,7 +371,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_2", communityName: "My community 2", - communityImage: Constants.tokenIcon("ICOS", false) + communityImage: Constants.tokenIcon("ICOS", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_11", @@ -361,7 +393,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_2", communityName: "My community 2", - communityImage: Constants.tokenIcon("ICOS", false) + communityImage: Constants.tokenIcon("ICOS", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_12", @@ -382,7 +415,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_2", communityName: "My community 2", - communityImage: Constants.tokenIcon("ICOS", false) + communityImage: Constants.tokenIcon("ICOS", false), + tokenType: Constants.TokenType.ERC721 }, { tokenId: "id_13", @@ -403,7 +437,8 @@ SplitView { mediaUrl: Qt.resolvedUrl(""), communityId: "community_2", communityName: "My community 2", - communityImage: Constants.tokenIcon("ICOS", false) + communityImage: Constants.tokenIcon("ICOS", false), + tokenType: Constants.TokenType.ERC721 } ] @@ -420,8 +455,10 @@ SplitView { ColumnLayout { spacing: 20 - Text { - text: "Values to set before popup is launched" + CheckBox { + id: interactiveCheckbox + text: "Is interactive" + checked: true } Text { @@ -491,6 +528,28 @@ SplitView { text: "token selected is: " + simpleSend.selectedTokenKey } + RowLayout { + Layout.fillWidth: true + TextField { + id: amountInput + Layout.preferredWidth: 200 + Layout.preferredHeight: 50 + validator: RegularExpressionValidator { + regularExpression: /^\d*\.?\d*$/ + } + } + Button { + text: "update in modal" + onClicked: simpleSend.selectedAmount = amountInput.text + } + } + Text { + text: "amount selected in base unit: " + simpleSend.selectedAmountInBaseUnit + } + Text { + text: "amount entered is: " + simpleSend.selectedAmount + } + RolesRenamingModel { id: collectiblesKeyModel sourceModel: collectiblesSelectionAdaptor.model diff --git a/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml b/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml index 96d8c5a3ba..b1d2a502fc 100644 --- a/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml +++ b/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml @@ -58,10 +58,6 @@ RowLayout { /** input property for programatic selection of network **/ property int selectedChainId - /** input property for programatic selection of token - (asset/collectible/collection) **/ - property string selectedTokenKey - /** signal to propagate that an asset was selected **/ signal assetSelected(string key) /** signal to propagate that a collection was selected **/ @@ -71,32 +67,10 @@ RowLayout { /** signal to propagate that a network was selected **/ signal networkSelected(string chainId) - QtObject { - id: d - readonly property bool selectedTokenNotAvailableOnAssetsOrCollectiblesList: !selectedAssetEntry.available && !selectedCollectibleEntry.available - onSelectedTokenNotAvailableOnAssetsOrCollectiblesListChanged: { - if(selectedTokenNotAvailableOnAssetsOrCollectiblesList) { - // reset token selector in case selected tokens doesnt exist in either models - tokenSelector.setSelection("", "", "") - } - } - - function updateAssetInTokenSelector(available, item) { - if(available) { - tokenSelector.setSelection(item.symbol, - Constants.tokenIcon(item.symbol), - item.tokensKey) - } - } - - function updateCollectibleInTokenSelector(available, item) { - if(available) { - const id = item.communityId ? item.collectionUid : item.uid - tokenSelector.setSelection(item.name, - item.imageUrl || item.mediaUrl, - id) - } - } + /** input function for programatic selection of token + (asset/collectible/collection) **/ + function setToken(name, icon, key) { + tokenSelector.setSelection(name, icon, key) } implicitHeight: sendModalTitleText.height @@ -181,22 +155,4 @@ RowLayout { onToggleNetwork: root.networkSelected(chainId) } - - ModelEntry { - id: selectedAssetEntry - sourceModel: root.assetsModel - key: "tokensKey" - value: root.selectedTokenKey - onAvailableChanged: d.updateAssetInTokenSelector(available, item) - onItemChanged: d.updateAssetInTokenSelector(available, item) - } - - ModelEntry { - id: selectedCollectibleEntry - sourceModel: root.collectiblesModel - key: "symbol" - value: root.selectedTokenKey - onAvailableChanged: d.updateCollectibleInTokenSelector(available, item) - onItemChanged: d.updateCollectibleInTokenSelector(available, item) - } } diff --git a/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml b/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml index 3eb31c7458..ff0ad37657 100644 --- a/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml +++ b/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml @@ -53,10 +53,6 @@ Rectangle { /** input property for programatic selection of network **/ property int selectedChainId: -1 - /** input property for programatic selection of token - (asset/collectible/collection) **/ - property string selectedTokenKey - /** signal to propagate that an asset was selected **/ signal assetSelected(string key) /** signal to propagate that a collection was selected **/ @@ -66,6 +62,12 @@ Rectangle { /** signal to propagate that a network was selected **/ signal networkSelected(string chainId) + /** input function for programatic selection of token + (asset/collectible/collection) **/ + function setToken(name, icon, key) { + sendModalHeader.setToken(name, icon, key) + } + enabled: root.isScrolling color: Theme.palette.baseColor3 radius: 8 @@ -114,7 +116,6 @@ Rectangle { collectiblesModel: root.collectiblesModel selectedChainId: root.selectedChainId - selectedTokenKey: root.selectedTokenKey onCollectibleSelected: root.collectibleSelected(key) onCollectionSelected: root.collectionSelected(key) diff --git a/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml b/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml index 65b0cbada9..9b4636d689 100644 --- a/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml +++ b/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml @@ -1,15 +1,22 @@ import QtQuick 2.15 import QtQuick.Layouts 1.14 +import StatusQ 0.1 import StatusQ.Core 0.1 import StatusQ.Controls 0.1 import StatusQ.Core.Theme 0.1 +import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Popups.Dialog 0.1 +import StatusQ.Core.Backpressure 0.1 import shared.popups.send.views 1.0 import shared.controls 1.0 import AppLayouts.Wallet.panels 1.0 +import AppLayouts.Wallet.controls 1.0 +import AppLayouts.Wallet 1.0 + +import utils 1.0 StatusDialog { id: root @@ -64,33 +71,124 @@ StatusDialog { Only networks valid as per mainnet/testnet selection **/ required property var networksModel + /** Input property holds currently selected Fiat currency **/ + required property string currentCurrency + /** Input function to format currency amount to locale string **/ + required property var fnFormatCurrencyAmount + + /** input property to decide if send mdoal is interactive or prefilled**/ + property bool interactive /** property to set and expose currently selected account **/ property string selectedAccountAddress - /** property to set and expose currently selected network **/ property int selectedChainId - /** property to set and expose currently selected token key **/ property string selectedTokenKey + /** property to set and expose the amount to send from outside without any localization **/ + property string selectedAmount + /** output property to set currently set amount to send + Crypto value in a base unit as a string integer, + e.g. 1000000000000000000 for 1 ETH **/ + readonly property string selectedAmountInBaseUnit: amountToSend.amount QtObject { id: d readonly property bool isScrolling: scrollView.flickable.contentY > sendModalHeader.height + + // Used to get asset entry if selected token is an asset + readonly property var selectedAssetEntry: ModelEntry { + sourceModel: root.assetsModel + key: "tokensKey" + value: root.selectedTokenKey + } + + // Used to get collectible entry if selected token is a collectible + readonly property var selectedCollectibleEntry: ModelEntry { + sourceModel: root.collectiblesModel + key: "symbol" + value: root.selectedTokenKey + } + + /** exposes the currently selected token entry **/ + readonly property var selectedTokenEntry: selectedAssetEntry.available ? + selectedAssetEntry.item : + selectedCollectibleEntry.available ? + selectedCollectibleEntry.item: null + onSelectedTokenEntryChanged: { + if(!selectedAssetEntry.available && !selectedCollectibleEntry.available) { + d.debounceResetTokenSelector() + } + if(selectedAssetEntry.available && !!selectedTokenEntry) { + d.setTokenOnBothHeaders(selectedTokenEntry.symbol, + Constants.tokenIcon(selectedTokenEntry.symbol), + selectedTokenEntry.tokensKey) + } + else if(selectedCollectibleEntry.available && !!selectedTokenEntry) { + const id = selectedTokenEntry.communityId ? + selectedTokenEntry.collectionUid : + selectedTokenEntry.uid + d.setTokenOnBothHeaders(selectedTokenEntry.name, + selectedTokenEntry.imageUrl || selectedTokenEntry.mediaUrl, + id) + } + } + + function setTokenOnBothHeaders(name, icon, key) { + sendModalHeader.setToken(name, icon, key) + stickySendModalHeader.setToken(name, icon, key) + } + + readonly property var debounceResetTokenSelector: Backpressure.debounce(root, 0, function() { + if(!selectedAssetEntry.available && !selectedCollectibleEntry.available) { + // reset token selector in case selected tokens doesnt exist in either models + d.setTokenOnBothHeaders("", "", "") + root.selectedTokenKey = "" + } + }) + + readonly property bool isCollectibleSelected: { + if(!selectedTokenEntry) + return false + const type = selectedAssetEntry.available ? selectedAssetEntry.item.type : + selectedCollectibleEntry.available ? selectedCollectibleEntry.item.tokenType : + Constants.TokenType.Unknown + return (type === Constants.TokenType.ERC721 || type === Constants.TokenType.ERC1155) + } + + readonly property string selectedCryptoTokenSymbol: !!d.selectedTokenEntry ? + d.selectedTokenEntry.symbol: "" + + readonly property double maxSafeCryptoValue: { + const maxCryptoBalance = !!d.selectedTokenEntry && !!d.selectedTokenEntry.currentBalance ? + d.selectedTokenEntry.currentBalance : 0 + return WalletUtils.calculateMaxSafeSendAmount(maxCryptoBalance, d.selectedCryptoTokenSymbol) + } } width: 556 padding: 0 leftPadding: Theme.xlPadding rightPadding: Theme.xlPadding + bottomPadding: Theme.xlPadding topMargin: margins + accountSelector.height + Theme.padding background: StatusDialogBackground { color: Theme.palette.baseColor3 } + // Bindings needed for exposing and setting raw values from AmountToSend + Binding on selectedAmount { + value: amountToSend.text + } + onSelectedAmountChanged: { + if(!!selectedAmount && amountToSend.text !== root.selectedAmount) { + amountToSend.setValue(root.selectedAmount) + } + } + Item { id: sendModalcontentItem @@ -121,6 +219,8 @@ StatusDialog { // Sticky header only visible when scrolling StickySendModalHeader { + id: stickySendModalHeader + width: root.width anchors.top: accountSelector.bottom anchors.topMargin:Theme.padding @@ -135,7 +235,6 @@ StatusDialog { collectiblesModel: root.collectiblesModel selectedChainId: root.selectedChainId - selectedTokenKey: root.selectedTokenKey onCollectibleSelected: root.selectedTokenKey = key onCollectionSelected: root.selectedTokenKey = key @@ -148,7 +247,6 @@ StatusDialog { id: scrollView anchors.fill: parent - anchors.topMargin: 28 contentWidth: availableWidth padding: 0 @@ -171,6 +269,7 @@ StatusDialog { id: sendModalHeader Layout.fillWidth: true + Layout.topMargin: 28 isScrolling: d.isScrolling @@ -179,7 +278,6 @@ StatusDialog { collectiblesModel: root.collectiblesModel selectedChainId: root.selectedChainId - selectedTokenKey: root.selectedTokenKey onCollectibleSelected: root.selectedTokenKey = key onCollectionSelected: root.selectedTokenKey = key @@ -187,31 +285,66 @@ StatusDialog { onNetworkSelected: root.selectedChainId = chainId } - // TODO: Remove these Dummy items added only to test dialog resizing - readonly property string longLoremIpsum: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." - Text { + // Amount to send entry + AmountToSend { + id: amountToSend + Layout.fillWidth: true - text: scrollViewLayout.longLoremIpsum.repeat(3) - wrapMode: Text.WordWrap + + interactive: root.interactive + dividerVisible: true + progressivePixelReduction: false + /** TODO: connect this with suggested routes being fetched as price + gets updated each time a new proposal is fetched + bottomTextLoading: root.suggestedRoutesLoading **/ + + /** TODO: connect to max safe value for eth. + For now simply checking balance in case of both eth and other ERC20's **/ + markAsInvalid: SQUtils.AmountsArithmetic.fromNumber(d.maxSafeCryptoValue, multiplierIndex).cmp(amount) === -1 + + selectedSymbol: amountToSend.fiatMode ? + root.currentCurrency: + d.selectedCryptoTokenSymbol + price: !!d.selectedTokenEntry && + !!d.selectedTokenEntry.marketDetails ? + d.selectedTokenEntry.marketDetails.currencyPrice.amount : 1 + multiplierIndex: !!d.selectedTokenEntry && + !!d.selectedTokenEntry.decimals ? + d.selectedTokenEntry.decimals : 0 + formatFiat: amount => root.fnFormatCurrencyAmount( + amount, root.currentCurrency) + formatBalance: amount => root.fnFormatCurrencyAmount( + amount, d.selectedCryptoTokenSymbol) + + visible: !!root.selectedTokenKey && !d.isCollectibleSelected + onVisibleChanged: if(visible) forceActiveFocus() + + bottomRightComponent: MaxSendButton { + id: maxButton + + formattedValue: { + const price = !!d.selectedTokenEntry && !!d.selectedTokenEntry.marketDetails ? + d.selectedTokenEntry.marketDetails.currencyPrice.amount : 0 + let maxSafeValue = amountToSend.fiatMode ? d.maxSafeCryptoValue * price : d.maxSafeCryptoValue + return root.fnFormatCurrencyAmount( + maxSafeValue, + amountToSend.selectedSymbol, + { noSymbol: !amountToSend.fiatMode, + roundingMode: LocaleUtils.RoundingMode.Down + }) + } + markAsInvalid: amountToSend.markAsInvalid + /** TODO: Remove below customisations after + https://github.com/status-im/status-desktop/issues/15709 + and make the button clickable **/ + enabled: false + background: Rectangle { + radius: 20 + color: type === StatusBaseButton.Type.Danger ? Theme.palette.dangerColor3 : Theme.palette.primaryColor3 + } + disabledTextColor: type === StatusBaseButton.Type.Danger ? Theme.palette.dangerColor1 : Theme.palette.primaryColor1 + } } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 200 - opacity: 0.2 - color: "red" - } - Text { - Layout.fillWidth: true - text: scrollViewLayout.longLoremIpsum.repeat(3) - wrapMode: Text.WordWrap - } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 200 - opacity: 0.2 - color: "red" - } - // End Dummy items } } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index d96ee9e8f9..c146074369 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -660,6 +660,7 @@ Item { simpleSendEnabled: appMain.featureFlagsStore.simpleSendEnabled + // for simple send walletAccountsModel: WalletStores.RootStore.accounts flatNetworksModel: WalletStores.RootStore.flatNetworks areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled @@ -667,6 +668,9 @@ Item { currentCurrency: appMain.currencyStore.currentCurrency showCommunityAssetsInSend: appMain.tokensStore.showCommunityAssetsInSend collectiblesBySymbolModel: WalletStores.RootStore.collectiblesStore.jointCollectiblesBySymbolModel + fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) { + return appMain.currencyStore.formatCurrencyAmount(amount, symbol) + } Component.onCompleted: { // It's requested from many nested places, so as a workaround we use diff --git a/ui/app/mainui/SendModalHandler.qml b/ui/app/mainui/SendModalHandler.qml index 229fa893e0..996ceb86a0 100644 --- a/ui/app/mainui/SendModalHandler.qml +++ b/ui/app/mainui/SendModalHandler.qml @@ -86,6 +86,8 @@ QtObject { /** whether community tokens are shown in send modal based on a global setting **/ required property var showCommunityAssetsInSend + /** required function to format currency amount to locale string **/ + required property var fnFormatCurrencyAmount function openSend(params = {}) { // TODO remove once simple send is feature complete @@ -230,6 +232,9 @@ QtObject { collectiblesModel: collectiblesSelectionAdaptor.model networksModel: root.filteredFlatNetworksModel + currentCurrency: root.currentCurrency + fnFormatCurrencyAmount: root.fnFormatCurrencyAmount + onClosed: destroy() TokenSelectorViewAdaptor { @@ -252,7 +257,13 @@ QtObject { enabledChainIds: [simpleSendModal.selectedChainId] networksModel: root.filteredFlatNetworksModel - collectiblesModel: root.collectiblesBySymbolModel + collectiblesModel: SortFilterProxyModel { + sourceModel: root.collectiblesBySymbolModel + filters: ValueFilter { + roleName: "soulbound" + value: false + } + } } } } diff --git a/ui/imports/shared/popups/send/views/AmountToSend.qml b/ui/imports/shared/popups/send/views/AmountToSend.qml index eb5b9b88fa..db0eef2230 100644 --- a/ui/imports/shared/popups/send/views/AmountToSend.qml +++ b/ui/imports/shared/popups/send/views/AmountToSend.qml @@ -76,6 +76,10 @@ Control { property bool mainInputLoading property bool bottomTextLoading + /* This allows user to add a component to the right of bottom text + Not set = not shown */ + property alias bottomRightComponent: bottomRightComponent.sourceComponent + /* Allows mark input as invalid when it's valid number but doesn't satisfy * arbitrary external criteria, e.g. is higher than maximum expected value. */ property bool markAsInvalid: false @@ -193,14 +197,11 @@ Control { return validator.maxDecimalDigits + validator.maxIntegralDigits } else { let availableSpaceForAmount = root.availableWidth - currencyField.contentWidth - layout.spacing - return Math.floor(availableSpaceForAmount/textMetrics.tightBoundingRect.width) + // k is a coefficient based on the font style (typically 𝑘 ≈ 0.6) + let digitWidth = textField.font.pixelSize * 0.6 + return Math.floor(availableSpaceForAmount/digitWidth) } } - - readonly property TextMetrics textMetrics: TextMetrics { - font: textField.font - text: "0" - } } contentItem: ColumnLayout { @@ -285,66 +286,73 @@ Control { Layout.fillWidth: true Layout.preferredHeight: 1 Layout.bottomMargin: 12 - color: Theme.palette.separator + color: Theme.palette.directColor8 visible: root.dividerVisible } - StatusBaseText { - id: bottomItem - - objectName: "bottomItemText" - + RowLayout { Layout.fillWidth: true + StatusBaseText { + id: bottomItem - text: { - const divisor = SQUtils.AmountsArithmetic.fromExponent( - d.fiatMode ? root.multiplierIndex - : root.fiatDecimalPlaces) - const divided = SQUtils.AmountsArithmetic.div( - SQUtils.AmountsArithmetic.fromString( - d.secondaryValue), divisor) - const asNumber = SQUtils.AmountsArithmetic.toNumber(divided) + objectName: "bottomItemText" - return d.fiatMode ? root.formatBalance(asNumber) - : root.formatFiat(asNumber) - } + Layout.fillWidth: true - elide: Text.ElideMiddle - font.pixelSize: 13 - color: Theme.palette.directColor5 - - MouseArea { - objectName: "amountToSend_mouseArea" - - anchors.fill: parent - cursorShape: enabled ? Qt.PointingHandCursor : undefined - enabled: root.fiatInputInteractive - - onClicked: { - const secondaryValue = d.secondaryValue - - d.fiatMode = !d.fiatMode - - if (textField.length === 0) - return - - const decimalPlaces = d.fiatMode ? root.fiatDecimalPlaces - : root.multiplierIndex + text: { const divisor = SQUtils.AmountsArithmetic.fromExponent( - decimalPlaces) + d.fiatMode ? root.multiplierIndex + : root.fiatDecimalPlaces) + const divided = SQUtils.AmountsArithmetic.div( + SQUtils.AmountsArithmetic.fromString( + d.secondaryValue), divisor) + const asNumber = SQUtils.AmountsArithmetic.toNumber(divided) - const stringNumber = SQUtils.AmountsArithmetic.div( - SQUtils.AmountsArithmetic.fromString(secondaryValue), - divisor).toFixed(decimalPlaces) - - const trimmed = d.fiatMode - ? stringNumber - : d.removeDecimalTrailingZeros(stringNumber) - - textField.text = d.localize(trimmed) + return d.fiatMode ? root.formatBalance(asNumber) + : root.formatFiat(asNumber) } + + elide: Text.ElideMiddle + font.pixelSize: 13 + color: Theme.palette.directColor5 + + MouseArea { + objectName: "amountToSend_mouseArea" + + anchors.fill: parent + cursorShape: enabled ? Qt.PointingHandCursor : undefined + enabled: root.fiatInputInteractive + + onClicked: { + const secondaryValue = d.secondaryValue + + d.fiatMode = !d.fiatMode + + if (textField.length === 0) + return + + const decimalPlaces = d.fiatMode ? root.fiatDecimalPlaces + : root.multiplierIndex + const divisor = SQUtils.AmountsArithmetic.fromExponent( + decimalPlaces) + + const stringNumber = SQUtils.AmountsArithmetic.div( + SQUtils.AmountsArithmetic.fromString(secondaryValue), + divisor).toFixed(decimalPlaces) + + const trimmed = d.fiatMode + ? stringNumber + : d.removeDecimalTrailingZeros(stringNumber) + + textField.text = d.localize(trimmed) + } + } + visible: !root.bottomTextLoading + } + Loader { + id: bottomRightComponent + Layout.alignment: Qt.AlignVCenter } - visible: !root.bottomTextLoading } LoadingComponent {