1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-04 06:45:45 +02:00

settings: add support for default and local moderators

- add configurable list of default moderators
- add option for enabling local moderators
- indicate when participant is locally muted on moderation overlay
- small typo fixes

Change-Id: I1669c903be3c3a3f2344f1d95d8b618e62b9d412
This commit is contained in:
ababi 2020-12-14 11:44:22 +01:00
parent 4a7c859197
commit 7450350348
27 changed files with 424 additions and 231 deletions

View file

@ -138,6 +138,7 @@ unix {
# Input
HEADERS += \
src/avatarimageprovider.h \
src/moderatorlistmodel.h \
src/networkmanager.h \
src/smartlistmodel.h \
src/updatemanager.h \
@ -187,6 +188,7 @@ HEADERS += \
SOURCES += \
src/bannedlistmodel.cpp \
src/accountlistmodel.cpp \
src/moderatorlistmodel.cpp \
src/networkmanager.cpp \
src/runguard.cpp \
src/updatemanager.cpp \

View file

@ -47,7 +47,7 @@
<file>src/settingsview/components/PluginItemDelegate.qml</file>
<file>src/mainview/components/MediaHandlerItemDelegate.qml</file>
<file>src/commoncomponents/PreferenceItemDelegate.qml</file>
<file>src/settingsview/components/BannedItemDelegate.qml</file>
<file>src/settingsview/components/ContactItemDelegate.qml</file>
<file>src/settingsview/components/MediaCodecDelegate.qml</file>
<file>src/settingsview/components/NameRegistrationDialog.qml</file>
<file>src/settingsview/components/LinkDeviceDialog.qml</file>
@ -92,7 +92,6 @@
<file>src/mainview/js/incomingcallpagecreation.js</file>
<file>src/mainview/components/ContactSearchBar.qml</file>
<file>src/mainview/components/VideoCallPage.qml</file>
<file>src/mainview/components/CallAdvancedOptions.qml</file>
<file>src/mainview/components/ParticipantOverlay.qml</file>
<file>src/mainview/components/ProjectCreditsScrollView.qml</file>
<file>src/mainview/components/AccountComboBoxPopup.qml</file>

View file

@ -356,18 +356,9 @@ AccountAdapter::connectAccount(const QString& accountId)
QObject::disconnect(accountStatusChangedConnection_);
QObject::disconnect(contactAddedConnection_);
QObject::disconnect(accountProfileChangedConnection_);
QObject::disconnect(addedToConferenceConnection_);
QObject::disconnect(contactUnbannedConnection_);
accountProfileChangedConnection_
= QObject::connect(&LRCInstance::accountModel(),
&lrc::api::NewAccountModel::profileUpdated,
[this](const QString& accountId) {
if (LRCInstance::getCurrAccId() == accountId)
emit accountStatusChanged(accountId);
});
accountStatusChangedConnection_
= QObject::connect(accInfo.accountModel,
&lrc::api::NewAccountModel::accountStatusChanged,

View file

@ -108,6 +108,7 @@ signals:
* Trigger other components to reconnect account related signals.
*/
void accountStatusChanged(QString accountId = {});
void updateConversationForAddedContact();
/*
* send report failure to QML to make it show the right UI state .
@ -144,7 +145,6 @@ private:
QMetaObject::Connection accountStatusChangedConnection_;
QMetaObject::Connection contactAddedConnection_;
QMetaObject::Connection addedToConferenceConnection_;
QMetaObject::Connection accountProfileChangedConnection_;
QMetaObject::Connection contactUnbannedConnection_;
QMetaObject::Connection registeredNameSavedConnection_;
};

View file

@ -30,7 +30,6 @@
class AudioOutputDeviceModel : public QAbstractListModel
{
Q_OBJECT
public:
public:
enum Role { Device_ID = Qt::UserRole + 1, ID_UTF8 };
Q_ENUM(Role)

View file

@ -24,8 +24,6 @@
class BannedListModel : public QAbstractListModel
{
Q_OBJECT
BannedListModel(const BannedListModel& cpy);
public:
enum Role { ContactName = Qt::UserRole + 1, ContactID };
Q_ENUM(Role)

View file

@ -413,6 +413,14 @@ Item {
property string maximizeParticipant: qsTr("Maximize")
property string minimizeParticipant: qsTr("Minimize")
property string hangupParticipant: qsTr("Hangup")
property string localMuted: qsTr("local muted")
// Settings moderation
property string conferenceModeration: qsTr("Conference moderation")
property string defaultModerators: qsTr("Default moderators")
property string enableLocalModerators: qsTr("Enable local moderators")
property string addDefaultModerator: qsTr("Add default moderator")
property string removeDefaultModerator: qsTr("Remove default moderator")
// Daemon reconnection
property string reconnectDaemon: qsTr("Trying to reconnect to the Jami daemon (dring)…")

View file

@ -35,15 +35,31 @@ ContactAdapter::getContactSelectableModel(int type)
* Called from qml every time contact picker refreshes.
*/
listModeltype_ = static_cast<SmartListModel::Type>(type);
smartListModel_.reset(new SmartListModel(this, listModeltype_));
if (listModeltype_ == SmartListModel::Type::CONVERSATION) {
defaultModerators_ =
LRCInstance::accountModel().getDefaultModerators(LRCInstance::getCurrAccId());
smartListModel_.reset(new SmartListModel(this, listModeltype_));
smartListModel_->fillConversationsList();
} else {
smartListModel_.reset(new SmartListModel(this, listModeltype_));
}
selectableProxyModel_->setSourceModel(smartListModel_.get());
/*
* Adjust filter.
*/
switch (listModeltype_) {
case SmartListModel::Type::CONVERSATION:
selectableProxyModel_->setPredicate([this]
(const QModelIndex& index, const QRegExp&) {
return !defaultModerators_.contains(index.data(SmartListModel::URI).toString());
});
break;
case SmartListModel::Type::CONFERENCE:
selectableProxyModel_->setPredicate([this](const QModelIndex& index, const QRegExp&) {
selectableProxyModel_->setPredicate([](const QModelIndex& index, const QRegExp&) {
return index.data(SmartListModel::Presence).toBool();
});
break;
@ -77,9 +93,16 @@ ContactAdapter::setSearchFilter(const QString& filter)
{
if (listModeltype_ == SmartListModel::Type::CONFERENCE) {
smartListModel_->setConferenceableFilter(filter);
} else if (listModeltype_ == SmartListModel::Type::CONVERSATION) {
selectableProxyModel_->setPredicate([this, filter](
const QModelIndex& index,
const QRegExp&) {
return (!defaultModerators_.contains(index.data(SmartListModel::URI).toString())
&& index.data(SmartListModel::DisplayName).toString().contains(filter));
});
}
selectableProxyModel_->setFilterRegExp(
QRegExp(filter, Qt::CaseInsensitive, QRegExp::FixedString));
QRegExp(filter, Qt::CaseInsensitive, QRegExp::FixedString));
}
void
@ -157,6 +180,17 @@ ContactAdapter::contactSelected(int index)
callModel->hangUp(destCallId);
}
} break;
case SmartListModel::Type::CONVERSATION: {
const auto contactUri = contactIndex.data(SmartListModel::Role::URI).value<QString>();
if (contactUri.isEmpty()) {
return;
}
LRCInstance::accountModel().setDefaultModerator(
LRCInstance::getCurrAccId(), contactUri, true);
emit defaultModeratorsUpdated();
} break;
default:
break;
}

View file

@ -95,4 +95,10 @@ private:
*/
std::unique_ptr<SmartListModel> smartListModel_;
std::unique_ptr<SelectableProxyModel> selectableProxyModel_;
QStringList defaultModerators_;
signals:
void defaultModeratorsUpdated();
};

