From 3076dd2f57d0744fcf2ef583382d0282382c9c30 Mon Sep 17 00:00:00 2001 From: RomanChornii Date: Fri, 21 Jun 2024 00:13:15 +0300 Subject: [PATCH] chore(Wallet.RootStore): Moved backend independent methods to a stateless WalletUtils singleton fixes: #14804 --- .../Profile/stores/ProfileStore.qml | 2 +- .../AppLayouts/Profile/stores/WalletStore.qml | 23 +++++- .../Profile/views/RPCStatsModal.qml | 2 +- .../Profile/views/wallet/AccountView.qml | 4 +- ui/app/AppLayouts/Wallet/WalletUtils.qml | 78 ++++++++++++++++++- .../controls/SavedAddressesDelegate.qml | 2 +- .../AppLayouts/Wallet/popups/ReceiveModal.qml | 2 +- .../popups/SavedAddressActivityPopup.qml | 2 +- .../Wallet/popups/TransactionAddressMenu.qml | 2 +- ui/app/AppLayouts/Wallet/stores/RootStore.qml | 76 +----------------- .../Wallet/views/AccountContextMenu.qml | 2 +- .../Wallet/views/TransactionDetailView.qml | 6 +- .../collectibles/CollectibleDetailView.qml | 5 +- ui/imports/shared/stores/RootStore.qml | 4 - ui/imports/shared/views/HistoryView.qml | 5 +- ui/imports/utils/Utils.qml | 4 + 16 files changed, 120 insertions(+), 99 deletions(-) diff --git a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml index 58f2d07bb..f6e4013f4 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml @@ -80,7 +80,7 @@ QtObject { } function copyToClipboard(value) { - globalUtils.copyToClipboard(value) + Utils.copyToClipboard(value) } function saveProfileIdentityChanges(displayName, bio, imageInfo) { diff --git a/ui/app/AppLayouts/Profile/stores/WalletStore.qml b/ui/app/AppLayouts/Profile/stores/WalletStore.qml index cd7a28a86..5a60125e3 100644 --- a/ui/app/AppLayouts/Profile/stores/WalletStore.qml +++ b/ui/app/AppLayouts/Profile/stores/WalletStore.qml @@ -162,8 +162,27 @@ QtObject { return networksModuleInst.getNetworkShortNames(chainIds) } - function copyToClipboard(textToCopy) { - globalUtils.copyToClipboard(textToCopy) + function processPreferredSharingNetworkToggle(preferredSharingNetworks, toggledNetwork) { + let prefChains = preferredSharingNetworks + if(prefChains.length === root.flatNetworks.count) { + prefChains = [toggledNetwork.chainId.toString()] + } + else if(!prefChains.includes(toggledNetwork.chainId.toString())) { + prefChains.push(toggledNetwork.chainId.toString()) + } + else { + if(prefChains.length === 1) { + prefChains = getAllNetworksChainIds() + } + else { + for(var i = 0; i < prefChains.length;i++) { + if(prefChains[i] === toggledNetwork.chainId.toString()) { + prefChains.splice(i, 1) + } + } + } + } + return prefChains } function getNetworkData(combinedNetwork) { diff --git a/ui/app/AppLayouts/Profile/views/RPCStatsModal.qml b/ui/app/AppLayouts/Profile/views/RPCStatsModal.qml index 09d88dadc..3e9869a68 100644 --- a/ui/app/AppLayouts/Profile/views/RPCStatsModal.qml +++ b/ui/app/AppLayouts/Profile/views/RPCStatsModal.qml @@ -148,7 +148,7 @@ StatusDialog { CopyToClipBoardButton { id: copyToClipboardButton - onCopyClicked: root.walletStore.copyToClipboard(textToCopy) + onCopyClicked: Utils.copyToClipboard(textToCopy) onPressed: function() { let copiedText = "Total" + '\t' + d.totalFilteredCalls + " of " + d.totalCalls + '\n' + '\n' for (let i = 0; i < resultsListView.model.count; i++) { diff --git a/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml b/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml index f04c4a021..dfa3006f3 100644 --- a/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml +++ b/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml @@ -196,7 +196,7 @@ ColumnLayout { copyButtonEnabled: true title: qsTr("Derivation Path") subTitle: !!root.account? Utils.getPathForDisplay(root.account.path) : "" - onCopyClicked: root.walletStore.copyToClipboard(!!root.account? root.account.path : "") + onCopyClicked: Utils.copyToClipboard(!!root.account? root.account.path : "") visible: !!subTitle && !d.privateKeyAccount && !d.watchOnlyAccount } Separator { @@ -332,7 +332,7 @@ ColumnLayout { areTestNetworksEnabled: root.walletStore.areTestNetworksEnabled isGoerliEnabled: root.walletStore.isGoerliEnabled preferredSharedNetworkNamesArray: d.preferredSharingNetworkShortNames.split(":").filter(Boolean) - onCopyToClipboard: root.walletStore.copyToClipboard(address) + onCopyToClipboard: Utils.copyToClipboard(address) } WalletKeypairAccountMenu { diff --git a/ui/app/AppLayouts/Wallet/WalletUtils.qml b/ui/app/AppLayouts/Wallet/WalletUtils.qml index d2658d8bf..a27669029 100644 --- a/ui/app/AppLayouts/Wallet/WalletUtils.qml +++ b/ui/app/AppLayouts/Wallet/WalletUtils.qml @@ -7,9 +7,36 @@ import StatusQ.Core.Theme 0.1 import StatusQ.Core.Utils 0.1 as StatusQUtils -import "stores" as WalletStores +import AppLayouts.Wallet.stores 1.0 as WalletStores QtObject { + + property QtObject _d: QtObject { + id: d + + property var chainColors: ({}) + + function initChainColors(model) { + for (let i = 0; i < model.count; i++) { + const item = SQUtils.ModelUtils.get(model, i) + chainColors[item.shortName] = item.chainColor + } + } + + function colorForChainShortName(chainShortName) { + return d.chainColors[chainShortName] + } + + readonly property Connections walletRootStoreConnections: Connections { + target: WalletStores.RootStore + + function onFlatNetworksChanged() { + d.initChainColors(WalletStores.RootStore.flatNetworks) + } + } + + } + function colorizedChainPrefix(prefix) { if (!prefix) return "" @@ -21,7 +48,7 @@ QtObject { for (let i in prefixes) { const pref = prefixes[i] - let col = WalletStores.RootStore.colorForChainShortName(pref) + let col = d.colorForChainShortName(pref) if (!col) col = defaultColor @@ -73,4 +100,51 @@ QtObject { return value - Math.max(0.0001, Math.min(0.01, value * 0.1)) } + + function getAssetForSendTx(tx) { + if (tx.isNFT) { + return { + uid: tx.tokenID, + chainId: tx.chainId, + name: tx.nftName, + imageUrl: tx.nftImageUrl, + collectionUid: "", + collectionName: "" + } + } else { + return tx.symbol + } + } + + function isTxRepeatable(tx) { + if (!tx || tx.txType !== Constants.TransactionType.Send) + return false + + let res = root.lookupAddressObject(tx.sender) + if (!res || res.type !== RootStore.LookupType.Account || res.object.walletType == Constants.watchWalletType) + return false + + if (tx.isNFT) { + // TODO #12275: check if account owns enough NFT + } else { + // TODO #12275: Check if account owns enough tokens + } + + return true + } + + function getExplorerNameForNetwork(networkShortName) { + if (networkShortName === Constants.networkShortChainNames.arbitrum) { + return qsTr("Arbiscan Explorer") + } + if (networkShortName === Constants.networkShortChainNames.optimism) { + return qsTr("Optimism Explorer") + } + return qsTr("Etherscan Explorer") + } + + function getTwitterLink(twitterHandle) { + const prefix = Constants.socialLinkPrefixesByType[Constants.socialLinkType.twitter] + return prefix + twitterHandle + } } diff --git a/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml b/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml index 9bdd8a304..135fdb3f0 100644 --- a/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml +++ b/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml @@ -178,7 +178,7 @@ StatusListItem { timeout: 1500 autoDismissMenu: true onTriggered: { - store.copyToClipboard(d.visibleAddress) + Utils.copyToClipboard(d.visibleAddress) } } diff --git a/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml b/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml index 8911b4b17..34e4c460c 100644 --- a/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml +++ b/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml @@ -34,7 +34,7 @@ StatusModal { property bool switchingAccounsEnabled: true property bool changingPreferredChainsEnabled: true - property string qrImageSource: store.getQrCode(d.visibleAddress) + property string qrImageSource: Utils.getQrCode(d.visibleAddress) property var getNetworkShortNames: function(chainIDsString) { return store.getNetworkShortNames(chainIDsString) } diff --git a/ui/app/AppLayouts/Wallet/popups/SavedAddressActivityPopup.qml b/ui/app/AppLayouts/Wallet/popups/SavedAddressActivityPopup.qml index 0eda33cc2..e0c62320f 100644 --- a/ui/app/AppLayouts/Wallet/popups/SavedAddressActivityPopup.qml +++ b/ui/app/AppLayouts/Wallet/popups/SavedAddressActivityPopup.qml @@ -227,7 +227,7 @@ StatusModal { anchors.top: addressText.top icon.name: "copy" type: StatusRoundButton.Type.Tertiary - onClicked: WalletStore.RootStore.copyToClipboard(d.visibleAddress) + onClicked: Utils.copyToClipboard(d.visibleAddress) } } diff --git a/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml b/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml index 2ac8a2bfb..810edd0f4 100644 --- a/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml +++ b/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml @@ -277,7 +277,7 @@ StatusMenu { } } icon.name: "copy" - onTriggered: RootStore.copyToClipboard(d.selectedAddress) + onTriggered: Utils.copyToClipboard(d.selectedAddress) } StatusAction { id: showQrAction diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml index f89c2744e..4217ef998 100644 --- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml @@ -130,15 +130,6 @@ QtObject { tokensList: walletAssetsStore.groupedAccountAssetsModel } - property var chainColors: ({}) - - function initChainColors(model) { - for (let i = 0; i < model.count; i++) { - const item = SQUtils.ModelUtils.get(model, i) - chainColors[item.shortName] = item.chainColor - } - } - readonly property Connections walletSectionConnections: Connections { target: root.walletSectionInst function onWalletAccountRemoved(address) { @@ -153,9 +144,6 @@ QtObject { } } - function colorForChainShortName(chainShortName) { - return d.chainColors[chainShortName] - } property var flatNetworks: networksModule.flatNetworks property SortFilterProxyModel filteredFlatModel: SortFilterProxyModel { @@ -163,10 +151,6 @@ QtObject { filters: ValueFilter { roleName: "isTest"; value: root.areTestNetworksEnabled } } - onFlatNetworksChanged: { - d.initChainColors(flatNetworks) - } - property var cryptoRampServicesModel: walletSectionBuySellCrypto.model function resetCurrentViewedHolding(type) { @@ -228,10 +212,6 @@ QtObject { walletSection.updateCurrency(newCurrency) } - function getQrCode(address) { - return globalUtils.qrCode(address) - } - function getNameForWalletAddress(address) { return walletSectionAccounts.getNameByAddress(address) } @@ -316,7 +296,7 @@ QtObject { if (acc) { res = {type: RootStore.LookupType.Account, object: acc} } else { - let sa = SQUtils.ModelUtils.getByKey(walletSectionSavedAddresses.model, "address", address) + let sa = SQUtils.ModelUtils.getByKey(walletSectionSavedAddressesInst.model, "address", address) if (sa) { res = {type: RootStore.LookupType.SavedAddress, object: sa} } @@ -325,38 +305,6 @@ QtObject { return res } - function getAssetForSendTx(tx) { - if (tx.isNFT) { - return { - uid: tx.tokenID, - chainId: tx.chainId, - name: tx.nftName, - imageUrl: tx.nftImageUrl, - collectionUid: "", - collectionName: "" - } - } else { - return tx.symbol - } - } - - function isTxRepeatable(tx) { - if (!tx || tx.txType !== Constants.TransactionType.Send) - return false - - let res = root.lookupAddressObject(tx.sender) - if (!res || res.type !== RootStore.LookupType.Account || res.object.walletType == Constants.watchWalletType) - return false - - if (tx.isNFT) { - // TODO #12275: check if account owns enough NFT - } else { - // TODO #12275: Check if account owns enough tokens - } - - return true - } - function isOwnedAccount(address) { return walletSectionAccounts.isOwnedAccount(address) } @@ -391,10 +339,6 @@ QtObject { networksModule.toggleNetwork(chainId) } - function copyToClipboard(text) { - globalUtils.copyToClipboard(text) - } - function runAddAccountPopup() { walletSection.runAddAccountPopup(false) } @@ -411,10 +355,6 @@ QtObject { walletSectionSend.switchReceiveAccountByAddress(address) } - function toggleWatchOnlyAccounts() { - walletSection.toggleWatchOnlyAccounts() - } - function getAllNetworksChainIds() { let result = [] let chainIdsArray = SQUtils.ModelUtils.modelToFlatArray(root.filteredFlatModel, "chainId") @@ -494,16 +434,6 @@ QtObject { } } - function getExplorerNameForNetwork(networkShortName) { - if (networkShortName === Constants.networkShortChainNames.arbitrum) { - return qsTr("Arbiscan Explorer") - } - if (networkShortName === Constants.networkShortChainNames.optimism) { - return qsTr("Optimism Explorer") - } - return qsTr("Etherscan Explorer") - } - function getOpenSeaNetworkName(networkShortName) { let networkName = Constants.openseaExplorerLinks.ethereum if (networkShortName === Constants.networkShortChainNames.mainnet) { @@ -553,8 +483,4 @@ QtObject { return "%1/assets/%2/%3/%4".arg(baseLink).arg(networkName).arg(contractAddress).arg(tokenId) } - function getTwitterLink(twitterHandle) { - const prefix = Constants.socialLinkPrefixesByType[Constants.socialLinkType.twitter] - return prefix + twitterHandle - } } diff --git a/ui/app/AppLayouts/Wallet/views/AccountContextMenu.qml b/ui/app/AppLayouts/Wallet/views/AccountContextMenu.qml index 9ce1500fd..b5d3cfba4 100644 --- a/ui/app/AppLayouts/Wallet/views/AccountContextMenu.qml +++ b/ui/app/AppLayouts/Wallet/views/AccountContextMenu.qml @@ -27,7 +27,7 @@ StatusMenu { icon.name: "copy" timeout: 1500 enabled: !!root.account - onTriggered: RootStore.copyToClipboard(root.account.address?? "") + onTriggered: Utils.copyToClipboard(root.account.address?? "") } StatusMenuSeparator { diff --git a/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml b/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml index adc4d2bef..7ddfab28e 100644 --- a/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml +++ b/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml @@ -770,10 +770,10 @@ Item { if (!d.isTransactionValid || root.overview.isWatchOnlyAccount) return false - return WalletStores.RootStore.isTxRepeatable(tx) + return WalletUtils.isTxRepeatable(tx) } onClicked: { - let asset = WalletStores.RootStore.getAssetForSendTx(tx) + let asset = WalletUtils.getAssetForSendTx(tx) let req = Helpers.lookupAddressesForSendModal(tx.sender, tx.recipient, asset, tx.isNFT, tx.amount) root.sendModal.preSelectedAccount = req.preSelectedAccount @@ -795,7 +795,7 @@ Item { icon.width: 20 icon.height: 20 size: StatusButton.Small - onClicked: RootStore.copyToClipboard(transactionHeader.getDetailsString(d.details)) + onClicked: Utils.copyToClipboard(transactionHeader.getDetailsString(d.details)) } } } diff --git a/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml b/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml index 17608b4f2..f5d754116 100644 --- a/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml +++ b/ui/app/AppLayouts/Wallet/views/collectibles/CollectibleDetailView.qml @@ -16,6 +16,7 @@ import shared.controls 1.0 import shared.views 1.0 import shared.popups 1.0 +import AppLayouts.Wallet 1.0 import "../../stores" import "../../controls" @@ -96,7 +97,7 @@ Item { networkShortName: !!collectible ? collectible.networkShortName : "" networkColor: !!collectible ?collectible.networkColor : "" networkIconURL: !!collectible ? collectible.networkIconUrl : "" - networkExplorerName: !!collectible ? root.walletRootStore.getExplorerNameForNetwork(collectible.networkShortName): "" + networkExplorerName: !!collectible ? WalletUtils.getExplorerNameForNetwork(collectible.networkShortName): "" collectibleLinkEnabled: Utils.getUrlStatus(d.collectibleLink) collectionLinkEnabled: (!!communityDetails && communityDetails.name) || Utils.getUrlStatus(d.collectionLink) explorerLinkEnabled: Utils.getUrlStatus(d.blockExplorerLink) @@ -338,7 +339,7 @@ Item { primaryText: qsTr("Twitter") secondaryText: !!collectible ? collectible.twitterHandle : "" visible: !!collectible && collectible.twitterHandle - onClicked: Global.openLinkWithConfirmation(root.walletRootStore.getTwitterLink(collectible.twitterHandle), Constants.socialLinkPrefixesByType[Constants.socialLinkType.twitter]) + onClicked: Global.openLinkWithConfirmation(WalletUtils.getTwitterLink(collectible.twitterHandle), Constants.socialLinkPrefixesByType[Constants.socialLinkType.twitter]) } } } diff --git a/ui/imports/shared/stores/RootStore.qml b/ui/imports/shared/stores/RootStore.qml index c5def0e55..cc9a4342d 100644 --- a/ui/imports/shared/stores/RootStore.qml +++ b/ui/imports/shared/stores/RootStore.qml @@ -37,10 +37,6 @@ QtObject { property var flatNetworks: networksModule.flatNetworks - function hex2Dec(value) { - return globalUtils.hex2Dec(value) - } - readonly property var formationChars: (["*", "`", "~"]) function getSelectedTextWithFormationChars(messageInputField) { let i = 1 diff --git a/ui/imports/shared/views/HistoryView.qml b/ui/imports/shared/views/HistoryView.qml index 63da428ef..ff12968b2 100644 --- a/ui/imports/shared/views/HistoryView.qml +++ b/ui/imports/shared/views/HistoryView.qml @@ -19,6 +19,7 @@ import "../popups/send" import "../stores" import "../controls" +import AppLayouts.Wallet 1.0 import AppLayouts.Wallet.stores 1.0 as WalletStores import AppLayouts.Wallet.popups 1.0 import AppLayouts.Wallet.controls 1.0 @@ -310,13 +311,13 @@ ColumnLayout { enabled: { if (!overview.isWatchOnlyAccount && !tx) return false - return WalletStores.RootStore.isTxRepeatable(tx) + return WalletUtils.isTxRepeatable(tx) } onTriggered: { if (!tx) return - let asset = WalletStores.RootStore.getAssetForSendTx(tx) + let asset = WalletUtils.getAssetForSendTx(tx) let req = Helpers.lookupAddressesForSendModal(tx.sender, tx.recipient, asset, tx.isNFT, tx.amount) diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index 0d9ea1e84..b2242efbd 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -963,4 +963,8 @@ QtObject { function getUrlStatus(url) { return globalUtilsInst.isValidURL(url) } + + function getQrCode(address) { + return globalUtilsInst.qrCode(address) + } }