feat(WalletFirst): Integrate the BuyReceiveBanner in the app

+ store the card state in user settings
+ amend the BannerCard close button state. It needs to change color on hover and to become visible only when the card is hovered.
This commit is contained in:
Alex Jbanca 2024-11-22 17:57:21 +02:00 committed by Alex Jbanca
parent 271fc15bd4
commit fa4755ce9e
12 changed files with 126 additions and 29 deletions

View File

@ -8,9 +8,12 @@ import utils 1.0
import Storybook 1.0
import AppLayouts.Wallet.controls 1.0
import AppLayouts.Wallet.panels 1.0
import Qt.labs.settings 1.1
import StatusQ.Popups.Dialog 0.1
SplitView {
id: root
@ -196,6 +199,20 @@ SplitView {
onHideRequested: logs.logEvent(`hide requested: ${key}`)
onHideCommunityAssetsRequested: logs.logEvent(`hide community assets requested: ${communityKey}`)
onManageTokensRequested: logs.logEvent(`manage tokens requested`)
bannerComponent: buyReceiveBannerComponent
Component {
id: buyReceiveBannerComponent
BuyReceiveBanner {
id: banner
topPadding: anyVisibleItems ? 8 : 0
bottomPadding: anyVisibleItems ? 20 : 0
onCloseBuy: buyEnabled = false
onCloseReceive: receiveEnabled = false
}
}
}
}
@ -226,6 +243,7 @@ SplitView {
id: sorterVisibleCheckBox
text: "sorter visible"
checked: false
}
CheckBox {
id: customOrderAvailableCheckBox

View File

@ -14,6 +14,7 @@ import utils 1.0
import AppLayouts.stores 1.0 as AppLayoutStores
import AppLayouts.Communities.stores 1.0 as CommunitiesStore
import AppLayouts.Wallet.panels 1.0
import AppLayouts.Wallet.views 1.0
import AppLayouts.Wallet.stores 1.0
@ -128,6 +129,15 @@ SplitView {
isUpdating: ctrlUpdatingCheckbox.checked
isFetching: ctrlFetchingCheckbox.checked
isError: ctrlErrorCheckbox.checked
bannerComponent: BuyReceiveBanner {
id: buyReceiveBanner
buyEnabled: buyBannerCheckbox.checked
receiveEnabled: receiveBannerCheckbox.checked
onBuyClicked: logs.logEvent("onBuyClicked")
onReceiveClicked: logs.logEvent("onReceiveClicked")
onCloseBuy: buyBannerCheckbox.checked = false
onCloseReceive: receiveBannerCheckbox.checked = false
}
Settings {
id: settingsStore
@ -178,6 +188,16 @@ SplitView {
checked: false
text: "isError"
}
CheckBox {
id: buyBannerCheckbox
checked: true
text: "buy banner visible"
}
CheckBox {
id: receiveBannerCheckbox
checked: true
text: "sell banner visible"
}
ColumnLayout {
Layout.fillWidth: true

View File

@ -39,7 +39,7 @@ Item {
function test_hoverState() {
compare(componentUnderTest.hovered, false)
mouseMove(componentUnderTest)
mouseMove(componentUnderTest, componentUnderTest.width / 2, componentUnderTest.height / 2)
compare(componentUnderTest.hovered, true)
const closeButton = findChild(componentUnderTest, "bannerCard_closeButton")
@ -68,6 +68,7 @@ Item {
componentUnderTest.close.connect(() => {
closed = true
})
mouseMove(closeButton, closeButton.width / 2, closeButton.height / 2)
mouseClick(closeButton)
compare(closed, true)
compare(clicked, false)

View File

@ -91,6 +91,7 @@ Item {
const buyCard = findChild(componentUnderTest, "buyCard")
verify(!!buyCard)
const closeButton = findChild(buyCard, "bannerCard_closeButton")
mouseMove(buyCard, buyCard.width / 2, buyCard.height / 2)
verify(!!closeButton)
verify(closeButton.visible)
@ -103,6 +104,7 @@ Item {
const receiveCard = findChild(componentUnderTest, "receiveCard")
verify(!!receiveCard)
const closeButton = findChild(receiveCard, "bannerCard_closeButton")
mouseMove(receiveCard, receiveCard.width / 2, receiveCard.height / 2)
verify(!!closeButton)
verify(closeButton.visible)
@ -127,6 +129,7 @@ Item {
const buyCard = findChild(componentUnderTest, "buyCard")
verify(!!buyCard)
const closeButton = findChild(buyCard, "bannerCard_closeButton")
mouseMove(buyCard, buyCard.width / 2, buyCard.height / 2)
verify(!!closeButton)
verify(closeButton.visible)

View File

@ -8965,6 +8965,8 @@
<file>assets/png/traffic_lights/maximize_pressed.png</file>
<file>assets/png/traffic_lights/minimise.png</file>
<file>assets/png/traffic_lights/minimise_pressed.png</file>
<file>assets/png/wallet/wallet-green.png</file>
<file>assets/png/wallet/flying-coin.png</file>
<file>assets/png/appearance-dark.png</file>
<file>assets/png/appearance-light.png</file>
<file>assets/png/appearance-system.png</file>

View File

@ -179,6 +179,17 @@ Item {
RootStore.selectedAddress :
StatusQUtils.ModelUtils.get(RootStore.nonWatchAccounts, 0, "address")
}
function launchBuyCryptoModal() {
const walletStore = RootStore
d.buyFormData.selectedWalletAddress = d.getSelectedOrFirstNonWatchedAddress()
d.buyFormData.selectedNetworkChainId = StatusQUtils.ModelUtils.getByKey(RootStore.filteredFlatModel, "layer", 1, "chainId")
if(!!walletStore.currentViewedHoldingTokensKey && walletStore.currentViewedHoldingType === Constants.TokenType.ERC20) {
d.buyFormData.selectedTokenKey = walletStore.currentViewedHoldingTokensKey
}
Global.openBuyCryptoModalRequested(d.buyFormData)
}
}
SignPhraseModal {
@ -235,6 +246,7 @@ Item {
d.swapFormData.defaultToTokenKey = RootStore.areTestNetworksEnabled ? Constants.swap.testStatusTokenKey : Constants.swap.mainnetStatusTokenKey
Global.openSwapModalRequested(d.swapFormData)
}
onLaunchBuyCryptoModal: d.launchBuyCryptoModal()
}
}
@ -364,14 +376,7 @@ Item {
d.swapFormData.defaultToTokenKey = RootStore.areTestNetworksEnabled ? Constants.swap.testStatusTokenKey : Constants.swap.mainnetStatusTokenKey
Global.openSwapModalRequested(d.swapFormData)
}
onLaunchBuyCryptoModal: {
d.buyFormData.selectedWalletAddress = d.getSelectedOrFirstNonWatchedAddress()
d.buyFormData.selectedNetworkChainId = StatusQUtils.ModelUtils.getByKey(RootStore.filteredFlatModel, "layer", 1, "chainId")
if(!!walletStore.currentViewedHoldingTokensKey && walletStore.currentViewedHoldingType === Constants.TokenType.ERC20) {
d.buyFormData.selectedTokenKey = walletStore.currentViewedHoldingTokensKey
}
Global.openBuyCryptoModalRequested(d.buyFormData)
}
onLaunchBuyCryptoModal: d.launchBuyCryptoModal()
ModelEntry {
id: selectedCommunityForCollectible

View File

@ -15,7 +15,7 @@ Control {
property alias image: image.source
property alias title: title.text
property alias subTitle: subTitle.text
property alias closeEnabled: closeButton.visible
property bool closeEnabled: true
signal clicked()
signal close()
@ -86,7 +86,8 @@ Control {
Layout.preferredWidth: 16
Layout.preferredHeight: 16
icon: "close"
color: Theme.palette.baseColor1
color: closeHoverHandler.hovered ? Theme.palette.directColor1 : Theme.palette.baseColor1
visible: root.closeEnabled && root.hovered
TapHandler {
id: closeHandler
acceptedButtons: Qt.LeftButton
@ -94,6 +95,9 @@ Control {
root.close()
}
}
HoverHandler {
id: closeHoverHandler
}
}
}
}

View File

@ -29,7 +29,7 @@ Control {
objectName: "buyCard"
Layout.fillWidth: true
Layout.preferredWidth: root.buyEnabled ? layout.width / layout.children.length : 0
title: qsTr("Ways to buy crypto")
title: qsTr("Ways to buy assets")
subTitle: qsTr("Via card or bank transfer")
image: Theme.png("wallet/wallet-green")
closeEnabled: root.closeEnabled
@ -51,7 +51,7 @@ Control {
objectName: "receiveCard"
Layout.fillWidth: true
Layout.preferredWidth: root.receiveEnabled ? layout.width / layout.children.length : 0
title: qsTr("Receive crypto")
title: qsTr("Receive assets")
subTitle: qsTr("Deposit to your Wallet address")
image: Theme.png("wallet/flying-coin")
closeEnabled: root.closeEnabled

View File

@ -36,6 +36,7 @@ ColumnLayout {
property bool isFetching: false // Indicates if a collectibles page is being loaded from the backend
property bool isUpdating: false // Indicates if the collectibles list is being updated
property bool isError: false // Indicates an error occurred while updating/fetching the collectibles list
property alias bannerComponent: banner.sourceComponent
// allows/disables choosing custom sort order from a sorter
property bool customOrderAvailable
@ -436,6 +437,11 @@ ColumnLayout {
}
}
Loader {
id: banner
Layout.fillWidth: true
}
ShapeRectangle {
Layout.fillWidth: true
Layout.topMargin: Theme.padding

View File

@ -7,6 +7,7 @@ import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Popups.Dialog 0.1
import AppLayouts.Wallet.controls 1.0
@ -35,6 +36,7 @@ RightTabBaseView {
property alias currentTabIndex: walletTabBar.currentIndex
signal launchShareAddressModal()
signal launchBuyCryptoModal()
signal launchSwapModal(string tokensKey)
function resetView() {
@ -78,6 +80,30 @@ RightTabBaseView {
readonly property var detailedCollectibleActivityController: RootStore.tmpActivityController0
}
Settings {
id: walletSettings
category: "walletSettings-" + root.contactsStore.myPublicKey
property real collectiblesViewCustomOrderApplyTimestamp: 0
property bool buyBannerEnabled: true
property bool receiveBannerEnabled: true
}
Component {
id: buyReceiveBannerComponent
BuyReceiveBanner {
id: banner
topPadding: anyVisibleItems ? 8 : 0
bottomPadding: anyVisibleItems ? 20 : 0
onBuyClicked: root.launchBuyCryptoModal()
onReceiveClicked: root.launchShareAddressModal()
buyEnabled: walletSettings.buyBannerEnabled
receiveEnabled: walletSettings.receiveBannerEnabled
onCloseBuy: walletSettings.buyBannerEnabled = false
onCloseReceive: walletSettings.receiveBannerEnabled = false
}
}
Component {
id: confirmHideCommunityAssetsPopup
@ -258,6 +284,7 @@ RightTabBaseView {
sorterVisible: filterButton.checked
customOrderAvailable: RootStore.walletAssetsStore.assetsController.hasSettings
model: assetsViewAdaptor.model
bannerComponent: buyReceiveBannerComponent
marketDataError: !!root.networkConnectionStore
? root.networkConnectionStore.getMarketNetworkDownText()
@ -360,12 +387,6 @@ RightTabBaseView {
Component.onCompleted: refreshSortSettings()
Component.onDestruction: saveSortSettings()
readonly property Settings walletSettings: Settings {
id: walletSettings
category: "walletSettings-" + root.contactsStore.myPublicKey
property real collectiblesViewCustomOrderApplyTimestamp: 0
}
readonly property Settings settings: Settings {
id: settings
property int currentSortValue: SortOrderComboBox.TokenOrderDateAdded
@ -381,6 +402,7 @@ RightTabBaseView {
sendEnabled: root.networkConnectionStore.sendBuyBridgeEnabled && !RootStore.overview.isWatchOnlyAccount && RootStore.overview.canSend
filterVisible: filterButton.checked
customOrderAvailable: controller.hasSettings
bannerComponent: buyReceiveBannerComponent
onCollectibleClicked: {
RootStore.collectiblesStore.getDetailedCollectible(chainId, contractAddress, tokenId)
RootStore.setCurrentViewedHolding(uid, uid, tokenType, communityId)
@ -438,6 +460,7 @@ RightTabBaseView {
currencyStore: root.sharedRootStore.currencyStore
showAllAccounts: RootStore.showAllAccounts
filterVisible: false // TODO #16761: Re-enable filter for activity when implemented
bannerComponent: buyReceiveBannerComponent
}
}
}

View File

@ -64,6 +64,8 @@ Control {
property bool communitySwapVisible: false
property string balanceError
// banner component to be displayed on top of the list
property alias bannerComponent: banner.sourceComponent
// global market data error, presented for all tokens expecting market data
property string marketDataError
@ -218,6 +220,11 @@ Control {
StatusDialogDivider { Layout.fillWidth: true }
}
Loader {
id: banner
Layout.fillWidth: true
}
DelegateModel {
id: regularModel

View File

@ -42,6 +42,9 @@ ColumnLayout {
property bool hideVerticalScrollbar: false
property int firstItemOffset: 0
// banner component to be displayed on top of the list
property alias bannerComponent: banner.sourceComponent
property real yPosition: transactionListRoot.visibleArea.yPosition * transactionListRoot.contentHeight
function resetView() {
@ -127,16 +130,6 @@ ColumnLayout {
wrapMode: Text.WordWrap
}
ShapeRectangle {
id: noTxs
Layout.fillWidth: true
Layout.preferredHeight: 42
Layout.topMargin: !nonArchivalNodeError.visible? root.firstItemOffset : 0
visible: !d.isInitialLoading && !root.walletRootStore.currentActivityFiltersStore.filtersSet && transactionListRoot.count === 0
font.pixelSize: Theme.primaryTextFontSize
text: qsTr("Activity for this account will appear here")
}
Loader {
id: filterPanelLoader
active: root.filterVisible && (d.isInitialLoading || transactionListRoot.count > 0 || root.walletRootStore.currentActivityFiltersStore.filtersSet)
@ -151,6 +144,21 @@ ColumnLayout {
}
}
Loader {
id: banner
Layout.fillWidth: true
}
ShapeRectangle {
id: noTxs
Layout.fillWidth: true
Layout.preferredHeight: 42
Layout.topMargin: !nonArchivalNodeError.visible? root.firstItemOffset : 0
visible: !d.isInitialLoading && !root.walletRootStore.currentActivityFiltersStore.filtersSet && transactionListRoot.count === 0
font.pixelSize: Theme.primaryTextFontSize
text: qsTr("Activity for this account will appear here")
}
Item {
id: transactionListWrapper
Layout.alignment: Qt.AlignTop