View file

@ -19,7 +19,7 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import net.jami.Models 1.0 //Albert
import net.jami.Models 1.0
import net.jami.Adapters 1.0
import net.jami.Constants 1.0

View file

@ -1,141 +0,0 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@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.14
import QtQuick.Layouts 1.14
import QtQuick.Controls.Universal 2.14
import net.jami.Models 1.0
import net.jami.Constants 1.0
import "../../commoncomponents"
Popup {
id: contactPickerPopup
property int type: ContactPicker.ContactPickerType.JAMICONFERENCE
// Important to keep it one, since enum in c++ starts at one for conferences.
enum ContactPickerType {
JAMICONFERENCE = 1,
SIPTRANSFER
}
contentWidth: 250
contentHeight: contactPickerPopupRectColumnLayout.height + 50
padding: 0
modal: true
contentItem: Rectangle {
id: contactPickerPopupRect
width: 250
PushButton {
id: closeButton
anchors.top: contactPickerPopupRect.top
anchors.topMargin: 5
anchors.right: contactPickerPopupRect.right
anchors.rightMargin: 5
source: "qrc:/images/icons/ic_close_black_24dp.png"
onClicked: {
contactPickerPopup.close()
}
}
ColumnLayout {
id: contactPickerPopupRectColumnLayout
anchors.top: contactPickerPopupRect.top
anchors.topMargin: 15
Text {
id: contactPickerTitle
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: contactPickerPopupRect.width
Layout.preferredHeight: 30
font.pointSize: JamiTheme.textFontSize
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: type === ContactPicker.ContactPickerType.JAMICONFERENCE ? qsTr("Add to conference") : qsTr("Transfer this call")
}
ContactSearchBar {
id: contactPickerContactSearchBar
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 5
Layout.bottomMargin: 5
Layout.preferredWidth: contactPickerPopupRect.width - 10
Layout.preferredHeight: 35
onContactSearchBarTextChanged: {
ContactAdapter.setSearchFilter(text)
}
Component.onCompleted: {
contactPickerContactSearchBar.setPlaceholderString(
qsTr("Search contacts"))
}
}
ListView {
id: contactPickerListView
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: contactPickerPopupRect.width
Layout.preferredHeight: 200
model: ContactAdapter.getContactSelectableModel(type)
clip: true
delegate: ContactPickerItemDelegate {
id: contactPickerItemDelegate
}
ScrollIndicator.vertical: ScrollIndicator {}
}
}
radius: 10
color: "white"
}
onAboutToShow: {
// Reset the model on each show.
contactPickerListView.model = ContactAdapter.getContactSelectableModel(
type)
}
background: Rectangle {
color: "transparent"
}
}

