From a4b1b5500a2dd5cedea67b68bdddab0877e9ae1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Tue, 4 Jul 2023 16:35:00 +0200 Subject: [PATCH] chore(CommunitySettingsView): Sections cross referencing simplified Additionally: - stack components directly define content of the left list - fixed navigation from Permissions section to minting - various code style fixes Closes: #11179 --- .../views/CommunitySettingsView.qml | 525 +++++++++--------- 1 file changed, 257 insertions(+), 268 deletions(-) diff --git a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml index d8f664918e..41fbfa1872 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml @@ -1,31 +1,25 @@ import QtQuick 2.15 import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 import QtQuick.Dialogs 1.3 -import QtGraphicalEffects 1.15 import SortFilterProxyModel 0.2 -import utils 1.0 -import shared.panels 1.0 -import shared.popups 1.0 - +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Core.Utils 0.1 as StatusQUtils import StatusQ.Layout 0.1 -import StatusQ.Components 0.1 -import StatusQ.Controls 0.1 -import StatusQ.Controls.Validators 0.1 - -import AppLayouts.Communities.controls 1.0 +import shared.panels 1.0 +import shared.popups 1.0 import shared.stores 1.0 import shared.views.chat 1.0 +import utils 1.0 +import AppLayouts.Communities.controls 1.0 import AppLayouts.Communities.panels 1.0 import AppLayouts.Communities.popups 1.0 -import AppLayouts.Communities.layouts 1.0 StatusSectionLayout { id: root @@ -34,32 +28,6 @@ StatusSectionLayout { hasUnseenNotifications: activityCenterStore.hasUnseenNotifications onNotificationButtonClicked: Global.openActivityCenterPopup() - readonly property var settingsMenuModel: [ - { - id: Constants.CommunitySettingsSections.Overview, - name: qsTr("Overview"), icon: "show", enabled: true - }, - { - id: Constants.CommunitySettingsSections.Members, - name: qsTr("Members"), icon: "group-chat", enabled: true - }, - { - id: Constants.CommunitySettingsSections.Permissions, - name: qsTr("Permissions"), icon: "objects", enabled: true - }, - { - id: Constants.CommunitySettingsSections.MintTokens, - name: qsTr("Mint Tokens"), icon: "token", enabled: root.isOwner - }, - { - id: Constants.CommunitySettingsSections.Airdrops, - name: qsTr("Airdrops"), icon: "airdrop", enabled: root.isOwner - } - ] - - // TODO: Next community settings options: - // {name: qsTr("Token sales"), icon: "token-sale"}, - // {name: qsTr("Subscriptions"), icon: "subscription"}, property var rootStore property var chatCommunitySectionModule property var community @@ -78,7 +46,8 @@ StatusSectionLayout { if (!!json) tagsArray = json.map(tag => tag.name) } catch (e) { - console.warn("Error parsing community tags: ", community.tags, " error: ", e.message) + console.warn("Error parsing community tags: ", community.tags, + " error: ", e.message) } } return JSON.stringify(tagsArray) @@ -86,14 +55,14 @@ StatusSectionLayout { signal backToCommunityClicked + backButtonName: stackLayout.children[d.currentIndex].previousPageName || "" + //navigate to a specific section and subsection function goTo(section: int, subSection: int) { d.goTo(section, subSection) } - onBackButtonClicked: { - stackLayout.children[d.currentIndex].navigateBack() - } + onBackButtonClicked: stackLayout.children[d.currentIndex].navigateBack() leftPanel: Item { anchors.fill: parent @@ -132,20 +101,20 @@ StatusSectionLayout { Layout.fillHeight: true Layout.leftMargin: Style.current.padding Layout.rightMargin: Style.current.padding - model: root.settingsMenuModel + model: stackLayout.children spacing: 8 delegate: StatusNavigationListItem { - objectName: "CommunitySettingsView_NavigationListItem_" + modelData.name - width: listView.width - title: modelData.name - asset.name: modelData.icon + objectName: "CommunitySettingsView_NavigationListItem_" + model.sectionName + width: ListView.view.width + title: model.sectionName + asset.name: model.sectionIcon asset.height: 24 asset.width: 24 selected: d.currentIndex === index onClicked: d.currentIndex = index - visible: modelData.enabled - height: modelData.enabled ? implicitHeight : 0 + visible: model.sectionEnabled + height: visible ? implicitHeight : 0 } } } @@ -180,6 +149,11 @@ StatusSectionLayout { currentIndex: d.currentIndex OverviewSettingsPanel { + readonly property int sectionKey: Constants.CommunitySettingsSections.Overview + readonly property string sectionName: qsTr("Overview") + readonly property string sectionIcon: "show" + readonly property bool sectionEnabled: true + communityId: root.community.id name: root.community.name description: root.community.description @@ -202,7 +176,8 @@ StatusSectionLayout { StatusQUtils.Utils.filterXSS(item.description), StatusQUtils.Utils.filterXSS(item.introMessage), StatusQUtils.Utils.filterXSS(item.outroMessage), - item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess : Constants.communityChatPublicAccess, + item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess + : Constants.communityChatPublicAccess, item.color.toString().toUpperCase(), item.selectedTags, Utils.getImageAndCropInfoJson(item.logoImagePath, item.logoCropRect), @@ -228,10 +203,14 @@ StatusSectionLayout { privateKey: root.chatCommunitySectionModule.exportCommunity(root.community.id), }) } - onPreviousPageNameChanged: root.backButtonName = previousPageName } MembersSettingsPanel { + readonly property int sectionKey: Constants.CommunitySettingsSections.Members + readonly property string sectionName: qsTr("Members") + readonly property string sectionIcon: "group-chat" + readonly property bool sectionEnabled: true + rootStore: root.rootStore membersModel: root.community.members bannedMembersModel: root.community.bannedMembers @@ -248,6 +227,11 @@ StatusSectionLayout { } PermissionsSettingsPanel { + readonly property int sectionKey: Constants.CommunitySettingsSections.Permissions + readonly property string sectionName: qsTr("Permissions") + readonly property string sectionIcon: "objects" + readonly property bool sectionEnabled: true + readonly property PermissionsStore permissionsStore: rootStore.permissionsStore @@ -275,27 +259,36 @@ StatusSectionLayout { onRemovePermissionRequested: permissionsStore.removePermission(key) - onPreviousPageNameChanged: root.backButtonName = previousPageName - onNavigateToMintTokenSettings: { - root.goTo(Constants.CommunitySettingsSections.MintTokens) + root.goTo(Constants.CommunitySettingsSections.MintTokens) + mintPanel.openNewTokenForm(false) } } MintTokensSettingsPanel { id: mintPanel + readonly property int sectionKey: Constants.CommunitySettingsSections.MintTokens + readonly property string sectionName: qsTr("Mint Tokens") + readonly property string sectionIcon: "token" + readonly property bool sectionEnabled: root.isOwner + readonly property CommunityTokensStore communityTokensStore: rootStore.communityTokensStore function setFeesInfo(ethCurrency, fiatCurrency, errorCode) { - if (errorCode === Constants.ComputeFeeErrorCode.Success || errorCode === Constants.ComputeFeeErrorCode.Balance) { - let valueStr = LocaleUtils.currencyAmountToLocaleString(ethCurrency) + "(" + LocaleUtils.currencyAmountToLocaleString(fiatCurrency) + ")" + if (errorCode === Constants.ComputeFeeErrorCode.Success + || errorCode === Constants.ComputeFeeErrorCode.Balance) { + + const valueStr = LocaleUtils.currencyAmountToLocaleString(ethCurrency) + + "(" + LocaleUtils.currencyAmountToLocaleString(fiatCurrency) + ")" mintPanel.feeText = valueStr - if (errorCode === Constants.ComputeFeeErrorCode.Balance) { + + if (errorCode === Constants.ComputeFeeErrorCode.Balance) mintPanel.errorText = qsTr("Not enough funds to make transaction") - } + mintPanel.isFeeLoading = false + return } else if (errorCode === Constants.ComputeFeeErrorCode.Infura) { mintPanel.errorText = qsTr("Infura error") @@ -316,180 +309,53 @@ StatusSectionLayout { allNetworks: communityTokensStore.allNetworks accounts: root.rootStore.accounts - onPreviousPageNameChanged: root.backButtonName = previousPageName - onSignMintTransactionOpened: communityTokensStore.computeDeployFee(chainId, accountAddress, tokenType) - onMintCollectible: communityTokensStore.deployCollectible(root.community.id, collectibleItem) - onMintAsset: communityTokensStore.deployAsset(root.community.id, assetItem) - onSignRemoteDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(remotelyDestructTokensList, tokenKey) - onRemotelyDestructCollectibles: { - communityTokensStore.remoteSelfDestructCollectibles(root.community.id, - remotelyDestructTokensList, - tokenKey) - } - onSignBurnTransactionOpened: communityTokensStore.computeBurnFee(tokenKey, amount) - onBurnToken: communityTokensStore.burnToken(root.community.id, tokenKey, amount) - onDeleteToken: communityTokensStore.deleteToken(root.community.id, tokenKey) + onSignMintTransactionOpened: + communityTokensStore.computeDeployFee( + chainId, accountAddress, tokenType) + + onMintCollectible: + communityTokensStore.deployCollectible( + root.community.id, collectibleItem) + + onMintAsset: + communityTokensStore.deployAsset(root.community.id, assetItem) + + onSignRemoteDestructTransactionOpened: + communityTokensStore.computeSelfDestructFee( + remotelyDestructTokensList, tokenKey) + + onRemotelyDestructCollectibles: + communityTokensStore.remoteSelfDestructCollectibles( + root.community.id, remotelyDestructTokensList, tokenKey) + + onSignBurnTransactionOpened: + communityTokensStore.computeBurnFee(tokenKey, amount) + + onBurnToken: + communityTokensStore.burnToken(root.community.id, tokenKey, amount) + + onDeleteToken: + communityTokensStore.deleteToken(root.community.id, tokenKey) onAirdropToken: { root.goTo(Constants.CommunitySettingsSections.Airdrops) - } + // Force a token selection to be airdroped with default amount 1 + airdropPanel.selectToken(tokenKey, 1, type) - Connections { - target: rootStore.communityTokensStore - function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) { - mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode) - } - - function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) { - mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode) - } - - function onBurnFeeUpdated(ethCurrency, fiatCurrency, errorCode) { - mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode) - } - - function onRemoteDestructStateChanged(communityId, tokenName, status, url) { - if (root.community.id !== communityId) { - return - } - - let title = "" - let loading = false - let type = Constants.ephemeralNotificationType.normal - switch (status) { - case Constants.ContractTransactionStatus.InProgress: - title = qsTr("Remotely destroying tokens...") - loading = true - break - case Constants.ContractTransactionStatus.Completed: - title = qsTr("%1 tokens destroyed").arg(tokenName) - type = Constants.ephemeralNotificationType.success - break - case Constants.ContractTransactionStatus.Failed: - title = qsTr("%1 tokens destruction failed").arg(tokenName) - break - default: - console.warn("Unknown destruction state: "+status) - return - } - Global.displayToastMessage(title, - qsTr("View on etherscan"), - "", - loading, - type, - url) - } - - function onAirdropStateChanged(communityId, tokenName, chainName, status, url) { - if (root.community.id !== communityId) { - return - } - - let title = "" - let loading = false - let type = Constants.ephemeralNotificationType.normal - switch (status) { - case Constants.ContractTransactionStatus.InProgress: - title = qsTr("Airdrop on %1 in progress...").arg(chainName) - loading = true - break - case Constants.ContractTransactionStatus.Completed: - title = qsTr("Airdrop on %1 in complete").arg(chainName) - type = Constants.ephemeralNotificationType.success - break - case Constants.ContractTransactionStatus.Failed: - title = qsTr("Airdrop on %1 failed").arg(chainName) - break - default: - console.warn("Unknown airdrop state: "+status) - return - } - Global.displayToastMessage(title, - qsTr("View on etherscan"), - "", - loading, - type, - url) - } - - function onBurnStateChanged(communityId, tokenName, status, url) { - if (root.community.id !== communityId) { - return - } - - let title = "" - let loading = false - let type = Constants.ephemeralNotificationType.normal - switch (status) { - case Constants.ContractTransactionStatus.InProgress: - title = qsTr("%1 being burned...").arg(tokenName) - loading = true - break - case Constants.ContractTransactionStatus.Completed: - title = qsTr("%1 burning is complete").arg(tokenName) - type = Constants.ephemeralNotificationType.success - break - case Constants.ContractTransactionStatus.Failed: - title = qsTr("%1 burning is failed").arg(tokenName) - break - default: - console.warn("Unknown burning state: "+status) - return - } - Global.displayToastMessage(title, - qsTr("View on etherscan"), - "", - loading, - type, - url) - } - - function onDeploymentStateChanged(communityId, status, url) { - if (root.community.id !== communityId) { - return - } - - let title = "" - let loading = false - let type = Constants.ephemeralNotificationType.normal - switch (status) { - case Constants.ContractTransactionStatus.InProgress: - title = qsTr("Token is being minted...") - loading = true - break - case Constants.ContractTransactionStatus.Completed: - title = qsTr("Token minting finished") - type = Constants.ephemeralNotificationType.success - break - case Constants.ContractTransactionStatus.Failed: - title = qsTr("Token minting failed") - break - default: - console.warn("Unknown deploy state: "+status) - return - } - Global.displayToastMessage(title, - qsTr("View on etherscan"), - "", - loading, - type, - url) - } - } - - Connections { - target: airdropPanel - - function onNavigateToMintTokenSettings(isAssetType) { - mintPanel.openNewTokenForm(isAssetType) - } + // Set given addresses as recipients + airdropPanel.addAddresses(addresses) } } AirdropsSettingsPanel { id: airdropPanel + readonly property int sectionKey: Constants.CommunitySettingsSections.Airdrops + readonly property string sectionName: qsTr("Airdrops") + readonly property string sectionIcon: "airdrop" + readonly property bool sectionEnabled: root.isOwner + communityDetails: d.communityDetails readonly property CommunityTokensStore communityTokensStore: rootStore.communityTokensStore @@ -569,48 +435,24 @@ StatusSectionLayout { return chatContentModule.usersModule.model } - onPreviousPageNameChanged: root.backButtonName = previousPageName - onAirdropClicked: communityTokensStore.airdrop(root.community.id, airdropTokens, addresses) - onNavigateToMintTokenSettings: root.goTo(Constants.CommunitySettingsSections.MintTokens) + onAirdropClicked: communityTokensStore.airdrop(root.community.id, + airdropTokens, addresses) + + onNavigateToMintTokenSettings: { + root.goTo(Constants.CommunitySettingsSections.MintTokens) + mintPanel.openNewTokenForm(isAssetType) + } onAirdropFeesRequested: communityTokensStore.computeAirdropFee( root.community.id, contractKeysAndAmounts, addresses) - - Connections { - target: mintPanel - - function onAirdropToken(tokenKey, type, addresses) { - // Force a token selection to be airdroped with default amount 1 - airdropPanel.selectToken(tokenKey, 1, type) - - // Set given addresses as recipients - airdropPanel.addAddresses(addresses) - } - } - - Connections { - target: rootStore.communityTokensStore - - function onAirdropFeeUpdated(airdropFees) { - airdropPanel.airdropFees = airdropFees - } - } } - - onCurrentIndexChanged: - root.backButtonName = stackLayout.children[d.currentIndex].previousPageName || "" } - onSettingsMenuModelChanged: d.currentIndex = 0 - QtObject { id: d property int currentIndex: 0 - readonly property var currentItem: stackLayout && stackLayout.children[d.currentIndex] - ? stackLayout.children[d.currentIndex] - : null readonly property QtObject communityDetails: QtObject { readonly property string id: root.community.id @@ -622,23 +464,26 @@ StatusSectionLayout { } function goTo(section: int, subSection: int) { - //find and enable section - const matchingIndex = listView.model.findIndex((modelItem, index) => modelItem.id === section && modelItem.enabled) + const stackContent = stackLayout.children - if(matchingIndex === -1) - return + for (let i = 0; stackContent.length; i++) { + const item = stackContent[i] - d.currentIndex = matchingIndex + if (item.sectionKey === section) { + d.currentIndex = i - //find and enable subsection if subSection navigation is available - if(d.currentItem && d.currentItem.goTo) { - d.currentItem.goTo(subSection) + if(item.goTo) + item.goTo(subSection) + + break + } } } } MessageDialog { id: errorDialog + title: qsTr("Error editing the community") icon: StandardIcon.Critical standardButtons: StandardButton.Ok @@ -646,6 +491,7 @@ StatusSectionLayout { Component { id: transferOwnershipPopup + TransferOwnershipPopup { anchors.centerIn: parent store: root.rootStore @@ -655,6 +501,7 @@ StatusSectionLayout { Component { id: noPermissionsPopupCmp + NoPermissionsToJoinPopup { onRejectButtonClicked: { root.rootStore.declineRequestToJoinCommunity(requestId, communityId) @@ -664,16 +511,158 @@ StatusSectionLayout { } } + Connections { - target: root.chatCommunitySectionModule - function onOpenNoPermissionsToJoinPopup(communityName: string, userName: string, communityId: string, requestId: string) { - Global.openPopup(noPermissionsPopupCmp, { - communityName: communityName, - userName: userName, - communityId: communityId, - requestId: requestId - }) + target: rootStore.communityTokensStore + + function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) { + mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode) } + function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) { + mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode) + } + + function onBurnFeeUpdated(ethCurrency, fiatCurrency, errorCode) { + mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode) + } + + function onAirdropFeeUpdated(airdropFees) { + airdropPanel.airdropFees = airdropFees + } + + function onRemoteDestructStateChanged(communityId, tokenName, status, url) { + if (root.community.id !== communityId) + return + + let title = "" + let loading = false + let type = Constants.ephemeralNotificationType.normal + + switch (status) { + case Constants.ContractTransactionStatus.InProgress: + title = qsTr("Remotely destroying tokens...") + loading = true + break + case Constants.ContractTransactionStatus.Completed: + title = qsTr("%1 tokens destroyed").arg(tokenName) + type = Constants.ephemeralNotificationType.success + break + case Constants.ContractTransactionStatus.Failed: + title = qsTr("%1 tokens destruction failed").arg(tokenName) + break + default: + console.warn("Unknown destruction state: "+status) + return + } + + Global.displayToastMessage(title, qsTr("View on etherscan"), "", + loading, type, url) + } + + function onAirdropStateChanged(communityId, tokenName, chainName, + status, url) { + if (root.community.id !== communityId) + return + + let title = "" + let loading = false + let type = Constants.ephemeralNotificationType.normal + + switch (status) { + case Constants.ContractTransactionStatus.InProgress: + title = qsTr("Airdrop on %1 in progress...").arg(chainName) + loading = true + break + case Constants.ContractTransactionStatus.Completed: + title = qsTr("Airdrop on %1 in complete").arg(chainName) + type = Constants.ephemeralNotificationType.success + break + case Constants.ContractTransactionStatus.Failed: + title = qsTr("Airdrop on %1 failed").arg(chainName) + break + default: + console.warn("Unknown airdrop state: "+status) + return + } + + Global.displayToastMessage(title, qsTr("View on etherscan"), "", + loading, type, url) + } + + function onBurnStateChanged(communityId, tokenName, status, url) { + if (root.community.id !== communityId) + return + + let title = "" + let loading = false + let type = Constants.ephemeralNotificationType.normal + + switch (status) { + case Constants.ContractTransactionStatus.InProgress: + title = qsTr("%1 being burned...").arg(tokenName) + loading = true + break + case Constants.ContractTransactionStatus.Completed: + title = qsTr("%1 burning is complete").arg(tokenName) + type = Constants.ephemeralNotificationType.success + break + case Constants.ContractTransactionStatus.Failed: + title = qsTr("%1 burning is failed").arg(tokenName) + break + default: + console.warn("Unknown burning state: "+status) + return + } + + Global.displayToastMessage(title, qsTr("View on etherscan"), "", + loading, type, url) + } + + function onDeploymentStateChanged(communityId, status, url) { + if (root.community.id !== communityId) + return + + let title = "" + let loading = false + let type = Constants.ephemeralNotificationType.normal + + switch (status) { + case Constants.ContractTransactionStatus.InProgress: + title = qsTr("Token is being minted...") + loading = true + break + case Constants.ContractTransactionStatus.Completed: + title = qsTr("Token minting finished") + type = Constants.ephemeralNotificationType.success + break + case Constants.ContractTransactionStatus.Failed: + title = qsTr("Token minting failed") + break + default: + console.warn("Unknown deploy state: "+status) + return + } + + Global.displayToastMessage(title, qsTr("View on etherscan"), "", + loading, type, url) + } + } + + Connections { + target: root.chatCommunitySectionModule + + function onOpenNoPermissionsToJoinPopup(communityName: string, + userName: string, communityId: + string, requestId: string) { + const properties = { + communityName: communityName, + userName: userName, + communityId: communityId, + requestId: requestId + } + + Global.openPopup(noPermissionsPopupCmp, properties) + } } }