diff --git a/jami-qt.pro b/jami-qt.pro
index 57df5322..d57fd245 100644
--- a/jami-qt.pro
+++ b/jami-qt.pro
@@ -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 \
diff --git a/qml.qrc b/qml.qrc
index b8e16a65..0181fbc4 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -47,7 +47,7 @@
src/settingsview/components/PluginItemDelegate.qml
src/mainview/components/MediaHandlerItemDelegate.qml
src/commoncomponents/PreferenceItemDelegate.qml
- src/settingsview/components/BannedItemDelegate.qml
+ src/settingsview/components/ContactItemDelegate.qml
src/settingsview/components/MediaCodecDelegate.qml
src/settingsview/components/NameRegistrationDialog.qml
src/settingsview/components/LinkDeviceDialog.qml
@@ -92,7 +92,6 @@
src/mainview/js/incomingcallpagecreation.js
src/mainview/components/ContactSearchBar.qml
src/mainview/components/VideoCallPage.qml
- src/mainview/components/CallAdvancedOptions.qml
src/mainview/components/ParticipantOverlay.qml
src/mainview/components/ProjectCreditsScrollView.qml
src/mainview/components/AccountComboBoxPopup.qml
diff --git a/src/accountadapter.cpp b/src/accountadapter.cpp
index 53918936..fa3d3b52 100644
--- a/src/accountadapter.cpp
+++ b/src/accountadapter.cpp
@@ -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,
diff --git a/src/accountadapter.h b/src/accountadapter.h
index a6e55df4..ac950a34 100644
--- a/src/accountadapter.h
+++ b/src/accountadapter.h
@@ -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_;
};
diff --git a/src/audiooutputdevicemodel.h b/src/audiooutputdevicemodel.h
index 376e3636..a615869d 100644
--- a/src/audiooutputdevicemodel.h
+++ b/src/audiooutputdevicemodel.h
@@ -30,7 +30,6 @@
class AudioOutputDeviceModel : public QAbstractListModel
{
Q_OBJECT
-public:
public:
enum Role { Device_ID = Qt::UserRole + 1, ID_UTF8 };
Q_ENUM(Role)
diff --git a/src/bannedlistmodel.h b/src/bannedlistmodel.h
index 28a2951e..a44abc88 100644
--- a/src/bannedlistmodel.h
+++ b/src/bannedlistmodel.h
@@ -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)
diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml
index dbb213c0..97553b0e 100644
--- a/src/constant/JamiStrings.qml
+++ b/src/constant/JamiStrings.qml
@@ -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)…")
diff --git a/src/contactadapter.cpp b/src/contactadapter.cpp
index 00d7055d..85c15ddc 100644
--- a/src/contactadapter.cpp
+++ b/src/contactadapter.cpp
@@ -35,15 +35,31 @@ ContactAdapter::getContactSelectableModel(int type)
* Called from qml every time contact picker refreshes.
*/
listModeltype_ = static_cast(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();
+ if (contactUri.isEmpty()) {
+ return;
+ }
+
+ LRCInstance::accountModel().setDefaultModerator(
+ LRCInstance::getCurrAccId(), contactUri, true);
+ emit defaultModeratorsUpdated();
+
+ } break;
default:
break;
}
diff --git a/src/contactadapter.h b/src/contactadapter.h
index 09e67a8c..2ece5e91 100644
--- a/src/contactadapter.h
+++ b/src/contactadapter.h
@@ -95,4 +95,10 @@ private:
*/
std::unique_ptr smartListModel_;
std::unique_ptr selectableProxyModel_;
+
+ QStringList defaultModerators_;
+
+signals:
+ void defaultModeratorsUpdated();
+
};
diff --git a/src/mainview/components/AboutPopUp.qml b/src/mainview/components/AboutPopUp.qml
index 94c96de7..8b684d6b 100644
--- a/src/mainview/components/AboutPopUp.qml
+++ b/src/mainview/components/AboutPopUp.qml
@@ -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
diff --git a/src/mainview/components/CallAdvancedOptions.qml b/src/mainview/components/CallAdvancedOptions.qml
deleted file mode 100644
index d67f0361..00000000
--- a/src/mainview/components/CallAdvancedOptions.qml
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2020 by Savoir-faire Linux
- * Author: Sébastien Blin
- * Author: Mingrui Zhang
- *
- * 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 .
- */
-
-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"
- }
-}
diff --git a/src/mainview/components/CallOverlay.qml b/src/mainview/components/CallOverlay.qml
index 84dc5bd9..d5fe292e 100644
--- a/src/mainview/components/CallOverlay.qml
+++ b/src/mainview/components/CallOverlay.qml
@@ -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()
}
}
diff --git a/src/mainview/components/ContactPicker.qml b/src/mainview/components/ContactPicker.qml
index 9d767d07..3f9f2ce8 100644
--- a/src/mainview/components/ContactPicker.qml
+++ b/src/mainview/components/ContactPicker.qml
@@ -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 {
diff --git a/src/mainview/components/ParticipantOverlay.qml b/src/mainview/components/ParticipantOverlay.qml
index 04e987c4..f801d89d 100644
--- a/src/mainview/components/ParticipantOverlay.qml
+++ b/src/mainview/components/ParticipantOverlay.qml
@@ -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
diff --git a/src/mainview/components/ParticipantOverlayMenu.qml b/src/mainview/components/ParticipantOverlayMenu.qml
index 55818ff5..27099409 100644
--- a/src/mainview/components/ParticipantOverlayMenu.qml
+++ b/src/mainview/components/ParticipantOverlayMenu.qml
@@ -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 {
diff --git a/src/mainview/js/contactpickercreation.js b/src/mainview/js/contactpickercreation.js
index 7ce7b62e..6cbf70b6 100644
--- a/src/mainview/js/contactpickercreation.js
+++ b/src/mainview/js/contactpickercreation.js
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang
@@ -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})
}
}
diff --git a/src/mainview/js/mediahandlerpickercreation.js b/src/mainview/js/mediahandlerpickercreation.js
index 1a14eca2..b35346c0 100644
--- a/src/mainview/js/mediahandlerpickercreation.js
+++ b/src/mainview/js/mediahandlerpickercreation.js
@@ -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})
}
}
diff --git a/src/moderatorlistmodel.cpp b/src/moderatorlistmodel.cpp
new file mode 100644
index 00000000..41d13547
--- /dev/null
+++ b/src/moderatorlistmodel.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Albert Babí Oller
+ *
+ * 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 .
+ */
+
+#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
+ModeratorListModel::roleNames() const
+{
+ QHash 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();
+}
diff --git a/src/moderatorlistmodel.h b/src/moderatorlistmodel.h
new file mode 100644
index 00000000..060f376c
--- /dev/null
+++ b/src/moderatorlistmodel.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Albert Babí Oller
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include
+
+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 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();
+};
diff --git a/src/qmlregister.cpp b/src/qmlregister.cpp
index e1bea27c..73ad895d 100644
--- a/src/qmlregister.cpp
+++ b/src/qmlregister.cpp
@@ -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);
diff --git a/src/settingsadapter.cpp b/src/settingsadapter.cpp
index 8dbc9adc..b444653a 100644
--- a/src/settingsadapter.cpp
+++ b/src/settingsadapter.cpp
@@ -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);
+}
diff --git a/src/settingsadapter.h b/src/settingsadapter.h
index 53e1f156..cabf798c 100644
--- a/src/settingsadapter.h
+++ b/src/settingsadapter.h
@@ -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*)
diff --git a/src/settingsview/SettingsView.qml b/src/settingsview/SettingsView.qml
index 3369d5a4..87af87a0 100644
--- a/src/settingsview/SettingsView.qml
+++ b/src/settingsview/SettingsView.qml
@@ -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
diff --git a/src/settingsview/components/AdvancedCallSettings.qml b/src/settingsview/components/AdvancedCallSettings.qml
index d396227c..e389581b 100644
--- a/src/settingsview/components/AdvancedCallSettings.qml
+++ b/src/settingsview/components/AdvancedCallSettings.qml
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Aline Gondim Santos
+ * Author: Albert Babí Oller
*
* 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()
+ }
+ }
}
}
diff --git a/src/settingsview/components/BannedContacts.qml b/src/settingsview/components/BannedContacts.qml
index 26fa8bb0..2364f3dd 100644
--- a/src/settingsview/components/BannedContacts.qml
+++ b/src/settingsview/components/BannedContacts.qml
@@ -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)
}
}
}
diff --git a/src/settingsview/components/BannedItemDelegate.qml b/src/settingsview/components/ContactItemDelegate.qml
similarity index 89%
rename from src/settingsview/components/BannedItemDelegate.qml
rename to src/settingsview/components/ContactItemDelegate.qml
index d83e8894..029a764f 100644
--- a/src/settingsview/components/BannedItemDelegate.qml
+++ b/src/settingsview/components/ContactItemDelegate.qml
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2019-2020 by Savoir-faire Linux
- * Author: Yang Wang
+ * Author: Yang Wang
+ * Author: Albert Babí Oller
*
* 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()
}
}
}
diff --git a/src/settingsview/components/NameRegistrationDialog.qml b/src/settingsview/components/NameRegistrationDialog.qml
index d6ca3e17..9c39a075 100644
--- a/src/settingsview/components/NameRegistrationDialog.qml
+++ b/src/settingsview/components/NameRegistrationDialog.qml
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Yang Wang
- * Author: Albert Babí
+ * Author: Albert Babí
*
* 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