View file

@ -440,8 +440,6 @@ Rectangle {
ContactPickerCreation.createContactPickerObjects(
ContactPicker.ContactPickerType.JAMICONFERENCE,
callOverlayRect)
ContactPickerCreation.calculateCurrentGeo(
callOverlayRect.width / 2, callOverlayRect.height / 2)
ContactPickerCreation.openContactPicker()
}
@ -551,20 +549,6 @@ Rectangle {
color: "transparent"
onWidthChanged: {
ContactPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2,
callOverlayRect.height / 2)
MediaHandlerPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2,
callOverlayRect.height / 2)
}
onHeightChanged: {
ContactPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2,
callOverlayRect.height / 2)
MediaHandlerPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2,
callOverlayRect.height / 2)
}
CallViewContextMenu {
id: callViewContextMenu
@ -573,16 +557,12 @@ Rectangle {
ContactPickerCreation.createContactPickerObjects(
ContactPicker.ContactPickerType.SIPTRANSFER,
callOverlayRect)
ContactPickerCreation.calculateCurrentGeo(
callOverlayRect.width / 2, callOverlayRect.height / 2)
ContactPickerCreation.openContactPicker()
}
onPluginItemClicked: {
// Create media handler picker - PLUGINS
MediaHandlerPickerCreation.createMediaHandlerPickerObjects(callOverlayRect)
MediaHandlerPickerCreation.calculateCurrentGeo(
callOverlayRect.width / 2, callOverlayRect.height / 2)
MediaHandlerPickerCreation.openMediaHandlerPicker()
}
}

View file

