diff --git a/qml.qrc b/qml.qrc index fd9a00373927053cf407ed396ddbfcd52c25fc76..2d10eef933d77dfb95c431df990caa1012d2e672 100644 --- a/qml.qrc +++ b/qml.qrc @@ -109,6 +109,7 @@ <file>src/mainview/components/SidePanelTabBar.qml</file> <file>src/mainview/components/WelcomePageQrDialog.qml</file> <file>src/mainview/components/ConversationSmartListContextMenu.qml</file> + <file>src/mainview/components/SwarmParticipantContextMenu.qml</file> <file>src/mainview/components/CallViewContextMenu.qml</file> <file>src/mainview/components/UserProfile.qml</file> <file>src/mainview/components/SwarmDetailsPanel.qml</file> diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml index 4a88a1ed81746e86d0eb7058e70a75316157497e..bb1a7917edb0f1f02f32ae4396480e05df34812f 100644 --- a/src/constant/JamiStrings.qml +++ b/src/constant/JamiStrings.qml @@ -623,4 +623,9 @@ Item { // NewSwarmPage property string createTheSwarm: qsTr("Create the swarm") + property string goToConversation: qsTr("Go to conversation") + property string promoteAdministrator: qsTr("Promote to administrator") + property string kickMember: qsTr("Kick member") + property string administrator: qsTr("Administrator") + property string invited: qsTr("Invited") } diff --git a/src/mainview/components/SwarmDetailsPanel.qml b/src/mainview/components/SwarmDetailsPanel.qml index 12bab5f768a3dc2dc9fa947032f618fc4435148e..8cac190c883cf262e88b83c6c7e7580b7643b290 100644 --- a/src/mainview/components/SwarmDetailsPanel.qml +++ b/src/mainview/components/SwarmDetailsPanel.qml @@ -48,6 +48,8 @@ Rectangle { Layout.alignment: Qt.AlignCenter Layout.preferredWidth: JamiTheme.avatarSizeInCall Layout.preferredHeight: JamiTheme.avatarSizeInCall + Layout.topMargin: JamiTheme.swarmDetailsPageTopMargin + Layout.bottomMargin: JamiTheme.preferredMarginSize imageId: LRCInstance.selectedConvUid @@ -164,50 +166,97 @@ Rectangle { spacing: JamiTheme.preferredMarginSize anchors.topMargin: JamiTheme.preferredMarginSize - model: CurrentConversation.uris - delegate: RowLayout { - spacing: 10 + SwarmParticipantContextMenu { + id: contextMenu - Avatar { - width: JamiTheme.smartListAvatarSize - height: JamiTheme.smartListAvatarSize - z: -index + function openMenuAt(x, y, participantUri) { + contextMenu.x = x + contextMenu.y = y + contextMenu.conversationId = CurrentConversation.id + contextMenu.participantUri = participantUri - imageId: CurrentAccount.uri == modelData ? CurrentAccount.id : modelData - showPresenceIndicator: UtilsAdapter.getContactPresence(CurrentAccount.id, modelData) - mode: CurrentAccount.uri == modelData ? Avatar.Mode.Account : Avatar.Mode.Contact + openMenu() } + } - ElidedTextLabel { - id: bestName - - Layout.preferredWidth: JamiTheme.preferredFieldWidth - Layout.preferredHeight: JamiTheme.preferredFieldHeight - - eText: UtilsAdapter.getContactBestName(CurrentAccount.id, modelData) - maxWidth: JamiTheme.preferredFieldWidth + model: CurrentConversation.uris + delegate: Item { - font.pointSize: JamiTheme.participantFontSize - color: JamiTheme.primaryForegroundColor - font.kerning: true + width: members.width + height: JamiTheme.smartListItemHeight - verticalAlignment: Text.AlignVCenter + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: function (mouse) { + contextMenu.openMenuAt(x + mouse.x, y + mouse.y, modelData) + } } - ElidedTextLabel { - id: role - - Layout.preferredHeight: JamiTheme.preferredFieldHeight - - eText: UtilsAdapter.getParticipantRole(CurrentAccount.id, CurrentConversation.id, modelData) - maxWidth: JamiTheme.preferredFieldWidth - - font.pointSize: JamiTheme.participantFontSize - color: JamiTheme.textColorHovered - font.kerning: true - - horizontalAlignment: Text.AlignRight - verticalAlignment: Text.AlignVCenter + RowLayout { + spacing: 10 + + Avatar { + width: JamiTheme.smartListAvatarSize + height: JamiTheme.smartListAvatarSize + Layout.leftMargin: JamiTheme.preferredMarginSize + z: -index + opacity: { + var role = UtilsAdapter.getParticipantRole(CurrentAccount.id, CurrentConversation.id, modelData) + return role === Member.Role.INVITED ? 0.5 : 1 + } + + imageId: CurrentAccount.uri == modelData ? CurrentAccount.id : modelData + showPresenceIndicator: UtilsAdapter.getContactPresence(CurrentAccount.id, modelData) + mode: CurrentAccount.uri == modelData ? Avatar.Mode.Account : Avatar.Mode.Contact + } + + ElidedTextLabel { + id: bestName + + Layout.preferredWidth: JamiTheme.preferredFieldWidth + Layout.preferredHeight: JamiTheme.preferredFieldHeight + + eText: UtilsAdapter.getContactBestName(CurrentAccount.id, modelData) + maxWidth: JamiTheme.preferredFieldWidth + + font.pointSize: JamiTheme.participantFontSize + color: JamiTheme.primaryForegroundColor + opacity: { + var role = UtilsAdapter.getParticipantRole(CurrentAccount.id, CurrentConversation.id, modelData) + return role === Member.Role.INVITED ? 0.5 : 1 + } + font.kerning: true + + verticalAlignment: Text.AlignVCenter + } + + ElidedTextLabel { + id: role + + Layout.preferredHeight: JamiTheme.preferredFieldHeight + + eText: { + var role = UtilsAdapter.getParticipantRole(CurrentAccount.id, CurrentConversation.id, modelData) + if (role === Member.Role.ADMIN) + return JamiStrings.administrator + if (role === Member.Role.INVITED) + return JamiStrings.invited + return "" + } + maxWidth: JamiTheme.preferredFieldWidth + + font.pointSize: JamiTheme.participantFontSize + color: JamiTheme.textColorHovered + opacity: { + var role = UtilsAdapter.getParticipantRole(CurrentAccount.id, CurrentConversation.id, modelData) + return role === Member.Role.INVITED ? 0.5 : 1 + } + font.kerning: true + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } } } } diff --git a/src/mainview/components/SwarmParticipantContextMenu.qml b/src/mainview/components/SwarmParticipantContextMenu.qml new file mode 100644 index 0000000000000000000000000000000000000000..17f0df985f6ca07f9034d9a2c78f812ef8820faf --- /dev/null +++ b/src/mainview/components/SwarmParticipantContextMenu.qml @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +import QtQuick + +import net.jami.Models 1.1 +import net.jami.Adapters 1.1 +import net.jami.Constants 1.1 + +import "../../commoncomponents" +import "../../commoncomponents/contextmenu" + +ContextMenuAutoLoader { + id: root + property var conversationId: "" + property var participantUri: "" + + // TODO get authorization + + property list<GeneralMenuItem> menuItems: [ + GeneralMenuItem { + id: startVideoCallItem + itemName: JamiStrings.startVideoCall + onClicked: { + } + }, + GeneralMenuItem { + id: startAudioCall + itemName: JamiStrings.startAudioCall + onClicked: { + } + }, + GeneralMenuItem { + id: goToConversation + + itemName: JamiStrings.goToConversation + onClicked: { + } + }, + GeneralMenuItem { + id: promoteAdministrator + itemName: JamiStrings.promoteAdministrator + }, + GeneralMenuItem { + id: blockContact + itemName: JamiStrings.blockContact + iconSource: JamiResources.block_black_24dp_svg + }, + GeneralMenuItem { + id: kickMember + itemName: JamiStrings.kickMember + + // TODO can trigger (enough permission for self and member accepted) + onClicked: { + MessagesAdapter.removeConversationMember(conversationId, participantUri) + } + } + ] + + Component.onCompleted: menuItemsToLoad = menuItems +} diff --git a/src/messagesadapter.cpp b/src/messagesadapter.cpp index 64ed54c7fab26f2d7f5bbf875b831386352b13e1..fb4a4c0a8a3d9f749c623475c2e6aa0f75eeb06e 100644 --- a/src/messagesadapter.cpp +++ b/src/messagesadapter.cpp @@ -384,6 +384,13 @@ MessagesAdapter::removeConversation(const QString& convUid) accInfo.conversationModel->removeConversation(convUid); } +void +MessagesAdapter::removeConversationMember(const QString& convUid, const QString& memberUri) +{ + auto& accInfo = lrcInstance_->getCurrentAccountInfo(); + accInfo.conversationModel->removeConversationMember(convUid, memberUri); +} + void MessagesAdapter::removeContact(const QString& convUid, bool banContact) { diff --git a/src/messagesadapter.h b/src/messagesadapter.h index c64cef54553d164fd459a8a833d06aef7b2cdd50..1840cb6aa985205a875ee5448338b147252ec67c 100644 --- a/src/messagesadapter.h +++ b/src/messagesadapter.h @@ -85,6 +85,7 @@ protected: Q_INVOKABLE void connectConversationModel(); Q_INVOKABLE void sendConversationRequest(); Q_INVOKABLE void removeConversation(const QString& convUid); + Q_INVOKABLE void removeConversationMember(const QString& convUid, const QString& participantUri); Q_INVOKABLE void removeContact(const QString& convUid, bool banContact = false); Q_INVOKABLE void clearConversationHistory(const QString& accountId, const QString& convUid); Q_INVOKABLE void acceptInvitation(const QString& convId = {});