2022-06-28 15:03:10 +00:00
|
|
|
import QtQuick 2.14
|
|
|
|
import QtQuick.Layouts 1.14
|
|
|
|
import QtQuick.Controls 2.14
|
|
|
|
|
|
|
|
import StatusQ.Core 0.1
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
import StatusQ.Controls 0.1
|
|
|
|
import StatusQ.Components 0.1
|
|
|
|
import StatusQ.Popups 0.1
|
|
|
|
|
|
|
|
import utils 1.0
|
2023-05-19 16:07:50 +00:00
|
|
|
import shared.views.chat 1.0
|
2022-06-28 15:03:10 +00:00
|
|
|
import shared.controls.chat 1.0
|
2023-08-07 13:35:14 +00:00
|
|
|
import shared.controls 1.0
|
2022-06-28 15:03:10 +00:00
|
|
|
|
2023-06-23 06:17:04 +00:00
|
|
|
import AppLayouts.Communities.layouts 1.0
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
Item {
|
|
|
|
id: root
|
|
|
|
|
|
|
|
property string placeholderText
|
|
|
|
property var model
|
2023-06-20 07:14:25 +00:00
|
|
|
property var rootStore
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
signal kickUserClicked(string id, string name)
|
|
|
|
signal banUserClicked(string id, string name)
|
|
|
|
signal unbanUserClicked(string id)
|
|
|
|
|
2022-08-04 07:49:41 +00:00
|
|
|
signal acceptRequestToJoin(string id)
|
|
|
|
signal declineRequestToJoin(string id)
|
|
|
|
|
2022-06-28 15:03:10 +00:00
|
|
|
enum TabType {
|
|
|
|
AllMembers,
|
2022-08-04 07:49:41 +00:00
|
|
|
BannedMembers,
|
|
|
|
PendingRequests,
|
|
|
|
DeclinedRequests
|
2022-06-28 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
2023-06-26 11:48:45 +00:00
|
|
|
property int panelType: MembersTabPanel.TabType.AllMembers
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
anchors.fill: parent
|
2022-08-08 15:56:57 +00:00
|
|
|
spacing: 30
|
2022-06-28 15:03:10 +00:00
|
|
|
|
2023-08-17 08:55:28 +00:00
|
|
|
SearchBox {
|
2022-06-28 15:03:10 +00:00
|
|
|
id: memberSearch
|
2022-09-22 22:18:15 +00:00
|
|
|
Layout.preferredWidth: 400
|
2022-08-08 15:56:57 +00:00
|
|
|
Layout.leftMargin: 12
|
2022-06-28 15:03:10 +00:00
|
|
|
placeholderText: root.placeholderText
|
2023-04-19 16:48:57 +00:00
|
|
|
enabled: !!model && model.count > 0
|
2022-06-28 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
2023-08-17 08:55:28 +00:00
|
|
|
StatusListView {
|
2022-06-28 15:03:10 +00:00
|
|
|
id: membersList
|
2022-10-25 19:08:15 +00:00
|
|
|
objectName: "CommunityMembersTabPanel_MembersListViews"
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
|
|
|
|
model: root.model
|
2023-08-17 08:55:28 +00:00
|
|
|
spacing: 0
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
delegate: StatusMemberListItem {
|
|
|
|
id: memberItem
|
|
|
|
|
2023-08-17 08:55:28 +00:00
|
|
|
readonly property bool itsMe: model.pubKey.toLowerCase() === Global.userProfile.pubKey.toLowerCase()
|
2022-08-04 07:49:41 +00:00
|
|
|
readonly property bool isHovered: memberItem.sensor.containsMouse
|
2023-06-23 07:19:26 +00:00
|
|
|
readonly property bool canBeBanned: !memberItem.itsMe && (model.memberRole !== Constants.memberRole.owner && model.memberRole !== Constants.memberRole.admin)
|
2023-08-08 08:41:59 +00:00
|
|
|
readonly property bool canEnableKickBanButtons: canBeBanned && root.panelType === MembersTabPanel.TabType.AllMembers
|
|
|
|
readonly property bool kickEnabled: canEnableKickBanButtons && model.membershipRequestState !== Constants.CommunityMembershipRequestState.KickedPending
|
|
|
|
readonly property bool banEnabled: canEnableKickBanButtons && model.membershipRequestState !== Constants.CommunityMembershipRequestState.BannedPending
|
|
|
|
readonly property bool kickVisible: (isHovered || !kickEnabled) && banEnabled
|
|
|
|
readonly property bool banVisible: (isHovered || !banEnabled) && kickEnabled
|
|
|
|
readonly property bool unBanVisible: (root.panelType === MembersTabPanel.TabType.BannedMembers) && isHovered && canBeBanned
|
|
|
|
|
|
|
|
readonly property bool isRejectedPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.RejectedPending
|
|
|
|
readonly property bool isAcceptedPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.AcceptedPending
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
statusListItemComponentsSlot.spacing: 16
|
2022-08-04 07:49:41 +00:00
|
|
|
statusListItemTitleArea.anchors.rightMargin: 0
|
|
|
|
statusListItemSubTitle.elide: Text.ElideRight
|
|
|
|
rightPadding: 75
|
2022-08-08 15:56:57 +00:00
|
|
|
leftPadding: 12
|
2022-06-28 15:03:10 +00:00
|
|
|
|
|
|
|
components: [
|
2023-08-08 08:41:59 +00:00
|
|
|
DisabledTooltipButton {
|
|
|
|
id: kickButton
|
2023-08-17 08:55:28 +00:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-08 08:41:59 +00:00
|
|
|
visible: kickVisible
|
|
|
|
interactive: kickEnabled
|
|
|
|
tooltipText: qsTr("Waiting for owner node to come online")
|
|
|
|
buttonComponent: StatusButton {
|
|
|
|
objectName: "MemberListItem_KickButton"
|
|
|
|
text: model.membershipRequestState === Constants.CommunityMembershipRequestState.KickedPending ? qsTr("Kick pending") : qsTr("Kick")
|
|
|
|
type: StatusBaseButton.Type.Danger
|
|
|
|
size: StatusBaseButton.Size.Small
|
2023-08-17 08:55:28 +00:00
|
|
|
onClicked: root.kickUserClicked(model.pubKey, memberItem.title)
|
2023-08-08 08:41:59 +00:00
|
|
|
enabled: kickButton.interactive
|
|
|
|
}
|
2022-06-28 15:03:10 +00:00
|
|
|
},
|
|
|
|
|
2023-08-08 08:41:59 +00:00
|
|
|
DisabledTooltipButton {
|
|
|
|
id: banButton
|
2023-08-17 08:55:28 +00:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-08 08:41:59 +00:00
|
|
|
//using opacity instead of visible to avoid the acceptButton jumping around
|
|
|
|
opacity: banVisible
|
|
|
|
interactive: banEnabled
|
2023-08-17 08:55:28 +00:00
|
|
|
tooltipText: banVisible ? qsTr("Waiting for owner node to come online") : ""
|
2023-08-08 08:41:59 +00:00
|
|
|
buttonComponent: StatusButton {
|
|
|
|
text: model.membershipRequestState === Constants.CommunityMembershipRequestState.BannedPending || !banVisible ? qsTr("Ban pending") : qsTr("Ban")
|
|
|
|
type: StatusBaseButton.Type.Danger
|
|
|
|
size: StatusBaseButton.Size.Small
|
2023-08-17 08:55:28 +00:00
|
|
|
onClicked: root.banUserClicked(model.pubKey, memberItem.title)
|
2023-08-08 08:41:59 +00:00
|
|
|
enabled: banButton.interactive
|
|
|
|
}
|
2022-06-28 15:03:10 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
StatusButton {
|
2023-08-17 08:55:28 +00:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-08 08:41:59 +00:00
|
|
|
visible: unBanVisible
|
2022-06-28 15:03:10 +00:00
|
|
|
text: qsTr("Unban")
|
|
|
|
onClicked: root.unbanUserClicked(model.pubKey)
|
2022-08-04 07:49:41 +00:00
|
|
|
},
|
|
|
|
|
2023-08-07 13:35:14 +00:00
|
|
|
DisabledTooltipButton {
|
|
|
|
id: acceptButton
|
2023-08-17 08:55:28 +00:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-07 13:35:14 +00:00
|
|
|
visible: ((root.panelType === MembersTabPanel.TabType.PendingRequests ||
|
|
|
|
root.panelType === MembersTabPanel.TabType.DeclinedRequests) && isHovered) ||
|
2023-08-08 08:41:59 +00:00
|
|
|
isAcceptedPending
|
2023-08-07 13:35:14 +00:00
|
|
|
//TODO: Only the current user can reject a pending request, so we should check that here
|
|
|
|
|
|
|
|
tooltipText: qsTr("Waiting for owner node to come online")
|
2023-08-08 08:41:59 +00:00
|
|
|
interactive: !isAcceptedPending
|
2023-08-07 13:35:14 +00:00
|
|
|
buttonComponent: StatusButton {
|
2023-08-08 08:41:59 +00:00
|
|
|
text: isAcceptedPending ? qsTr("Accept Pending") : qsTr("Accept")
|
2023-08-07 13:35:14 +00:00
|
|
|
icon.name: "checkmark-circle"
|
|
|
|
icon.color: enabled ? Theme.palette.successColor1 : disabledTextColor
|
|
|
|
normalColor: Theme.palette.successColor2
|
|
|
|
hoverColor: Theme.palette.successColor3
|
|
|
|
textColor: Theme.palette.successColor1
|
|
|
|
loading: model.requestToJoinLoading
|
|
|
|
enabled: acceptButton.interactive
|
|
|
|
onClicked: root.acceptRequestToJoin(model.requestToJoinId)
|
|
|
|
}
|
2023-03-21 11:21:23 +00:00
|
|
|
},
|
|
|
|
|
2023-08-07 13:35:14 +00:00
|
|
|
DisabledTooltipButton {
|
|
|
|
id: rejectButton
|
2023-08-17 08:55:28 +00:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-07 13:35:14 +00:00
|
|
|
//using opacity instead of visible to avoid the acceptButton jumping around
|
2023-08-08 08:41:59 +00:00
|
|
|
opacity: ((root.panelType === MembersTabPanel.TabType.PendingRequests) && isHovered) || isRejectedPending
|
2023-08-07 13:35:14 +00:00
|
|
|
//TODO: Only the current user can reject a pending request, so we should check that here
|
|
|
|
|
|
|
|
tooltipText: qsTr("Waiting for owner node to come online")
|
2023-08-08 08:41:59 +00:00
|
|
|
interactive: !isRejectedPending
|
2023-08-07 13:35:14 +00:00
|
|
|
buttonComponent: StatusButton {
|
2023-08-08 08:41:59 +00:00
|
|
|
text: isRejectedPending ? qsTr("Reject pending") : qsTr("Reject")
|
2023-08-07 13:35:14 +00:00
|
|
|
type: StatusBaseButton.Type.Danger
|
|
|
|
icon.name: "close-circle"
|
|
|
|
icon.color: enabled ? Style.current.danger : disabledTextColor
|
|
|
|
enabled: rejectButton.interactive
|
|
|
|
onClicked: root.declineRequestToJoin(model.requestToJoinId)
|
|
|
|
}
|
2022-06-28 15:03:10 +00:00
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
width: membersList.width
|
|
|
|
visible: memberSearch.text === "" || title.toLowerCase().includes(memberSearch.text.toLowerCase())
|
|
|
|
height: visible ? implicitHeight : 0
|
|
|
|
color: "transparent"
|
|
|
|
|
2023-04-19 16:48:57 +00:00
|
|
|
pubKey: model.isEnsVerified ? "" : Utils.getElidedCompressedPk(model.pubKey)
|
2022-06-28 15:03:10 +00:00
|
|
|
nickName: model.localNickname
|
2022-12-05 09:56:44 +00:00
|
|
|
userName: ProfileUtils.displayName("", model.ensName, model.displayName, model.alias)
|
2022-06-28 15:03:10 +00:00
|
|
|
status: model.onlineStatus
|
2022-09-06 15:06:33 +00:00
|
|
|
asset.color: Utils.colorForColorId(model.colorId)
|
2022-08-11 11:55:08 +00:00
|
|
|
asset.name: model.icon
|
2022-09-09 12:51:10 +00:00
|
|
|
asset.isImage: !!model.icon
|
|
|
|
asset.isLetterIdenticon: !model.icon
|
2022-08-11 11:55:08 +00:00
|
|
|
asset.width: 40
|
|
|
|
asset.height: 40
|
2023-01-10 11:29:24 +00:00
|
|
|
ringSettings.ringSpecModel: model.colorHash
|
2023-06-26 11:48:45 +00:00
|
|
|
statusListItemIcon.badge.visible: (root.panelType === MembersTabPanel.TabType.AllMembers)
|
2022-06-28 15:03:10 +00:00
|
|
|
|
2023-04-06 14:23:19 +00:00
|
|
|
onClicked: {
|
|
|
|
if(mouse.button === Qt.RightButton) {
|
2023-05-19 16:07:50 +00:00
|
|
|
Global.openMenu(memberContextMenuComponent, this, {
|
|
|
|
selectedUserPublicKey: model.pubKey,
|
2023-08-17 08:55:28 +00:00
|
|
|
selectedUserDisplayName: memberItem.title,
|
2023-05-19 16:07:50 +00:00
|
|
|
selectedUserIcon: asset.name,
|
|
|
|
})
|
2023-04-06 14:23:19 +00:00
|
|
|
} else {
|
2023-05-19 16:07:50 +00:00
|
|
|
Global.openProfilePopup(model.pubKey)
|
2023-04-06 14:23:19 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-28 15:03:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-19 16:07:50 +00:00
|
|
|
|
|
|
|
Component {
|
|
|
|
id: memberContextMenuComponent
|
|
|
|
|
|
|
|
ProfileContextMenu {
|
|
|
|
id: memberContextMenuView
|
|
|
|
store: root.rootStore
|
2023-08-17 08:55:28 +00:00
|
|
|
myPublicKey: Global.userProfile.pubKey
|
2023-05-19 16:07:50 +00:00
|
|
|
|
|
|
|
onOpenProfileClicked: {
|
|
|
|
Global.openProfilePopup(publicKey, null)
|
|
|
|
}
|
|
|
|
onCreateOneToOneChat: {
|
|
|
|
Global.changeAppSectionBySectionType(Constants.appSection.chat)
|
|
|
|
root.rootStore.chatCommunitySectionModule.createOneToOneChat(communityId, chatId, ensName)
|
|
|
|
}
|
|
|
|
onClosed: {
|
|
|
|
destroy()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-28 15:03:10 +00:00
|
|
|
}
|