@ -33,7 +33,8 @@ Popup {
// Important to keep it one, since enum in c++ starts at one for conferences.
enum ContactPickerType {
JAMICONFERENCE = 1,
CONVERSATION = 0,
JAMICONFERENCE,
SIPTRANSFER
}
@ -84,7 +85,16 @@ Popup {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: type === ContactPicker.ContactPickerType.JAMICONFERENCE ? qsTr("Add to conference") : qsTr("Transfer this call")
text: {
switch(type) {
case ContactPicker.ContactPickerType.JAMICONFERENCE:
return qsTr("Add to conference")
case ContactPicker.ContactPickerType.SIPTRANSFER:
return qsTr("Transfer this call")
default:
return qsTr("Add default moderator")
}
}
}
ContactSearchBar {
@ -127,9 +137,8 @@ Popup {
}
onAboutToShow: {
// Reset the model on each show.
contactPickerListView.model = ContactAdapter.getContactSelectableModel(
type)
contactPickerListView.model =
ContactAdapter.getContactSelectableModel(type)
}
background: Rectangle {

View file

@ -70,12 +70,12 @@ Rectangle {
overlayMenu.showUnsetModerator = isHost && !isLocal && participantIsModerator
var muteState = CallAdapter.getMuteState(overlayMenu.uri)
var isLocalMuted = muteState === CallAdapter.LOCAL_MUTED
overlayMenu.isLocalMuted = muteState === CallAdapter.LOCAL_MUTED
|| muteState === CallAdapter.BOTH_MUTED
var isModeratorMuted = muteState === CallAdapter.MODERATOR_MUTED
|| muteState === CallAdapter.BOTH_MUTED
participantIsMuted = isLocalMuted || isModeratorMuted
participantIsMuted = overlayMenu.isLocalMuted || isModeratorMuted
overlayMenu.showModeratorMute = isModerator && !isModeratorMuted
overlayMenu.showModeratorUnmute = isModerator && isModeratorMuted

View file

@ -41,6 +41,7 @@ Rectangle {
property string uri: ""
property string bestName: ""
property bool isLocalMuted: false
property bool showSetModerator: false
property bool showUnsetModerator: false
property bool showModeratorMute: false
@ -150,7 +151,10 @@ Rectangle {
: JamiTheme.whiteColor
onClicked: CallAdapter.muteParticipant(uri, showModeratorMute)
onHoveredChanged: toggleParticipantToolTip.visible = hovered
onHoveredChanged: {
toggleParticipantToolTip.visible = hovered
localMutedText.visible = hovered && isLocalMuted
}
Text {
id: toggleParticipantToolTip
@ -167,6 +171,22 @@ Rectangle {
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.tinyFontSize
}
Text {
id: localMutedText
visible: false
width: parent.width
text: "(" + JamiStrings.localMuted + ")"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
anchors.top: parent.bottom
anchors.topMargin: 16
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.tinyFontSize
}
}
PushButton {

View file

@ -1,4 +1,3 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
@ -27,7 +26,6 @@ var contactPickerObject
function createContactPickerObjects(type, parent) {
if (contactPickerObject) {
/*
* If already created, reset parameters, since object cannot be destroyed.
*/
@ -49,23 +47,15 @@ function finishCreation(type, parent) {
"type": type
})
if (contactPickerObject === null) {
/*
* Error Handling.
*/
console.log("Error creating object for contact picker")
}
}
/*
* Put contact picker in the middle of container.
*/
function calculateCurrentGeo(containerX, containerY) {
if (contactPickerObject) {
contactPickerObject.x = containerX - contactPickerObject.width / 2
contactPickerObject.y = containerY - contactPickerObject.height / 2
} else {
contactPickerObject.x = Qt.binding(function(){
return parent.width/2 - contactPickerObject.width / 2})
contactPickerObject.y = Qt.binding(function(){
return parent.height/2 - contactPickerObject.height / 2})
}
}

View file

@ -47,17 +47,11 @@ function finishCreation(parent) {
* Error Handling.
*/
console.log("Error creating object for mediahandler picker")
}
}
/*
* Put mediahandler picker in the middle of container.
*/
function calculateCurrentGeo(containerX, containerY) {
if (mediahandlerPickerObject) {
mediahandlerPickerObject.x = containerX - mediahandlerPickerObject.width / 2
mediahandlerPickerObject.y = containerY - mediahandlerPickerObject.height / 2
} else {
mediahandlerPickerObject.x = Qt.binding(function(){
return parent.width/2 - mediahandlerPickerObject.width / 2})
mediahandlerPickerObject.y = Qt.binding(function(){
return parent.height/2 - mediahandlerPickerObject.height / 2})
}
}

116
src/moderatorlistmodel.cpp Normal file
View file

@ -0,0 +1,116 @@
/*
* Copyright (C) 2019-2020 by Savoir-faire Linux
* Author: Albert Babí Oller <albert.babi@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 <http://www.gnu.org/licenses/>.
*/
#include "moderatorlistmodel.h"
#include "lrcinstance.h"
ModeratorListModel::ModeratorListModel(QObject* parent)
: QAbstractListModel(parent)
{}
ModeratorListModel::~ModeratorListModel() {}
int
ModeratorListModel::rowCount(const QModelIndex& parent) const
{
if (!parent.isValid()) {
return LRCInstance::accountModel().getDefaultModerators(
LRCInstance::getCurrentAccountInfo().id).size();
}
return 0;
}
int
ModeratorListModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
/*
* Only need one column.
*/
return 1;
}
QVariant
ModeratorListModel::data(const QModelIndex& index, int role) const
{
QStringList list = LRCInstance::accountModel().getDefaultModerators(
LRCInstance::getCurrAccId());
if (!index.isValid() || list.size() <= index.row()) {
return QVariant();
}
auto contactInfo = LRCInstance::getCurrentAccountInfo().contactModel->getContact(
list.at(index.row()));
switch (role) {
case Role::ContactName: {
QString str = LRCInstance::getCurrentAccountInfo().contactModel->
bestNameForContact(list.at(index.row()));
return QVariant(str);
}
case Role::ContactID:
return QVariant(contactInfo.profileInfo.uri);
}
return QVariant();
}
QHash<int, QByteArray>
ModeratorListModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[ContactName] = "ContactName";
roles[ContactID] = "ContactID";
return roles;
}
QModelIndex
ModeratorListModel::index(int row, int column, const QModelIndex& parent) const
{
Q_UNUSED(parent);
if (column != 0) {
return QModelIndex();
}
if (row >= 0 && row < rowCount()) {
return createIndex(row, column);
}
return QModelIndex();
}
QModelIndex
ModeratorListModel::parent(const QModelIndex& child) const
{
Q_UNUSED(child);
return QModelIndex();
}
Qt::ItemFlags
ModeratorListModel::flags(const QModelIndex& index) const
{
auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable;
if (!index.isValid()) {
return QAbstractItemModel::flags(index);
}
return flags;
}
void
ModeratorListModel::reset()
{
beginResetModel();
endResetModel();
}

51
src/moderatorlistmodel.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2019-2020 by Savoir-faire Linux
* Author: Albert Babí Oller <albert.babi@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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractListModel>
class ModeratorListModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Role { ContactName = Qt::UserRole + 1, ContactID };
Q_ENUM(Role)
explicit ModeratorListModel(QObject* parent = nullptr);
~ModeratorListModel();
/*
* QAbstractListModel override.
*/
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
/*
* Override role name as access point in qml.
*/
QHash<int, QByteArray> roleNames() const override;
QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& child) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
/*
* This function is to reset the model when there's new account added.
*/
Q_INVOKABLE void reset();
};

View file

@ -26,6 +26,7 @@
#include "audiooutputdevicemodel.h"
#include "avadapter.h"
#include "bannedlistmodel.h"
#include "moderatorlistmodel.h"
#include "calladapter.h"
#include "contactadapter.h"
#include "conversationsadapter.h"
@ -103,6 +104,7 @@ registerTypes()
QML_REGISTERTYPE("net.jami.Models", MediaHandlerItemListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", PreferenceItemListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", BannedListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", ModeratorListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", MediaCodecListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", AccountsToMigrateListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", AudioInputDeviceModel, 1, 0);

View file

@ -1016,3 +1016,30 @@ SettingsAdapter::set_FilePrivateKey(QString text)
confProps.TLS.privateKeyFile = text;
LRCInstance::accountModel().setAccountConfig(LRCInstance::getCurrAccId(), confProps);
}
void
SettingsAdapter::setDefaultModerator(const QString& accountId,
const QString& peerURI,
const bool& state)
{
return LRCInstance::accountModel().setDefaultModerator(accountId, peerURI, state);
}
QStringList
SettingsAdapter::getDefaultModerators(const QString& accountId)
{
return LRCInstance::accountModel().getDefaultModerators(accountId);
}
void
SettingsAdapter::enableLocalModerators(const QString& accountId,
const bool& isModEnabled)
{
return LRCInstance::accountModel().enableLocalModerators(accountId, isModEnabled);
}
bool
SettingsAdapter::isLocalModeratorsEnabled(const QString& accountId)
{
return LRCInstance::accountModel().isLocalModeratorsEnabled(accountId);
}

View file

@ -227,5 +227,14 @@ public:
Q_INVOKABLE void set_FileCACert(QString text);
Q_INVOKABLE void set_FileUserCert(QString text);
Q_INVOKABLE void set_FilePrivateKey(QString text);
Q_INVOKABLE void setDefaultModerator(const QString& accountID,
const QString& peerURI,
const bool& state);
Q_INVOKABLE QStringList getDefaultModerators(const QString& accId);
Q_INVOKABLE void enableLocalModerators(const QString& accountID,
const bool& isModEnabled);
Q_INVOKABLE bool isLocalModeratorsEnabled(const QString& accountId);
};
Q_DECLARE_METATYPE(SettingsAdapter*)

