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:
parent
6d0c125546
commit
a45754ed8c
16 changed files with 180 additions and 42 deletions
1
qml.qrc
1
qml.qrc
|
@ -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>
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -257,6 +257,11 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
ReadOnlyFooter {
|
||||
visible: CurrentConversation.readOnly
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
MessageWebViewFooter {
|
||||
id: messageWebViewFooter
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ Rectangle {
|
|||
function handleParticipantsInfo(infos) {
|
||||
if (infos.length === 0) {
|
||||
bestName = UtilsAdapter.getBestName(LRCInstance.currentAccountId,
|
||||
UtilsAdapter.getCurrConvId())
|
||||
LRCInstance.selectedConvUid)
|
||||
} else {
|
||||
bestName = ""
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
76
src/mainview/components/ReadOnlyFooter.qml
Normal file
76
src/mainview/components/ReadOnlyFooter.qml
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 = "");
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue