status-desktop/ui/app/AppLayouts/Chat/CommunityComponents/CommunityDetailPopup.qml

254 lines
7.9 KiB
QML
Raw Normal View History

2020-12-11 20:29:46 +00:00
import QtQuick 2.12
import QtQuick.Dialogs 1.3
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
import "../ContactsColumn"
ModalPopup {
property QtObject community: chatsModel.communities.observedCommunity
2020-12-11 20:29:46 +00:00
property string communityId: community.id
property string name: community.name
property string description: community.description
2020-12-11 20:38:10 +00:00
property int access: community.access
property string source: community.thumbnailImage
2020-12-11 20:38:10 +00:00
property int nbMembers: community.nbMembers
property bool ensOnly: community.ensOnly
property bool canJoin: community.canJoin
property bool canRequestAccess: community.canRequestAccess
fix(Communities): don't crash on rejoin attempt Prior to this commit there was a scenario where the application would crash due a memory bug when attempting to (re)join a community. The scenario is as follows: 1. User creates or has been invited to community with `ON_REQUEST` permissions 2. User leaves community 3. User decides to rejoin, so she selects the community she's been part of and hits the "Join" button At this point Status Desktop would send a new `RequestToJoin` request, as the community has a corresponding permissions setting. This would then result in an `already a member` error in status-go, because status-go checks whether the requestee is already part of the members list of the community. The error isn't handled inside Status Desktop which causes a crash because we're trying to access data in memory that doesn't exist. Why is this happening? While this might be unexpected, when leaving a community (as done on step 2 of the mentioned scenario), users don't actually lose membership but simply "unsubscribe" from all channels in the community in question and their `joined` flag is set to `false`. From that point on, re-joininng a community is done by sending a `JoinCommunity` request (instead of `RequestToJoin`), which will then set the `joined` flag to `true` and doesn't actually check the membership in the database. This commit ensures we're calling the right API by checking whether not only whether the community is needs `ON _REQUEST` permissions, but also whether the user isn't already a member of it. Fixes #2017
2021-03-09 11:50:45 +00:00
property bool isMember: community.isMember
2020-12-11 20:29:46 +00:00
id: popup
header: Item {
height: childrenRect.height
width: parent.width
RoundedImage {
id: communityImg
source: popup.source
width: 40
height: 40
}
StyledTextEdit {
id: communityName
text: popup.name
anchors.top: parent.top
anchors.topMargin: 2
anchors.left: communityImg.right
anchors.leftMargin: Style.current.smallPadding
font.bold: true
font.pixelSize: 17
readOnly: true
}
StyledText {
id: accessText
2020-12-11 20:38:10 +00:00
text: {
switch(access) {
2021-02-18 16:36:05 +00:00
//% "Public community"
case Constants.communityChatPublicAccess: return qsTrId("public-community");
//% "Invitation only community"
case Constants.communityChatInvitationOnlyAccess: return qsTrId("invitation-only-community");
//% "On request community"
case Constants.communityChatOnRequestAccess: return qsTrId("on-request-community");
//% "Unknown community"
default: return qsTrId("unknown-community");
2020-12-11 20:38:10 +00:00
}
}
2020-12-11 20:29:46 +00:00
anchors.left: communityName.left
anchors.top: communityName.bottom
anchors.topMargin: 2
font.pixelSize: 15
font.weight: Font.Thin
color: Style.current.secondaryText
}
StyledText {
visible: popup.ensOnly
text: qsTr(" - ENS Only")
anchors.left: accessText.right
anchors.verticalCenter: accessText.verticalCenter
anchors.topMargin: 2
font.pixelSize: 15
font.weight: Font.Thin
color: Style.current.secondaryText
}
2020-12-11 20:29:46 +00:00
}
StyledText {
id: descriptionText
text: popup.description
2020-12-15 16:04:19 +00:00
wrapMode: Text.Wrap
2020-12-11 20:29:46 +00:00
width: parent.width
font.pixelSize: 15
font.weight: Font.Thin
}
Item {
id: memberContainer
width: parent.width
height: memberImage.height
anchors.top: descriptionText.bottom
anchors.topMargin: Style.current.padding
SVGImage {
id: memberImage
source: "../../../img/member.svg"
width: 16
height: 16
}
StyledText {
2020-12-15 16:04:19 +00:00
text: nbMembers === 1 ?
2021-02-18 16:36:05 +00:00
//% "1 member"
qsTrId("1-member") :
//% "%1 members"
qsTrId("-1-members").arg(popup.nbMembers)
2020-12-11 20:29:46 +00:00
wrapMode: Text.WrapAnywhere
width: parent.width
anchors.left: memberImage.right
anchors.leftMargin: 4
font.pixelSize: 15
font.weight: Font.Medium
}
}
Separator {
id: sep1
anchors.left: parent.left
anchors.right: parent.right
anchors.top: memberContainer.bottom
anchors.topMargin: Style.current.smallPadding
anchors.leftMargin: -Style.current.padding
anchors.rightMargin: -Style.current.padding
}
StyledText {
id: chatsTitle
2021-02-18 16:36:05 +00:00
//% "Chats"
text: qsTrId("chats")
2020-12-11 20:29:46 +00:00
anchors.top: sep1.bottom
anchors.topMargin: Style.current.bigPadding
font.pixelSize: 15
font.weight: Font.Thin
}
ListView {
id: chatsList
width: parent.width
anchors.top: chatsTitle.bottom
anchors.topMargin: 4
anchors.bottom: parent.bottom
clip: true
model: community.chats
2020-12-15 16:04:19 +00:00
boundsBehavior: Flickable.StopAtBounds
2020-12-11 20:29:46 +00:00
delegate: Channel {
id: channelItem
unviewedMessagesCount: ""
width: parent.width
name: model.name
lastMessage: model.description
contentType: Constants.messageType
border.width: 0
color: Style.current.transparent
2020-12-15 16:04:19 +00:00
enableMouseArea: false
2020-12-11 20:29:46 +00:00
}
}
2020-12-11 20:38:10 +00:00
2020-12-11 20:29:46 +00:00
footer: Item {
width: parent.width
height: backButton.height
2020-12-11 20:29:46 +00:00
StatusIconButton {
id: backButton
icon.name: "leave_chat"
width: 44
height: 44
iconColor: Style.current.primary
highlighted: true
icon.color: Style.current.primary
icon.width: 28
icon.height: 28
radius: width / 2
onClicked: {
openPopup(communitiesPopupComponent)
popup.close()
}
}
StatusButton {
property bool isPendingRequest: {
if (access !== Constants.communityChatOnRequestAccess) {
return false
}
return chatsModel.communities.isCommunityRequestPending(communityId)
}
text: {
if (ensOnly && !profileModel.profile.ensVerified) {
return qsTr("Membership requires an ENS username")
}
if (canJoin) {
return qsTr("Join %1").arg(popup.name);
}
if (isPendingRequest) {
return qsTr("Pending")
}
switch(access) {
case Constants.communityChatPublicAccess: return qsTr("Join %1").arg(popup.name);
case Constants.communityChatInvitationOnlyAccess: return qsTr("You need to be invited");
case Constants.communityChatOnRequestAccess: return qsTr("Request to join %1").arg(popup.name);
default: return qsTr("Unknown community");
}
}
enabled: {
if (ensOnly && !profileModel.profile.ensVerified) {
return false
}
if (canJoin) {
return true
}
if (access === Constants.communityChatInvitationOnlyAccess || isPendingRequest) {
return false
}
return true
}
2020-12-11 20:29:46 +00:00
anchors.right: parent.right
onClicked: {
let error
fix(Communities): don't crash on rejoin attempt Prior to this commit there was a scenario where the application would crash due a memory bug when attempting to (re)join a community. The scenario is as follows: 1. User creates or has been invited to community with `ON_REQUEST` permissions 2. User leaves community 3. User decides to rejoin, so she selects the community she's been part of and hits the "Join" button At this point Status Desktop would send a new `RequestToJoin` request, as the community has a corresponding permissions setting. This would then result in an `already a member` error in status-go, because status-go checks whether the requestee is already part of the members list of the community. The error isn't handled inside Status Desktop which causes a crash because we're trying to access data in memory that doesn't exist. Why is this happening? While this might be unexpected, when leaving a community (as done on step 2 of the mentioned scenario), users don't actually lose membership but simply "unsubscribe" from all channels in the community in question and their `joined` flag is set to `false`. From that point on, re-joininng a community is done by sending a `JoinCommunity` request (instead of `RequestToJoin`), which will then set the `joined` flag to `true` and doesn't actually check the membership in the database. This commit ensures we're calling the right API by checking whether not only whether the community is needs `ON _REQUEST` permissions, but also whether the user isn't already a member of it. Fixes #2017
2021-03-09 11:50:45 +00:00
if (access === Constants.communityChatOnRequestAccess && !popup.isMember) {
error = chatsModel.communities.requestToJoinCommunity(popup.communityId,
profileModel.profile.ensVerified ? profileModel.profile.username : "")
if (!error) {
enabled = false
text = qsTr("Pending")
}
} else {
error = chatsModel.communities.joinCommunity(popup.communityId, true)
}
2020-12-11 20:29:46 +00:00
if (error) {
joiningError.text = error
return joiningError.open()
}
popup.close()
}
}
MessageDialog {
id: joiningError
2021-02-18 16:36:05 +00:00
//% "Error joining the community"
title: qsTrId("error-joining-the-community")
2020-12-11 20:29:46 +00:00
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
}
}