1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-03 14:25:38 +02:00

conversations: provide descriptive help banner for read-only convs

Adds a new chat view footer to describe for read-only conversations
to describe the concept and provide options to remove the contact
or restart a new conversation with the contact.

Gitlab: #475
Change-Id: I6ca0e8dfbf49f17a6ff93a2744c552b76d923773
This commit is contained in:
Andreas Traczyk 2021-08-06 18:03:15 -04:00
parent 6d0c125546
commit a45754ed8c
16 changed files with 180 additions and 42 deletions

View file

@ -161,5 +161,6 @@
<file>src/commoncomponents/BubbleLabel.qml</file>
<file>src/commoncomponents/BackButton.qml</file>
<file>src/commoncomponents/JamiSwitch.qml</file>
<file>src/mainview/components/ReadOnlyFooter.qml</file>
</qresource>
</RCC>

View file

@ -40,6 +40,8 @@ Item {
property string contactSearchInvitations: qsTr("Search your invitations")
property string invitations: qsTr("Invitations")
property string description: qsTr("Jami is free software for universal communication which respects the freedoms and the privacy of its users.")
property string contactLeft: qsTr("You are viewing a conversation where all participants other than you have left. New interactions will not be possible.")
property string newConversation: qsTr("Start new conversation")
// AboutPopUp
property string version: qsTr("Version") + (UpdateManager.isCurrentVersionBeta() ? " (BETA)" : "")
@ -222,6 +224,7 @@ Item {
property string startVideoCall: qsTr("Start video call")
property string startAudioCall: qsTr("Start audio call")
property string clearConversation: qsTr("Clear conversation")
property string removeConversation: qsTr("Remove conversation")
property string removeContact: qsTr("Remove contact")
property string blockContact: qsTr("Block contact")
property string contactDetails: qsTr("Contact details")

View file

@ -311,7 +311,7 @@ Item {
property real wizardButtonWidth: 400
// Main application spec
property real mainViewMinWidth: 300
property real mainViewMinWidth: 332
property real mainViewMinHeight: 500
property real wizardViewMinWidth: 500

View file

@ -433,6 +433,53 @@ ConversationsAdapter::getConvInfoMap(const QString& convId)
{"readOnly", convInfo.readOnly}};
}
void
ConversationsAdapter::restartConversation(const QString& convId)
{
// make sure this conversation meets the criteria of a "restartable" conv
// 'readOnly' implies 'isSwarm'
auto& accInfo = lrcInstance_->getCurrentAccountInfo();
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convId);
if (convInfo.uid.isEmpty() || !convInfo.isCoreDialog() || !convInfo.readOnly) {
return;
}
// get the ONE_TO_ONE conv's peer uri
auto peerUri = accInfo.conversationModel->peersForConversation(convId).at(0);
// store a copy of the original contact so we can re-add them
// Note: we set the profile::Type to TEMPORARY to invoke a full add
// when calling ContactModel::addContact
auto contactInfo = accInfo.contactModel->getContact(peerUri);
contactInfo.profileInfo.type = profile::Type::TEMPORARY;
Utils::oneShotConnect(
accInfo.contactModel.get(),
&ContactModel::contactRemoved,
[this, &accInfo, contactInfo](const QString& peerUri) {
// setup a callback to select another ONE_TO_ONE conversation for this peer
// once the new conversation becomes ready
Utils::oneShotConnect(
accInfo.conversationModel.get(),
&ConversationModel::conversationReady,
[this, peerUri, &accInfo](const QString& convId) {
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convId);
// 3. filter for the correct contact-conversation and select it
if (!convInfo.uid.isEmpty() && convInfo.isCoreDialog() && !convInfo.readOnly
&& peerUri
== accInfo.conversationModel->peersForConversation(convId).at(0)) {
lrcInstance_->selectConversation(convId);
}
});
// 2. add the contact and await the conversationReady signal
accInfo.contactModel->addContact(contactInfo);
});
// 1. remove the contact and await the contactRemoved signal
accInfo.contactModel->removeContact(peerUri);
}
bool
ConversationsAdapter::connectConversationModel()
{

View file

@ -50,6 +50,7 @@ public:
Q_INVOKABLE bool connectConversationModel();
Q_INVOKABLE void setFilter(const QString& filterString);
Q_INVOKABLE QVariantMap getConvInfoMap(const QString& convId);
Q_INVOKABLE void restartConversation(const QString& convId);
Q_SIGNALS:
void showConversation(const QString& accountId, const QString& convUid);

View file

@ -175,7 +175,7 @@ ListView {
enabled: root.visible
onActivated: MessagesAdapter.clearConversationHistory(
LRCInstance.currentAccountId,
UtilsAdapter.getCurrConvId())
LRCInstance.selectedConvUid)
}
Shortcut {
@ -183,7 +183,8 @@ ListView {
context: Qt.ApplicationShortcut
enabled: root.visible
onActivated: {
MessagesAdapter.blockConversation(UtilsAdapter.getCurrConvId())
MessagesAdapter.blockConversation(
LRCInstance.selectedConvUid)
}
}
@ -192,9 +193,7 @@ ListView {
context: Qt.ApplicationShortcut
enabled: root.visible
onActivated: MessagesAdapter.removeConversation(
LRCInstance.currentAccountId,
UtilsAdapter.getCurrConvId(),
false)
LRCInstance.selectedConvUid)
}
Shortcut {

View file

@ -77,6 +77,15 @@ ContextMenuAutoLoader {
responsibleAccountId,
responsibleConvUid)
},
GeneralMenuItem {
id: removeConversation
canTrigger: isSwarm && !hasCall
itemName: JamiStrings.removeConversation
iconSource: JamiResources.delete_24dp_svg
onClicked: MessagesAdapter.removeConversation(
responsibleConvUid)
},
GeneralMenuItem {
id: removeContact
@ -84,8 +93,7 @@ ContextMenuAutoLoader {
|| contactType === Profile.Type.SIP)
itemName: JamiStrings.removeContact
iconSource: JamiResources.ic_hangup_participant_24dp_svg
onClicked: MessagesAdapter.removeConversation(responsibleAccountId,
responsibleConvUid)
onClicked: MessagesAdapter.removeContact(responsibleConvUid)
},
GeneralMenuItem {
id: hangup

View file

@ -257,6 +257,11 @@ Rectangle {
}
}
ReadOnlyFooter {
visible: CurrentConversation.readOnly
Layout.fillWidth: true
}
MessageWebViewFooter {
id: messageWebViewFooter

View file

@ -88,7 +88,7 @@ Rectangle {
function handleParticipantsInfo(infos) {
if (infos.length === 0) {
bestName = UtilsAdapter.getBestName(LRCInstance.currentAccountId,
UtilsAdapter.getCurrConvId())
LRCInstance.selectedConvUid)
} else {
bestName = ""
}

View file

@ -66,7 +66,7 @@ Popup {
} else {
// Reset the model on each show.
var accountId = LRCInstance.currentAccountId
var peerId = UtilsAdapter.getPeerUri(accountId, UtilsAdapter.getCurrConvId())
var peerId = UtilsAdapter.getPeerUri(accountId, LRCInstance.selectedConvUid)
pluginhandlerPickerListView.model = PluginAdapter.getChatHandlerSelectableModel(accountId, peerId)
}
}
@ -80,7 +80,7 @@ Popup {
pluginhandlerPickerListView.model = PluginAdapter.getMediaHandlerSelectableModel(callId)
} else {
var accountId = LRCInstance.currentAccountId
var peerId = UtilsAdapter.getPeerUri(accountId, UtilsAdapter.getCurrConvId())
var peerId = UtilsAdapter.getPeerUri(accountId, LRCInstance.selectedConvUid)
PluginModel.toggleChatHandler(handlerId, accountId, peerId, !isLoaded)
pluginhandlerPickerListView.model = PluginAdapter.getChatHandlerSelectableModel(accountId, peerId)
}
@ -139,7 +139,7 @@ Popup {
return PluginAdapter.getMediaHandlerSelectableModel(callId)
} else {
var accountId = LRCInstance.currentAccountId
var peerId = UtilsAdapter.getPeerUri(accountId, UtilsAdapter.getCurrConvId())
var peerId = UtilsAdapter.getPeerUri(accountId, LRCInstance.selectedConvUid)
return PluginAdapter.getChatHandlerSelectableModel(accountId, peerId)
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Andreas Traczyk <andreas.traczyk@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 2.14
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.14
import net.jami.Adapters 1.0
import net.jami.Constants 1.0
import "../../commoncomponents"
Control {
padding: 12
background: Rectangle {
anchors.fill: parent
color: JamiTheme.primaryBackgroundColor
Rectangle {
anchors.top: parent.top
height: JamiTheme.messageWebViewHairLineSize
width: parent.width
color: JamiTheme.tabbarBorderColor
}
}
contentItem: ColumnLayout {
spacing: 12
Text {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
text: JamiStrings.contactLeft
font.pointSize: JamiTheme.textFontSize + 2
color: JamiTheme.textColor
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
spacing: 12
MaterialButton {
text: JamiStrings.removeContact
font.pointSize: JamiTheme.textFontSize + 2
onClicked: MessagesAdapter.removeContact(
LRCInstance.selectedConvUid)
}
MaterialButton {
text: JamiStrings.newConversation
font.pointSize: JamiTheme.textFontSize + 2
onClicked: ConversationsAdapter.restartConversation(
LRCInstance.selectedConvUid)
}
}
}
}

View file

@ -543,20 +543,27 @@ MessagesAdapter::clearConversationHistory(const QString& accountId, const QStrin
}
void
MessagesAdapter::removeConversation(const QString& accountId,
const QString& convUid,
bool banContact)
MessagesAdapter::removeConversation(const QString& convUid)
{
QStringList list = lrcInstance_->accountModel().getDefaultModerators(accountId);
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convUid, accountId);
const auto contactURI = convInfo.participants.front();
auto& accInfo = lrcInstance_->getCurrentAccountInfo();
accInfo.conversationModel->removeConversation(convUid);
}
if (!contactURI.isEmpty() && list.contains(contactURI)) {
lrcInstance_->accountModel().setDefaultModerator(accountId, contactURI, false);
void
MessagesAdapter::removeContact(const QString& convUid, bool banContact)
{
auto& accInfo = lrcInstance_->getCurrentAccountInfo();
// remove the uri from the default moderators list
// TODO: seems like this should be done in libringclient
QStringList list = lrcInstance_->accountModel().getDefaultModerators(accInfo.id);
const auto contactUri = accInfo.conversationModel->peersForConversation(convUid).at(0);
if (!contactUri.isEmpty() && list.contains(contactUri)) {
lrcInstance_->accountModel().setDefaultModerator(accInfo.id, contactUri, false);
}
lrcInstance_->getAccountInfo(accountId).conversationModel->removeConversation(convUid,
banContact);
// actually remove the contact
accInfo.contactModel->removeContact(contactUri, banContact);
}
void

View file

@ -44,9 +44,8 @@ protected:
Q_INVOKABLE void setupChatView(const QVariantMap& convInfo);
Q_INVOKABLE void connectConversationModel();
Q_INVOKABLE void sendConversationRequest();
Q_INVOKABLE void removeConversation(const QString& accountId,
const QString& convUid,
bool banContact = false);
Q_INVOKABLE void removeConversation(const QString& convUid);
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 = {});
Q_INVOKABLE void refuseInvitation(const QString& convUid = "");

View file

@ -77,35 +77,34 @@ BaseDialog {
Description: qsTr("Fullscreen")
KeyLength: 1
}
// TODO: add the following after redesign
// ListElement {
// Shortcut: Qt.platform.os !== "windows" ? "Ctrl+Q" : "Alt+F4"
// Description: Qt.platform.os !== "windows" ? qsTr("Quit") : qsTr("Exit")
// KeyLength: 2
// }
}
ListModel {
id: keyboardConversationShortcutsModel
ListElement {
Shortcut: "Shift+Ctrl+C"
Shortcut: "Ctrl+Shift+C"
Description: qsTr("Start an audio call")
KeyLength: 3
}
ListElement {
Shortcut: "Shift+Ctrl+X"
Shortcut: "Ctrl+Shift+X"
Description: qsTr("Start a video call")
KeyLength: 3
}
ListElement {
Shortcut: "Shift+Ctrl+L"
Shortcut: "Ctrl+Shift+L"
Description: qsTr("Clear history")
KeyLength: 3
}
ListElement {
Shortcut: "Shift+Ctrl+B"
Shortcut: "Ctrl+Shift+B"
Description: qsTr("Block contact")
KeyLength: 3
}
ListElement {
Shortcut: "Ctrl+Shift+Delete"
Description: qsTr("Remove conversation")
KeyLength: 3
}
ListElement {
Shortcut: "Shift+Ctrl+A"
Description: qsTr("Accept contact request")

View file

@ -150,12 +150,6 @@ UtilsAdapter::setConversationFilter(const QString& filter)
lrcInstance_->getCurrentConversationModel()->setFilter(filter);
}
const QString
UtilsAdapter::getCurrConvId()
{
return lrcInstance_->get_selectedConvUid();
}
const QStringList
UtilsAdapter::getCurrAccList()
{

View file

@ -53,7 +53,6 @@ public:
Q_INVOKABLE const QString getPeerUri(const QString& accountId, const QString& uid);
Q_INVOKABLE QString getBestId(const QString& accountId);
Q_INVOKABLE const QString getBestId(const QString& accountId, const QString& uid);
Q_INVOKABLE const QString getCurrConvId();
Q_INVOKABLE const QStringList getCurrAccList();
Q_INVOKABLE int getAccountListSize();
Q_INVOKABLE bool hasCall(const QString& accountId);