feat(WC-establish-connection): Fine-tune dApps button

1. Transform the dApps button into a combo box and add badge indicator + tooltip
2. Add storybook page
3. Adding tests
4. Minor fixes - dApps popup width, ModelUtils imports
This commit is contained in:
Alex Jbanca 2024-06-19 16:13:32 +03:00 committed by Alex Jbanca
parent c59ac4f3f0
commit 4bcda69d4a
12 changed files with 388 additions and 166 deletions

View File

@ -341,7 +341,7 @@ Item {
function startTestCase() {
d.activeTestCase = settings.testCase
if(root.visible) {
dappsWorkflow.clicked()
dappsWorkflow.popup.open()
}
}

View File

@ -0,0 +1,78 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import AppLayouts.Wallet.controls 1.0
SplitView {
id: root
width: 400
height: 400
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
DappsComboBox {
id: connectedDappComboBox
anchors.centerIn: parent
model: emptyModelCheckbox.checked ? emptyModel : dappsModel
}
ListModel {
id: emptyModel
}
ListModel {
id: dappsModel
ListElement {
name: "Test dApp 1"
url: "https://dapp.test/1"
iconUrl: "https://se-sdk-dapp.vercel.app/assets/eip155:1.png"
}
ListElement {
name: "Test dApp 2"
url: "https://dapp.test/2"
iconUrl: "https://react-app.walletconnect.com/assets/eip155-1.png"
}
ListElement {
name: "Test dApp 3"
url: "https://dapp.test/3"
iconUrl: "https://react-app.walletconnect.com/assets/eip155-1.png"
}
ListElement {
name: "Test dApp 4 - very long name !!!!!!!!!!!!!!!!"
url: "https://dapp.test/4"
iconUrl: "https://react-app.walletconnect.com/assets/eip155-1.png"
}
ListElement {
name: "Test dApp 5 - very long url"
url: "https://dapp.test/very_long/url/unusual"
iconUrl: "https://react-app.walletconnect.com/assets/eip155-1.png"
}
ListElement {
name: "Test dApp 6"
url: "https://dapp.test/6"
iconUrl: "https://react-app.walletconnect.com/assets/eip155-1.png"
}
}
}
Pane {
id: controls
SplitView.preferredWidth: 300
SplitView.fillHeight: true
ColumnLayout {
CheckBox {
id: emptyModelCheckbox
text: "Empty model"
checked: false
}
}
}
}
// category: Controls
// https://www.figma.com/design/HrmZp1y4S77QJezRFRl6ku/dApp-Interactions---Milestone-1?node-id=130-31949&t=hnzB58fTnEnx2z84-0

View File

