diff --git a/ui/app/AppLayouts/Communities/stores/CommunitiesStore.qml b/ui/app/AppLayouts/Communities/stores/CommunitiesStore.qml index e1293f844f..aac9cb3498 100644 --- a/ui/app/AppLayouts/Communities/stores/CommunitiesStore.qml +++ b/ui/app/AppLayouts/Communities/stores/CommunitiesStore.qml @@ -246,6 +246,13 @@ QtObject { args.description, args.color, args.emoji, from) } + function isDisplayNameDupeOfCommunityMember(displayName) { + if (displayName === "") + return false + + return communitiesModuleInst.isDisplayNameDupeOfCommunityMember(displayName) + } + readonly property Connections connections: Connections { target: communitiesModuleInst function onImportingCommunityStateChanged(communityId, state, errorMsg) { diff --git a/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml b/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml index 6d8d3fcae9..e995208e22 100644 --- a/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml +++ b/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml @@ -13,6 +13,7 @@ import shared.panels 1.0 import shared 1.0 import shared.popups 1.0 import shared.controls 1.0 +import shared.validators 1.0 import utils 1.0 import "../popups" @@ -116,7 +117,7 @@ Item { input.clearable: true errorMessageCmp.wrapMode: Text.NoWrap errorMessageCmp.horizontalAlignment: Text.AlignHCenter - validators: Constants.validators.displayName + validators: displayNameValidators.validators onTextChanged: { userImage.name = text; } @@ -126,6 +127,10 @@ Item { d.doAction() } } + + DisplayNameValidators { + id: displayNameValidators + } } } diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index fc701020c6..0d327b3e37 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -29,6 +29,7 @@ import StatusQ.Core.Utils 0.1 as SQUtils import SortFilterProxyModel 0.2 import AppLayouts.stores 1.0 as AppLayoutsStores +import AppLayouts.Communities.stores 1.0 as CommunitiesStore StatusSectionLayout { id: root @@ -38,6 +39,7 @@ StatusSectionLayout { property SharedStores.RootStore sharedRootStore property ProfileSectionStore store property AppLayoutsStores.RootStore globalStore + property CommunitiesStore.CommunitiesStore communitiesStore required property var sendModalPopup property var systemPalette property var emojiPopup @@ -146,6 +148,8 @@ StatusSectionLayout { profileStore: root.store.profileStore contactsStore: root.store.contactsStore + communitiesStore: root.communitiesStore + sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile) contentWidth: d.contentWidth diff --git a/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml index 6c56472ed0..d51842984f 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml @@ -33,7 +33,6 @@ Item { label: qsTr("Display name") placeholderText: qsTr("Display Name") charLimit: Constants.keypair.nameLengthMax - validators: Constants.validators.displayName input.tabNavItem: bioInput.input.edit } diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml index a2b5eff795..3efb0f4ffd 100644 --- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml +++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml @@ -8,6 +8,7 @@ import shared 1.0 import shared.panels 1.0 import shared.popups 1.0 import shared.stores 1.0 +import shared.validators 1.0 import shared.controls.chat 1.0 import "../popups" @@ -24,12 +25,14 @@ import StatusQ.Controls 0.1 import AppLayouts.Profile.helpers 1.0 import AppLayouts.Profile.panels 1.0 import AppLayouts.Wallet.stores 1.0 +import AppLayouts.Communities.stores 1.0 SettingsContentBase { id: root property ProfileStore profileStore property ContactsStore contactsStore + property CommunitiesStore communitiesStore property bool sendToAccountEnabled: false @@ -294,8 +297,15 @@ SettingsContentBase { displayName.input.edit.readOnly: isEnsName displayName.text: profileStore.name displayName.validationMode: StatusInput.ValidationMode.Always - displayName.validators: isEnsName ? [] : Constants.validators.displayName + displayName.validators: isEnsName ? [] : displayNameValidators.validators bio.text: profileStore.bio + + DisplayNameValidators { + id: displayNameValidators + + myDisplayName: root.profileStore.name + communitiesStore: root.communitiesStore + } } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 24cf4f25db..d9608387ee 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -1438,6 +1438,7 @@ Item { sharedRootStore: appMain.sharedRootStore store: appMain.rootStore.profileSectionStore globalStore: appMain.rootStore + communitiesStore: appMain.communitiesStore sendModalPopup: sendModal systemPalette: appMain.sysPalette emojiPopup: statusEmojiPopup.item diff --git a/ui/imports/shared/validators/DisplayNameValidators.qml b/ui/imports/shared/validators/DisplayNameValidators.qml new file mode 100644 index 0000000000..8a895a1f94 --- /dev/null +++ b/ui/imports/shared/validators/DisplayNameValidators.qml @@ -0,0 +1,60 @@ +import QtQuick 2.15 + +import StatusQ.Controls.Validators 0.1 + +import AppLayouts.Communities.stores 1.0 +import utils 1.0 + +QtObject { + id: root + + /** + * communitiesStore and myDisplayName are optional. When provided + */ + property CommunitiesStore communitiesStore + property string myDisplayName + + readonly property list validators: [ + StatusValidator { + name: "startsWithSpaceValidator" + validate: t => !(t.startsWith(" ") || t.endsWith(" ")) + errorMessage: qsTr("Display Names can’t start or end with a space") + }, + StatusRegularExpressionValidator { + regularExpression: /^$|^[a-zA-Z0-9\-_\u0020]+$/ + errorMessage: qsTr("Invalid characters (use A-Z and 0-9, hyphens and underscores only)") + }, + StatusMinLengthValidator { + minLength: Constants.keypair.nameLengthMin + errorMessage: qsTr("Display Names must be at least %n character(s) long", + "", Constants.keypair.nameLengthMin) + }, + // TODO: Create `StatusMaxLengthValidator` in StatusQ + StatusValidator { + name: "maxLengthValidator" + validate: t => t.length <= Constants.keypair.nameLengthMax + errorMessage: qsTr("Display Names can’t be longer than %n character(s)", + "", Constants.keypair.nameLengthMax) + }, + StatusValidator { + name: "endsWith-ethValidator" + validate: t => !(t.endsWith("-eth") || t.endsWith("_eth") || t.endsWith(".eth")) + errorMessage: qsTr("Display Names can’t end in “.eth”, “_eth” or “-eth”") + }, + StatusValidator { + name: "isAliasValidator" + validate: function (t) { return !Utils.isAlias(t) } + errorMessage: qsTr("Adjective-animal Display Name formats are not allowed") + }, + StatusValidator { + name: "isDuplicateInComunitiesValidator" + validate: displayName => { + if (!root.communitiesStore || displayName === root.myDisplayName) + return true + + return !communitiesStore.isDisplayNameDupeOfCommunityMember(displayName) + } + errorMessage: qsTr("This Display Name is already in use in one of your joined communities") + } + ] +} diff --git a/ui/imports/shared/validators/qmldir b/ui/imports/shared/validators/qmldir new file mode 100644 index 0000000000..d2c6d195f2 --- /dev/null +++ b/ui/imports/shared/validators/qmldir @@ -0,0 +1 @@ +DisplayNameValidators 1.0 DisplayNameValidators.qml diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index e72c259abc..54a1646ff9 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -1,10 +1,8 @@ pragma Singleton -import QtQuick 2.13 +import QtQml 2.15 -import StatusQ.Components 0.1 import StatusQ.Controls.Validators 0.1 -import StatusQ.Core.Theme 0.1 QtObject { @@ -555,43 +553,6 @@ QtObject { errorMessage: qsTr("Key pair must be at least %n character(s)", "", keypair.nameLengthMin) } ] - - readonly property list displayName: [ - StatusValidator { - name: "startsWithSpaceValidator" - validate: function (t) { return !(t.startsWith(" ") || t.endsWith(" "))} - errorMessage: qsTr("Display Names can’t start or end with a space") - }, - StatusRegularExpressionValidator { - regularExpression: /^$|^[a-zA-Z0-9\-_\u0020]+$/ - errorMessage: qsTr("Invalid characters (use A-Z and 0-9, hyphens and underscores only)") - }, - StatusMinLengthValidator { - minLength: keypair.nameLengthMin - errorMessage: qsTr("Display Names must be at least %n character(s) long", "", keypair.nameLengthMin) - }, - // TODO: Create `StatusMaxLengthValidator` in StatusQ - StatusValidator { - name: "maxLengthValidator" - validate: function (t) { return t.length <= keypair.nameLengthMax } - errorMessage: qsTr("Display Names can’t be longer than %n character(s)", "", keypair.nameLengthMax) - }, - StatusValidator { - name: "endsWith-ethValidator" - validate: function (t) { return !(t.endsWith("-eth") || t.endsWith("_eth") || t.endsWith(".eth")) } - errorMessage: qsTr("Display Names can’t end in “.eth”, “_eth” or “-eth”") - }, - StatusValidator { - name: "isAliasValidator" - validate: function (t) { return !Utils.isAlias(t) } - errorMessage: qsTr("Adjective-animal Display Name formats are not allowed") - }, - StatusValidator { - name: "isDuplicateInComunitiesValidator" - validate: function(t) { return !Utils.isDisplayNameDupeOfCommunityMember(t) } - errorMessage: qsTr("This Display Name is already in use in one of your joined communities") - } - ] } readonly property QtObject settingsSection: QtObject { diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml index d468ba51ef..87ad9474fd 100644 --- a/ui/imports/utils/Global.qml +++ b/ui/imports/utils/Global.qml @@ -9,7 +9,6 @@ QtObject { property int settingsSubsection: Constants.settingsSubsection.profile property int settingsSubSubsection: -1 - property var userProfile property bool appIsReady: false // use the generic var as type to break the cyclic dependency diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index 064d11bb26..60b723039b 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -967,20 +967,4 @@ QtObject { function addTimestampToURL(url) { return globalUtilsInst.addTimestampToURL(url) } - - // Returns true if the provided displayName occurs in community members - function isDisplayNameDupeOfCommunityMember(displayName) { - if (!communitiesModuleInst) - return false - - if (displayName === "") - return false - - const myDisplayName = Global.userProfile ? Global.userProfile.name : "" - - if (displayName === myDisplayName) - return false - - return communitiesModuleInst.isDisplayNameDupeOfCommunityMember(displayName) - } } diff --git a/ui/main.qml b/ui/main.qml index a67369d933..391901489d 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -190,7 +190,6 @@ StatusWindow { if (!appLoadingAnimation.runningProgressAnimation) { mainModule.fakeLoadingScreenFinished() } - Global.userProfile = userProfile Global.appIsReady = true loader.sourceComponent = app