From a3554153d51e2e94919283eba8a22e4862dca512 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Sat, 7 May 2022 19:18:34 +0200 Subject: [PATCH] Add participants view in video conference, and admin mode. Fix ConferenceModel object synchronization. Use Me() and participantList to get local participant in ConferenceModel --- linphone-app/resources.qrc | 4 +- .../src/components/call/CallModel.cpp | 2 +- .../src/components/call/CallModel.hpp | 2 +- .../src/components/calls/CallsListModel.cpp | 2 + .../components/chat-room/ChatRoomModel.cpp | 18 +-- .../components/chat-room/ChatRoomModel.hpp | 20 +-- .../conference/ConferenceListener.cpp | 5 +- .../conference/ConferenceListener.hpp | 3 +- .../components/conference/ConferenceModel.cpp | 45 +++++- .../components/conference/ConferenceModel.hpp | 15 ++ .../ParticipantDeviceListModel.cpp | 4 +- .../participant/ParticipantListModel.cpp | 135 +++++++++++++--- .../participant/ParticipantListModel.hpp | 34 ++-- .../participant/ParticipantModel.cpp | 3 +- .../participant/ParticipantProxyModel.cpp | 37 ++++- .../participant/ParticipantProxyModel.hpp | 8 +- .../search/SearchSipAddressesProxyModel.cpp | 14 +- .../Styles/View/ParticipantsListViewStyle.qml | 88 +++++++++++ .../ui/modules/Linphone/Styles/qmldir | 4 +- .../Linphone/View/ParticipantsListView.qml | 147 ++++++++++++++++++ linphone-app/ui/modules/Linphone/qmldir | 3 +- .../ui/views/App/Calls/VideoConference.qml | 3 +- .../App/Calls/VideoConferenceFullscreen.qml | 3 +- .../views/App/Calls/VideoConferenceMenu.qml | 32 +++- .../Styles/Calls/VideoConferenceMenuStyle.qml | 1 + linphone-sdk | 2 +- 26 files changed, 550 insertions(+), 84 deletions(-) create mode 100644 linphone-app/ui/modules/Linphone/Styles/View/ParticipantsListViewStyle.qml create mode 100644 linphone-app/ui/modules/Linphone/View/ParticipantsListView.qml diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index 60600aa08..11eb802cd 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -381,13 +381,15 @@ ui/modules/Linphone/Styles/qmldir ui/modules/Linphone/Styles/TelKeypad/TelKeypadStyle.qml ui/modules/Linphone/Styles/Timeline/TimelineStyle.qml - ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml + ui/modules/Linphone/Styles/View/ParticipantsListViewStyle.qml ui/modules/Linphone/Styles/View/ParticipantsViewStyle.qml + ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml ui/modules/Linphone/TelKeypad/TelKeypadButton.qml ui/modules/Linphone/TelKeypad/TelKeypad.js ui/modules/Linphone/TelKeypad/TelKeypad.qml ui/modules/Linphone/Timeline/Timeline.js ui/modules/Linphone/Timeline/Timeline.qml + ui/modules/Linphone/View/ParticipantsListView.qml ui/modules/Linphone/View/ParticipantsView.qml ui/modules/Linphone/View/SipAddressesView.qml ui/scripts/LinphoneUtils/linphone-utils.js diff --git a/linphone-app/src/components/call/CallModel.cpp b/linphone-app/src/components/call/CallModel.cpp index f1d9640bb..17296d54d 100644 --- a/linphone-app/src/components/call/CallModel.cpp +++ b/linphone-app/src/components/call/CallModel.cpp @@ -161,7 +161,7 @@ ChatRoomModel * CallModel::getChatRoomModel() const{ } ConferenceModel * CallModel::getConferenceModel(){ - return getConferenceSharedModel().get(); + return mConferenceModel.get(); } QSharedPointer CallModel::getConferenceSharedModel(){ diff --git a/linphone-app/src/components/call/CallModel.hpp b/linphone-app/src/components/call/CallModel.hpp index aae73dcc9..bfb571d05 100644 --- a/linphone-app/src/components/call/CallModel.hpp +++ b/linphone-app/src/components/call/CallModel.hpp @@ -121,7 +121,7 @@ public: ContactModel *getContactModel() const; ChatRoomModel * getChatRoomModel() const; - Q_INVOKABLE ConferenceModel* getConferenceModel(); + ConferenceModel* getConferenceModel(); QSharedPointer getConferenceSharedModel(); bool isInConference () const { diff --git a/linphone-app/src/components/calls/CallsListModel.cpp b/linphone-app/src/components/calls/CallsListModel.cpp index 6b634708d..a15cdffd2 100644 --- a/linphone-app/src/components/calls/CallsListModel.cpp +++ b/linphone-app/src/components/calls/CallsListModel.cpp @@ -323,6 +323,8 @@ QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& se } if( address) chatRoomParticipants.push_back( address ); + else + qWarning() << "Failed to add participant to conference, bad address : " << (participant ? participant->getSipAddress() : p.toString()); } params->enableEncryption(securityLevel>0); diff --git a/linphone-app/src/components/chat-room/ChatRoomModel.cpp b/linphone-app/src/components/chat-room/ChatRoomModel.cpp index c471b2d79..e87169efd 100644 --- a/linphone-app/src/components/chat-room/ChatRoomModel.cpp +++ b/linphone-app/src/components/chat-room/ChatRoomModel.cpp @@ -1189,7 +1189,7 @@ void ChatRoomModel::onParticipantAdded(const std::shared_ptr if( e != events.end() ) insertNotice(*e); updateLastUpdateTime(); - emit participantAdded(chatRoom, eventLog); + emit participantAdded(eventLog); emit fullPeerAddressChanged(); } @@ -1199,7 +1199,7 @@ void ChatRoomModel::onParticipantRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ updateLastUpdateTime(); - emit participantDeviceAdded(chatRoom, eventLog); + emit participantDeviceAdded(eventLog); } void ChatRoomModel::onParticipantDeviceRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ updateLastUpdateTime(); - emit participantDeviceRemoved(chatRoom, eventLog); + emit participantDeviceRemoved(eventLog); } void ChatRoomModel::onConferenceJoined(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ @@ -1264,7 +1264,7 @@ void ChatRoomModel::onConferenceJoined(const std::shared_ptr setUnreadMessagesCount(mChatRoom->getUnreadMessagesCount()); // Update message count. In the case of joining conference, the conference id was not valid thus, the missing count was not about the chat room but a global one. updateLastUpdateTime(); emit usernameChanged(); - emit conferenceJoined(chatRoom, eventLog); + emit conferenceJoined(eventLog); emit isReadOnlyChanged(); } @@ -1281,7 +1281,7 @@ void ChatRoomModel::onConferenceLeft(const std::shared_ptr & insertNotice(*e); } updateLastUpdateTime(); - emit conferenceLeft(chatRoom, eventLog); + emit conferenceLeft(eventLog); emit isReadOnlyChanged(); } } @@ -1308,11 +1308,11 @@ void ChatRoomModel::onConferenceAddressGeneration(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress){ updateLastUpdateTime(); - emit participantRegistrationSubscriptionRequested(chatRoom, participantAddress); + emit participantRegistrationSubscriptionRequested(participantAddress); } void ChatRoomModel::onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress){ - emit participantRegistrationUnsubscriptionRequested(chatRoom, participantAddress); + emit participantRegistrationUnsubscriptionRequested(participantAddress); } void ChatRoomModel::onChatMessageShouldBeStored(const std::shared_ptr & chatRoom, const std::shared_ptr & message){ diff --git a/linphone-app/src/components/chat-room/ChatRoomModel.hpp b/linphone-app/src/components/chat-room/ChatRoomModel.hpp index 886ad5fb6..44c40af02 100644 --- a/linphone-app/src/components/chat-room/ChatRoomModel.hpp +++ b/linphone-app/src/components/chat-room/ChatRoomModel.hpp @@ -266,16 +266,16 @@ signals: // Chat Room listener callbacks - void securityEvent(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void participantAdded(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void participantRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void participantDeviceAdded(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void participantDeviceRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void participantAdminStatusChanged(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void participantRegistrationSubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress); - void participantRegistrationUnsubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress); - void conferenceJoined(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void conferenceLeft(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); + void securityEvent(const std::shared_ptr & eventLog); + void participantAdded(const std::shared_ptr & eventLog); + void participantRemoved(const std::shared_ptr & eventLog); + void participantDeviceAdded(const std::shared_ptr & eventLog); + void participantDeviceRemoved(const std::shared_ptr & eventLog); + void participantAdminStatusChanged(const std::shared_ptr & eventLog); + void participantRegistrationSubscriptionRequested(const std::shared_ptr & participantAddress); + void participantRegistrationUnsubscriptionRequested(const std::shared_ptr & participantAddress); + void conferenceJoined(const std::shared_ptr & eventLog); + void conferenceLeft(const std::shared_ptr & eventLog); private: diff --git a/linphone-app/src/components/conference/ConferenceListener.cpp b/linphone-app/src/components/conference/ConferenceListener.cpp index a0f7ea22d..21b8a28c8 100644 --- a/linphone-app/src/components/conference/ConferenceListener.cpp +++ b/linphone-app/src/components/conference/ConferenceListener.cpp @@ -42,7 +42,7 @@ ConferenceListener::~ConferenceListener(){ // LINPHONE LISTENERS //----------------------------------------------------------------------------------------------------------------------- void ConferenceListener::onParticipantAdded(const std::shared_ptr & conference, const std::shared_ptr & participant){ - qDebug() << "onParticipantAdded"; + qDebug() << "onParticipantAdded: " << participant->getAddress()->asString().c_str(); emit participantAdded(participant); } void ConferenceListener::onParticipantRemoved(const std::shared_ptr & conference, const std::shared_ptr & participant){ @@ -61,6 +61,7 @@ void ConferenceListener::onParticipantDeviceRemoved(const std::shared_ptr & conference, const std::shared_ptr & participant){ qDebug() << "onParticipantAdminStatusChanged"; + emit participantAdminStatusChanged(participant); } void ConferenceListener::onParticipantDeviceLeft(const std::shared_ptr & conference, const std::shared_ptr & participantDevice){ qDebug() << "onParticipantDeviceLeft"; @@ -97,4 +98,4 @@ void ConferenceListener::onAudioDeviceChanged(const std::shared_ptr & conference, const std::shared_ptr & participant) override; virtual void onParticipantRemoved(const std::shared_ptr & conference, const std::shared_ptr & participant) override; + virtual void onParticipantAdminStatusChanged(const std::shared_ptr & conference, const std::shared_ptr & participant) override; virtual void onParticipantDeviceAdded(const std::shared_ptr & conference, const std::shared_ptr & participantDevice) override; virtual void onParticipantDeviceRemoved(const std::shared_ptr & conference, const std::shared_ptr & participantDevice) override; - virtual void onParticipantAdminStatusChanged(const std::shared_ptr & conference, const std::shared_ptr & participant) override; virtual void onParticipantDeviceLeft(const std::shared_ptr & conference, const std::shared_ptr & device) override; virtual void onParticipantDeviceJoined(const std::shared_ptr & conference, const std::shared_ptr & device) override; virtual void onParticipantDeviceMediaCapabilityChanged(const std::shared_ptr & conference, const std::shared_ptr & device) override; @@ -53,6 +53,7 @@ public: signals: void participantAdded(const std::shared_ptr & participant); void participantRemoved(const std::shared_ptr & participant); + void participantAdminStatusChanged(const std::shared_ptr & participant); void participantDeviceAdded(const std::shared_ptr & participantDevice); void participantDeviceRemoved(const std::shared_ptr & participantDevice); void participantDeviceLeft(const std::shared_ptr & participantDevice); diff --git a/linphone-app/src/components/conference/ConferenceModel.cpp b/linphone-app/src/components/conference/ConferenceModel.cpp index a18477515..db5043b88 100644 --- a/linphone-app/src/components/conference/ConferenceModel.cpp +++ b/linphone-app/src/components/conference/ConferenceModel.cpp @@ -39,6 +39,7 @@ void ConferenceModel::connectTo(ConferenceListener * listener){ connect(listener, &ConferenceListener::participantAdded, this, &ConferenceModel::onParticipantAdded); connect(listener, &ConferenceListener::participantRemoved, this, &ConferenceModel::onParticipantRemoved); + connect(listener, &ConferenceListener::participantAdminStatusChanged, this, &ConferenceModel::onParticipantAdminStatusChanged); connect(listener, &ConferenceListener::participantDeviceAdded, this, &ConferenceModel::onParticipantDeviceAdded); connect(listener, &ConferenceListener::participantDeviceRemoved, this, &ConferenceModel::onParticipantDeviceRemoved); connect(listener, &ConferenceListener::participantDeviceLeft, this, &ConferenceModel::onParticipantDeviceLeft); @@ -59,6 +60,8 @@ QSharedPointer ConferenceModel::create(std::shared_ptr conference, QObject *parent) : QObject(parent) { App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE mConference = conference; + //updateLocalParticipant(); + mParticipantListModel = QSharedPointer::create(this); mConferenceListener = std::make_shared(); connectTo(mConferenceListener.get()); mConference->addListener(mConferenceListener); @@ -68,6 +71,21 @@ ConferenceModel::~ConferenceModel(){ mConference->removeListener(mConferenceListener); } +bool ConferenceModel::updateLocalParticipant(){ + bool changed = false; + // First try to use findParticipant + auto localParticipant = mConference->findParticipant(mConference->getCall()->getCallLog()->getLocalAddress()); + // Me is not in participants, use Me(). + if( !localParticipant) + localParticipant = mConference->getMe(); + if( localParticipant){ + mLocalParticipant = QSharedPointer::create(localParticipant); + qWarning() << "Is Admin: " << localParticipant->isAdmin() << " " << mLocalParticipant->getAdminStatus(); + changed = true; + } + return changed; +} + std::shared_ptr ConferenceModel::getConference()const{ return mConference; } @@ -84,17 +102,40 @@ qint64 ConferenceModel::getElapsedSeconds() const { return getStartDate().secsTo(QDateTime::currentDateTime()); } +ParticipantModel* ConferenceModel::getLocalParticipant() const{ + if( mLocalParticipant) { + qWarning() << "LocalParticipant admin : " << mLocalParticipant->getAdminStatus() << " " << (mLocalParticipant->getParticipant() ? mLocalParticipant->getParticipant()->isAdmin() : -1); + }else + qWarning() << "NULL"; + return mLocalParticipant.get(); +} + +ParticipantListModel* ConferenceModel::getParticipants() const{ + return mParticipantListModel.get(); +} + //----------------------------------------------------------------------------------------------------------------------- // LINPHONE LISTENERS //----------------------------------------------------------------------------------------------------------------------- void ConferenceModel::onParticipantAdded(const std::shared_ptr & participant){ - qDebug() << "Me devices : " << mConference->getMe()->getDevices().size(); + qDebug() << "Added call, participant count: " << mConference->getParticipantList().size(); + if(!mLocalParticipant){ + if(updateLocalParticipant()) + emit localParticipantChanged(); + } emit participantAdded(participant); } void ConferenceModel::onParticipantRemoved(const std::shared_ptr & participant){ qDebug() << "Me devices : " << mConference->getMe()->getDevices().size(); emit participantRemoved(participant); } +void ConferenceModel::onParticipantAdminStatusChanged(const std::shared_ptr & participant){ + qWarning() << "onParticipantAdminStatusChanged: " << participant->getAddress()->asString().c_str(); + if(participant == mLocalParticipant->getParticipant()) + emit mLocalParticipant->adminStatusChanged(); + emit participantAdminStatusChanged(participant); +} + void ConferenceModel::onParticipantDeviceAdded(const std::shared_ptr & participantDevice){ qDebug() << "Me devices : " << mConference->getMe()->getDevices().size(); emit participantDeviceAdded(participantDevice); @@ -130,4 +171,4 @@ void ConferenceModel::onSubjectChanged(const std::string& string){ } -//----------------------------------------------------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------------------------------------------------- diff --git a/linphone-app/src/components/conference/ConferenceModel.hpp b/linphone-app/src/components/conference/ConferenceModel.hpp index 51bc4b4dc..269d7d704 100644 --- a/linphone-app/src/components/conference/ConferenceModel.hpp +++ b/linphone-app/src/components/conference/ConferenceModel.hpp @@ -28,7 +28,10 @@ #include #include +#include "components/participant/ParticipantModel.hpp" + class ConferenceListener; +class ParticipantListModel; class ConferenceModel : public QObject{ Q_OBJECT @@ -36,19 +39,26 @@ public: Q_PROPERTY(QString subject READ getSubject NOTIFY subjectChanged) Q_PROPERTY(QDateTime startDate READ getStartDate CONSTANT) + Q_PROPERTY(ParticipantListModel* participants READ getParticipants CONSTANT) + Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged) + static QSharedPointer create(std::shared_ptr chatRoom, QObject *parent = Q_NULLPTR); ConferenceModel(std::shared_ptr content, QObject *parent = Q_NULLPTR); virtual ~ConferenceModel(); + bool updateLocalParticipant(); // true if changed std::shared_ptr getConference()const; QString getSubject() const; QDateTime getStartDate() const; Q_INVOKABLE qint64 getElapsedSeconds() const; + Q_INVOKABLE ParticipantModel* getLocalParticipant() const; + ParticipantListModel* getParticipants() const; virtual void onParticipantAdded(const std::shared_ptr & participant); virtual void onParticipantRemoved(const std::shared_ptr & participant); + virtual void onParticipantAdminStatusChanged(const std::shared_ptr & participant); virtual void onParticipantDeviceAdded(const std::shared_ptr & participantDevice); virtual void onParticipantDeviceRemoved(const std::shared_ptr & participantDevice); virtual void onParticipantDeviceLeft(const std::shared_ptr & device); @@ -61,8 +71,10 @@ public: //--------------------------------------------------------------------------- signals: + void localParticipantChanged(); void participantAdded(const std::shared_ptr & participant); void participantRemoved(const std::shared_ptr & participant); + void participantAdminStatusChanged(const std::shared_ptr & participant); void participantDeviceAdded(const std::shared_ptr & participantDevice); void participantDeviceRemoved(const std::shared_ptr & participantDevice); void participantDeviceLeft(const std::shared_ptr & participantDevice); @@ -78,6 +90,9 @@ private: std::shared_ptr mConference; std::shared_ptr mConferenceListener; + + QSharedPointer mLocalParticipant; + QSharedPointer mParticipantListModel; }; Q_DECLARE_METATYPE(QSharedPointer) diff --git a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp index 2d374437f..16816bbb9 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp @@ -176,7 +176,7 @@ QSharedPointer ParticipantDeviceListModel::get(std::shar bool ParticipantDeviceListModel::isMe(std::shared_ptr deviceToCheck)const{ if(mCallModel){ - auto devices = mCallModel->getConferenceModel()->getConference()->getMe()->getDevices(); + auto devices = mCallModel->getConferenceSharedModel()->getConference()->getMe()->getDevices(); auto deviceToCheckAddress = deviceToCheck->getAddress(); for(auto device : devices){ if(deviceToCheckAddress == device->getAddress()) @@ -328,4 +328,4 @@ void ParticipantDeviceListModel::onParticipantDeviceIsSpeakingChanged(const std: void ParticipantDeviceListModel::onParticipantDeviceSpeaking(){ emit participantSpeaking(qobject_cast(sender())); -} \ No newline at end of file +} diff --git a/linphone-app/src/components/participant/ParticipantListModel.cpp b/linphone-app/src/components/participant/ParticipantListModel.cpp index 38ea540ff..1800c299c 100644 --- a/linphone-app/src/components/participant/ParticipantListModel.cpp +++ b/linphone-app/src/components/participant/ParticipantListModel.cpp @@ -21,6 +21,7 @@ #include "components/core/CoreManager.hpp" #include "components/settings/AccountSettingsModel.hpp" #include "components/sip-addresses/SipAddressesModel.hpp" +#include "components/conference/ConferenceModel.hpp" #include "utils/Utils.hpp" #include "ParticipantListModel.hpp" @@ -39,21 +40,42 @@ ParticipantListModel::ParticipantListModel (ChatRoomModel * chatRoomModel, QObje connect(mChatRoomModel, &ChatRoomModel::conferenceJoined, this, &ParticipantListModel::onConferenceJoined); - connect(mChatRoomModel, &ChatRoomModel::participantAdded, this, &ParticipantListModel::onParticipantAdded); - connect(mChatRoomModel, &ChatRoomModel::participantRemoved, this, &ParticipantListModel::onParticipantRemoved); + connect(mChatRoomModel, &ChatRoomModel::participantAdded, this, QOverload &>::of(&ParticipantListModel::onParticipantAdded)); + connect(mChatRoomModel, &ChatRoomModel::participantRemoved, this, QOverload &>::of(&ParticipantListModel::onParticipantRemoved)); + connect(mChatRoomModel, &ChatRoomModel::participantAdminStatusChanged, this, QOverload &>::of(&ParticipantListModel::onParticipantAdminStatusChanged)); + connect(mChatRoomModel, &ChatRoomModel::participantDeviceAdded, this, &ParticipantListModel::onParticipantDeviceAdded); connect(mChatRoomModel, &ChatRoomModel::participantDeviceRemoved, this, &ParticipantListModel::onParticipantDeviceRemoved); - connect(mChatRoomModel, &ChatRoomModel::participantAdminStatusChanged, this, &ParticipantListModel::onParticipantAdminStatusChanged); + connect(mChatRoomModel, &ChatRoomModel::participantRegistrationSubscriptionRequested, this, &ParticipantListModel::onParticipantRegistrationSubscriptionRequested); connect(mChatRoomModel, &ChatRoomModel::participantRegistrationUnsubscriptionRequested, this, &ParticipantListModel::onParticipantRegistrationUnsubscriptionRequested); updateParticipants(); } } + +ParticipantListModel::ParticipantListModel (ConferenceModel * conferenceModel, QObject *parent) : ProxyListModel(parent) { + if( conferenceModel) { + mConferenceModel = conferenceModel;//CoreManager::getInstance()->getChatRoomModel(chatRoomModel); + + connect(mConferenceModel, &ConferenceModel::participantAdded, this, QOverload &>::of(&ParticipantListModel::onParticipantAdded)); + connect(mConferenceModel, &ConferenceModel::participantRemoved, this, QOverload &>::of(&ParticipantListModel::onParticipantRemoved)); + connect(mConferenceModel, &ConferenceModel::participantAdminStatusChanged, this, QOverload &>::of(&ParticipantListModel::onParticipantAdminStatusChanged)); + + //connect(mConferenceModel, &ConferenceModel::participantDeviceAdded, this, &ParticipantListModel::onParticipantDeviceAdded); + //connect(mConferenceModel, &ConferenceModel::participantDeviceRemoved, this, &ParticipantListModel::onParticipantDeviceRemoved); + + + updateParticipants(); + } +} + + ParticipantListModel::~ParticipantListModel(){ mList.clear(); mChatRoomModel = nullptr; + mConferenceModel = nullptr; } // ----------------------------------------------------------------------------- @@ -62,6 +84,10 @@ ChatRoomModel *ParticipantListModel::getChatRoomModel() const{ return mChatRoomModel; } +ConferenceModel *ParticipantListModel::getConferenceModel() const{ + return mConferenceModel; +} + std::list> ParticipantListModel::getParticipants()const{ std::list> participants; for(auto participant : mList){ @@ -119,11 +145,16 @@ bool ParticipantListModel::contains(const QString& address) const{ // ----------------------------------------------------------------------------- void ParticipantListModel::updateParticipants () { - if( mChatRoomModel) { + if( mChatRoomModel || mConferenceModel) { bool changed = false; - auto dbParticipants = mChatRoomModel->getChatRoom()->getParticipants(); - auto me = mChatRoomModel->getChatRoom()->getMe(); - dbParticipants.push_front(me); + auto dbParticipants = (mChatRoomModel ? mChatRoomModel->getChatRoom()->getParticipants() : mConferenceModel->getConference()->getParticipantList()); + std::shared_ptr me; + if( mChatRoomModel ) + me = mChatRoomModel->getChatRoom()->getMe(); + else if( mConferenceModel->getLocalParticipant()) + me = mConferenceModel->getLocalParticipant()->getParticipant(); + if(me) + dbParticipants.push_front(me); //Remove left participants //for(auto participant : mList){ @@ -186,6 +217,16 @@ void ParticipantListModel::add (QSharedPointer participant){ emit participantsChanged(); } +void ParticipantListModel::add(const std::shared_ptr & participant){ + auto unconstParticipant = (mChatRoomModel ? mChatRoomModel->getChatRoom()->findParticipant(participant->getAddress()) : mConferenceModel->getConference()->findParticipant(participant->getAddress())); + if( unconstParticipant) + add(QSharedPointer::create(unconstParticipant)); +} + +void ParticipantListModel::add(const std::shared_ptr & participantAddress){ + add((mChatRoomModel ? mChatRoomModel->getChatRoom()->findParticipant(participantAddress) : mConferenceModel->getConference()->findParticipant(participantAddress))); +} + void ParticipantListModel::remove (ParticipantModel *model) { QString address = model->getSipAddress(); int index = 0; @@ -217,15 +258,30 @@ const QSharedPointer ParticipantListModel::getParticipant(cons }else return nullptr; } +const QSharedPointer ParticipantListModel::getParticipant(const std::shared_ptr& pParticipant) const{ + if(pParticipant){ + auto itParticipant = std::find_if(mList.begin(), mList.end(), [pParticipant] (const QSharedPointer& participant){ + return participant.objectCast()->getParticipant() == pParticipant; + }); + if( itParticipant == mList.end()) + return nullptr; + else + return itParticipant->objectCast(); + }else + return nullptr; +} //------------------------------------------------------------- void ParticipantListModel::setAdminStatus(const std::shared_ptr participant, const bool& isAdmin){ - mChatRoomModel->getChatRoom()->setParticipantAdminStatus(participant, isAdmin); + if(mChatRoomModel) + mChatRoomModel->getChatRoom()->setParticipantAdminStatus(participant, isAdmin); + if(mConferenceModel) + mConferenceModel->getConference()->setParticipantAdminStatus(participant, isAdmin); } -void ParticipantListModel::onSecurityEvent(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog) { +void ParticipantListModel::onSecurityEvent(const std::shared_ptr & eventLog) { auto address = eventLog->getParticipantAddress(); if(address) { auto participant = getParticipant(address); @@ -240,37 +296,66 @@ void ParticipantListModel::onSecurityEvent(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ - updateParticipants(); -} -void ParticipantListModel::onParticipantAdded(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ +void ParticipantListModel::onConferenceJoined(){ updateParticipants(); } -void ParticipantListModel::onParticipantRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ - updateParticipants(); +void ParticipantListModel::onParticipantAdded(const std::shared_ptr & eventLog){ + qWarning() << "onParticipantAdded event: " << eventLog->getParticipantAddress()->asString().c_str(); + add(eventLog->getParticipantAddress()); } -void ParticipantListModel::onParticipantAdminStatusChanged(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ - - auto participant = getParticipant(eventLog->getParticipantAddress()); - if( participant){ - emit participant->adminStatusChanged();// Request to participant to update its status from its data - } +void ParticipantListModel::onParticipantAdded(const std::shared_ptr & participant){ + qWarning() << "onParticipantAdded part: " << participant->getAddress()->asString().c_str(); + add(participant); } -void ParticipantListModel::onParticipantDeviceAdded(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ + +void ParticipantListModel::onParticipantAdded(const std::shared_ptr& address){ + qWarning() << "onParticipantAdded addr: " << address->asString().c_str(); + add(address); +} + +void ParticipantListModel::onParticipantRemoved(const std::shared_ptr & eventLog){ + onParticipantRemoved(eventLog->getParticipantAddress()); +} + +void ParticipantListModel::onParticipantRemoved(const std::shared_ptr & participant){ + auto p = getParticipant(participant); + if(p) + remove(p.get()); +} + +void ParticipantListModel::onParticipantRemoved(const std::shared_ptr& address){ + auto participant = getParticipant(address); + if(participant) + remove(participant.get()); +} + + +void ParticipantListModel::onParticipantAdminStatusChanged(const std::shared_ptr & eventLog){ + onParticipantAdminStatusChanged(eventLog->getParticipantAddress()); +} +void ParticipantListModel::onParticipantAdminStatusChanged(const std::shared_ptr & participant){ + auto p = getParticipant(participant); + if( participant) emit p->adminStatusChanged();// Request to participant to update its status from its data +} +void ParticipantListModel::onParticipantAdminStatusChanged(const std::shared_ptr& address ){ + auto participant = getParticipant(address); + if( participant) emit participant->adminStatusChanged();// Request to participant to update its status from its data +} +void ParticipantListModel::onParticipantDeviceAdded(const std::shared_ptr & eventLog){ auto participant = getParticipant(eventLog->getParticipantAddress()); if( participant){ emit participant->deviceCountChanged(); } } -void ParticipantListModel::onParticipantDeviceRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog){ +void ParticipantListModel::onParticipantDeviceRemoved(const std::shared_ptr & eventLog){ auto participant = getParticipant(eventLog->getParticipantAddress()); if( participant){ emit participant->deviceCountChanged(); } } -void ParticipantListModel::onParticipantRegistrationSubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress){ +void ParticipantListModel::onParticipantRegistrationSubscriptionRequested(const std::shared_ptr & participantAddress){ } -void ParticipantListModel::onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress){ +void ParticipantListModel::onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr & participantAddress){ } diff --git a/linphone-app/src/components/participant/ParticipantListModel.hpp b/linphone-app/src/components/participant/ParticipantListModel.hpp index 287b3e79f..efe0d89e0 100644 --- a/linphone-app/src/components/participant/ParticipantListModel.hpp +++ b/linphone-app/src/components/participant/ParticipantListModel.hpp @@ -26,12 +26,15 @@ #include "components/chat-room/ChatRoomModel.hpp" #include "app/proxyModel/ProxyListModel.hpp" +class ConferenceModel; + // ============================================================================= class ParticipantListModel : public ProxyListModel { Q_OBJECT public: ParticipantListModel (ChatRoomModel * chatRoomModel, QObject *parent = Q_NULLPTR); + ParticipantListModel (ConferenceModel * conferenceModel, QObject *parent = Q_NULLPTR); virtual ~ParticipantListModel(); Q_PROPERTY(ChatRoomModel* chatRoomModel READ getChatRoomModel CONSTANT) @@ -43,12 +46,16 @@ public: void update(); void selectAll(const bool& selected); const QSharedPointer getParticipant(const std::shared_ptr& address) const; + const QSharedPointer getParticipant(const std::shared_ptr& participant) const; void add (QSharedPointer participant); + void add(const std::shared_ptr & participant); + void add(const std::shared_ptr & participantAddress); void updateParticipants(); // Update list from Chat Room // Remove a chatroom Q_INVOKABLE void remove (ParticipantModel *importer); Q_INVOKABLE ChatRoomModel* getChatRoomModel() const; + Q_INVOKABLE ConferenceModel* getConferenceModel() const; std::list> getParticipants()const; Q_INVOKABLE QString addressesToString()const; @@ -60,15 +67,21 @@ public: public slots: void setAdminStatus(const std::shared_ptr participant, const bool& isAdmin); - void onSecurityEvent(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onConferenceJoined(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onParticipantAdded(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onParticipantRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onParticipantAdminStatusChanged(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onParticipantDeviceAdded(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onParticipantDeviceRemoved(const std::shared_ptr & chatRoom, const std::shared_ptr & eventLog); - void onParticipantRegistrationSubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress); - void onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr & chatRoom, const std::shared_ptr & participantAddress); + void onSecurityEvent(const std::shared_ptr & eventLog); + void onConferenceJoined(); + void onParticipantAdded(const std::shared_ptr & participant); + void onParticipantAdded(const std::shared_ptr & eventLog); + void onParticipantAdded(const std::shared_ptr& address); + void onParticipantRemoved(const std::shared_ptr & participant); + void onParticipantRemoved(const std::shared_ptr & eventLog); + void onParticipantRemoved(const std::shared_ptr& address); + void onParticipantAdminStatusChanged(const std::shared_ptr & participant); + void onParticipantAdminStatusChanged(const std::shared_ptr & eventLog); + void onParticipantAdminStatusChanged(const std::shared_ptr& address ); + void onParticipantDeviceAdded(const std::shared_ptr & eventLog); + void onParticipantDeviceRemoved(const std::shared_ptr & eventLog); + void onParticipantRegistrationSubscriptionRequested(const std::shared_ptr & participantAddress); + void onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr & participantAddress); signals: void securityLevelChanged(); @@ -76,7 +89,8 @@ signals: void participantsChanged(); private: - ChatRoomModel* mChatRoomModel; + ChatRoomModel* mChatRoomModel = nullptr; + ConferenceModel *mConferenceModel = nullptr; }; Q_DECLARE_METATYPE(QSharedPointer); #endif // PARTICIPANT_LIST_MODEL_H_ diff --git a/linphone-app/src/components/participant/ParticipantModel.cpp b/linphone-app/src/components/participant/ParticipantModel.cpp index 9e35b7199..9a19730a5 100644 --- a/linphone-app/src/components/participant/ParticipantModel.cpp +++ b/linphone-app/src/components/participant/ParticipantModel.cpp @@ -65,7 +65,8 @@ bool ParticipantModel::getInviting() const{ } bool ParticipantModel::isMe() const{ - return CoreManager::getInstance()->getAccountSettingsModel()->getUsedSipAddress()->weakEqual(Utils::interpretUrl(getSipAddress())); + QString sipAddress = getSipAddress(); + return !sipAddress.isEmpty() ? CoreManager::getInstance()->getAccountSettingsModel()->getUsedSipAddress()->weakEqual(Utils::interpretUrl(sipAddress)) : false; } QString ParticipantModel::getSipAddress() const{ diff --git a/linphone-app/src/components/participant/ParticipantProxyModel.cpp b/linphone-app/src/components/participant/ParticipantProxyModel.cpp index 396c8435e..cc8b4949a 100644 --- a/linphone-app/src/components/participant/ParticipantProxyModel.cpp +++ b/linphone-app/src/components/participant/ParticipantProxyModel.cpp @@ -23,6 +23,7 @@ #include "components/core/CoreManager.hpp" #include "components/settings/AccountSettingsModel.hpp" #include "components/sip-addresses/SipAddressesModel.hpp" +#include "components/conference/ConferenceModel.hpp" #include "utils/Utils.hpp" #include "ParticipantListModel.hpp" @@ -36,7 +37,6 @@ // ----------------------------------------------------------------------------- ParticipantProxyModel::ParticipantProxyModel (QObject *parent) : QSortFilterProxyModel(parent) { - mChatRoomModel = nullptr; } // ----------------------------------------------------------------------------- @@ -45,6 +45,10 @@ ChatRoomModel *ParticipantProxyModel::getChatRoomModel() const{ return mChatRoomModel; } +ConferenceModel *ParticipantProxyModel::getConferenceModel() const{ + return mConferenceModel; +} + ParticipantListModel * ParticipantProxyModel::getParticipantListModel() const{ return qobject_cast(sourceModel()); } @@ -61,7 +65,7 @@ QVariantList ParticipantProxyModel::getParticipants() const{ QVariantList participants; ParticipantListModel * list = qobject_cast(sourceModel()); for(int i = 0 ; i < list->rowCount() ; ++i) - participants << QVariant::fromValue(list->getAt(i)); + participants << QVariant::fromValue(list->getAt(i).get()); return participants; } @@ -84,8 +88,8 @@ void ParticipantProxyModel::setChatRoomModel(ChatRoomModel * chatRoomModel){ emit participantListModelChanged(); for(int i = 0 ; i < participants->getCount() ; ++i) emit addressAdded(participants->getAt(i)->getSipAddress()); - }else { - setSourceModel(new ParticipantListModel(nullptr, this)); + }else if(!sourceModel()){ + setSourceModel(new ParticipantListModel((ChatRoomModel*)nullptr, this)); emit participantListModelChanged(); } sort(0); @@ -93,6 +97,24 @@ void ParticipantProxyModel::setChatRoomModel(ChatRoomModel * chatRoomModel){ } } +void ParticipantProxyModel::setConferenceModel(ConferenceModel * conferenceModel){ + if(!mConferenceModel || mConferenceModel != conferenceModel){ + mConferenceModel = conferenceModel; + if(mConferenceModel) { + auto participants = mConferenceModel->getParticipants(); + setSourceModel(participants); + emit participantListModelChanged(); + for(int i = 0 ; i < participants->getCount() ; ++i) + emit addressAdded(participants->getAt(i)->getSipAddress()); + }else if(!sourceModel()){ + setSourceModel(new ParticipantListModel((ConferenceModel*)nullptr, this)); + emit participantListModelChanged(); + } + sort(0); + emit conferenceModelChanged(); + } +} + void ParticipantProxyModel::setShowMe(const bool& show){ if(mShowMe != show){ mShowMe = show; @@ -120,8 +142,11 @@ void ParticipantProxyModel::addAddress(const QString& address){ void ParticipantProxyModel::removeModel(ParticipantModel * participant){ if(participant) { QString sipAddress = participant->getSipAddress(); - if(mChatRoomModel && mChatRoomModel->getChatRoom() && participant->getParticipant() ) - mChatRoomModel->getChatRoom()->removeParticipant(participant->getParticipant()); // Remove already added + auto dbParticipant = participant->getParticipant(); + if(mChatRoomModel && dbParticipant && mChatRoomModel->getChatRoom()) + mChatRoomModel->getChatRoom()->removeParticipant(dbParticipant); // Remove already added + if( mConferenceModel && dbParticipant && mConferenceModel->getConference()) + mConferenceModel->getConference()->removeParticipant(dbParticipant ); ParticipantListModel * participantsModel = qobject_cast(sourceModel()); participantsModel->remove(participant); emit countChanged(); diff --git a/linphone-app/src/components/participant/ParticipantProxyModel.hpp b/linphone-app/src/components/participant/ParticipantProxyModel.hpp index 6830a7a6d..bb176cc4a 100644 --- a/linphone-app/src/components/participant/ParticipantProxyModel.hpp +++ b/linphone-app/src/components/participant/ParticipantProxyModel.hpp @@ -27,6 +27,7 @@ class ParticipantModel; class ChatRoomModel; class ParticipantListModel; +class ConferenceModel; // ============================================================================= class QWindow; @@ -40,6 +41,7 @@ public: ParticipantProxyModel ( QObject *parent = Q_NULLPTR); Q_PROPERTY(ChatRoomModel* chatRoomModel READ getChatRoomModel WRITE setChatRoomModel NOTIFY chatRoomModelChanged) + Q_PROPERTY(ConferenceModel* conferenceModel READ getConferenceModel WRITE setConferenceModel NOTIFY conferenceModelChanged) Q_PROPERTY(ParticipantListModel * participantListModel READ getParticipantListModel NOTIFY participantListModelChanged) Q_PROPERTY(int count READ getCount NOTIFY countChanged) Q_PROPERTY(bool showMe READ getShowMe WRITE setShowMe NOTIFY showMeChanged) @@ -48,6 +50,7 @@ public: bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; ChatRoomModel *getChatRoomModel() const; + ConferenceModel *getConferenceModel() const; ParticipantListModel * getParticipantListModel() const; Q_INVOKABLE QStringList getSipAddresses() const; Q_INVOKABLE QVariantList getParticipants() const; @@ -55,6 +58,7 @@ public: bool getShowMe() const; void setChatRoomModel(ChatRoomModel * chatRoomModel); + void setConferenceModel(ConferenceModel * conferenceModel); void setShowMe(const bool& show); Q_INVOKABLE void addAddress(const QString& address); @@ -64,6 +68,7 @@ public: signals: void chatRoomModelChanged(); + void conferenceModelChanged(); void participantListModelChanged(); void countChanged(); void showMeChanged(); @@ -71,7 +76,8 @@ signals: void addressRemoved(QString sipAddress); private: - ChatRoomModel *mChatRoomModel; + ChatRoomModel *mChatRoomModel = nullptr; + ConferenceModel *mConferenceModel = nullptr; bool mShowMe = true; }; diff --git a/linphone-app/src/components/search/SearchSipAddressesProxyModel.cpp b/linphone-app/src/components/search/SearchSipAddressesProxyModel.cpp index 5bb1d6cd6..66d8acd4d 100644 --- a/linphone-app/src/components/search/SearchSipAddressesProxyModel.cpp +++ b/linphone-app/src/components/search/SearchSipAddressesProxyModel.cpp @@ -52,20 +52,24 @@ void SearchSipAddressesProxyModel::setFilter (const QString &pattern){ void SearchSipAddressesProxyModel::addAddressToIgnore(const QString& address){ std::shared_ptr a = Utils::interpretUrl(address); - mResultsToIgnore[Utils::coreStringToAppString(a->asStringUriOnly())] = true; - invalidate(); + if(a) { + mResultsToIgnore[Utils::coreStringToAppString(a->asStringUriOnly())] = true; + invalidate(); + } } void SearchSipAddressesProxyModel::removeAddressToIgnore(const QString& address){ std::shared_ptr a = Utils::interpretUrl(address); - mResultsToIgnore.remove(Utils::coreStringToAppString(a->asStringUriOnly())); - invalidate(); + if( a){ + mResultsToIgnore.remove(Utils::coreStringToAppString(a->asStringUriOnly())); + invalidate(); + } } bool SearchSipAddressesProxyModel::isIgnored(const QString& address) const{ if(address != ""){ std::shared_ptr a = Utils::interpretUrl(address); - return mResultsToIgnore.contains(Utils::coreStringToAppString(a->asStringUriOnly())); + return a ? mResultsToIgnore.contains(Utils::coreStringToAppString(a->asStringUriOnly())) : false; } return false; } diff --git a/linphone-app/ui/modules/Linphone/Styles/View/ParticipantsListViewStyle.qml b/linphone-app/ui/modules/Linphone/Styles/View/ParticipantsListViewStyle.qml new file mode 100644 index 000000000..e104e3352 --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Styles/View/ParticipantsListViewStyle.qml @@ -0,0 +1,88 @@ +pragma Singleton +import QtQml 2.2 +import QtQuick 2.7 + +import Units 1.0 +import ColorsList 1.0 + +// ============================================================================= +QtObject { + property string sectionName: 'ParticipantsListView' + property int height: 500 + property int width: 450 + + property QtObject mainLayout: QtObject { + property int topMargin: 15 + property int leftMargin: 25 + property int rightMargin: 25 + property int spacing: 7 + } + + property QtObject searchBar : QtObject{ + property int topMargin : 10 + } + + property QtObject results : QtObject{ + property int topMargin : 10 + property color color : ColorsList.add(sectionName+'_results', 'g').color + property QtObject title : QtObject{ + property int topMargin: 10 + property int leftMargin: 20 + property color color: ColorsList.add(sectionName+'_results_title', 'j').color + property int pointSize : Units.dp * 11 + property int weight : Font.DemiBold + } + property QtObject header: QtObject{ + property int rightMargin: 55 + property color color: Colors.t.color + property int weight : Font.Light + property int pointSize : Units.dp * 10 + + } + } + + property QtObject leaveButton : + QtObject { + property QtObject backgroundColor: QtObject { + property color disabled: ColorsList.add(sectionName+'_leave_bg_d', 'o').color + property color hovered: ColorsList.add(sectionName+'_leave_bg_h', 'j').color + property color normal: ColorsList.add(sectionName+'_leave_bg_n', 'k').color + property color pressed: ColorsList.add(sectionName+'_leave_bg_p', 'i').color + } + + property QtObject textColor: QtObject { + property color disabled: ColorsList.add(sectionName+'_leave_text_d', 'q').color + property color hovered: ColorsList.add(sectionName+'_leave_text_h', 'q').color + property color normal: ColorsList.add(sectionName+'_leave_text_n', 'i').color + property color pressed: ColorsList.add(sectionName+'_leave_text_p', 'q').color + } + property QtObject borderColor : QtObject{ + property color disabled: ColorsList.add(sectionName+'_leave_border_d', 'q').color + property color hovered: ColorsList.add(sectionName+'_leave_border_h', 'q').color + property color normal: ColorsList.add(sectionName+'_leave_border_n', 'i').color + property color pressed: ColorsList.add(sectionName+'_leave_border_p', 'q').color + } + } + property QtObject addParticipant: QtObject { + property int iconSize: 30 + property string name : 'addParticipant' + property string icon : 'add_participant_custom' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'l_n_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'l_h_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'l_p_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'l_n_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'l_h_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'l_p_b_fg').color + } + property QtObject removeParticipant: QtObject { + property int iconSize: 30 + property string name : 'removeParticipant' + property string icon : 'remove_participant_custom' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'l_n_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'l_h_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'l_p_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'l_n_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'l_h_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'l_p_b_fg').color + } +} diff --git a/linphone-app/ui/modules/Linphone/Styles/qmldir b/linphone-app/ui/modules/Linphone/Styles/qmldir index 929a90265..8697c1dfe 100644 --- a/linphone-app/ui/modules/Linphone/Styles/qmldir +++ b/linphone-app/ui/modules/Linphone/Styles/qmldir @@ -51,5 +51,7 @@ singleton TelKeypadStyle 1.0 TelKeypad/TelKeypadStyle.qml singleton TimelineStyle 1.0 Timeline/TimelineStyle.qml -singleton SipAddressesViewStyle 1.0 View/SipAddressesViewStyle.qml +singleton ParticipantsListViewStyle 1.0 View/ParticipantsListViewStyle.qml singleton ParticipantsViewStyle 1.0 View/ParticipantsViewStyle.qml +singleton SipAddressesViewStyle 1.0 View/SipAddressesViewStyle.qml + diff --git a/linphone-app/ui/modules/Linphone/View/ParticipantsListView.qml b/linphone-app/ui/modules/Linphone/View/ParticipantsListView.qml new file mode 100644 index 000000000..93d064e13 --- /dev/null +++ b/linphone-app/ui/modules/Linphone/View/ParticipantsListView.qml @@ -0,0 +1,147 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +import Common 1.0 +import Linphone 1.0 +//import LinphoneUtils 1.0 +import LinphoneEnums 1.0 + +import App.Styles 1.0 +import Common.Styles 1.0 +import Linphone.Styles 1.0 +import Units 1.0 +import UtilsCpp 1.0 + + +// ============================================================================= + +ColumnLayout { + id:mainLayout + property ChatRoomModel chatRoomModel + property ConferenceModel conferenceModel + + property ParticipantModel me: conferenceModel && conferenceModel.localParticipant + + property bool isAdmin : (chatRoomModel && chatRoomModel.isMeAdmin && !chatRoomModel.isReadOnly) || (me && me.adminStatus) + property bool canHandleParticipants : isAdmin && ( (chatRoomModel && chatRoomModel.canHandleParticipants) || conferenceModel) + property bool haveEncryption: chatRoomModel && chatRoomModel.haveEncryption + onIsAdminChanged: console.log("participantsListView is admin : "+isAdmin) + onCanHandleParticipantsChanged: console.log("CanHandleParticipants:"+canHandleParticipants) + spacing: ParticipantsListViewStyle.mainLayout.spacing + Component.onCompleted: console.log("participantsListView : " +isAdmin +", "+canHandleParticipants +", " +chatRoomModel+", "+conferenceModel + ", "+conferenceModel.localParticipant +", " +conferenceModel.localParticipant.adminStatus) + + SmartSearchBar { + id: smartSearchBar + + Layout.fillWidth: true + Layout.topMargin: ParticipantsListViewStyle.searchBar.topMargin + + showHeader:false + + visible: mainLayout.isAdmin && mainLayout.canHandleParticipants + + maxMenuHeight: MainWindowStyle.searchBox.maxHeight + //: 'Add Participants' : Placeholder in a search bar for adding participant to the chat room + placeholderText: 'addParticipantPlaceholder' + //: 'Search participants in your contact list in order to invite them into the chat room.' + //~ Tooltip Explanation for inviting the selected participants into chat room + tooltipText: 'addParticipantTooltip' + actions:[{ + colorSet: ParticipantsListViewStyle.addParticipant, + secure: mainLayout.haveEncryption, + visible: true, + secureIconVisibleHandler : function(entry) { + return entry.sipAddress && mainLayout.haveEncryption && UtilsCpp.hasCapability(entry.sipAddress, LinphoneEnums.FriendCapabilityLimeX3Dh); + }, + handler: function (entry) { + selectedParticipants.addAddress(entry.sipAddress) + }, + }] + + onEntryClicked: { + selectedParticipants.addAddress(entry.sipAddress) + } + } + + + ScrollableListViewField { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.bottomMargin: 5 + + //readOnly: toAddView.count >= conferenceManager.maxParticipants + textFieldStyle: TextFieldStyle.normal + + ColumnLayout{ + anchors.fill:parent + spacing:0 + Text{ + Layout.topMargin: ParticipantsListViewStyle.results.title.topMargin + Layout.leftMargin: ParticipantsListViewStyle.results.title.leftMargin + //: 'Participant list' + text:qsTr('participantList') + color: ParticipantsListViewStyle.results.title.color + font.pointSize:ParticipantsListViewStyle.results.title.pointSize + font.weight: ParticipantsListViewStyle.results.title.weight + } + Text{ + Layout.preferredHeight: implicitHeight + Layout.rightMargin: ParticipantsListViewStyle.results.header.rightMargin + Layout.alignment: Qt.AlignRight | Qt.AlignBottom + //Layout.topMargin: ParticipantsListViewStyle.results.topMargin + //: 'Admin' : Admin(istrator) + //~ one word for admin status + text : qsTr('adminStatus') + + color: ParticipantsListViewStyle.results.header.color + font.pointSize: ParticipantsListViewStyle.results.header.pointSize + font.weight: ParticipantsListViewStyle.results.header.weight + visible: mainLayout.isAdmin && participantView.count > 0 + + } + + ParticipantsView { + id: participantView + Layout.fillHeight: true + Layout.fillWidth: true + //anchors.fill: parent + + showContactAddress:false + showSwitch : mainLayout.isAdmin + showSeparator: false + showAdminStatus:!mainLayout.isAdmin + isSelectable: false + hoveredCursor:Qt.WhatsThisCursor + + + actions: mainLayout.isAdmin ? [{ + colorSet: ParticipantsListViewStyle.removeParticipant, + secure:0, + visible:true, + tooltipText: 'Remove this participant from the selection', + handler: function (entry) { + selectedParticipants.removeModel(entry) + // ++lastContacts.reloadCount + } + }] + : [] + + genSipAddress: '' + + model: ParticipantProxyModel { + id:selectedParticipants + chatRoomModel: mainLayout.chatRoomModel + conferenceModel: mainLayout.conferenceModel + onAddressAdded: smartSearchBar.addAddressToIgnore(sipAddress) + onAddressRemoved: smartSearchBar.removeAddressToIgnore(sipAddress) + showMe: mainLayout.isAdmin + + } + + onEntryClicked: { + contactItem.showContactAddress = !contactItem.showContactAddress + } + } + } + } +} diff --git a/linphone-app/ui/modules/Linphone/qmldir b/linphone-app/ui/modules/Linphone/qmldir index 6de91ac0a..23ff039da 100644 --- a/linphone-app/ui/modules/Linphone/qmldir +++ b/linphone-app/ui/modules/Linphone/qmldir @@ -52,6 +52,7 @@ TelKeypad 1.0 TelKeypad/TelKeypad.qml Timeline 1.0 Timeline/Timeline.qml +ParticipantsListView 1.0 View/ParticipantsListView.qml +ParticipantsView 1.0 View/ParticipantsView.qml SipAddressesView 1.0 View/SipAddressesView.qml -ParticipantsView 1.0 View/ParticipantsView.qml diff --git a/linphone-app/ui/views/App/Calls/VideoConference.qml b/linphone-app/ui/views/App/Calls/VideoConference.qml index 7f9b900be..eef287da9 100644 --- a/linphone-app/ui/views/App/Calls/VideoConference.qml +++ b/linphone-app/ui/views/App/Calls/VideoConference.qml @@ -24,7 +24,7 @@ Rectangle { id: conference property CallModel callModel - property ConferenceModel conferenceModel: callModel && callModel.getConferenceModel() + property ConferenceModel conferenceModel: callModel && callModel.conferenceModel property bool cameraIsReady : false property bool previewIsReady : false property bool isFullScreen: false // Use this variable to test if we are in fullscreen. Do not test _fullscreen : we need to clean memory before having the window (see .js file) @@ -249,6 +249,7 @@ Rectangle { Layout.preferredWidth: 400 Layout.rightMargin: 30 callModel: conference.callModel + conferenceModel: conference.conferenceModel visible: false onClose: rightMenu.visible = !rightMenu.visible } diff --git a/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml b/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml index f9248d82d..c47226601 100644 --- a/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml +++ b/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml @@ -66,7 +66,7 @@ Window { id: conference property CallModel callModel - property ConferenceModel conferenceModel: callModel && callModel.getConferenceModel() + property ConferenceModel conferenceModel: callModel && callModel.conferenceModel property var _fullscreen: null property bool listCallsOpened: false @@ -287,6 +287,7 @@ Window { Layout.preferredWidth: 400 Layout.rightMargin: 30 callModel: conference.callModel + conferenceModel: conference.conferenceModel visible: false onClose: rightMenu.visible = !rightMenu.visible } diff --git a/linphone-app/ui/views/App/Calls/VideoConferenceMenu.qml b/linphone-app/ui/views/App/Calls/VideoConferenceMenu.qml index bd0150168..076753c1e 100644 --- a/linphone-app/ui/views/App/Calls/VideoConferenceMenu.qml +++ b/linphone-app/ui/views/App/Calls/VideoConferenceMenu.qml @@ -24,6 +24,10 @@ import 'qrc:/ui/scripts/Utils/utils.js' as Utils Rectangle{ id: mainItem property CallModel callModel + property ConferenceModel conferenceModel: callModel.conferenceModel + property ParticipantModel me: conferenceModel.localParticipant + property bool isMeAdmin: me && me.adminStatus + onIsMeAdminChanged: console.log("Is admin : " +isMeAdmin) signal close() height: 500 @@ -95,8 +99,12 @@ Rectangle{ , icon: (mainItem.callModel.videoEnabled ? (mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid ? VideoConferenceMenuStyle.settingsIcons.gridIcon : VideoConferenceMenuStyle.settingsIcons.activeSpeakerIcon) : VideoConferenceMenuStyle.settingsIcons.audioOnlyIcon) - , nextPage:layoutMenu} - ] + , nextPage:layoutMenu}, + + {text: mainItem.isMeAdmin ? 'Inviter des participants' : 'Participants' + , icon: VideoConferenceMenuStyle.settingsIcons.participantsIcon + , nextPage:participantsMenu} + ] delegate: Borders{ bottomColor: VideoConferenceMenuStyle.list.border.color @@ -150,6 +158,7 @@ Rectangle{ } } } +//----------------------------------------------------------------------------------------------------------------------------- Component{ id: mediaMenu ColumnLayout{ @@ -172,6 +181,7 @@ Rectangle{ } } } +//----------------------------------------------------------------------------------------------------------------------------- Component{ id: layoutMenu ColumnLayout{ @@ -224,5 +234,23 @@ Rectangle{ } } } +//----------------------------------------------------------------------------------------------------------------------------- + Component{ + id: participantsMenu + ColumnLayout{ + Layout.fillHeight: true + Layout.fillWidth: true + ParticipantsListView{ + Layout.fillHeight: true + Layout.fillWidth: true + //Layout.minimumHeight: fitHeight + conferenceModel: mainItem.conferenceModel + } + Item{// Spacer + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } } } diff --git a/linphone-app/ui/views/App/Styles/Calls/VideoConferenceMenuStyle.qml b/linphone-app/ui/views/App/Styles/Calls/VideoConferenceMenuStyle.qml index bf2034906..b9b9ad93c 100644 --- a/linphone-app/ui/views/App/Styles/Calls/VideoConferenceMenuStyle.qml +++ b/linphone-app/ui/views/App/Styles/Calls/VideoConferenceMenuStyle.qml @@ -44,6 +44,7 @@ QtObject { property string activeSpeakerIcon: 'conference_layout_active_speaker_custom' property string audioOnlyIcon: 'conference_audio_only_custom' property string mediaIcon: 'micro_on_custom' + property string participantsIcon: 'participants_custom' property int width: 40 property int height: 40 } diff --git a/linphone-sdk b/linphone-sdk index c8d936196..074802f6c 160000 --- a/linphone-sdk +++ b/linphone-sdk @@ -1 +1 @@ -Subproject commit c8d936196b84855415e90d41346e7b3a25374077 +Subproject commit 074802f6c0bcc7f095e94faad804ce083de3bcc3