@ -14,6 +14,8 @@ public slots:
QGuiApplication::setOrganizationName(QStringLiteral("Status"));
QGuiApplication::setOrganizationDomain(QStringLiteral("status.im"));
qputenv("QT_QUICK_CONTROLS_HOVER_ENABLED", QByteArrayLiteral("1"));
const QStringList additionalImportPaths {
STATUSQ_MODULE_IMPORT_PATH,
QML_IMPORT_ROOT + QStringLiteral("/../ui/app"),

View File

@ -537,7 +537,7 @@ Item {
// waitForRendering(controlUnderTest)
// compare(dappsListReadySpy.count, 1, "expected dappsListReady signal to be emitted")
// let popup = findChild(controlUnderTest, "dappsPopup")
// let popup = findChild(controlUnderTest, "dappsListPopup")
// verify(!!popup)
// verify(popup.opened)
@ -553,7 +553,7 @@ Item {
// mouseClick(controlUnderTest)
// waitForRendering(controlUnderTest)
// let popup = findChild(controlUnderTest, "dappsPopup")
// let popup = findChild(controlUnderTest, "dappsListPopup")
// verify(!!popup)
// verify(popup.opened)

View File

@ -0,0 +1,100 @@
import QtQuick 2.15
import QtQml.Models 2.15
import QtTest 1.15
import AppLayouts.Wallet.controls 1.0
Item {
id: root
width: 600
height: 400
Component {
id: componentUnderTest
DappsComboBox {
anchors.centerIn: parent
model: ListModel {}
}
}
SignalSpy {
id: dappsListReadySpy
target: controlUnderTest
signalName: "dappsListReady"
}
property DappsComboBox controlUnderTest: null
TestCase {
name: "DappsComboBox"
when: windowShown
function init() {
controlUnderTest = createTemporaryObject(componentUnderTest, root)
dappsListReadySpy.clear()
}
function test_basicGeometry() {
verify(controlUnderTest.width > 0)
verify(controlUnderTest.height > 0)
}
function test_showStatusIndicator() {
const indicator = findChild(controlUnderTest, "dappBadge")
compare(indicator.visible, false)
controlUnderTest.model.append({name: "Test dApp 1", url: "https://dapp.test/1", iconUrl: "https://se-sdk-dapp.vercel.app/assets/eip155:1.png"})
compare(indicator.visible, true)
controlUnderTest.model.clear()
compare(indicator.visible, false)
}
function test_dappIcon() {
const icon = findChild(controlUnderTest, "dappIcon")
compare(icon.icon, "dapp")
compare(icon.width, 16)
compare(icon.height, 16)
compare(icon.status, Image.Ready)
}
function test_openingPopup() {
mouseClick(controlUnderTest)
const popup = findChild(controlUnderTest, "dappsListPopup")
compare(popup.visible, true)
compare(popup.x, controlUnderTest.width - popup.width)
compare(popup.y, controlUnderTest.height + 4)
compare(popup.width, 312)
verify(popup.height > 0)
compare(dappsListReadySpy.count, 1)
const background = findChild(controlUnderTest, "dappsBackground")
compare(background.active, true)
mouseClick(controlUnderTest)
compare(popup.visible, false)
compare(background.active, false)
}
function test_hoverState() {
const background = findChild(controlUnderTest, "dappsBackground")
compare(background.active, false)
mouseMove(controlUnderTest, controlUnderTest.width/2, controlUnderTest.height/2)
compare(background.active, true)
compare(controlUnderTest.hovered, true)
const dappTooltip = findChild(controlUnderTest, "dappTooltip")
wait(dappTooltip.delay + 50)
compare(dappTooltip.visible, true)
compare(dappTooltip.text, "dApp connections")
verify(dappTooltip.width > 0)
verify(dappTooltip.height > 0)
verify(dappTooltip.y > controlUnderTest.height)
mouseMove(root)
compare(background.active, false)
compare(dappTooltip.visible, false)
}
}
}

View File

@ -2,6 +2,7 @@ pragma Singleton
import QtQuick 2.14
import StatusQ 0.1
import StatusQ.Internal 0.1 as Internal
QtObject {

View File

@ -1,27 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import shared.controls 1.0
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
StatusButton {
id: root
implicitHeight: 38
size: StatusBaseButton.Size.Small
borderColor: Theme.palette.directColor7
normalColor: Theme.palette.transparent
hoverColor: Theme.palette.baseColor2
textPosition: StatusBaseButton.TextPosition.Left
textColor: Theme.palette.baseColor1
icon.name: "dapp"
icon.height: 16
icon.width: 16
icon.color: hovered ? Theme.palette.directColor1 : Theme.palette.baseColor1
}

View File

@ -0,0 +1,106 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15
import StatusQ 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
implicitHeight: 50
required property string name
required property string url
required property string iconUrl
signal disconnectDapp()
RowLayout {
anchors.fill: parent
anchors.margins: 8
Item {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
StatusImage {
id: iconImage
anchors.fill: parent
source: iconUrl
visible: !fallbackImage.visible
}
StatusIcon {
id: fallbackImage
anchors.fill: parent
icon: "dapp"
color: Theme.palette.baseColor1
visible: iconImage.isLoading || iconImage.isError || !iconUrl
}
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: iconImage.width
height: iconImage.height
radius: width / 2
visible: false
}
}
}
ColumnLayout {
Layout.leftMargin: 12
Layout.rightMargin: 12
StatusBaseText {
text: name
Layout.fillWidth: true
font.pixelSize: 13
font.bold: true
elide: Text.ElideRight
clip: true
}
StatusBaseText {
text: url
Layout.fillWidth: true
font.pixelSize: 12
color: Theme.palette.baseColor1
elide: Text.ElideRight
clip: true
}
}
// TODO #14588 - Show tooltip on hover "Disconnect dApp"
StatusRoundButton {
implicitWidth: 32
implicitHeight: 32
radius: width / 2
icon.name: "disconnect"
onClicked: {
console.debug(`TODO #14755 - Disconnect ${name}`)
//root.disconnectDapp()
}
}
}
}

View File

@ -0,0 +1,86 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15
import shared.controls 1.0
import shared.popups.walletconnect 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Components.private 0.1 as SQP
ComboBox {
id: root
signal dappsListReady
signal pairDapp
implicitHeight: 38
implicitWidth: 38
background: SQP.StatusComboboxBackground {
objectName: "dappsBackground"
active: root.down || root.hovered
}
indicator: null
contentItem: Item {
objectName: "dappsContentItem"
StatusBadge {
objectName: "dappBadge"
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 5
width: 6
height: 6
visible: root.delegateModel.count > 0
}
StatusIcon {
objectName: "dappIcon"
anchors.centerIn: parent
width: 16
height: 16
icon: "dapp"
color: Theme.palette.baseColor1
}
}
delegate: DAppDelegate {
width: ListView.view.width
}
popup: DAppsListPopup {
objectName: "dappsListPopup"
x: root.width - width
y: root.height + 4
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
delegateModel: root.delegateModel
onPairWCDapp: {
root.pairDapp()
this.close()
}
onOpened: {
root.dappsListReady()
}
}
StatusToolTip {
id: tooltip
objectName: "dappTooltip"
visible: root.hovered && !root.down
text: qsTr("dApp connections")
orientation: StatusToolTip.Orientation.Bottom
y: root.height + 14
}
}

View File

@ -14,8 +14,8 @@ MaxSendButton 1.0 MaxSendButton.qml
InformationTileAssetDetails 1.0 InformationTileAssetDetails.qml
StatusNetworkListItemTag 1.0 StatusNetworkListItemTag.qml
CollectibleBalanceTag 1.0 CollectibleBalanceTag.qml
ConnectedDappsButton 1.0 ConnectedDappsButton.qml
CollectibleLinksTags 1.0 CollectibleLinksTags.qml
DappsComboBox 1.0 DappsComboBox.qml
SwapExchangeButton 1.0 SwapExchangeButton.qml
EditSlippagePanel 1.0 EditSlippagePanel.qml
TokenSelector 1.0 TokenSelector.qml

View File

@ -11,19 +11,18 @@ import AppLayouts.Wallet.services.dapps.types 1.0
import shared.stores 1.0
import utils 1.0
ConnectedDappsButton {
DappsComboBox {
id: root
required property WalletConnectService wcService
signal dappsListReady()
signal pairWCReady()
onClicked: {
dappsListLoader.active = true
}
model: root.wcService.dappsModel
highlighted: dappsListLoader.active
onPairDapp: {
pairWCLoader.active = true
}
Loader {
id: pairWCLoader
@ -47,34 +46,6 @@ ConnectedDappsButton {
}
}
Loader {
id: dappsListLoader
active: false
onLoaded: {
item.open()
root.dappsListReady()
}
sourceComponent: DAppsListPopup {
visible: true
model: root.wcService.dappsModel
onPairWCDapp: {
pairWCLoader.active = true
this.close()
}
onOpened: {
this.x = root.width - this.contentWidth - 2 * this.padding
this.y = root.height + 4
}
onClosed: dappsListLoader.active = false
}
}
Loader {
id: connectDappLoader

View File

@ -1,5 +1,6 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15
@ -15,10 +16,12 @@ Popup {
objectName: "dappsPopup"
required property var model
required property DelegateModel delegateModel
signal pairWCDapp()
width: 312
modal: false
padding: 8
closePolicy: Popup.CloseOnEscape | Popup.CloseOnOutsideClick | Popup.CloseOnPressOutside
@ -41,11 +44,9 @@ Popup {
}
}
ColumnLayout {
contentItem: ColumnLayout {
id: mainLayout
implicitWidth: 280
spacing: 8
ShapeRectangle {
@ -84,13 +85,9 @@ Popup {
Layout.preferredHeight: contentHeight
Layout.maximumHeight: 280
model: root.model
model: root.delegateModel
visible: !listPlaceholder.visible
delegate: DAppDelegate {
implicitWidth: listView.width
}
ScrollBar.vertical: null
}
@ -105,96 +102,4 @@ Popup {
}
}
}
component DAppDelegate: Item {
implicitHeight: 50
required property string name
required property string url
required property string iconUrl
RowLayout {
anchors.fill: parent
anchors.margins: 8
Item {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
StatusImage {
id: iconImage
anchors.fill: parent
source: iconUrl
visible: !fallbackImage.visible
}
StatusIcon {
id: fallbackImage
anchors.fill: parent
icon: "dapp"
color: Theme.palette.baseColor1
visible: iconImage.isLoading || iconImage.isError || !iconUrl
}
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: iconImage.width
height: iconImage.height
radius: width / 2
visible: false
}
}
}
ColumnLayout {
Layout.leftMargin: 12
Layout.rightMargin: 12
StatusBaseText {
text: name
Layout.fillWidth: true
font.pixelSize: 13
font.bold: true
elide: Text.ElideRight
clip: true
}
StatusBaseText {
text: url
Layout.fillWidth: true
font.pixelSize: 12
color: Theme.palette.baseColor1
elide: Text.ElideRight
clip: true
}
}
// TODO #14588 - Show tooltip on hover "Disconnect dApp"
StatusRoundButton {
implicitWidth: 32
implicitHeight: 32
radius: width / 2
icon.name: "disconnect"
onClicked: {
console.debug(`TODO #14755 - Disconnect ${name}`)
//root.disconnectDapp()
}
}
}
}
}