From 6c040f28e7cfd1dd5e849087bd48843520d102b7 Mon Sep 17 00:00:00 2001 From: RomanChornii Date: Tue, 30 Jul 2024 01:14:04 +0300 Subject: [PATCH] fix(dApps): Improved handling of connected dApps. 1. Hiding DApps button on not supported wallet account selection 2. Filtering DApps in connected dApps list based on account selection closes: #15589 closes: #15647 --- storybook/pages/DAppsWorkflowPage.qml | 2 + storybook/pages/DappsComboBoxPage.qml | 19 +++++++++- .../AppLayouts/Wallet/panels/WalletHeader.qml | 5 ++- .../services/dapps/DAppsListProvider.qml | 38 +++++++++++++++---- .../services/dapps/WalletConnectService.qml | 24 ++++++++++-- .../Wallet/services/dapps/helpers.js | 12 ++---- .../popups/walletconnect/DAppsListPopup.qml | 2 + 7 files changed, 81 insertions(+), 21 deletions(-) diff --git a/storybook/pages/DAppsWorkflowPage.qml b/storybook/pages/DAppsWorkflowPage.qml index c281a253b31..11de19d1358 100644 --- a/storybook/pages/DAppsWorkflowPage.qml +++ b/storybook/pages/DAppsWorkflowPage.qml @@ -418,6 +418,8 @@ Item { // Name mismatch between storybook and production readonly property var groupedAccountAssetsModel: groupedAccountsAssetsModel } + + readonly property string selectedAddress: "" } onDisplayToastMessage: (message, isErr) => { diff --git a/storybook/pages/DappsComboBoxPage.qml b/storybook/pages/DappsComboBoxPage.qml index 870b1883f8a..81c8f6d669c 100644 --- a/storybook/pages/DappsComboBoxPage.qml +++ b/storybook/pages/DappsComboBoxPage.qml @@ -17,7 +17,7 @@ SplitView { id: connectedDappComboBox anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter - model: emptyModelCheckbox.checked ? emptyModel : dappsModel + model: emptyModelCheckbox.checked ? emptyModel : smallModelCheckbox.checked ? smallModel: dappsModel popup.visible: true } @@ -25,6 +25,15 @@ SplitView { id: emptyModel } + ListModel { + id: smallModel + ListElement { + name: "SMALL Model" + url: "https://dapp.test/1" + iconUrl: "https://se-sdk-dapp.vercel.app/assets/eip155:1.png" + } + } + ListModel { id: dappsModel ListElement { @@ -96,10 +105,16 @@ SplitView { text: "Empty model" checked: false } + + CheckBox { + id: smallModelCheckbox + text: "Small model" + checked: false + } } } } // category: Controls -// https://www.figma.com/design/HrmZp1y4S77QJezRFRl6ku/dApp-Interactions---Milestone-1?node-id=130-31949&t=hnzB58fTnEnx2z84-0 \ No newline at end of file +// https://www.figma.com/design/HrmZp1y4S77QJezRFRl6ku/dApp-Interactions---Milestone-1?node-id=130-31949&t=hnzB58fTnEnx2z84-0 diff --git a/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml b/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml index 342d8ba513e..c03d2f5cffb 100644 --- a/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml +++ b/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml @@ -133,9 +133,12 @@ Item { spacing: 8 - visible: !root.walletStore.showSavedAddresses && Global.featureFlags.dappsEnabled + visible: !root.walletStore.showSavedAddresses + && Global.featureFlags.dappsEnabled + && Global.walletConnectService.isServiceAvailableForAddressSelection enabled: !!Global.walletConnectService + wcService: Global.walletConnectService loginType: root.store.loginType selectedAccountAddress: root.walletStore.selectedAddress diff --git a/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml b/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml index 26cd50e36ca..2188e52fd84 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml @@ -1,7 +1,10 @@ import QtQuick 2.15 +import StatusQ 0.1 import StatusQ.Core.Utils 0.1 +import SortFilterProxyModel 0.2 + import AppLayouts.Wallet.services.dapps 1.0 import shared.stores 1.0 @@ -15,7 +18,25 @@ QObject { required property DAppsStore store required property var supportedAccountsModel - readonly property alias dappsModel: d.dappsModel + property string selectedAddress: "" + + readonly property SortFilterProxyModel dappsModel: SortFilterProxyModel { + objectName: "DAppsModelFiltered" + sourceModel: d.dappsModel.count ? d.dappsModel : null + filters: FastExpressionFilter { + enabled: !!root.selectedAddress + + function isAddressIncluded(addresses, addressToFind) { + const dataArray = ModelUtils.modelToFlatArray(addresses, "address") + return dataArray.includes(addressToFind) + } + + expression: { + return isAddressIncluded(model.accountAddresses, root.selectedAddress) + } + expectedRoles: ["accountAddresses"] + } + } function updateDapps() { d.updateDappsModel() @@ -26,6 +47,8 @@ QObject { property ListModel dappsModel: ListModel { id: dapps + dynamicRoles: true + objectName: "DAppsModel" } property var dappsListReceivedFn: null @@ -52,18 +75,19 @@ QObject { sdk.getActiveSessions((allSessions) => { root.store.dappsListReceived.disconnect(dappsListReceivedFn); - let tmpMap = {} - var topics = [] - const sessions = DAppsHelpers.filterActiveSessionsForKnownAccounts(allSessions, root.supportedAccountsModel) - for (const key in sessions) { - const dapp = sessions[key].peer.metadata + const tmpMap = {} + const topics = [] + const sessions = DAppsHelpers.activeSessionsWithKnownAccountAddresses(allSessions) + for (const sessionID in sessions) { + const session = sessions[sessionID] + const dapp = session.peer.metadata if (!!dapp.icons && dapp.icons.length > 0) { dapp.iconUrl = dapp.icons[0] } else { dapp.iconUrl = "" } tmpMap[dapp.url] = dapp; - topics.push(key) + topics.push(sessionID) } // TODO #15075: on SDK dApps refresh update the model that has data source from persistence instead of using reset dapps.clear(); diff --git a/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml b/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml index dfca0c10d55..cad9f2ad71a 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml @@ -35,6 +35,8 @@ QObject { readonly property alias dappsModel: dappsProvider.dappsModel readonly property alias requestHandler: requestHandler + readonly property bool isServiceAvailableForAddressSelection: dappsProvider.supportedAccountsModel.count + readonly property var validAccounts: SortFilterProxyModel { sourceModel: d.supportedAccountsModel proxyRoles: [ @@ -110,7 +112,7 @@ QObject { function disconnectDapp(url) { wcSDK.getActiveSessions((allSessions) => { - const sessions = DAppsHelpers.filterActiveSessionsForKnownAccounts(allSessions, d.supportedAccountsModel) + const sessions = DAppsHelpers.activeSessionsWithKnownAccountAddresses(allSessions) for (const sessionID in sessions) { const session = sessions[sessionID] const dapp = session.peer.metadata @@ -226,7 +228,13 @@ QObject { QObject { id: d - readonly property var supportedAccountsModel: root.walletRootStore.nonWatchAccounts + readonly property var supportedAccountsModel: SortFilterProxyModel { + sourceModel: root.walletRootStore.nonWatchAccounts + filters: ValueFilter { + roleName: "keycardAccount" + value: false + } + } property var currentSessionProposal: null property var acceptedSessionProposal: null @@ -265,7 +273,17 @@ QObject { sdk: root.wcSDK store: root.store - supportedAccountsModel: d.supportedAccountsModel + supportedAccountsModel: SortFilterProxyModel { + objectName: "SelectedAddressModelForDAppsListProvider" + sourceModel: d.supportedAccountsModel + filters: ValueFilter { + roleName: "address" + value: root.walletRootStore.selectedAddress === model.address + enabled: !root.walletRootStore.showAllAccounts + } + } + + selectedAddress: root.walletRootStore.selectedAddress } // Timeout for the corner case where the URL was already dismissed and the SDK doesn't respond with an error nor advances with the proposal diff --git a/ui/app/AppLayouts/Wallet/services/dapps/helpers.js b/ui/app/AppLayouts/Wallet/services/dapps/helpers.js index 85b2fbc9300..e58daf414e0 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/helpers.js +++ b/ui/app/AppLayouts/Wallet/services/dapps/helpers.js @@ -96,7 +96,7 @@ function extractInfoFromPairUri(uri) { return { topic, expiry } } -function filterActiveSessionsForKnownAccounts(sessions, accountsModel) { +function activeSessionsWithKnownAccountAddresses(sessions) { let knownSessions = ({}) Object.keys(sessions).forEach((topic) => { const session = sessions[topic] @@ -105,13 +105,9 @@ function filterActiveSessionsForKnownAccounts(sessions, accountsModel) { eip155Addresses.map(eip155Address => eip155Address.split(':').pop().trim()) ); const uniqueAddresses = Array.from(accountSet); - const firstAccount = SQUtils.ModelUtils.getFirstModelEntryIf(accountsModel, (account) => { - return uniqueAddresses.includes(account.address) - }) - if (!firstAccount) { - return - } + + session.peer.metadata.accountAddresses = uniqueAddresses.map(value => ({ address: value })); knownSessions[topic] = session }) return knownSessions -} \ No newline at end of file +} diff --git a/ui/imports/shared/popups/walletconnect/DAppsListPopup.qml b/ui/imports/shared/popups/walletconnect/DAppsListPopup.qml index 4a2e3b95d8a..26e3c160fef 100644 --- a/ui/imports/shared/popups/walletconnect/DAppsListPopup.qml +++ b/ui/imports/shared/popups/walletconnect/DAppsListPopup.qml @@ -48,7 +48,9 @@ Popup { contentItem: ColumnLayout { id: mainLayout + spacing: 0 + ShapeRectangle { id: listPlaceholder