diff --git a/storybook/pages/SendModalFooterPage.qml b/storybook/pages/SendModalFooterPage.qml index 3d1414e58e..906bcd4cba 100644 --- a/storybook/pages/SendModalFooterPage.qml +++ b/storybook/pages/SendModalFooterPage.qml @@ -22,8 +22,9 @@ SplitView { width: 595 loading: loadingCheckbox.checked + error: errorCheckbox.checked - onReviewSendClicked: console.log("review send clicked") + onReviewSendClicked: logs.logEvent("review send clicked") } } @@ -41,11 +42,16 @@ SplitView { text: "loading" } + CheckBox { + id: errorCheckbox + text: "error" + } + Button { text: "set fees values" onClicked: { loadingCheckbox.checked = false - footer.estimateTime = "~60s" + footer.estimatedTime = "~60s" footer.estimatedFees = "1.45 EUR" } } diff --git a/storybook/pages/SimpleSendModalPage.qml b/storybook/pages/SimpleSendModalPage.qml index 829e785b03..99ae36858b 100644 --- a/storybook/pages/SimpleSendModalPage.qml +++ b/storybook/pages/SimpleSendModalPage.qml @@ -121,10 +121,16 @@ SplitView { } }) - onFetchFees: { - console.log("Fetch fees...") - d.setFees() + onFormChanged: { + estimatedCryptoFees = "" + estimatedFiatFees = "" + estimatedTime = "" + if(formCorrectlyFilled) { + console.log("Fetch fees...") + d.setFees() + } } + onReviewSendClicked: console.log("Review send clicked") Binding on selectedAccountAddress { @@ -488,7 +494,7 @@ SplitView { } } - LogsAndControlsPanel { + Pane { SplitView.minimumHeight: 100 SplitView.minimumWidth: 300 SplitView.maximumWidth: 380 diff --git a/storybook/pages/SimpleTransactionsFeesPage.qml b/storybook/pages/SimpleTransactionsFeesPage.qml index 0f1c38304c..1400cab01e 100644 --- a/storybook/pages/SimpleTransactionsFeesPage.qml +++ b/storybook/pages/SimpleTransactionsFeesPage.qml @@ -1,5 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 +import QtQuick.Layouts 1.14 import StatusQ.Core.Theme 0.1 @@ -9,7 +10,6 @@ import AppLayouts.Wallet.panels 1.0 SplitView { orientation: Qt.Vertical - Logs { id: logs } Rectangle { SplitView.fillHeight: true @@ -23,20 +23,26 @@ SplitView { cryptoFees: qsTr("0.0007 ETH") fiatFees: qsTr("1.45 EUR") loading: loadingCheckbox.checked + error: errorCheckbox.checked } } - LogsAndControlsPanel { + Pane { id: logsAndControlsPanel SplitView.minimumHeight: 100 SplitView.preferredHeight: 200 - logsView.logText: logs.logText + ColumnLayout { + CheckBox { + id: loadingCheckbox + text: "loading" + } - CheckBox { - id: loadingCheckbox - text: "loading" + CheckBox { + id: errorCheckbox + text: "error" + } } } } diff --git a/ui/StatusQ/src/StatusQ/Components/private/StatusComboboxBackground.qml b/ui/StatusQ/src/StatusQ/Components/private/StatusComboboxBackground.qml index cb66042202..26b594ccda 100644 --- a/ui/StatusQ/src/StatusQ/Components/private/StatusComboboxBackground.qml +++ b/ui/StatusQ/src/StatusQ/Components/private/StatusComboboxBackground.qml @@ -11,7 +11,7 @@ Rectangle { border.width: 1 border.color: Theme.palette.directColor7 radius: 8 - color: root.active ? Theme.palette.baseColor2 : "transparent" + color: root.active ? Theme.palette.directColor8 : "transparent" HoverHandler { cursorShape: root.enabled ? Qt.PointingHandCursor : undefined } diff --git a/ui/app/AppLayouts/Wallet/controls/TokenSelector.qml b/ui/app/AppLayouts/Wallet/controls/TokenSelector.qml index 91dd648787..28289ff3ba 100644 --- a/ui/app/AppLayouts/Wallet/controls/TokenSelector.qml +++ b/ui/app/AppLayouts/Wallet/controls/TokenSelector.qml @@ -17,9 +17,6 @@ Control { /** Expected model structure: see SearchableCollectiblesPanel::model **/ property alias collectiblesModel: tokenSelectorPanel.collectiblesModel - /** Exposes insatnce of popup **/ - property var popup: dropdown - /** Sets size of the TokenSelectorButton **/ property alias size: tokenSelectorButton.size @@ -45,6 +42,10 @@ Control { } } + function close() { + dropdown.close() + } + QObject { id: d diff --git a/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml b/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml index b1d2a502fc..2bec2349ee 100644 --- a/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml +++ b/ui/app/AppLayouts/Wallet/panels/SendModalHeader.qml @@ -65,7 +65,7 @@ RowLayout { /** signal to propagate that a collectible was selected **/ signal collectibleSelected(string key) /** signal to propagate that a network was selected **/ - signal networkSelected(string chainId) + signal networkSelected(int chainId) /** input function for programatic selection of token (asset/collectible/collection) **/ @@ -79,7 +79,7 @@ RowLayout { // if not closed during scrolling they move with the header and it feels undesirable onIsScrollingChanged: { - tokenSelector.popup.close() + tokenSelector.close() networkFilter.control.popup.close() } @@ -135,7 +135,7 @@ RowLayout { Layout.alignment: Qt.AlignTop - control.bottomPadding: 0 + control.popup.y: networkFilter.height flatNetworks: root.networksModel diff --git a/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml b/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml index c21f5400fd..cfcde4396d 100644 --- a/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml +++ b/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml @@ -1,6 +1,6 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.14 +import QtQuick.Layouts 1.15 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 @@ -16,22 +16,23 @@ Control { property string fiatFees /** property to set loading state in the fees component **/ property bool loading + /** property to set error state in the fees component **/ + property bool error QtObject { id: d - readonly property string loadingText: "----------" + readonly property string loadingText: "XXXXXXXXXX" } implicitHeight: 64 padding: Theme.padding - topPadding: 12 - bottomPadding: 12 + verticalPadding: 12 background: Rectangle { color: Theme.palette.indirectColor1 - radius: 8 + radius: Theme.radius } contentItem: RowLayout { @@ -64,7 +65,8 @@ Control { Layout.fillWidth: true loading: root.loading - customColor: Theme.palette.baseColor1 + customColor: root.error ? Theme.palette.dangerColor1: + Theme.palette.baseColor1 lineHeightMode: Text.FixedHeight lineHeight: 22 @@ -78,7 +80,8 @@ Control { Layout.alignment: Qt.AlignRight loading: root.loading - customColor: Theme.palette.baseColor1 + customColor: root.error ? Theme.palette.dangerColor1: + Theme.palette.baseColor1 lineHeightMode: Text.FixedHeight lineHeight: 22 diff --git a/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml b/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml index ff0ad37657..f4cae8d46a 100644 --- a/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml +++ b/ui/app/AppLayouts/Wallet/panels/StickySendModalHeader.qml @@ -1,10 +1,11 @@ -import QtQuick 2.14 +import QtQuick 2.15 +import QtQuick.Controls 2.15 import QtGraphicalEffects 1.15 import StatusQ.Core.Theme 0.1 import StatusQ.Popups.Dialog 0.1 -Rectangle { +Control { id: root /** @@ -48,10 +49,10 @@ Rectangle { Not using visible property directly here as the animation on implicitHeight doesnt work **/ - property bool isScrolling + property bool stickyHeaderVisible /** input property for programatic selection of network **/ - property int selectedChainId: -1 + property int selectedChainId /** signal to propagate that an asset was selected **/ signal assetSelected(string key) @@ -60,7 +61,7 @@ Rectangle { /** signal to propagate that a collectible was selected **/ signal collectibleSelected(string key) /** signal to propagate that a network was selected **/ - signal networkSelected(string chainId) + signal networkSelected(int chainId) /** input function for programatic selection of token (asset/collectible/collection) **/ @@ -68,48 +69,56 @@ Rectangle { sendModalHeader.setToken(name, icon, key) } - enabled: root.isScrolling - color: Theme.palette.baseColor3 - radius: 8 + QtObject { + id: d + readonly property int bottomMargin: 12 + } - implicitHeight: root.isScrolling ? - sendModalHeader.implicitHeight + - sendModalHeader.anchors.topMargin + - sendModalHeader.anchors.bottomMargin: - 0 - implicitWidth: sendModalHeader.implicitWidth + - sendModalHeader.anchors.leftMargin + - sendModalHeader.anchors.rightMargin + implicitHeight: root.stickyHeaderVisible ? + implicitContentHeight + Theme.padding + d.bottomMargin : 0 + horizontalPadding: Theme.xlPadding + bottomPadding: d.bottomMargin + topPadding: root.stickyHeaderVisible ? Theme.padding : -implicitContentHeight - Theme.padding - // Drawer animation for stickey heade Behavior on implicitHeight { NumberAnimation { duration: 350 } } - - // cover for the bottom rounded corners - Rectangle { - width: parent.width - height: parent.radius - anchors.bottom: parent.bottom - color: parent.color + Behavior on topPadding { + NumberAnimation { duration: 350 } } - SendModalHeader { - id: sendModalHeader + background: Rectangle { + color: root.implicitHeight > d.bottomMargin ? Theme.palette.baseColor3: Theme.palette.transparent + radius: 8 - width: parent.width - - anchors { - fill: parent - leftMargin: Theme.xlPadding - rightMargin: Theme.xlPadding - topMargin: 16 - bottomMargin: 12 + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 2 + samples: 37 + color: Theme.palette.dropShadow } + // cover for the bottom rounded corners + Rectangle { + width: parent.width + height: parent.radius + anchors.bottom: parent.bottom + color: parent.color + } + + StatusDialogDivider { + anchors.bottom: parent.bottom + width: parent.width + } + } + + contentItem: SendModalHeader { + id: sendModalHeader + isStickyHeader: true - isScrolling: root.isScrolling + isScrolling: root.stickyHeaderVisible networksModel: root.networksModel assetsModel: root.assetsModel @@ -122,18 +131,4 @@ Rectangle { onAssetSelected: root.assetSelected(key) onNetworkSelected: root.networkSelected(chainId) } - - StatusDialogDivider { - anchors.bottom: parent.bottom - width: parent.width - } - - layer.enabled: true - layer.effect: DropShadow { - horizontalOffset: 0 - verticalOffset: 2 - samples: 37 - color: Theme.palette.dropShadow - } } - diff --git a/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml b/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml index 41dd282232..352d2ce602 100644 --- a/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml +++ b/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml @@ -1,5 +1,5 @@ import QtQuick 2.15 -import QtQuick.Layouts 1.14 +import QtQuick.Layouts 1.15 import StatusQ 0.1 import StatusQ.Core 0.1 @@ -102,6 +102,9 @@ StatusDialog { e.g. 1000000000000000000 for 1 ETH **/ readonly property string selectedAmountInBaseUnit: amountToSend.amount + /** property to scheck if form has been filled correctly **/ + readonly property bool formCorrectlyFilled: d.allValuesFilledCorrectly() + /** TODO: replace with new and improved recipient selector StatusDateRangePicker TBD under https://github.com/status-im/status-desktop/issues/16916 **/ property alias selectedRecipientAddress: recipientsPanel.selectedRecipientAddress @@ -114,14 +117,22 @@ StatusDialog { /** Output signal to request signing of the transaction **/ signal reviewSendClicked() - /** Output signal to request fetching fees **/ - signal fetchFees() + /** Output signal to inform that the forms been updated **/ + signal formChanged() QtObject { id: d - readonly property bool isScrolling: - scrollView.flickable.contentY > sendModalHeader.height + readonly property real scrollViewContentY: scrollView.flickable.contentY + onScrollViewContentYChanged: { + const buffer = sendModalHeader.height + scrollViewLayout.spacing + if (scrollViewContentY > buffer) { + d.stickyHeaderVisible = true + } else if (scrollViewContentY === 0) { + d.stickyHeaderVisible = false + } + } + property bool stickyHeaderVisible: false // Used to get asset entry if selected token is an asset readonly property var selectedAssetEntry: ModelEntry { @@ -215,20 +226,7 @@ StatusDialog { root.selectedAmount, amountToSend.markAsInvalid, amountToSend.valid] - onCombinedPropertyChangedHandlerChanged: Qt.callLater(() => d.fetchFees()) - - function resetFees() { - root.estimatedCryptoFees = "" - root.estimatedFiatFees = "" - root.estimatedTime = "" - } - - function fetchFees() { - resetFees() - if(allValuesFilledCorrectly()) { - root.fetchFees() - } - } + onCombinedPropertyChangedHandlerChanged: Qt.callLater(() => root.formChanged()) readonly property bool feesIsLoading: !root.estimatedCryptoFees && !root.estimatedFiatFees && @@ -237,8 +235,7 @@ StatusDialog { width: 556 padding: 0 - leftPadding: Theme.xlPadding - rightPadding: Theme.xlPadding + horizontalPadding: Theme.xlPadding topMargin: margins + accountSelector.height + Theme.padding background: StatusDialogBackground { @@ -287,28 +284,36 @@ StatusDialog { } // Sticky header only visible when scrolling - StickySendModalHeader { - id: stickySendModalHeader - - width: root.width + Item { + height: childrenRect.height + Theme.smallPadding anchors.top: accountSelector.bottom - anchors.topMargin:Theme.padding + anchors.topMargin: Theme.padding anchors.left: parent.left anchors.leftMargin: -Theme.xlPadding + anchors.right: parent.right + anchors.rightMargin: -Theme.xlPadding + + clip: true z: 1 - isScrolling: d.isScrolling + StickySendModalHeader { + id: stickySendModalHeader - networksModel: root.networksModel - assetsModel: root.assetsModel - collectiblesModel: root.collectiblesModel + width: parent.width - selectedChainId: root.selectedChainId + stickyHeaderVisible: d.stickyHeaderVisible - onCollectibleSelected: root.selectedTokenKey = key - onCollectionSelected: root.selectedTokenKey = key - onAssetSelected: root.selectedTokenKey = key - onNetworkSelected: root.selectedChainId = chainId + networksModel: root.networksModel + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel + + selectedChainId: root.selectedChainId + + onCollectibleSelected: root.selectedTokenKey = key + onCollectionSelected: root.selectedTokenKey = key + onAssetSelected: root.selectedTokenKey = key + onNetworkSelected: root.selectedChainId = chainId + } } // Main scrollable Layout @@ -340,7 +345,7 @@ StatusDialog { Layout.fillWidth: true Layout.topMargin: 28 - isScrolling: d.isScrolling + isScrolling: d.stickyHeaderVisible networksModel: root.networksModel assetsModel: root.assetsModel @@ -400,8 +405,7 @@ StatusDialog { return root.fnFormatCurrencyAmount( maxSafeValue, amountToSend.selectedSymbol, - { noSymbol: !amountToSend.fiatMode, - roundingMode: LocaleUtils.RoundingMode.Down + { roundingMode: LocaleUtils.RoundingMode.Down }) } markAsInvalid: amountToSend.markAsInvalid @@ -474,7 +478,7 @@ StatusDialog { footer: SendModalFooter { width: root.width - estimateTime: root.estimatedTime + estimatedTime: root.estimatedTime estimatedFees: root.estimatedFiatFees loading: d.feesIsLoading && d.allValuesFilledCorrectly() diff --git a/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml b/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml index dbe8027ae4..33950bae6b 100644 --- a/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml +++ b/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml @@ -13,9 +13,11 @@ StatusDialogFooter { /** property to set loading state **/ property bool loading /** property to set estimated time **/ - property string estimateTime + property string estimatedTime /** property to set estimates fees in fiat **/ property string estimatedFees + /** property to set error state **/ + property bool error // Signal to propogate Send clicked signal reviewSendClicked() @@ -29,7 +31,7 @@ StatusDialogFooter { id: d readonly property string emptyText: "--" - readonly property string loadingText: "----------" + readonly property string loadingText: "XXXXXXXXXX" } leftButtons: ObjectModel { @@ -40,17 +42,19 @@ StatusDialogFooter { spacing: 0 StatusBaseText { + font.weight: Font.Medium color: Theme.palette.directColor5 text: qsTr("Est time") } StatusTextWithLoadingState { id: estimatedTime - customColor: !!root.estimateTime ? Theme.palette.directColor1: + font.weight: Font.Medium + customColor: !!root.estimatedTime ? Theme.palette.directColor1: Theme.palette.directColor5 loading: root.loading - text: !!root.estimateTime ? root.estimateTime: + text: !!root.estimatedTime ? root.estimatedTime: root.loading ? d.loadingText : d.emptyText } } @@ -60,14 +64,18 @@ StatusDialogFooter { spacing: 0 StatusBaseText { + font.weight: Font.Medium color: Theme.palette.directColor5 text: qsTr("Est fees") } StatusTextWithLoadingState { id: estimatedFees - customColor: !!root.estimatedFees ? Theme.palette.directColor1: - Theme.palette.directColor5 + font.weight: Font.Medium + customColor: root.error ? Theme.palette.dangerColor1: + !!root.estimatedFees ? + Theme.palette.directColor1: + Theme.palette.directColor5 loading: root.loading text: !!root.estimatedFees ? root.estimatedFees: @@ -83,7 +91,7 @@ StatusDialogFooter { Layout.rightMargin: Theme.padding disabledColor: Theme.palette.directColor8 - enabled: !!root.estimateTime && + enabled: !!root.estimatedTime && !!root.estimatedFees && !root.loading diff --git a/ui/app/mainui/SendModalHandler.qml b/ui/app/mainui/SendModalHandler.qml index b207f190b8..e1b1c8091b 100644 --- a/ui/app/mainui/SendModalHandler.qml +++ b/ui/app/mainui/SendModalHandler.qml @@ -82,10 +82,10 @@ QtObject { **/ required property var flatNetworksModel /** true if testnet mode is on **/ - required property var areTestNetworksEnabled + required property bool areTestNetworksEnabled /** whether community tokens are shown in send modal based on a global setting **/ - required property var showCommunityAssetsInSend + required property bool showCommunityAssetsInSend /** required function to format currency amount to locale string **/ required property var fnFormatCurrencyAmount @@ -238,6 +238,15 @@ QtObject { onClosed: destroy() + onFormChanged: { + estimatedCryptoFees = "" + estimatedFiatFees = "" + estimatedTime = "" + if(formCorrectlyFilled) { + // TODO: call stores fetchSuggestedRoutes api + } + } + TokenSelectorViewAdaptor { id: assetsSelectorViewAdaptor diff --git a/ui/imports/shared/popups/send/views/AmountToSend.qml b/ui/imports/shared/popups/send/views/AmountToSend.qml index c9041fc59b..0c612e0543 100644 --- a/ui/imports/shared/popups/send/views/AmountToSend.qml +++ b/ui/imports/shared/popups/send/views/AmountToSend.qml @@ -206,6 +206,7 @@ Control { } contentItem: ColumnLayout { + spacing: Theme.halfPadding StatusBaseText { id: captionText @@ -231,6 +232,7 @@ Control { Layout.preferredHeight: 44 padding: 0 + leftPadding: 0 background: null readOnly: !root.interactive @@ -286,7 +288,7 @@ Control { Rectangle { Layout.fillWidth: true Layout.preferredHeight: 1 - Layout.bottomMargin: 12 + Layout.bottomMargin: 4 color: Theme.palette.directColor8 visible: root.dividerVisible } @@ -363,7 +365,7 @@ Control { color: Theme.palette.directColor5 visible: hoverHandler.hovered } - RowLayout {} + Item { Layout.fillWidth: true } Loader { id: bottomRightComponent Layout.alignment: Qt.AlignVCenter