import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Window 2.15 import QtQuick.Dialogs 1.3 import QtQml.Models 2.15 import QtQml 2.15 import StatusQ.Core 0.1 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import StatusQ.Popups 0.1 import StatusQ.Popups.Dialog 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Core.Utils 0.1 as SQUtils import AppLayouts.stores 1.0 as AppLayoutStores import AppLayouts.Chat.popups 1.0 import AppLayouts.Profile.popups 1.0 import AppLayouts.Profile.stores 1.0 as ProfileStores import AppLayouts.Communities.popups 1.0 import AppLayouts.Communities.helpers 1.0 import AppLayouts.Wallet.popups.swap 1.0 import AppLayouts.Wallet.popups.buy 1.0 import AppLayouts.Wallet.popups 1.0 import AppLayouts.Wallet.adaptors 1.0 import AppLayouts.Communities.stores 1.0 import AppLayouts.Profile.helpers 1.0 import AppLayouts.Wallet.stores 1.0 as WalletStores import AppLayouts.Chat.stores 1.0 as ChatStores import shared.popups 1.0 import shared.status 1.0 import shared.stores 1.0 import shared.views 1.0 import utils 1.0 QtObject { id: root required property var popupParent required property RootStore sharedRootStore required property AppLayoutStores.RootStore rootStore required property CommunityTokensStore communityTokensStore property UtilsStore utilsStore property CommunitiesStore communitiesStore property ProfileStores.ProfileStore profileStore property ProfileStores.DevicesStore devicesStore property CurrenciesStore currencyStore property WalletStores.WalletAssetsStore walletAssetsStore property WalletStores.CollectiblesStore walletCollectiblesStore property NetworkConnectionStore networkConnectionStore property WalletStores.BuyCryptoStore buyCryptoStore property var allContactsModel property var mutualContactsModel property bool isDevBuild signal openExternalLink(string link) signal saveDomainToUnfurledWhitelist(string domain) signal ownershipDeclined(string communityId, string communityName) signal transferOwnershipRequested(string tokenId, string senderAddress) property var activePopupComponents: [] Component.onCompleted: { Global.openMarkAsIDVerifiedPopup.connect(openMarkAsIDVerifiedPopup) Global.openRemoveIDVerificationDialog.connect(openRemoveIDVerificationDialog) Global.openInviteFriendsToCommunityPopup.connect(openInviteFriendsToCommunityPopup) Global.openInviteFriendsToCommunityByIdPopup.connect(openInviteFriendsToCommunityByIdPopup) Global.openContactRequestPopup.connect(openContactRequestPopup) Global.openReviewContactRequestPopup.connect(openReviewContactRequestPopup) Global.openDownloadModalRequested.connect(openDownloadModal) Global.openImagePopup.connect(openImagePopup) Global.openVideoPopup.connect(openVideoPopup) Global.openProfilePopupRequested.connect(openProfilePopup) Global.openNicknamePopupRequested.connect(openNicknamePopup) Global.markAsUntrustedRequested.connect(openMarkAsUntrustedPopup) Global.blockContactRequested.connect(openBlockContactPopup) Global.unblockContactRequested.connect(openUnblockContactPopup) Global.openChangeProfilePicPopup.connect(openChangeProfilePicPopup) Global.openBackUpSeedPopup.connect(openBackUpSeedPopup) Global.openPinnedMessagesPopupRequested.connect(openPinnedMessagesPopup) Global.openCommunityProfilePopupRequested.connect(openCommunityProfilePopup) Global.createCommunityPopupRequested.connect(openCreateCommunityPopup) Global.importCommunityPopupRequested.connect(openImportCommunityPopup) Global.communityShareAddressesPopupRequested.connect(openCommunityShareAddressesPopup) Global.communityIntroPopupRequested.connect(openCommunityIntroPopup) Global.removeContactRequested.connect(openRemoveContactConfirmationPopup) Global.openPopupRequested.connect(openPopup) Global.closePopupRequested.connect(closePopup) Global.openDeleteMessagePopup.connect(openDeleteMessagePopup) Global.openDownloadImageDialog.connect(openDownloadImageDialog) Global.leaveCommunityRequested.connect(openLeaveCommunityPopup) Global.openTestnetPopup.connect(openTestnetPopup) Global.openExportControlNodePopup.connect(openExportControlNodePopup) Global.openImportControlNodePopup.connect(openImportControlNodePopup) Global.openEditSharedAddressesFlow.connect(openEditSharedAddressesPopup) Global.openTransferOwnershipPopup.connect(openTransferOwnershipPopup) Global.openFinaliseOwnershipPopup.connect(openFinaliseOwnershipPopup) Global.openDeclineOwnershipPopup.connect(openDeclineOwnershipPopup) Global.openFirstTokenReceivedPopup.connect(openFirstTokenReceivedPopup) Global.openConfirmHideAssetPopup.connect(openConfirmHideAssetPopup) Global.openConfirmHideCollectiblePopup.connect(openConfirmHideCollectiblePopup) Global.openCommunityMemberMessagesPopupRequested.connect(openCommunityMemberMessagesPopup) Global.openSwapModalRequested.connect(openSwapModal) Global.openBuyCryptoModalRequested.connect(openBuyCryptoModal) Global.privacyPolicyRequested.connect(() => openPopup(privacyPolicyPopupComponent)) Global.openPaymentRequestModalRequested.connect(openPaymentRequestModal) } property var currentPopup function openPopup(popupComponent, params = {}, cb = null) { if (activePopupComponents.includes(popupComponent)) { return } root.currentPopup = popupComponent.createObject(popupParent, params) root.currentPopup.open(); if (cb) cb(root.currentPopup) activePopupComponents.push(popupComponent) root.currentPopup.closed.connect(() => { const removeIndex = activePopupComponents.indexOf(popupComponent) if (removeIndex !== -1) { activePopupComponents.splice(removeIndex, 1) } }) } function closePopup() { if (!!root.currentPopup) root.currentPopup.close(); } function openDownloadModal(available: bool, version: string, url: string) { const popupProperties = { newVersionAvailable: available, downloadURL: url, currentVersion: rootStore.profileSectionStore.getCurrentVersion(), newVersion: version } openPopup(downloadPageComponent, popupProperties) } function openImagePopup(image, url, plain) { openPopup(imagePopupComponent, {image: image, url: url, plain: plain}) } function openVideoPopup(url) { openPopup(videoPopupComponent, { url: url }) } function openProfilePopup(publicKey: string, parentPopup, cb) { openPopup(profilePopupComponent, {publicKey: publicKey, parentPopup: parentPopup}, cb) } function openNicknamePopup(publicKey: string, cb) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails } openPopup(nicknamePopupComponent, properties, cb) } function openMarkAsUntrustedPopup(publicKey: string) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails } openPopup(markAsUntrustedComponent, properties) } function openBlockContactPopup(publicKey: string) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails } openPopup(blockContactConfirmationComponent, properties) } function openUnblockContactPopup(publicKey: string) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails } openPopup(unblockContactConfirmationComponent, properties) } function openChangeProfilePicPopup(cb) { var popup = changeProfilePicComponent.createObject(popupParent, {callback: cb}); popup.chooseImageToCrop() } function openBackUpSeedPopup() { openPopup(backupSeedModalComponent) } function openCommunityProfilePopup(store, community, communitySectionModule) { openPopup(communityProfilePopup, { store: store, community: community, communitySectionModule: communitySectionModule}) } function openMarkAsIDVerifiedPopup(publicKey, cb) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, true, true, true) const properties = { publicKey, contactDetails } openPopup(markAsIDVerifiedPopupComponent, properties, cb) } function openRemoveIDVerificationDialog(publicKey, cb) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, true, true, true) const properties = { publicKey, contactDetails } openPopup(removeIDVerificationPopupComponent, properties, cb) } function openInviteFriendsToCommunityPopup(community, communitySectionModule, cb) { openPopup(inviteFriendsToCommunityPopup, { community: community, communitySectionModule: communitySectionModule }, cb) } function openInviteFriendsToCommunityByIdPopup(communityId, cb) { root.rootStore.mainModuleInst.prepareCommunitySectionModuleForCommunityId(communityId) const communitySectionModuleData = root.rootStore.mainModuleInst.getCommunitySectionModule() const communityData = root.communitiesStore.getCommunityDetails(communityId) openPopup(inviteFriendsToCommunityPopup, { community: communityData, communitySectionModule: communitySectionModuleData }, cb) } function openContactRequestPopup(publicKey, cb) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails } openPopup(sendContactRequestPopupComponent, properties, cb) } function openReviewContactRequestPopup(publicKey, cb) { try { const crDetails = rootStore.contactStore.getLatestContactRequestForContactAsJson(publicKey) if (crDetails.from !== publicKey) { console.warn("Popups.openReviewContactRequestPopup: not matching publicKey:", publicKey) return } const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails, crDetails } openPopup(reviewContactRequestPopupComponent, properties, cb) } catch (e) { console.error("Popups.openReviewContactRequestPopup: error getting or parsing contact request data", e) } } function openPinnedMessagesPopup(store, messageStore, pinnedMessagesModel, messageToPin, chatId) { openPopup(pinnedMessagesPopup, { store: store, messageStore: messageStore, pinnedMessagesModel: pinnedMessagesModel, messageToPin: messageToPin, chatId: chatId }) } function openCommunityPopup(store, community, chatCommunitySectionModule) { openPopup(communityProfilePopup, {store: store, community: community, chatCommunitySectionModule: chatCommunitySectionModule}) } function openCreateCommunityPopup(isDiscordImport) { openPopup(createCommunitiesPopupComponent, {isDiscordImport: isDiscordImport}) } function openImportCommunityPopup() { openPopup(importCommunitiesPopupComponent) } function openCommunityIntroPopup(communityId, name, introMessage, imageSrc, isInvitationPending ) { openPopup(communityJoinDialogPopup, {communityId: communityId, communityName: name, introMessage: introMessage, communityIcon: imageSrc, isInvitationPending: isInvitationPending }) } function openCommunityShareAddressesPopup(communityId, name, imageSrc) { openPopup(communityJoinDialogPopup, {communityId: communityId, stackTitle: qsTr("Share addresses with %1's owner").arg(name), communityName: name, introMessage: qsTr("Share addresses to rejoin %1").arg(name), communityIcon: imageSrc, isInvitationPending: false }) } function openEditSharedAddressesPopup(communityId) { openPopup(editSharedAddressesPopupComponent, {communityId: communityId, isEditMode: true}) } function openDiscordImportProgressPopup(importingSingleChannel) { openPopup(discordImportProgressDialog, {importingSingleChannel: importingSingleChannel}) } function openRemoveContactConfirmationPopup(publicKey) { const contactDetails = Utils.getContactDetailsAsJson( publicKey, false, true, true) const properties = { publicKey, contactDetails } openPopup(removeContactConfirmationDialog, properties) } function openDeleteMessagePopup(messageId, messageStore) { openPopup(deleteMessageConfirmationDialogComponent, { messageId, messageStore }) } function openDownloadImageDialog(imageSource) { // We don't use `openPopup`, because there's no `FileDialog::closed` signal. const popup = downloadImageDialogComponent.createObject(popupParent, { imageSource }) popup.open() } function openLeaveCommunityPopup(community, communityId, outroMessage) { openPopup(leaveCommunityPopupComponent, {community, communityId, outroMessage}) } function openTestnetPopup() { openPopup(testnetModal) } function openExportControlNodePopup(community) { openPopup(exportControlNodePopup, { community }) } function openImportControlNodePopup(community) { openPopup(importControlNodePopup, { community }) } function openTransferOwnershipPopup(communityId, communityName, communityLogo, token) { openPopup(transferOwnershipPopup, { communityId, communityName, communityLogo, token }) } function openConfirmExternalLinkPopup(link, domain) { openPopup(confirmExternalLinkPopup, {link, domain}) } function openFinaliseOwnershipPopup(communityId) { openPopup(finaliseOwnershipPopup, { communityId: communityId }) } function openDeclineOwnershipPopup(communityId, communityName) { openPopup(declineOwnershipPopup, { communityName: communityName, communityId: communityId }) } function openFirstTokenReceivedPopup(communityId, communityName, communityLogo, tokenSymbol, tokenName, tokenAmount, tokenType, tokenImage) { openPopup(firstTokenReceivedPopup, { communityId: communityId, communityName: communityName, communityLogo: communityLogo, tokenSymbol: tokenSymbol, tokenName: tokenName, tokenAmount: tokenAmount, tokenType: tokenType, tokenImage: tokenImage }) } function openConfirmHideAssetPopup(assetSymbol, assetName, assetImage, isCommunityToken) { openPopup(confirmHideAssetPopup, { symbol: assetSymbol, name: assetName, icon: assetImage, isCommunityToken }) } function openConfirmHideCollectiblePopup(collectibleSymbol, collectibleName, collectibleImage, isCommunityToken) { openPopup(confirmHideCollectiblePopup, { collectibleSymbol, collectibleName, collectibleImage, isCommunityToken }) } function openCommunityMemberMessagesPopup(store, chatCommunitySectionModule, memberPubKey, displayName) { openPopup(communityMemberMessagesPopup, { rootStore: store, chatCommunitySectionModule: chatCommunitySectionModule, memberPubKey: memberPubKey, displayName: displayName }) } function openSwapModal(parameters) { openPopup(swapModal, {swapInputParamsForm: parameters}) } function openBuyCryptoModal(parameters) { openPopup(buyCryptoModal, { buyCryptoInputParamsForm: parameters }) } function openPaymentRequestModal(callback) { openPopup(paymentRequestModalComponent, {callback: callback}) } readonly property list _components: [ Component { id: removeContactConfirmationDialog RemoveContactPopup { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.removeContact(publicKey) if (removeIDVerification) rootStore.contactStore.removeTrustStatus(publicKey) if (markAsUntrusted) { rootStore.contactStore.markUntrustworthy(publicKey) Global.displaySuccessToastMessage(qsTr("%1 removed from contacts and marked as untrusted").arg(mainDisplayName)) } else { Global.displaySuccessToastMessage(qsTr("%1 removed from contacts").arg(mainDisplayName)) } close() } onClosed: destroy() } }, Component { id: markAsIDVerifiedPopupComponent MarkAsIDVerifiedDialog { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.markAsTrusted(publicKey) Global.displaySuccessToastMessage(qsTr("%1 marked as trusted").arg(mainDisplayName)) close() } onClosed: destroy() } }, Component { id: removeIDVerificationPopupComponent RemoveIDVerificationDialog { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.removeTrustStatus(publicKey) if (markAsUntrusted && removeContact) { rootStore.contactStore.markUntrustworthy(publicKey) rootStore.contactStore.removeContact(publicKey) Global.displaySuccessToastMessage(qsTr("%1 trust mark removed, removed from contacts and marked as untrusted").arg(mainDisplayName)) } else if (markAsUntrusted) { rootStore.contactStore.markUntrustworthy(publicKey) Global.displaySuccessToastMessage(qsTr("%1 trust mark removed and marked as untrusted").arg(mainDisplayName)) } else if (removeContact) { rootStore.contactStore.removeContact(publicKey) Global.displaySuccessToastMessage(qsTr("%1 trust mark removed and removed from contacts").arg(mainDisplayName)) } else { Global.displaySuccessToastMessage(qsTr("%1 trust mark removed").arg(mainDisplayName)) } close() } onClosed: destroy() } }, Component { id: inviteFriendsToCommunityPopup InviteFriendsToCommunityPopup { rootStore: root.rootStore contactsModel: root.mutualContactsModel onClosed: destroy() } }, Component { id: sendContactRequestPopupComponent SendContactRequestModal { rootStore: root.rootStore utilsStore: root.utilsStore onAccepted: rootStore.contactStore.sendContactRequest(publicKey, message) onClosed: destroy() } }, Component { id: reviewContactRequestPopupComponent ReviewContactRequestPopup { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.acceptContactRequest(publicKey, contactRequestId) Global.displaySuccessToastMessage(qsTr("Contact request accepted")) close() } onDiscarded: { rootStore.contactStore.dismissContactRequest(publicKey, contactRequestId) Global.displaySuccessToastMessage(qsTr("Contact request ignored")) close() } onClosed: destroy() } }, Component { id: backupSeedModalComponent BackupSeedModal { privacyStore: rootStore.profileSectionStore.privacyStore onClosed: destroy() } }, Component { id: downloadPageComponent DownloadPage { onClosed: destroy() } }, Component { id: imagePopupComponent StatusImageModal { id: imagePopup onClosed: destroy() } }, Component { id: videoPopupComponent StatusVideoModal { id: videoPopup onClosed: destroy() } }, Component { id: profilePopupComponent ProfileDialog { id: profilePopup property alias publicKey: contactModelEntry.publicKey readonly property bool isCurrentUser: contactDetails.isCurrentUser ContactModelEntry { id: contactModelEntry contactsModel: root.allContactsModel } contactDetails: contactModelEntry.contactDetails profileStore: rootStore.profileSectionStore.profileStore contactsStore: rootStore.profileSectionStore.contactsStore walletStore: WalletStores.RootStore utilsStore: root.utilsStore sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled showcaseCommunitiesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCommunitiesModel : rootStore.profileSectionStore.contactShowcaseCommunitiesModel showcaseAccountsModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseAccountsModel : rootStore.profileSectionStore.contactShowcaseAccountsModel showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel : rootStore.profileSectionStore.contactShowcaseCollectiblesModel showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel : rootStore.profileSectionStore.contactShowcaseSocialLinksModel assetsModel: rootStore.globalAssetsModel collectiblesModel: rootStore.globalCollectiblesModel onOpened: { isCurrentUser ? rootStore.profileSectionStore.requestOwnShowcase() : rootStore.profileSectionStore.requestContactShowcase(publicKey) } onClosed: { if (profilePopup.parentPopup) { profilePopup.parentPopup.close() } destroy() } } }, Component { id: changeProfilePicComponent ImageCropWorkflow { title: qsTr("Profile Picture") acceptButtonText: qsTr("Make this my Profile Pic") onImageCropped: { if (callback) { callback(image, cropRect.x.toFixed(), cropRect.y.toFixed(), (cropRect.x + cropRect.width).toFixed(), (cropRect.y + cropRect.height).toFixed()) return } rootStore.profileSectionStore.profileStore.uploadImage(image, cropRect.x.toFixed(), cropRect.y.toFixed(), (cropRect.x + cropRect.width).toFixed(), (cropRect.y + cropRect.height).toFixed()); } onDone: destroy() } }, Component { id: communityProfilePopup CommunityProfilePopup { onClosed: destroy() } }, Component { id: pinnedMessagesPopup PinnedMessagesPopup { sharedStore: root.sharedRootStore utilsStore: root.utilsStore onClosed: destroy() } }, Component { id: nicknamePopupComponent NicknamePopup { utilsStore: root.utilsStore onEditDone: { if (nickname !== newNickname) { rootStore.contactStore.changeContactNickname(publicKey, newNickname, optionalDisplayName, !!nickname) } close() } onRemoveNicknameRequested: { rootStore.contactStore.changeContactNickname(publicKey, "", optionalDisplayName, true) close() } onClosed: destroy() } }, Component { id: markAsUntrustedComponent MarkAsUntrustedPopup { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.markUntrustworthy(publicKey) if (removeContact) { rootStore.contactStore.removeContact(publicKey) Global.displaySuccessToastMessage(qsTr("%1 removed from contacts and marked as untrusted").arg(mainDisplayName)) } else { Global.displaySuccessToastMessage(qsTr("%1 marked as untrusted").arg(mainDisplayName)) } close() } onClosed: destroy() } }, Component { id: unblockContactConfirmationComponent UnblockContactConfirmationDialog { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.unblockContact(publicKey) Global.displaySuccessToastMessage(qsTr("%1 unblocked").arg(mainDisplayName)) close() } onClosed: destroy() } }, Component { id: blockContactConfirmationComponent BlockContactConfirmationDialog { utilsStore: root.utilsStore onAccepted: { rootStore.contactStore.blockContact(publicKey) if (removeIDVerification) rootStore.contactStore.removeTrustStatus(publicKey) if (removeContact) rootStore.contactStore.removeContact(publicKey) Global.displaySuccessToastMessage(qsTr("%1 blocked").arg(mainDisplayName)) close() } onClosed: destroy() } }, Component { id: importCommunitiesPopupComponent ImportCommunityPopup { store: root.communitiesStore onJoinCommunityRequested: { close() communitiesStore.spectateCommunity(communityId) openCommunityIntroPopup(communityId, communityDetails.name, communityDetails.introMessage, communityDetails.image, root.rootStore.isMyCommunityRequestPending(communityId)) } onClosed: destroy() } }, Component { id: communityJoinDialogPopup CommunityMembershipSetupDialog { id: dialogRoot requirementsCheckPending: root.rootStore.requirementsCheckPending checkingPermissionToJoinInProgress: root.rootStore.checkingPermissionToJoinInProgress joinPermissionsCheckCompletedWithoutErrors: root.rootStore.joinPermissionsCheckCompletedWithoutErrors walletAccountsModel: root.rootStore.walletAccountsModel walletCollectiblesModel: WalletStores.RootStore.collectiblesStore.allCollectiblesModel canProfileProveOwnershipOfProvidedAddressesFn: WalletStores.RootStore.canProfileProveOwnershipOfProvidedAddresses walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel permissionsModel: { root.rootStore.prepareTokenModelForCommunity(dialogRoot.communityId) return root.rootStore.permissionsModel } assetsModel: root.rootStore.assetsModel collectiblesModel: root.rootStore.collectiblesModel getCurrencyAmount: function (balance, symbol) { return currencyStore.getCurrencyAmount(balance, symbol) } onPrepareForSigning: { root.rootStore.prepareKeypairsForSigning(dialogRoot.communityId, dialogRoot.name, sharedAddresses, airdropAddress, false) dialogRoot.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel } onSignProfileKeypairAndAllNonKeycardKeypairs: { root.rootStore.signProfileKeypairAndAllNonKeycardKeypairs() } onSignSharedAddressesForKeypair: { root.rootStore.signSharedAddressesForKeypair(keyUid) } onJoinCommunity: { root.rootStore.joinCommunityOrEditSharedAddresses() } onCancelMembershipRequest: { root.rootStore.cancelPendingRequest(dialogRoot.communityId) } Connections { target: root.communitiesStore.communitiesModuleInst function onCommunityAccessRequested(communityId: string) { if (communityId !== dialogRoot.communityId) return root.communitiesStore.spectateCommunity(communityId); dialogRoot.close(); } function onCommunityAccessFailed(communityId: string, error: string) { if (communityId !== dialogRoot.communityId) return dialogRoot.close(); } } onSharedAddressesUpdated: { root.rootStore.updatePermissionsModel(dialogRoot.communityId, sharedAddresses) } onAboutToShow: { root.rootStore.communityKeyToImport = dialogRoot.communityId; } onClosed: { root.rootStore.communityKeyToImport = ""; root.rootStore.cleanJoinEditCommunityData() } Connections { target: root.rootStore.communitiesModuleInst function onAllSharedAddressesSigned() { if (dialogRoot.profileProvesOwnershipOfSelectedAddresses) { dialogRoot.joinCommunity() dialogRoot.close() return } if (dialogRoot.allAddressesToRevealBelongToSingleNonProfileKeypair) { dialogRoot.joinCommunity() dialogRoot.close() return } if (!!dialogRoot.replaceItem) { dialogRoot.replaceLoader.item.allSigned() } } } } }, Component { id: createCommunitiesPopupComponent CreateCommunityPopup { store: root.communitiesStore isDevBuild: root.isDevBuild onClosed: { destroy() } } }, Component { id: discordImportProgressDialog DiscordImportProgressDialog { store: root.communitiesStore } }, Component { id: deleteMessageConfirmationDialogComponent DeleteMessageConfirmationPopup { onClosed: destroy() } }, Component { id: downloadImageDialogComponent FileDialog { property string imageSource title: qsTr("Please choose a directory") selectFolder: true selectExisting: true selectMultiple: false modality: Qt.NonModal onAccepted: { SystemUtils.downloadImageByUrl(imageSource, fileUrl) destroy() } onRejected: { destroy() } } }, Component { id: leaveCommunityPopupComponent StatusModal { id: leavePopup property string community property string communityId property string outroMessage headerSettings.title: qsTr("Are you sure want to leave '%1'?").arg(community) padding: 16 width: 640 contentItem: ColumnLayout { spacing: 16 StatusBaseText { id: outroMessage Layout.fillWidth: true wrapMode: Text.WrapAtWordBoundaryOrAnywhere text: leavePopup.outroMessage visible: !!text } StatusMenuSeparator { Layout.fillWidth: true visible: outroMessage.visible } StatusBaseText { Layout.fillWidth: true wrapMode: Text.WrapAtWordBoundaryOrAnywhere font.pixelSize: 13 text: qsTr("You will need to request to join if you want to become a member again in the future. If you joined the Community via public key ensure you have a copy of it before you go.") } } rightButtons: [ StatusFlatButton { text: qsTr("Cancel") onClicked: leavePopup.close() }, StatusButton { objectName: "CommunitiesListPanel_leaveCommunityButtonInPopup" type: StatusBaseButton.Type.Danger text: qsTr("Leave %1").arg(leavePopup.community) onClicked: { leavePopup.close() root.rootStore.profileSectionStore.communitiesProfileModule.leaveCommunity(leavePopup.communityId) } } ] onClosed: destroy() } }, Component { id: testnetModal AlertPopup { width: 521 readonly property string mainTitle: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? qsTr("Turn off testnet mode") : qsTr("Turn on testnet mode") title: mainTitle alertLabel.textFormat: Text.RichText alertText: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? qsTr("Are you sure you want to turn off %1? All future transactions will be performed on live networks with real funds").arg("testnet mode") : qsTr("Are you sure you want to turn on %1? In this mode, all blockchain data displayed will come from testnets and all blockchain interactions will be with testnets. Testnet mode switches the entire app to using testnets only. Please switch this mode on only if you know exactly why you need to use it.").arg("testnet mode") acceptBtnText: mainTitle acceptBtnType: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? StatusBaseButton.Type.Normal : StatusBaseButton.Type.Warning asset.name: "settings" asset.color: Theme.palette.warningColor1 asset.bgColor: Theme.palette.warningColor3 onAcceptClicked: { root.rootStore.profileSectionStore.walletStore.toggleTestNetworksEnabled() Global.displayToastMessage(root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? qsTr("Testnet mode turned on") : qsTr("Testnet mode turned off") , "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "") } onCancelClicked: close() } }, Component { id: exportControlNodePopup ExportControlNodePopup { devicesStore: root.devicesStore onClosed: destroy() } }, Component { id: importControlNodePopup ImportControlNodePopup { onClosed: destroy() onImportControlNode: root.rootStore.promoteSelfToControlNode(communityId) } }, Component { id: editSharedAddressesPopupComponent CommunityMembershipSetupDialog { id: editSharedAddressesPopup readonly property ChatStores.RootStore chatStore: ChatStores.RootStore { contactsStore: root.rootStore.contactStore chatCommunitySectionModule: { root.rootStore.mainModuleInst.prepareCommunitySectionModuleForCommunityId(editSharedAddressesPopup.communityId) return root.rootStore.mainModuleInst.getCommunitySectionModule() } } isEditMode: true currentSharedAddresses: root.rootStore.myRevealedAddressesForCurrentCommunity currentAirdropAddress: root.rootStore.myRevealedAirdropAddressForCurrentCommunity communityName: chatStore.sectionDetails.name communityIcon: chatStore.sectionDetails.image requirementsCheckPending: root.rootStore.requirementsCheckPending checkingPermissionToJoinInProgress: root.rootStore.checkingPermissionToJoinInProgress joinPermissionsCheckCompletedWithoutErrors: root.rootStore.joinPermissionsCheckCompletedWithoutErrors introMessage: chatStore.sectionDetails.introMessage canProfileProveOwnershipOfProvidedAddressesFn: WalletStores.RootStore.canProfileProveOwnershipOfProvidedAddresses walletAccountsModel: root.rootStore.walletAccountsModel walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel walletCollectiblesModel: WalletStores.RootStore.collectiblesStore.allCollectiblesModel permissionsModel: { root.rootStore.prepareTokenModelForCommunity(editSharedAddressesPopup.communityId) return root.rootStore.permissionsModel } assetsModel: chatStore.assetsModel collectiblesModel: chatStore.collectiblesModel getCurrencyAmount: function (balance, symbol) { return root.currencyStore.getCurrencyAmount(balance, symbol) } onSharedAddressesUpdated: { root.rootStore.updatePermissionsModel(editSharedAddressesPopup.communityId, sharedAddresses) } onPrepareForSigning: { root.rootStore.prepareKeypairsForSigning(editSharedAddressesPopup.communityId, "", sharedAddresses, airdropAddress, true) editSharedAddressesPopup.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel } onSignProfileKeypairAndAllNonKeycardKeypairs: { root.rootStore.signProfileKeypairAndAllNonKeycardKeypairs() } onSignSharedAddressesForKeypair: { root.rootStore.signSharedAddressesForKeypair(keyUid) } onEditRevealedAddresses: { root.rootStore.joinCommunityOrEditSharedAddresses() } onClosed: { root.rootStore.cleanJoinEditCommunityData() } Connections { target: root.rootStore.communitiesModuleInst function onAllSharedAddressesSigned() { if (editSharedAddressesPopup.profileProvesOwnershipOfSelectedAddresses) { editSharedAddressesPopup.editRevealedAddresses() editSharedAddressesPopup.close() return } if (editSharedAddressesPopup.allAddressesToRevealBelongToSingleNonProfileKeypair) { editSharedAddressesPopup.editRevealedAddresses() editSharedAddressesPopup.close() return } if (!!editSharedAddressesPopup.replaceItem) { editSharedAddressesPopup.replaceLoader.item.allSigned() } } } } }, Component { id: transferOwnershipPopup TransferOwnershipPopup { onTransferOwnershipRequested: root.transferOwnershipRequested( tokenId, senderAddress) onClosed: destroy() } }, Component { id: confirmExternalLinkPopup ConfirmExternalLinkPopup { destroyOnClose: true onOpenExternalLink: root.openExternalLink(link) onSaveDomainToUnfurledWhitelist: root.saveDomainToUnfurledWhitelist(domain) } }, // Components related to transfer community ownership flow: Component { id: finaliseOwnershipPopup FinaliseOwnershipPopup { id: finalisePopup property string communityId readonly property var ownerTokenDetails: root.communityTokensStore.ownerTokenDetails readonly property var communityData : root.communitiesStore.getCommunityDetailsAsJson(communityId) Component.onCompleted: root.communityTokensStore.asyncGetOwnerTokenDetails(communityId) communityName: communityData.name communityLogo: communityData.image communityColor: communityData.color tokenSymbol: ownerTokenDetails.symbol tokenChainName: ownerTokenDetails.chainName feeText: feeSubscriber.feeText feeErrorText: feeSubscriber.feeErrorText isFeeLoading: !feeSubscriber.feesResponse accounts: WalletStores.RootStore.nonWatchAccounts destroyOnClose: true onRejectClicked: Global.openDeclineOwnershipPopup(finalisePopup.communityId, communityData.name) onFinaliseOwnershipClicked: signPopup.open() onVisitCommunityClicked: communitiesStore.navigateToCommunity(finalisePopup.communityId) onOpenControlNodeDocClicked: Global.openLink(link) SetSignerFeesSubscriber { id: feeSubscriber readonly property TransactionFeesBroker feesBroker: TransactionFeesBroker { communityTokensStore: root.communityTokensStore active: finalisePopup.contentItem.Window.window.active } chainId: finalisePopup.ownerTokenDetails.chainId contractAddress: finalisePopup.ownerTokenDetails.contractAddress accountAddress: finalisePopup.ownerTokenDetails.accountAddress enabled: finalisePopup.visible || signPopup.visible Component.onCompleted: feesBroker.registerSetSignerFeesSubscriber(feeSubscriber) } SignTransactionsPopup { id: signPopup title: qsTr("Sign transaction - update %1 smart contract").arg(finalisePopup.communityName) totalFeeText: finalisePopup.isFeeLoading ? "" : finalisePopup.feeText errorText: finalisePopup.feeErrorText accountName: finalisePopup.ownerTokenDetails.accountName model: QtObject { readonly property string title: finalisePopup.feeLabel readonly property string feeText: signPopup.totalFeeText readonly property bool error: finalisePopup.feeErrorText !== "" } onSignTransactionClicked: { finalisePopup.close() root.communityTokensStore.updateSmartContract(finalisePopup.communityId, finalisePopup.ownerTokenDetails.chainId, finalisePopup.ownerTokenDetails.contractAddress, finalisePopup.ownerTokenDetails.accountAddress) } } Connections { target: root function onOwnershipDeclined(communityId: string, communityName: string) { finalisePopup.close() root.communityTokensStore.ownershipDeclined(communityId, communityName) } } } }, Component { id: declineOwnershipPopup FinaliseOwnershipDeclinePopup { destroyOnClose: true onDeclineClicked: root.ownershipDeclined(communityId, communityName) } }, // End of components related to transfer community ownership flow. Component { id: firstTokenReceivedPopup FirstTokenReceivedPopup { destroyOnClose: true communitiesStore: root.communitiesStore onHideClicked: (tokenSymbol, tokenName, tokenImage, isAsset) => isAsset ? root.openConfirmHideAssetPopup(tokenSymbol, tokenName, tokenImage, true) : root.openConfirmHideCollectiblePopup(tokenSymbol, tokenName, tokenImage, true) } }, Component { id: confirmHideAssetPopup ConfirmHideAssetPopup { destroyOnClose: true required property bool isCommunityToken onConfirmButtonClicked: { if (isCommunityToken) root.walletAssetsStore.assetsController.showHideCommunityToken(symbol, false) else root.walletAssetsStore.assetsController.showHideRegularToken(symbol, false) close() Global.displayToastMessage(qsTr("%1 (%2) successfully hidden. You can toggle asset visibility via %3.").arg(name).arg(symbol) .arg(`` + qsTr("Settings", "Go to Settings") + ""), "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "") } } }, Component { id: confirmHideCollectiblePopup ConfirmationDialog { property string collectibleSymbol property string collectibleName property string collectibleImage property bool isCommunityToken width: 520 destroyOnClose: true confirmButtonLabel: qsTr("Hide collectible") cancelBtnType: "" showCancelButton: true headerSettings.title: qsTr("Hide %1").arg(collectibleName) headerSettings.asset.name: collectibleImage headerSettings.asset.bgRadius: Theme.radius confirmationText: qsTr("Are you sure you want to hide %1? You will no longer see or be able to interact with this collectible anywhere inside Status.").arg(collectibleName) onCancelButtonClicked: close() onConfirmButtonClicked: { if (isCommunityToken) root.walletCollectiblesStore.collectiblesController.showHideCommunityToken(collectibleSymbol, false) else root.walletCollectiblesStore.collectiblesController.showHideRegularToken(collectibleSymbol, false) close() Global.displayToastMessage(qsTr("%1 successfully hidden. You can toggle collectible visibility via %2.").arg(collectibleName) .arg(`` + qsTr("Settings", "Go to Settings") + ""), "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "") } } }, Component { id: communityMemberMessagesPopup CommunityMemberMessagesPopup { sharedRootStore: root.sharedRootStore utilsStore: root.utilsStore onClosed: destroy() } }, Component { id: swapModal SwapModal { swapAdaptor: SwapModalAdaptor { swapStore: WalletStores.SwapStore {} walletAssetsStore: root.walletAssetsStore currencyStore: root.currencyStore swapFormData: swapInputParamsForm swapOutputData: SwapOutputData{} } loginType: root.rootStore.loginType onClosed: destroy() } }, Component { id: buyCryptoModal BuyCryptoModal { buyProvidersModel: root.buyCryptoStore.providersModel isBuyProvidersModelLoading: root.buyCryptoStore.areProvidersLoading currentCurrency: root.currencyStore.currentCurrency walletAccountsModel: root.rootStore.accounts plainTokensBySymbolModel: root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel groupedAccountAssetsModel: root.walletAssetsStore.groupedAccountAssetsModel networksModel: root.rootStore.profileSectionStore.walletStore.flatNetworks areTestNetworksEnabled: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled Component.onCompleted: { fetchProviders.connect(root.buyCryptoStore.fetchProviders) fetchProviderUrl.connect(root.buyCryptoStore.fetchProviderUrl) root.buyCryptoStore.providerUrlReady.connect(providerUrlReady) } onClosed: destroy() } }, Component { id: privacyPolicyPopupComponent StatusDialog { width: 600 padding: 0 title: qsTr("Status Software Privacy Policy") StatusScrollView { id: privacyDialogScrollView anchors.fill: parent contentWidth: availableWidth StatusBaseText { width: privacyDialogScrollView.availableWidth wrapMode: Text.Wrap textFormat: Text.MarkdownText text: SQUtils.StringUtils.readTextFile(":/imports/assets/docs/privacy.mdwn") onLinkActivated: Global.openLinkWithConfirmation(link, SQUtils.StringUtils.extractDomainFromLink(link)) } } standardButtons: Dialog.Ok destroyOnClose: true } }, Component { id: paymentRequestModalComponent PaymentRequestModal { id: paymentRequestModal readonly property var tokenAdaptor: TokenSelectorViewAdaptor { assetsModel: null flatNetworksModel: WalletStores.RootStore.filteredFlatModel currentCurrency: root.currencyStore.currentCurrency plainTokensBySymbolModel: WalletStores.RootStore.tokensStore.plainTokensBySymbolModel enabledChainIds: [paymentRequestModal.selectedNetworkChainId] showAllTokens: true } property var callback: null currentCurrency: root.currencyStore.currentCurrency formatCurrencyAmount: root.currencyStore.formatCurrencyAmount flatNetworksModel: WalletStores.RootStore.filteredFlatModel accountsModel: WalletStores.RootStore.nonWatchAccounts assetsModel: tokenAdaptor.outputAssetsModel onAccepted: { if (!callback) { console.error("No callback set for Payment Request") return } callback(selectedAccountAddress, amount, selectedTokenKey, selectedNetworkChainId) } destroyOnClose: true } } ] }