View file

@ -27,6 +27,8 @@ import net.jami.Adapters 1.0
import net.jami.Constants 1.0
import "components"
import "../mainview/js/contactpickercreation.js" as ContactPickerCreation
Rectangle {
id: root

View file

@ -1,6 +1,7 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
* Author: Albert Babí Oller <albert.babi@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
@ -28,6 +29,8 @@ import net.jami.Adapters 1.0
import net.jami.Constants 1.0
import "../../commoncomponents"
import "../../mainview/components"
import "../../mainview/js/contactpickercreation.js" as ContactPickerCreation
ColumnLayout {
id: root
@ -43,6 +46,7 @@ ColumnLayout {
btnRingtone.setEnabled(SettingsAdapter.getAccountConfig_Ringtone_RingtoneEnabled())
btnRingtone.setText(UtilsAdapter.toFileInfoName(SettingsAdapter.getAccountConfig_Ringtone_RingtonePath()))
updateAndShowModeratorsSlot()
}
function changeRingtonePath(url) {
@ -54,6 +58,21 @@ ColumnLayout {
}
}
function updateAndShowModeratorsSlot() {
toggleLocalModerators.checked = SettingsAdapter.isLocalModeratorsEnabled(
AccountAdapter.currentAccountId)
moderatorListWidget.model.reset()
moderatorListWidget.visible = (moderatorListWidget.model.rowCount() > 0)
}
Connections {
target: ContactAdapter
function onDefaultModeratorsUpdated() {
updateAndShowModeratorsSlot()
}
}
JamiFileDialog {
id: ringtonePath_Dialog
@ -142,5 +161,78 @@ ColumnLayout {
SettingsAdapter.setIsRendezVous(checked)
}
}
ToggleSwitch {
id: toggleLocalModerators
labelText: JamiStrings.enableLocalModerators
fontPointSize: JamiTheme.settingsFontSize
onSwitchToggled: SettingsAdapter.enableLocalModerators(
AccountAdapter.currentAccountId, checked)
}
ElidedTextLabel {
Layout.fillWidth: true
eText: JamiStrings.defaultModerators
fontSize: JamiTheme.settingsFontSize
maxWidth: root.width - JamiTheme.preferredFieldHeight
- JamiTheme.preferredMarginSize * 4
}
ListViewJami {
id: moderatorListWidget
Layout.fillWidth: true
Layout.preferredHeight: 160
model: ModeratorListModel {}
delegate: ContactItemDelegate {
id: moderatorListDelegate
width: moderatorListWidget.width
height: 74
contactName: ContactName
contactID: ContactID
btnImgSource: "qrc:/images/icons/round-remove_circle-24px.svg"
btnToolTip: JamiStrings.removeDefaultModerator
onClicked: moderatorListWidget.currentIndex = index
onBtnContactClicked: {
SettingsAdapter.setDefaultModerator(
AccountAdapter.currentAccountId, contactID, false)
updateAndShowModeratorsSlot()
}
}
}
MaterialButton {
id: addDefaultModeratorPushButton
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: JamiTheme.preferredFieldWidth
Layout.preferredHeight: JamiTheme.preferredFieldHeight
color: JamiTheme.buttonTintedBlack
hoveredColor: JamiTheme.buttonTintedBlackHovered
pressedColor: JamiTheme.buttonTintedBlackPressed
outlined: true
toolTipText: JamiStrings.addDefaultModerator
source: "qrc:/images/icons/round-add-24px.svg"
text: JamiStrings.addDefaultModerator
onClicked: {
ContactPickerCreation.createContactPickerObjects(
ContactPicker.ContactPickerType.CONVERSATION,
mainView)
ContactPickerCreation.openContactPicker()
}
}
}
}

