diff --git a/storybook/PagesModel.qml b/storybook/PagesModel.qml index 58e56e75b1..a4da81d218 100644 --- a/storybook/PagesModel.qml +++ b/storybook/PagesModel.qml @@ -69,6 +69,10 @@ ListModel { title: "DeviceSyncingView" section: "Views" } + ListElement { + title: "CommunitiesView" + section: "Views" + } ListElement { title: "StatusCommunityCard" section: "Panels" diff --git a/storybook/figma.json b/storybook/figma.json index 1f242d6b57..e482512369 100644 --- a/storybook/figma.json +++ b/storybook/figma.json @@ -221,5 +221,8 @@ ], "StatusButton": [ "https://www.figma.com/file/MtAO3a7HnEH5xjCDVNilS7/%F0%9F%8E%A8-Design-System-%E2%8E%9C-Desktop?type=design&node-id=1-12&t=UHegCbqAa5K7qUKd-0" + ], + "CommunitiesView": [ + "https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=16089-387522&t=HRT9BmZXnl7Lt55Q-0" ] } diff --git a/storybook/pages/CommunitiesViewPage.qml b/storybook/pages/CommunitiesViewPage.qml new file mode 100644 index 0000000000..8873c9f290 --- /dev/null +++ b/storybook/pages/CommunitiesViewPage.qml @@ -0,0 +1,161 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 + +import StatusQ.Core 0.1 + +import AppLayouts.Profile.views 1.0 +import mainui 1.0 +import utils 1.0 + +import Storybook 1.0 +import Models 1.0 + +SplitView { + id: root + + Logs { id: logs } + + orientation: Qt.Vertical + + Popups { + popupParent: root + rootStore: QtObject {} + } + + ListModel { + id: emptyModel + } + + ListModel { + id: communitiesModel + Component.onCompleted: + append([{ + id: "0x0001", + name: "Test community", + description: "Lorem ipsum dolor sit amet", + introMessage: "Welcome to ze club", + outroMessage: "Sad to see you go", + joined: true, + spectated: false, + memberRole: Constants.memberRole.owner, + image: ModelsData.icons.dribble, + color: "yellow", + muted: false, + members: [ { pubKey: "0xdeadbeef" } ] + }, + { + id: "0x0002", + name: "Test community 2", + description: "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat.", + introMessage: "Welcome to ze club", + outroMessage: "Sad to see you go", + joined: true, + spectated: false, + memberRole: Constants.memberRole.none, + image: ModelsData.icons.status, + color: "peach", + muted: false, + members: [ { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" } ] + }, + { + id: "0x0003", + name: "Free to join", + introMessage: "Welcome to ze club", + description: "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat.", + outroMessage: "Sad to see you go", + joined: false, + spectated: true, + memberRole: Constants.memberRole.none, + image: "", + color: "red", + muted: false, + members: [ { pubKey: "0xdeadbeef" } ] + }, + { + id: "0x0004", + name: "Muted community", + introMessage: "Welcome to ze club", + description: "Lorem ipsum dolor sit amet", + outroMessage: "Sad to see you go", + joined: true, + spectated: false, + memberRole: Constants.memberRole.none, + image: "", + color: "whitesmoke", + muted: true, + members: [] + }, + { + id: "0x0005", + name: "Test community 4", + description: "Lorem ipsum dolor sit amet", + introMessage: "Welcome to ze club", + outroMessage: "Sad to see you go", + joined: true, + spectated: false, + memberRole: Constants.memberRole.admin, + image: ModelsData.icons.spotify, + color: "green", + muted: false, + members: [{ pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }, { pubKey: "0xdeadbeef" }] + }, + { + id: "0x0006", + name: "Pending request here", + description: "Lorem ipsum dolor sit amet", + introMessage: "Welcome to ze club", + outroMessage: "Sad to see you go", + joined: false, + spectated: true, + memberRole: Constants.memberRole.none, + image: ModelsData.icons.spotify, + color: "pink", + muted: false, + members: [{ pubKey: "0xdeadbeef" }] + } + ]) + } + + CommunitiesView { + SplitView.fillWidth: true + SplitView.preferredHeight: 400 + + contentWidth: 664 + profileSectionStore: QtObject { + property var communitiesProfileModule: QtObject { + function setCommunityMuted(communityId, mutedType) { + logs.logEvent("profileSectionStore::communitiesProfileModule::setCommunityMuted", ["communityId", "mutedType"], arguments) + } + function leaveCommunity(communityId) { + logs.logEvent("profileSectionStore::communitiesProfileModule::leaveCommunity", ["communityId"], arguments) + } + } + property var communitiesList: ctrlEmptyView.checked ? emptyModel : communitiesModel + } + rootStore: QtObject { + function isCommunityRequestPending(communityId) { + return communityId === "0x0006" + } + function cancelPendingRequest(communityId) { + logs.logEvent("rootStore::cancelPendingRequest", ["communityId"], arguments) + } + function setActiveCommunity(communityId) { + logs.logEvent("rootStore::setActiveCommunity", ["communityId"], arguments) + } + } + } + + LogsAndControlsPanel { + id: logsAndControlsPanel + + SplitView.minimumHeight: 100 + SplitView.preferredHeight: 200 + + logsView.logText: logs.logText + + Switch { + id: ctrlEmptyView + text: "No communities" + } + } +} diff --git a/ui/StatusQ/src/StatusQ/Components/StatusMemberListItem.qml b/ui/StatusQ/src/StatusQ/Components/StatusMemberListItem.qml index 90649e7704..b7e8465e98 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusMemberListItem.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusMemberListItem.qml @@ -143,11 +143,13 @@ StatusListItem { statusListItemIcon.badge.implicitHeight: 12 // 8 px + 2 px * 2 borders statusListItemIcon.badge.implicitWidth: 12 // 8 px + 2 px * 2 borders components: [ - StatusIcon { - anchors.verticalCenter: parent.verticalCenter - visible: root.isAdmin - icon: "crown" - color: Theme.palette.directColor1 + Loader { + active: root.isAdmin + sourceComponent: StatusIcon { + anchors.verticalCenter: parent.verticalCenter + icon: "crown" + color: Theme.palette.directColor1 + } } ] } diff --git a/ui/app/AppLayouts/Chat/ChatLayout.qml b/ui/app/AppLayouts/Chat/ChatLayout.qml index 584bf56fa7..be1e849196 100644 --- a/ui/app/AppLayouts/Chat/ChatLayout.qml +++ b/ui/app/AppLayouts/Chat/ChatLayout.qml @@ -91,25 +91,6 @@ StackLayout { } } } - - CommunityIntroDialog { - id: communityIntroDialog - - isInvitationPending: joinCommunityView.isInvitationPending - name: communityData.name - introMessage: communityData.introMessage - imageSrc: communityData.image - accessType: communityData.access - - onJoined: { - root.rootStore.requestToJoinCommunityWithAuthentication(communityData.id, root.rootStore.userProfileInst.name) - } - - onCancelMembershipRequest: { - root.rootStore.cancelPendingRequest(communityData.id) - joinCommunityView.isInvitationPending = root.rootStore.isCommunityRequestPending(communityData.id) - } - } } } @@ -136,7 +117,7 @@ StackLayout { viewAndPostPermissionsModel: root.permissionsStore.viewAndPostPermissionsModel assetsModel: root.rootStore.assetsModel collectiblesModel: root.rootStore.collectiblesModel - isInvitationPending: root.rootStore.isCommunityRequestPending(root.sectionItemModel.id) + isInvitationPending: root.rootStore.isCommunityRequestPending(chatView.communityId) onCommunityInfoButtonClicked: root.currentIndex = 1 onCommunityManageButtonClicked: root.currentIndex = 1 @@ -149,8 +130,8 @@ StackLayout { } onRevealAddressClicked: { Global.openPopup(communityIntroDialogPopup, { - communityId: root.sectionItemModel.id, - isInvitationPending: root.rootStore.isCommunityRequestPending(root.sectionItemModel.id), + communityId: chatView.communityId, + isInvitationPending: root.rootStore.isCommunityRequestPending(chatView.communityId), name: root.sectionItemModel.name, introMessage: root.sectionItemModel.introMessage, imageSrc: root.sectionItemModel.image, @@ -158,8 +139,8 @@ StackLayout { }) } onInvitationPendingClicked: { - root.rootStore.cancelPendingRequest(root.sectionItemModel.id) - chatView.isInvitationPending = root.rootStore.isCommunityRequestPending(root.sectionItemModel.id) + root.rootStore.cancelPendingRequest(chatView.communityId) + chatView.isInvitationPending = root.rootStore.isCommunityRequestPending(chatView.communityId) } } } diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersSettingsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersSettingsPanel.qml index 6a0ab458b3..d62c7dea97 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersSettingsPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersSettingsPanel.qml @@ -108,11 +108,10 @@ SettingsPageLayout { model: root.membersModel rootStore: root.rootStore placeholderText: { - if (root.membersModel.count === 0) { + if (root.membersModel.count === 0) return qsTr("No members to search") - } else { - return qsTr("Search %1's %n member(s)", "", root.membersModel ? root.membersModel.count : 0).arg(root.communityName) - } + + return qsTr("Search %1's %n member(s)", "", root.membersModel ? root.membersModel.count : 0).arg(root.communityName) } panelType: CommunityMembersTabPanel.TabType.AllMembers @@ -136,13 +135,10 @@ SettingsPageLayout { model: root.pendingMemberRequestsModel rootStore: root.rootStore placeholderText: { - if (root.pendingMemberRequestsModel.count === 0) { + if (root.pendingMemberRequestsModel.count === 0) return qsTr("No pending requests to search") - } else { - return qsTr("Search %1's %2 pending request%3").arg(root.communityName) - .arg(root.pendingMemberRequestsModel.count) - .arg(root.pendingMemberRequestsModel.count > 1 ? "s" : "") - } + + return qsTr("Search %1's %n pending request(s)", "", root.pendingMemberRequestsModel.count).arg(root.communityName) } panelType: CommunityMembersTabPanel.TabType.PendingRequests @@ -157,13 +153,10 @@ SettingsPageLayout { model: root.declinedMemberRequestsModel rootStore: root.rootStore placeholderText: { - if (root.declinedMemberRequestsModel.count === 0) { + if (root.declinedMemberRequestsModel.count === 0) return qsTr("No rejected members to search") - } else { - return qsTr("Search %1's %2 rejected member%3").arg(root.communityName) - .arg(root.declinedMemberRequestsModel.count) - .arg(root.declinedMemberRequestsModel.count > 1 ? "s" : "") - } + + return qsTr("Search %1's %n rejected member(s)", "", root.declinedMemberRequestsModel.count).arg(root.communityName) } panelType: CommunityMembersTabPanel.TabType.DeclinedRequests @@ -177,13 +170,10 @@ SettingsPageLayout { model: root.bannedMembersModel rootStore: root.rootStore placeholderText: { - if (root.bannedMembersModel.count === 0) { + if (root.bannedMembersModel.count === 0) return qsTr("No banned members to search") - } else { - return qsTr("Search %1's %2 banned member%3").arg(root.communityName) - .arg(root.bannedMembersModel.count) - .arg(root.bannedMembersModel.count > 1 ? "s" : "") - } + + return qsTr("Search %1's %n banned member(s)", "", root.bannedMembersModel.count).arg(root.communityName) } panelType: CommunityMembersTabPanel.TabType.BannedMembers diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml index 32392ded92..b1949e98ec 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml @@ -165,7 +165,7 @@ Item { ProfileContextMenu { id: memberContextMenuView store: root.rootStore - myPublicKey: root.rootStore.myPublicKey() + myPublicKey: userProfile.pubKey onOpenProfileClicked: { Global.openProfilePopup(publicKey, null) diff --git a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml index 2b6996cfe8..3f0200b410 100644 --- a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml @@ -632,6 +632,7 @@ StatusSectionLayout { TransferOwnershipPopup { anchors.centerIn: parent store: root.rootStore + onClosed: destroy() } } diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index 60a10993ba..5a6c478fe1 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -300,7 +300,6 @@ StatusSectionLayout { profileSectionStore: root.store rootStore: root.globalStore - contactStore: root.store.contactsStore sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.communitiesSettings) contentWidth: d.contentWidth } diff --git a/ui/app/AppLayouts/Profile/panels/CommunitiesListPanel.qml b/ui/app/AppLayouts/Profile/panels/CommunitiesListPanel.qml index 622ce1c762..a0f79b8f2e 100644 --- a/ui/app/AppLayouts/Profile/panels/CommunitiesListPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/CommunitiesListPanel.qml @@ -8,88 +8,155 @@ import StatusQ.Controls 0.1 import StatusQ.Popups 0.1 import utils 1.0 - import shared.controls.chat.menuItems 1.0 StatusListView { id: root - property bool hasAddedContacts: false + property var rootStore signal inviteFriends(var communityData) signal closeCommunityClicked(string communityId) signal leaveCommunityClicked(string community, string communityId, string outroMessage) - signal setCommunityMutedClicked(string communityId, int mutedType) - signal setActiveCommunityClicked(string communityId) + signal showCommunityIntroDialog(string communityId, string name, string introMessage, string imageSrc, int accessType) + signal cancelMembershipRequest(string communityId) interactive: false implicitHeight: contentItem.childrenRect.height spacing: 0 delegate: StatusListItem { - id: statusCommunityItem - width: parent.width + id: listItem + width: ListView.view.width title: model.name statusListItemTitle.font.pixelSize: 17 statusListItemTitle.font.bold: true + statusListItemIcon.anchors.verticalCenter: undefined + statusListItemIcon.anchors.top: statusListItemTitleArea.top subTitle: model.description tertiaryTitle: qsTr("%n member(s)", "", model.members.count) + statusListItemTertiaryTitle.font.weight: Font.Medium asset.name: model.image asset.isLetterIdenticon: !model.image asset.bgColor: model.color || Theme.palette.primaryColor1 asset.width: 40 asset.height: 40 - visible: model.joined - height: visible ? implicitHeight: 0 onClicked: setActiveCommunityClicked(model.id) - components: [ + readonly property bool isOwner: model.memberRole === Constants.memberRole.owner + readonly property bool isAdmin: model.memberRole === Constants.memberRole.admin + readonly property bool isInvitationPending: root.rootStore.isCommunityRequestPending(model.id) + components: [ StatusFlatButton { anchors.verticalCenter: parent.verticalCenter size: StatusBaseButton.Size.Small - icon.name: "dots-icon" - onClicked: menu.popup(0, height) + icon.name: "notification-muted" + icon.color: Theme.palette.baseColor1 + visible: model.muted + onClicked: root.setCommunityMutedClicked(model.id, Constants.MutingVariations.Unmuted) + }, + StatusFlatButton { + anchors.verticalCenter: parent.verticalCenter + size: StatusBaseButton.Size.Small + text: listItem.isInvitationPending ? qsTr("Membership Request Sent") : qsTr("View & Join Community") + visible: model.spectated + onClicked: root.showCommunityIntroDialog(model.id, model.name, model.introMessage, model.image, model.access) + }, + StatusFlatButton { + anchors.verticalCenter: parent.verticalCenter + size: StatusBaseButton.Size.Small + icon.name: "more" + icon.color: Theme.palette.directColor1 + highlighted: moreMenu.opened + onClicked: moreMenu.popup(-moreMenu.width + width, height + 4) - property StatusMenu menu: StatusMenu { - id: communityContextMenu - width: 180 + StatusMenu { + id: moreMenu StatusAction { - text: qsTr("Invite People") - icon.name: "share-ios" - enabled: model.canManageUsers - onTriggered: root.inviteFriends(model) - } - - MuteChatMenuItem { - enabled: !model.muted - title: qsTr("Mute Community") - onMuteTriggered: { - root.setCommunityMutedClicked(model.id, interval) - communityContextMenu.close() + text: qsTr("Community Admin") + icon.name: "settings" + enabled: listItem.isOwner || listItem.isAdmin + onTriggered: { + moreMenu.close() + Global.switchToCommunity(model.id) + Global.switchToCommunitySettings(model.id) } } - StatusAction { - enabled: model.muted text: qsTr("Unmute Community") - icon.name: "notification-muted" - onTriggered: root.setCommunityMutedClicked(model.id, Constants.MutingVariations.Unmuted) + enabled: model.muted + icon.name: "notification" + onTriggered: { + moreMenu.close() + root.setCommunityMutedClicked(model.id, Constants.MutingVariations.Unmuted) + } + } + MuteChatMenuItem { + enabled: (model.joined || (model.spectated && !listItem.isInvitationPending)) && !model.muted + title: qsTr("Mute Community") + onMuteTriggered: { + moreMenu.close() + root.setCommunityMutedClicked(model.id, interval) + } } - - StatusMenuSeparator {} - StatusAction { - text: model.spectated ? qsTr("Close Community") : qsTr("Leave Community") - icon.name: "arrow-left" + text: qsTr("Invite People") + icon.name: "invite-users" + onTriggered: { + moreMenu.close() + root.inviteFriends(model) + } + } + StatusAction { + id: shareAddressesMenuItem + text: qsTr("Edit Shared Addresses") + icon.name: "wallet" + enabled: { + if (listItem.isOwner) + return false + if (model.spectated && !listItem.isInvitationPending) + return false + return true + } + onTriggered: { + moreMenu.close() + Global.openEditSharedAddressesFlow(model.id) + // TODO shared addresses flow, cf https://github.com/status-im/status-desktop/issues/11138 + } + } + StatusMenuSeparator { + visible: shareAddressesMenuItem.enabled && leaveMenuItem.enabled + } + StatusAction { + id: leaveMenuItem + objectName: "CommunitiesListPanel_leaveCommunityPopupButton" + text: { + if (listItem.isInvitationPending) + return qsTr("Cancel Membership Request") + return model.spectated ? qsTr("Close Community") : qsTr("Leave Community") + } + icon.name: { + if (listItem.isInvitationPending) + return "arrow-left" + return model.spectated ? "close-circle" : "arrow-left" + } type: StatusAction.Type.Danger - onTriggered: model.spectated ? root.closeCommunityClicked(model.id) - : root.leaveCommunityClicked(model.name, model.id, model.outroMessage) + enabled: !listItem.isOwner + onTriggered: { + moreMenu.close() + if (listItem.isInvitationPending) + root.cancelMembershipRequest(model.id) + else if (model.spectated) + root.closeCommunityClicked(model.id) + else + root.leaveCommunityClicked(model.name, model.id, model.outroMessage) + } } } } diff --git a/ui/app/AppLayouts/Profile/views/CommunitiesView.qml b/ui/app/AppLayouts/Profile/views/CommunitiesView.qml index a2a4dd3923..b00fc1b571 100644 --- a/ui/app/AppLayouts/Profile/views/CommunitiesView.qml +++ b/ui/app/AppLayouts/Profile/views/CommunitiesView.qml @@ -23,7 +23,6 @@ SettingsContentBase { property var profileSectionStore property var rootStore - property var contactStore clip: true @@ -41,7 +40,7 @@ SettingsContentBase { ColumnLayout { id: noCommunitiesLayout anchors.fill: parent - visible: communitiesList.count === 0 + visible: !root.profileSectionStore.communitiesList.count Layout.alignment: Qt.AlignHCenter | Qt.AlignTop Image { @@ -90,53 +89,141 @@ SettingsContentBase { anchors.left: parent.left spacing: Style.current.padding - StatusBaseText { - anchors.left: parent.left - anchors.leftMargin: Style.current.padding - color: Theme.palette.baseColor1 - text: qsTr("Communities you've joined") + Heading { + text: qsTr("Owner") + visible: panelOwners.count } - CommunitiesListPanel { - id: communitiesList - - objectName: "CommunitiesView_communitiesListPanel" - width: parent.width - - model: SortFilterProxyModel { - id: filteredModel - - sourceModel: root.profileSectionStore.communitiesList - filters: [ - ValueFilter { - roleName: "joined" - value: true - } - ] + Panel { + id: panelOwners + filters: ValueFilter { + readonly property int role: Constants.memberRole.owner + roleName: "memberRole" + value: role } + } - onCloseCommunityClicked: { - root.profileSectionStore.communitiesProfileModule.leaveCommunity(communityId) + Heading { + text: qsTr("Admin") + visible: panelAdmins.count + } + + Panel { + id: panelAdmins + filters: ValueFilter { + readonly property int role: Constants.memberRole.admin + roleName: "memberRole" + value: role } + } - onLeaveCommunityClicked: { - Global.leaveCommunityRequested(community, communityId, outroMessage) + Heading { + text: qsTr("Member") + visible: panelMembers.count + } + + Panel { + id: panelMembers + filters: ExpressionFilter { + readonly property int ownerRole: Constants.memberRole.owner + readonly property int adminRole: Constants.memberRole.admin + expression: model.joined && model.memberRole !== ownerRole && model.memberRole !== adminRole } + } - onSetCommunityMutedClicked: { - root.profileSectionStore.communitiesProfileModule.setCommunityMuted(communityId, mutedType) - } + Heading { + text: qsTr("Pending") + visible: panelPendingRequests.count + } - onSetActiveCommunityClicked: { - rootStore.setActiveCommunity(communityId) - } - - onInviteFriends: { - Global.openInviteFriendsToCommunityPopup(communityData, - root.profileSectionStore.communitiesProfileModule, - null) + Panel { + id: panelPendingRequests + filters: ValueFilter { + roleName: "spectated" + value: true } } } } + + component Heading: StatusBaseText { + anchors.left: parent.left + anchors.leftMargin: Style.current.padding + color: Theme.palette.baseColor1 + } + + component Panel: CommunitiesListPanel { + id: panel + + property var filters + + width: parent.width + rootStore: root.rootStore + + model: SortFilterProxyModel { + sourceModel: root.profileSectionStore.communitiesList + filters: panel.filters + } + + onCloseCommunityClicked: { + root.profileSectionStore.communitiesProfileModule.leaveCommunity(communityId) + } + + onLeaveCommunityClicked: { + Global.leaveCommunityRequested(community, communityId, outroMessage) + } + + onSetCommunityMutedClicked: { + root.profileSectionStore.communitiesProfileModule.setCommunityMuted(communityId, mutedType) + } + + onSetActiveCommunityClicked: { + rootStore.setActiveCommunity(communityId) + } + + onInviteFriends: { + Global.openInviteFriendsToCommunityPopup(communityData, + root.profileSectionStore.communitiesProfileModule, + null) + } + onShowCommunityIntroDialog: { + Global.openPopup(communityIntroDialogPopup, { + communityId: communityId, + isInvitationPending: root.rootStore.isCommunityRequestPending(communityId), + name: name, + introMessage: introMessage, + imageSrc: imageSrc, + accessType: accessType + }) + } + onCancelMembershipRequest: { + root.rootStore.cancelPendingRequest(communityId) + } + } + + readonly property var communityIntroDialogPopup: Component { + id: communityIntroDialogPopup + CommunityIntroDialog { + id: communityIntroDialog + + property string communityId + + readonly property var chatCommunitySectionModule: { + root.rootStore.mainModuleInst.prepareCommunitySectionModuleForCommunityId(communityIntroDialog.communityId) + return root.rootStore.mainModuleInst.getCommunitySectionModule() + } + + onJoined: { + chatCommunitySectionModule.requestToJoinCommunityWithAuthentication(communityIntroDialog.communityId, root.rootStore.userProfileInst.name) + } + + onCancelMembershipRequest: { + root.rootStore.cancelPendingRequest(communityIntroDialog.communityId) + } + + onClosed: { + destroy() + } + } + } } diff --git a/ui/app/AppLayouts/stores/RootStore.qml b/ui/app/AppLayouts/stores/RootStore.qml index de646ae259..2d698e3036 100644 --- a/ui/app/AppLayouts/stores/RootStore.qml +++ b/ui/app/AppLayouts/stores/RootStore.qml @@ -93,6 +93,14 @@ QtObject { return communitiesModuleInst.isMemberOfCommunity(communityId, pubKey) } + function isCommunityRequestPending(id: string) { + return communitiesModuleInst.isCommunityRequestPending(id) + } + + function cancelPendingRequest(id: string) { + communitiesModuleInst.cancelRequestToJoinCommunity(id) + } + function copyToClipboard(text) { globalUtils.copyToClipboard(text) } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 50e26523a9..3730ceb881 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -369,7 +369,7 @@ Item { StatusAction { enabled: model.muted text: qsTr("Unmute Community") - icon.name: "notification-muted" + icon.name: "notification" onTriggered: { communityContextMenu.chatCommunitySectionModule.setCommunityMuted(Constants.MutingVariations.Unmuted) } @@ -1096,6 +1096,15 @@ Item { restoreMode: Binding.RestoreBindingOrValue } + Connections { + target: Global + function onSwitchToCommunitySettings(communityId: string) { + if (communityId !== model.id) + return + chatLayoutComponent.currentIndex = 1 // Settings + } + } + emojiPopup: statusEmojiPopup.item stickersPopup: statusStickersPopupLoader.item sectionItemModel: model diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index b6ec0d9e87..64c19fed74 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -549,8 +549,8 @@ QtObject { type: StatusBaseButton.Type.Danger text: qsTr("Leave %1").arg(leavePopup.community) onClicked: { - root.rootStore.profileSectionStore.communitiesProfileModule.leaveCommunity(leavePopup.communityId) leavePopup.close() + root.rootStore.profileSectionStore.communitiesProfileModule.leaveCommunity(leavePopup.communityId) } } ] diff --git a/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml b/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml index adb77ae4eb..dc79f5edbd 100644 --- a/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml +++ b/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml @@ -14,7 +14,7 @@ StatusMenu { title: isCommunityChat ? qsTr("Mute Channel") : qsTr("Mute Chat") - assetSettings.name: "notification" + assetSettings.name: "notification-muted" StatusAction { text: qsTr("For 15 mins") @@ -37,7 +37,7 @@ StatusMenu { } StatusAction { - text: qsTr("Until you turn it back on") + text: qsTr("Until I turn it back on") onTriggered: muteTriggered(Constants.MutingVariations.TillUnmuted) } } diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml index a9dd32f6bf..77a79bf011 100644 --- a/ui/imports/utils/Global.qml +++ b/ui/imports/utils/Global.qml @@ -54,9 +54,11 @@ QtObject { signal openSendModal(string address) signal switchToCommunity(string communityId) + signal switchToCommunitySettings(string communityId) signal createCommunityPopupRequested(bool isDiscordImport) signal importCommunityPopupRequested() signal leaveCommunityRequested(string community, string communityId, string outroMessage) + signal openEditSharedAddressesFlow(string communityId) signal playSendMessageSound() signal playNotificationSound()