From f05ffbce4442392d3c4dda12335138f86bc4c031 Mon Sep 17 00:00:00 2001 From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> Date: Thu, 29 Jul 2021 16:59:18 -0400 Subject: [PATCH] swarm: prevent interacting with read-only conversations Read-only conversation has: - a lock icon in the smartlist item - no message send bar in the chat view - no call actions available from the chat view header - no call actions available from the smartlist context menu - no double click to call Change-Id: I0497b94038b450f0a0a22fc007de1281b7b2214d Gitlab: #475 --- resources/icons/lock_black_24dp.svg | 1 + src/conversationlistmodelbase.cpp | 2 + src/conversationlistmodelbase.h | 3 +- src/conversationsadapter.cpp | 13 +++++-- src/conversationsadapter.h | 2 +- .../ConversationSmartListContextMenu.qml | 4 +- src/mainview/components/MessageWebView.qml | 17 +++++++-- .../components/MessageWebViewFooter.qml | 9 ++++- .../components/MessageWebViewHeader.qml | 8 ++-- .../components/SmartListItemDelegate.qml | 17 +++++++-- src/messagesadapter.cpp | 37 +++++++++++-------- src/messagesadapter.h | 11 +++--- 12 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 resources/icons/lock_black_24dp.svg diff --git a/resources/icons/lock_black_24dp.svg b/resources/icons/lock_black_24dp.svg new file mode 100644 index 000000000..1a38f2f68 --- /dev/null +++ b/resources/icons/lock_black_24dp.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g fill="none"><path d="M0 0h24v24H0V0z"/><path d="M0 0h24v24H0V0z" opacity=".87"/></g><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM9 6c0-1.66 1.34-3 3-3s3 1.34 3 3v2H9V6zm9 14H6V10h12v10zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/></svg> \ No newline at end of file diff --git a/src/conversationlistmodelbase.cpp b/src/conversationlistmodelbase.cpp index 4e92d8698..25eb8b821 100644 --- a/src/conversationlistmodelbase.cpp +++ b/src/conversationlistmodelbase.cpp @@ -149,6 +149,8 @@ ConversationListModelBase::dataForItem(item_t item, int role) const } return ret; } + case Role::ReadOnly: + return QVariant(item.readOnly); default: break; } diff --git a/src/conversationlistmodelbase.h b/src/conversationlistmodelbase.h index 2359d15ca..36979d3fc 100644 --- a/src/conversationlistmodelbase.h +++ b/src/conversationlistmodelbase.h @@ -48,7 +48,8 @@ X(IsRequest) \ X(Mode) \ X(Uris) \ - X(Monikers) + X(Monikers) \ + X(ReadOnly) namespace ConversationList { Q_NAMESPACE diff --git a/src/conversationsadapter.cpp b/src/conversationsadapter.cpp index 497f347bd..74e2567f1 100644 --- a/src/conversationsadapter.cpp +++ b/src/conversationsadapter.cpp @@ -274,8 +274,14 @@ ConversationsAdapter::onProfileUpdated(const QString& contactUri) } void -ConversationsAdapter::onConversationUpdated(const QString&) +ConversationsAdapter::onConversationUpdated(const QString& convId) { + // this could be the result of a member event + auto& convInfo = lrcInstance_->getConversationFromConvUid(convId); + if (convInfo.uid.isEmpty()) + return; + set_currentConvIsReadOnly(convInfo.readOnly); + updateConversationFilterData(); } @@ -283,8 +289,6 @@ void ConversationsAdapter::onFilterChanged() { updateConversationFilterData(); - if (!lrcInstance_->get_selectedConvUid().isEmpty()) - Q_EMIT indexRepositionRequested(); } void @@ -437,7 +441,8 @@ ConversationsAdapter::getConvInfoMap(const QString& convId) {"needsSyncing", convInfo.needsSyncing}, {"isAudioOnly", isAudioOnly}, {"callState", static_cast<int>(callState)}, - {"callStackViewShouldShow", callStackViewShouldShow}}; + {"callStackViewShouldShow", callStackViewShouldShow}, + {"readOnly", convInfo.readOnly}}; } bool diff --git a/src/conversationsadapter.h b/src/conversationsadapter.h index 60a066100..cae66565b 100644 --- a/src/conversationsadapter.h +++ b/src/conversationsadapter.h @@ -36,6 +36,7 @@ class ConversationsAdapter final : public QmlAdapterBase QML_PROPERTY(bool, filterRequests) QML_PROPERTY(int, totalUnreadMessageCount) QML_PROPERTY(int, pendingRequestCount) + QML_PROPERTY(bool, currentConvIsReadOnly) public: explicit ConversationsAdapter(SystemTray* systemTray, @@ -56,7 +57,6 @@ Q_SIGNALS: void showSearchStatus(const QString& status); void navigateToWelcomePageRequested(); - void indexRepositionRequested(); void conversationReady(const QString& convId); private Q_SLOTS: diff --git a/src/mainview/components/ConversationSmartListContextMenu.qml b/src/mainview/components/ConversationSmartListContextMenu.qml index a23d486b8..dd9fe7ff6 100644 --- a/src/mainview/components/ConversationSmartListContextMenu.qml +++ b/src/mainview/components/ConversationSmartListContextMenu.qml @@ -45,7 +45,7 @@ ContextMenuAutoLoader { GeneralMenuItem { id: startVideoCallItem - canTrigger: !hasCall + canTrigger: !hasCall && !ConversationsAdapter.currentConvIsReadOnly itemName: JamiStrings.startVideoCall iconSource: JamiResources.videocam_24dp_svg onClicked: { @@ -59,7 +59,7 @@ ContextMenuAutoLoader { GeneralMenuItem { id: startAudioCall - canTrigger: !hasCall + canTrigger: !hasCall && !ConversationsAdapter.currentConvIsReadOnly itemName: JamiStrings.startAudioCall iconSource: JamiResources.place_audiocall_24dp_svg onClicked: { diff --git a/src/mainview/components/MessageWebView.qml b/src/mainview/components/MessageWebView.qml index 35707086a..84aac50b8 100644 --- a/src/mainview/components/MessageWebView.qml +++ b/src/mainview/components/MessageWebView.qml @@ -114,9 +114,10 @@ Rectangle { Connections { target: MessagesAdapter - function onChangeInvitationViewRequest(show, isSwarm, needsSyncing, - title, convId) { - if (show) + function onSetChatViewMode(showInvitationPage, + isSwarm, needsSyncing, + title, convId) { + if (showInvitationPage) root.mode = MessageWebView.Mode.Invitation else { root.mode = MessageWebView.Mode.Chat @@ -129,6 +130,16 @@ Rectangle { } } + Connections { + target: ConversationsAdapter + + function onCurrentConvIsReadOnlyChanged() { + var isVisible = !ConversationsAdapter.currentConvIsReadOnly + setMessagingHeaderButtonsVisible(isVisible) + messageWebViewFooter.visible = isVisible + } + } + QtObject { id: jsBridgeObject diff --git a/src/mainview/components/MessageWebViewFooter.qml b/src/mainview/components/MessageWebViewFooter.qml index ac60be724..48821c80f 100644 --- a/src/mainview/components/MessageWebViewFooter.qml +++ b/src/mainview/components/MessageWebViewFooter.qml @@ -83,8 +83,13 @@ Rectangle { messageBar.textAreaObj.pasteText() } - function onChangeInvitationViewRequest(show, isSwarm) { - var footerVisibility = show ? !isSwarm : !show + function onSetChatViewMode(showInvitationPage, + isSwarm, needsSyncing, + title, convId, readOnly) { + var footerVisibility = showInvitationPage ? + !isSwarm : + !showInvitationPage + footerVisibility &= !readOnly messageBar.visible = footerVisibility dataTransferSendContainer.visible = footerVisibility root.visible = footerVisibility diff --git a/src/mainview/components/MessageWebViewHeader.qml b/src/mainview/components/MessageWebViewHeader.qml index 7d39aeda7..bc53aac53 100644 --- a/src/mainview/components/MessageWebViewHeader.qml +++ b/src/mainview/components/MessageWebViewHeader.qml @@ -27,7 +27,7 @@ import net.jami.Adapters 1.0 import "../../commoncomponents" Rectangle { - id: messagingHeaderRect + id: root property string userAliasLabelText property string userUserNameLabelText @@ -72,9 +72,9 @@ Rectangle { onClicked: { if (backToWelcomeViewButtonSource === JamiResources.back_24dp_svg) - messagingHeaderRect.backClicked() + root.backClicked() else - messagingHeaderRect.needToHideConversationInCall() + root.needToHideConversationInCall() } } @@ -84,7 +84,7 @@ Rectangle { Layout.alignment: Qt.AlignLeft | Qt.AlignTop // Width + margin. - Layout.preferredWidth: messagingHeaderRect.width + Layout.preferredWidth: root.width - backToWelcomeViewButton.width - buttonGroup.width - 45 Layout.fillHeight: true Layout.topMargin: 7 diff --git a/src/mainview/components/SmartListItemDelegate.qml b/src/mainview/components/SmartListItemDelegate.qml index 52a6ff309..9aae5880b 100644 --- a/src/mainview/components/SmartListItemDelegate.qml +++ b/src/mainview/components/SmartListItemDelegate.qml @@ -107,8 +107,15 @@ ItemDelegate { } } + // read-only conversation indicator + ResponsiveImage { + visible: ReadOnly + source: JamiResources.lock_black_24dp_svg + color: JamiTheme.primaryForegroundColor + } + ColumnLayout { - visible: InCall || UnreadMessagesCount + visible: (InCall || UnreadMessagesCount) && !ReadOnly Layout.preferredWidth: childrenRect.width Layout.fillHeight: true spacing: 2 @@ -153,9 +160,11 @@ ItemDelegate { ListView.view.model.select(index) if (LRCInstance.currentAccountType === Profile.Type.SIP) CallAdapter.placeAudioOnlyCall() - else - CallAdapter.placeCall() - + else { + if (!ConversationsAdapter.currentConvIsReadOnly) { + CallAdapter.placeCall() + } + } // TODO: factor this out (visible should be observing) communicationPageMessageWebView.setSendContactRequestButtonVisible(false) } diff --git a/src/messagesadapter.cpp b/src/messagesadapter.cpp index 9782c9b83..9e9843fa2 100644 --- a/src/messagesadapter.cpp +++ b/src/messagesadapter.cpp @@ -62,21 +62,24 @@ MessagesAdapter::setupChatView(const QVariantMap& convInfo) bool isLegacy = !convInfo["isSwarm"].toBool(); bool isRequest = convInfo["isRequest"].toBool(); bool needsSyncing = convInfo["needsSyncing"].toBool(); + bool readOnly = convInfo["readOnly"].toBool(); QMetaObject::invokeMethod(qmlObj_, "setSendContactRequestButtonVisible", Q_ARG(QVariant, isLegacy && isRequest)); QMetaObject::invokeMethod(qmlObj_, "setMessagingHeaderButtonsVisible", - Q_ARG(QVariant, !(isLegacy && (isRequest || needsSyncing)))); + Q_ARG(QVariant, + !readOnly && !(isLegacy && (isRequest || needsSyncing)))); setMessagesVisibility(false); setIsSwarm(!isLegacy); - Q_EMIT changeInvitationViewRequest(isRequest || needsSyncing, - isLegacy, - needsSyncing, - convInfo["title"].toString(), - convInfo["convId"].toString()); + Q_EMIT setChatViewMode(isRequest || needsSyncing, + isLegacy, + needsSyncing, + convInfo["title"].toString(), + convInfo["convId"].toString(), + readOnly); Utils::oneShotConnect(qmlObj_, SIGNAL(messagesCleared()), this, SLOT(slotMessagesCleared())); clearChatView(); @@ -369,14 +372,16 @@ MessagesAdapter::setConversationProfileData(const lrc::api::conversation::Info& QMetaObject::invokeMethod(qmlObj_, "setMessagingHeaderButtonsVisible", Q_ARG(QVariant, - !(convInfo.isSwarm() - && (convInfo.isRequest || convInfo.needsSyncing)))); - - Q_EMIT changeInvitationViewRequest(convInfo.isRequest or convInfo.needsSyncing, - convInfo.isSwarm(), - convInfo.needsSyncing, - title, - convInfo.uid); + !convInfo.readOnly + && !(convInfo.isSwarm() + && (convInfo.isRequest || convInfo.needsSyncing)))); + + Q_EMIT setChatViewMode(convInfo.isRequest || convInfo.needsSyncing, + convInfo.isSwarm(), + convInfo.needsSyncing, + title, + convInfo.uid, + convInfo.readOnly); if (convInfo.isSwarm()) return; @@ -593,7 +598,7 @@ MessagesAdapter::refuseInvitation(const QString& convUid) { const auto currentConvUid = convUid.isEmpty() ? lrcInstance_->get_selectedConvUid() : convUid; lrcInstance_->getCurrentConversationModel()->removeConversation(currentConvUid, false); - changeInvitationViewRequest(false); + Q_EMIT setChatViewMode(false); } void @@ -601,7 +606,7 @@ MessagesAdapter::blockConversation(const QString& convUid) { const auto currentConvUid = convUid.isEmpty() ? lrcInstance_->get_selectedConvUid() : convUid; lrcInstance_->getCurrentConversationModel()->removeConversation(currentConvUid, true); - changeInvitationViewRequest(false); + Q_EMIT setChatViewMode(false); } void diff --git a/src/messagesadapter.h b/src/messagesadapter.h index 69f5d0103..f8651c468 100644 --- a/src/messagesadapter.h +++ b/src/messagesadapter.h @@ -93,11 +93,12 @@ Q_SIGNALS: void newMessageBarPlaceholderText(QString placeholderText); void newFilePasted(QString filePath); void newTextPasted(); - void changeInvitationViewRequest(bool show, - bool isSwarm = false, - bool needsSyncing = false, - QString contactTitle = {}, - QString contactUri = {}); + void setChatViewMode(bool showInvitationPage, + bool isSwarm = false, + bool needsSyncing = false, + QString contactTitle = {}, + QString contactUri = {}, + bool readOnly = false); private Q_SLOTS: void slotMessagesCleared(); -- GitLab