View file

@ -30,7 +30,7 @@ import net.jami.Constants 1.0
import "../../commoncomponents"
ColumnLayout {
id:root
id: root
property bool isSIP
@ -120,18 +120,20 @@ ColumnLayout {
model: BannedListModel {}
delegate: BannedItemDelegate {
delegate: ContactItemDelegate {
id: bannedListDelegate
width: bannedListWidget.width
height: 74
contactName : ContactName
contactName: ContactName
contactID: ContactID
onClicked: bannedListWidget.currentIndex = index
btnImgSource: "qrc:/images/icons/round-remove_circle-24px.svg"
btnToolTip: JamiStrings.reinstateContact
onBtnReAddContactClicked: unban(index)
onClicked: bannedListWidget.currentIndex = index
onBtnContactClicked: unban(index)
}
}
}

View file

@ -1,6 +1,7 @@
/*
* Copyright (C) 2019-2020 by Savoir-faire Linux
* Author: Yang Wang <yang.wang@savoirfairelinux.com>
* Author: Yang Wang <yang.wang@savoirfairelinux.com>
* Author: Albert Babí Oller <albert.babi@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
@ -32,8 +33,10 @@ ItemDelegate {
property string contactName : ""
property string contactID: ""
property string btnImgSource: ""
property string btnToolTip: ""
signal btnReAddContactClicked
signal btnContactClicked
highlighted: ListView.isCurrentItem
background: Rectangle {
@ -74,7 +77,7 @@ ItemDelegate {
radius: {
var size = ((avatarImg.width <= avatarImg.height) ?
avatarImg.width:avatarImg.height)
return size /2
return size / 2
}
}
}
@ -82,12 +85,12 @@ ItemDelegate {
}
}
ColumnLayout{
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter
Label{
Label {
id: labelContactName
Layout.fillWidth: true
@ -104,7 +107,7 @@ ItemDelegate {
color: JamiTheme.textColor
}
Label{
Label {
id: labelContactId
Layout.fillWidth: true
@ -124,21 +127,21 @@ ItemDelegate {
}
}
PushButton{
id: btnReAddContact
PushButton {
id: btnContact
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.rightMargin: 16
Layout.preferredWidth: JamiTheme.preferredFieldHeight
Layout.preferredHeight: JamiTheme.preferredFieldHeight
source: "qrc:/images/icons/person_add-24px.svg"
source: btnImgSource
imageColor: JamiTheme.textColor
normalColor: highlighted? JamiTheme.selectedColor : JamiTheme.editBackgroundColor
toolTipText: JamiStrings.reinstateContact
toolTipText: btnToolTip
onClicked: btnReAddContactClicked()
onClicked: btnContactClicked()
}
}
}

View file

@ -1,7 +1,7 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Yang Wang <yang.wang@savoirfairelinux.com>
* Author: Albert Babí <yang.wang@savoirfairelinux.com>
* Author: Albert Babí <albert.babi@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