From 9029c332151cb82f80ae4768459d4c05e89e8238 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Mon, 17 Jan 2022 12:10:30 +0100 Subject: [PATCH] - Calendar ICS view on grids - Scheduling conferences - CameraDummy in case of unavailable Linphone streams - Remove some tests --- linphone-app/CMakeLists.txt | 6 + linphone-app/resources.qrc | 3 + linphone-app/src/components/Components.hpp | 1 + .../src/components/call/CallModel.cpp | 6 +- .../src/components/call/CallModel.hpp | 3 +- .../src/components/calls/CallsListModel.cpp | 63 +------- linphone-app/src/components/camera/Camera.cpp | 58 ++++--- linphone-app/src/components/camera/Camera.hpp | 1 + .../src/components/camera/CameraDummy.cpp | 44 ++++++ .../src/components/camera/CameraDummy.hpp | 37 +++++ .../src/components/camera/CameraPreview.cpp | 30 ++-- .../src/components/camera/CameraPreview.hpp | 24 +-- .../components/chat-room/ChatRoomModel.cpp | 11 +- .../components/conference/ConferenceModel.cpp | 13 +- .../components/conference/ConferenceModel.hpp | 2 + .../ConferenceInfoListModel.cpp | 39 +++-- .../ConferenceInfoListModel.hpp | 7 +- .../conferenceInfo/ConferenceInfoMapModel.cpp | 77 ++++++++++ .../conferenceInfo/ConferenceInfoMapModel.hpp | 48 ++++++ .../conferenceInfo/ConferenceInfoModel.cpp | 62 +++++++- .../conferenceInfo/ConferenceInfoModel.hpp | 23 ++- .../ConferenceInfoProxyModel.cpp | 9 +- .../ConferenceSchedulerModel.cpp | 62 ++++++++ .../ConferenceSchedulerModel.hpp | 54 +++++++ .../src/components/content/ContentModel.cpp | 8 + .../src/components/content/ContentModel.hpp | 5 + .../src/components/core/CoreHandlers.cpp | 28 +++- .../src/components/core/CoreHandlers.hpp | 5 +- .../ParticipantDeviceListModel.cpp | 105 +++++++++++-- .../ParticipantDeviceListModel.hpp | 5 + .../participant/ParticipantDeviceModel.cpp | 14 +- .../participant/ParticipantDeviceModel.hpp | 4 + .../ParticipantDeviceProxyModel.cpp | 20 ++- .../ParticipantDeviceProxyModel.hpp | 3 + .../components/timeline/TimelineListModel.cpp | 11 +- .../ui/modules/Common/Form/Mosaic.qml | 2 + .../Linphone/Chat/ChatCalendarMessage.qml | 143 ++++++++++++++++++ .../ui/modules/Linphone/Chat/ChatContent.qml | 13 +- .../modules/Linphone/Chat/ChatFileMessage.qml | 2 +- .../Linphone/Chat/ChatForwardMessage.qml | 2 +- .../ui/modules/Linphone/Chat/Message.qml | 1 + .../Styles/Chat/ChatCalendarMessageStyle.qml | 82 ++++++++++ .../ui/modules/Linphone/Styles/qmldir | 1 + linphone-app/ui/modules/Linphone/qmldir | 1 + linphone-app/ui/views/App/Calls/EndedCall.qml | 2 +- linphone-app/ui/views/App/Calls/Incall.js | 20 +-- linphone-app/ui/views/App/Calls/Incall.qml | 8 +- .../ui/views/App/Calls/IncallAvatar.qml | 9 +- .../ui/views/App/Calls/VideoConference.qml | 88 ++++++++--- .../ui/views/App/Main/Conferences.qml | 124 ++++----------- .../views/App/Main/Dialogs/NewConference.qml | 21 ++- .../Settings/Dialogs/SettingsVideoPreview.qml | 47 +++--- 52 files changed, 1121 insertions(+), 336 deletions(-) create mode 100644 linphone-app/src/components/camera/CameraDummy.cpp create mode 100644 linphone-app/src/components/camera/CameraDummy.hpp create mode 100644 linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.cpp create mode 100644 linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.hpp create mode 100644 linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.cpp create mode 100644 linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.hpp create mode 100644 linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml create mode 100644 linphone-app/ui/modules/Linphone/Styles/Chat/ChatCalendarMessageStyle.qml diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index cd0c2afc4..d882c9dd9 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -133,6 +133,7 @@ set(SOURCES src/components/calls/CallsListModel.cpp src/components/calls/CallsListProxyModel.cpp src/components/camera/Camera.cpp + src/components/camera/CameraDummy.cpp src/components/camera/CameraPreview.cpp src/components/chat/ChatModel.cpp src/components/chat-events/ChatCallModel.cpp @@ -151,7 +152,9 @@ set(SOURCES src/components/conference/ConferenceProxyModel.cpp src/components/conferenceInfo/ConferenceInfoModel.cpp src/components/conferenceInfo/ConferenceInfoListModel.cpp + src/components/conferenceInfo/ConferenceInfoMapModel.cpp src/components/conferenceInfo/ConferenceInfoProxyModel.cpp + src/components/conferenceScheduler/ConferenceSchedulerModel.cpp src/components/contact/ContactModel.cpp src/components/contact/VcardModel.cpp src/components/contacts/ContactsImporterModel.cpp @@ -248,6 +251,7 @@ set(HEADERS src/components/calls/CallsListModel.hpp src/components/calls/CallsListProxyModel.hpp src/components/camera/Camera.hpp + src/components/camera/CameraDummy.hpp src/components/camera/CameraPreview.hpp src/components/chat/ChatModel.hpp src/components/chat-events/ChatCallModel.hpp @@ -267,7 +271,9 @@ set(HEADERS src/components/conference/ConferenceProxyModel.hpp src/components/conferenceInfo/ConferenceInfoModel.hpp src/components/conferenceInfo/ConferenceInfoListModel.hpp + src/components/conferenceInfo/ConferenceInfoMapModel.hpp src/components/conferenceInfo/ConferenceInfoProxyModel.hpp + src/components/conferenceScheduler/ConferenceSchedulerModel.hpp src/components/contact/ContactModel.hpp src/components/contact/VcardModel.hpp src/components/contacts/ContactsImporterModel.hpp diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index b1661b964..5e987a2ab 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -14,6 +14,7 @@ assets/images/attachment_custom.svg assets/images/auto_answer_custom.svg assets/images/burger_menu_custom.svg + assets/images/calendar_participants_custom.svg assets/images/call_accept_custom.svg assets/images/call_chat_secure_custom.svg assets/images/call_chat_unsecure_custom.svg @@ -292,6 +293,7 @@ ui/modules/Linphone/Chat/ChatMenu.qml ui/modules/Linphone/Chat/ChatAudioMessage.qml ui/modules/Linphone/Chat/ChatAudioPreview.qml + ui/modules/Linphone/Chat/ChatCalendarMessage.qml ui/modules/Linphone/Chat/ChatFileMessage.qml ui/modules/Linphone/Chat/ChatFilePreview.qml ui/modules/Linphone/Chat/ChatForwardMessage.qml @@ -342,6 +344,7 @@ ui/modules/Linphone/Styles/Chat/ChatAudioMessageStyle.qml ui/modules/Linphone/Styles/Chat/ChatAudioPreviewStyle.qml ui/modules/Linphone/Styles/Chat/ChatFilePreviewStyle.qml + ui/modules/Linphone/Styles/Chat/ChatCalendarMessageStyle.qml ui/modules/Linphone/Styles/Chat/ChatForwardMessageStyle.qml ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml ui/modules/Linphone/Styles/Codecs/CodecsViewerStyle.qml diff --git a/linphone-app/src/components/Components.hpp b/linphone-app/src/components/Components.hpp index f518166ac..3da8ab581 100644 --- a/linphone-app/src/components/Components.hpp +++ b/linphone-app/src/components/Components.hpp @@ -40,6 +40,7 @@ #include "conferenceInfo/ConferenceInfoModel.hpp" #include "conferenceInfo/ConferenceInfoListModel.hpp" #include "conferenceInfo/ConferenceInfoProxyModel.hpp" +#include "conferenceScheduler/ConferenceSchedulerModel.hpp" #include "contact/ContactModel.hpp" #include "contact/VcardModel.hpp" #include "contacts/ContactsListModel.hpp" diff --git a/linphone-app/src/components/call/CallModel.cpp b/linphone-app/src/components/call/CallModel.cpp index 39263786c..820dbfbf2 100644 --- a/linphone-app/src/components/call/CallModel.cpp +++ b/linphone-app/src/components/call/CallModel.cpp @@ -420,6 +420,7 @@ void CallModel::handleCallStateChanged (const shared_ptr &call, break; case linphone::Call::State::UpdatedByRemote: + qWarning() << "UpdatedByRemote :" << (mCall ? mCall->getCurrentParams()->videoEnabled() + QString(" ")+mCall->getRemoteParams()->videoEnabled() : " call NULL"); if (mCall && !mCall->getCurrentParams()->videoEnabled() && mCall->getRemoteParams()->videoEnabled()) { mCall->deferUpdate(); emit videoRequested(); @@ -663,7 +664,7 @@ bool CallModel::getRemoteVideoEnabled () const { bool CallModel::getVideoEnabled () const { if(mCall){ shared_ptr params = mCall->getCurrentParams(); - return params && params->videoEnabled() && getStatus() == CallStatusConnected; + return params && params->videoEnabled() && getStatus() == CallStatusConnected && mCall->getState() == linphone::Call::State::StreamsRunning; }else return true; } @@ -795,7 +796,8 @@ void CallModel::setRemoteDisplayName(const std::string& name){ auto callLog = mCall->getCallLog(); if(name!= "") { auto core = CoreManager::getInstance()->getCore(); - callLog->setRemoteAddress(Utils::interpretUrl(getFullPeerAddress())); + auto address = Utils::interpretUrl(getFullPeerAddress()); + callLog->setRemoteAddress(address); } } emit fullPeerAddressChanged(); diff --git a/linphone-app/src/components/call/CallModel.hpp b/linphone-app/src/components/call/CallModel.hpp index 6a3861b08..b9cc7be88 100644 --- a/linphone-app/src/components/call/CallModel.hpp +++ b/linphone-app/src/components/call/CallModel.hpp @@ -189,7 +189,7 @@ signals: void fullPeerAddressChanged(); void transferAddressChanged (const QString &transferAddress); -private: +public: void handleCallEncryptionChanged (const std::shared_ptr &call); void handleCallStateChanged (const std::shared_ptr &call, linphone::Call::State state); @@ -255,6 +255,7 @@ private: static QString generateSavedFilename (const QString &from, const QString &to); +private: bool mIsInConference = false; bool mPausedByRemote = false; diff --git a/linphone-app/src/components/calls/CallsListModel.cpp b/linphone-app/src/components/calls/CallsListModel.cpp index 19fa4cccc..1793d03a5 100644 --- a/linphone-app/src/components/calls/CallsListModel.cpp +++ b/linphone-app/src/components/calls/CallsListModel.cpp @@ -389,67 +389,8 @@ QVariantMap CallsListModel::createConference(ConferenceInfoModel * conferenceInf std::shared_ptr timeline; auto timelineList = CoreManager::getInstance()->getTimelineListModel(); qInfo() << "Conference creation of " << conferenceInfo->getSubject() << " at " << securityLevel << " security";// and with " << conferenceInfo->getConferenceInfo()->getParticipants().size(); - - std::shared_ptr params = core->createConferenceParams(); - std::list > participants = conferenceInfo->getConferenceInfo()->getParticipants(); - std::shared_ptr localAddress; - - /* - for(auto p : participants){ - ParticipantModel* participant = p.value(); - std::shared_ptr address; - if(participant) { - address = Utils::interpretUrl(participant->getSipAddress()); - if(participant->getAdminStatus()) - admins << address; - }else{ - QString participant = p.toString(); - if( participant != "") - address = Utils::interpretUrl(participant); - } - if( address) - chatRoomParticipants.push_back( address ); - }*/ - auto proxy = core->getDefaultProxyConfig(); - params->setVideoEnabled(true); - params->setStartTime(conferenceInfo->getConferenceInfo()->getDateTime()); - params->setEndTime(conferenceInfo->getConferenceInfo()->getDateTime()+conferenceInfo->getConferenceInfo()->getDuration()*60); - params->setLayout(linphone::ConferenceLayout::Grid); - //params->setDescription(conferenceInfo->getConferenceInfo()->getDescription()); - - //params->enableEncryption(securityLevel>0); - -// if( securityLevel>0){ -// params->enableEncryption(true); -// }else -// params->setBackend(linphone::ChatRoomBackend::Basic); -// params->enableGroup( subject!="" ); - - - if(participants.size() > 0) { - params->setSubject(conferenceInfo->getSubject() != ""?Utils::appStringToCoreString(conferenceInfo->getSubject()):"Dummy Subject"); - if( !conference) { - core->createConferenceOnServer(params, localAddress, participants); - /* - //conference = core->createConferenceWithParams(params); - if(conference != nullptr && admins.size() > 0){ - for(auto a : admins) { - auto p = conference->findParticipant(a); - if( p ) - conference->setParticipantAdminStatus(p, true); - else - qWarning() <<"Cannot set admin for " << a->asString().c_str() << ". It is not found in conference."; - } - } - // Warning: Should not be needed but SDK doesn't ref it - mConferences.append(std::make_shared(conference)); - //ChatRoomInitializer::setAdminsAsync(params->getSubject(), params->getBackend(), params->groupEnabled(), admins ); - // timeline = timelineList->getTimeline(conference, false); - */ - } - - } - //result["created"] = (conference != nullptr); + auto conferenceScheduler = core->createConferenceScheduler(); + conferenceScheduler->setInfo(conferenceInfo->getConferenceInfo()); return result; } diff --git a/linphone-app/src/components/camera/Camera.cpp b/linphone-app/src/components/camera/Camera.cpp index 4d1079a23..c969250cd 100644 --- a/linphone-app/src/components/camera/Camera.cpp +++ b/linphone-app/src/components/camera/Camera.cpp @@ -28,6 +28,7 @@ #include "components/participant/ParticipantDeviceModel.hpp" #include "Camera.hpp" +#include "CameraDummy.hpp" // ============================================================================= @@ -37,7 +38,6 @@ namespace { constexpr int MaxFps = 30; } - // ============================================================================= Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) { // The fbo content must be y-mirrored because the ms rendering is y-inverted. @@ -77,41 +77,53 @@ public: QQuickFramebufferObject::Renderer *Camera::createRenderer () const { QQuickFramebufferObject::Renderer * renderer = NULL; if(mIsPreview){ - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(NULL);// Reset - renderer=(QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativePreviewWindowId(); - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer); + renderer = (QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativePreviewWindowId(); + if(renderer) + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(NULL);// Reset + renderer=(QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->createNativePreviewWindowId(); + if(renderer) + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer); }else{ + bool useDefaultWindow = false; if(mCallModel){ auto call = mCallModel->getCall(); if(call){ - call->setNativeVideoWindowId(NULL);// Reset renderer = (QQuickFramebufferObject::Renderer *) call->getNativeVideoWindowId(); - call->setNativeVideoWindowId(renderer); - }else{ - CoreManager::getInstance()->getCore()->setNativeVideoWindowId(NULL); - renderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->getNativeVideoWindowId(); - CoreManager::getInstance()->getCore()->setNativeVideoWindowId(renderer); - } + if(renderer) + call->setNativeVideoWindowId(NULL);// Reset + renderer = (QQuickFramebufferObject::Renderer *) call->createNativeVideoWindowId(); + if(renderer) + call->setNativeVideoWindowId(renderer); + }else + useDefaultWindow = true; }else if( mParticipantDeviceModel){ auto participantDevice = mParticipantDeviceModel->getDevice(); if(participantDevice){ - participantDevice->setNativeVideoWindowId(NULL);// Reset - renderer = (QQuickFramebufferObject::Renderer *) participantDevice->getNativeVideoWindowId(); - participantDevice->setNativeVideoWindowId(renderer); - }else{ + renderer = (QQuickFramebufferObject::Renderer *)participantDevice->getNativeVideoWindowId(); + if(renderer) + participantDevice->setNativeVideoWindowId(NULL);// Reset + renderer = (QQuickFramebufferObject::Renderer *) participantDevice->createNativeVideoWindowId(); + if(renderer) + participantDevice->setNativeVideoWindowId(renderer); + }else + useDefaultWindow = true; + } + if(useDefaultWindow){ + renderer = (QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativeVideoWindowId(); + if(renderer) CoreManager::getInstance()->getCore()->setNativeVideoWindowId(NULL); - enderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->getNativeVideoWindowId(); + renderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->createNativeVideoWindowId(); + if(renderer) CoreManager::getInstance()->getCore()->setNativeVideoWindowId(renderer); - } } } - - if(renderer) - return renderer; - else{ - qWarning() << "Camera stream couldn't start for Rendering"; - return new SafeFramebuffer(); + if( !renderer){ + qWarning() << "Camera stream couldn't start for Rendering. Retrying in 1s"; + renderer = new CameraDummy(); + QTimer::singleShot(1000, this, &Camera::requestNewRenderer); + } + return renderer; } // ----------------------------------------------------------------------------- diff --git a/linphone-app/src/components/camera/Camera.hpp b/linphone-app/src/components/camera/Camera.hpp index 00740ab05..a2fab4825 100644 --- a/linphone-app/src/components/camera/Camera.hpp +++ b/linphone-app/src/components/camera/Camera.hpp @@ -55,6 +55,7 @@ signals: void callChanged (CallModel *callModel); void isPreviewChanged (bool isPreview); void participantDeviceModelChanged(ParticipantDeviceModel *participantDeviceModel); + void requestNewRenderer(); private: CallModel *getCallModel () const; diff --git a/linphone-app/src/components/camera/CameraDummy.cpp b/linphone-app/src/components/camera/CameraDummy.cpp new file mode 100644 index 000000000..0c65f8f87 --- /dev/null +++ b/linphone-app/src/components/camera/CameraDummy.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 +#include +#include +#include + +#include "components/core/CoreManager.hpp" + +#include "CameraDummy.hpp" + +// ============================================================================= + + +CameraDummy::CameraDummy(){ +} + +QOpenGLFramebufferObject *CameraDummy::createFramebufferObject (const QSize &size){ + return new QOpenGLFramebufferObject(size); +} + +void CameraDummy::render (){ +} + +void CameraDummy::synchronize (QQuickFramebufferObject *item){ +} \ No newline at end of file diff --git a/linphone-app/src/components/camera/CameraDummy.hpp b/linphone-app/src/components/camera/CameraDummy.hpp new file mode 100644 index 000000000..a79df2ad3 --- /dev/null +++ b/linphone-app/src/components/camera/CameraDummy.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#ifndef CAMERA_DUMMY_H_ +#define CAMERA_DUMMY_H_ + +#include +#include + +// ============================================================================= + +class CameraDummy : public QQuickFramebufferObject::Renderer{ +public: + CameraDummy(); + QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override; + void render () override; + void synchronize (QQuickFramebufferObject *item) override; +}; + +#endif diff --git a/linphone-app/src/components/camera/CameraPreview.cpp b/linphone-app/src/components/camera/CameraPreview.cpp index 9a5835476..7e253a5ca 100644 --- a/linphone-app/src/components/camera/CameraPreview.cpp +++ b/linphone-app/src/components/camera/CameraPreview.cpp @@ -26,6 +26,7 @@ #include "components/core/CoreManager.hpp" #include "CameraPreview.hpp" +#include "CameraDummy.hpp" // ============================================================================= @@ -74,25 +75,16 @@ CameraPreview::~CameraPreview () { } } -class SafeFramebuffer : public QQuickFramebufferObject::Renderer{ -public: - SafeFramebuffer(){} - QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override{ - return new QOpenGLFramebufferObject(size); - } - void render () override{} - void synchronize (QQuickFramebufferObject *item) override{} -}; - QQuickFramebufferObject::Renderer *CameraPreview::createRenderer () const { - QQuickFramebufferObject::Renderer * renderer; - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(NULL);// Reset - renderer=(QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativePreviewWindowId(); - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer); + QQuickFramebufferObject::Renderer * renderer = (QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativePreviewWindowId(); if(renderer) - return renderer; - else{ - qWarning() << "Preview stream couldn't start for Rendering"; - return new SafeFramebuffer(); - } + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(NULL);// Reset + renderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->createNativePreviewWindowId(); + if( !renderer ) { + qWarning() << "Preview stream couldn't start for Rendering. Retrying in 1s"; + renderer = new CameraDummy(); + QTimer::singleShot(1000, this, &CameraPreview::requestNewRenderer); + }else + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer); + return renderer; } diff --git a/linphone-app/src/components/camera/CameraPreview.hpp b/linphone-app/src/components/camera/CameraPreview.hpp index 2a057ef30..3411d5e0b 100644 --- a/linphone-app/src/components/camera/CameraPreview.hpp +++ b/linphone-app/src/components/camera/CameraPreview.hpp @@ -23,24 +23,26 @@ #include #include -#include // ============================================================================= class CameraPreview : public QQuickFramebufferObject { - Q_OBJECT; - + Q_OBJECT + public: - CameraPreview (QQuickItem *parent = Q_NULLPTR); - ~CameraPreview (); - - QQuickFramebufferObject::Renderer *createRenderer () const override; + CameraPreview (QQuickItem *parent = Q_NULLPTR); + ~CameraPreview (); + + QQuickFramebufferObject::Renderer *createRenderer () const override; + +signals: + void requestNewRenderer(); private: - QTimer *mRefreshTimer = nullptr; - - static QMutex mCounterMutex; - static int mCounter; + QTimer *mRefreshTimer = nullptr; + + static QMutex mCounterMutex; + static int mCounter; }; #endif // CAMERA_PREVIEW_H_ diff --git a/linphone-app/src/components/chat-room/ChatRoomModel.cpp b/linphone-app/src/components/chat-room/ChatRoomModel.cpp index 8cd1192bb..f673f8d91 100644 --- a/linphone-app/src/components/chat-room/ChatRoomModel.cpp +++ b/linphone-app/src/components/chat-room/ChatRoomModel.cpp @@ -236,10 +236,17 @@ ChatRoomModel::ChatRoomModel (std::shared_ptr chatRoom, QObj connect(contact, &ContactModel::contactUpdated, this, &ChatRoomModel::fullPeerAddressChanged); } } - + // Get Max updatetime from chat room and last call event + auto callHistory = CallsListModel::getCallHistory(getParticipantAddress(), Utils::coreStringToAppString(mChatRoom->getLocalAddress()->asStringUriOnly())); + if(callHistory.size() > 0){ + auto callDate = callHistory.front()->getStartDate(); + if( callHistory.front()->getStatus() == linphone::Call::Status::Success ) + callDate += callHistory.front()->getDuration(); + setLastUpdateTime(QDateTime::fromMSecsSinceEpoch(max(mChatRoom->getLastUpdateTime(), callDate )*1000)); + }else + setLastUpdateTime(QDateTime::fromMSecsSinceEpoch(mChatRoom->getLastUpdateTime()*1000)); }else mParticipantListModel = nullptr; - } ChatRoomModel::~ChatRoomModel () { diff --git a/linphone-app/src/components/conference/ConferenceModel.cpp b/linphone-app/src/components/conference/ConferenceModel.cpp index da1a31239..096256e40 100644 --- a/linphone-app/src/components/conference/ConferenceModel.cpp +++ b/linphone-app/src/components/conference/ConferenceModel.cpp @@ -64,29 +64,36 @@ std::shared_ptr ConferenceModel::getConference()const{ //----------------------------------------------------------------------------------------------------------------------- void ConferenceModel::onParticipantAdded(const std::shared_ptr & conference, const std::shared_ptr & participant){ qWarning() << "onParticipantAdded is not yet implemented."; + qWarning() << "Me devices : " << conference->getMe()->getDevices().size(); } void ConferenceModel::onParticipantRemoved(const std::shared_ptr & conference, const std::shared_ptr & participant){ qWarning() << "onParticipantRemoved is not yet implemented."; + qWarning() << "Me devices : " << conference->getMe()->getDevices().size(); } void ConferenceModel::onParticipantDeviceAdded(const std::shared_ptr & conference, const std::shared_ptr & participantDevice){ + qWarning() << "Me devices : " << conference->getMe()->getDevices().size(); emit participantDeviceAdded(participantDevice); } void ConferenceModel::onParticipantDeviceRemoved(const std::shared_ptr & conference, const std::shared_ptr & participantDevice){ + qWarning() << "Me devices : " << conference->getMe()->getDevices().size(); emit participantDeviceRemoved(participantDevice); } void ConferenceModel::onParticipantAdminStatusChanged(const std::shared_ptr & conference, const std::shared_ptr & participant){ } void ConferenceModel::onParticipantDeviceLeft(const std::shared_ptr & conference, const std::shared_ptr & participantDevice){ + qWarning() << "Me devices : " << conference->getMe()->getDevices().size(); emit participantDeviceLeft(participantDevice); } void ConferenceModel::onParticipantDeviceJoined(const std::shared_ptr & conference, const std::shared_ptr & participantDevice){ + qWarning() << "Me devices : " << conference->getMe()->getDevices().size(); emit participantDeviceJoined(participantDevice); } -void ConferenceModel::onParticipantDeviceMediaChanged(const std::shared_ptr & conference, const std::shared_ptr & device){ - qWarning() << "onParticipantDeviceMediaChanged is not yet implemented."; +void ConferenceModel::onParticipantDeviceMediaChanged(const std::shared_ptr & conference, const std::shared_ptr & participantDevice){ + qWarning() << "ConferenceModel::onParticipantDeviceMediaChanged: " << (int)participantDevice->getStreamAvailability(linphone::StreamType::Video) << ". Me devices : " << conference->getMe()->getDevices().size(); + emit participantDeviceMediaChanged(participantDevice); } void ConferenceModel::onStateChanged(const std::shared_ptr & conference, linphone::Conference::State newState){ - qWarning() << "onStateChanged is not yet implemented."; + emit conferenceStateChanged(newState); } void ConferenceModel::onSubjectChanged(const std::shared_ptr & conference, const std::string & subject){ qWarning() << "onSubjectChanged is not yet implemented."; diff --git a/linphone-app/src/components/conference/ConferenceModel.hpp b/linphone-app/src/components/conference/ConferenceModel.hpp index 6885b82e3..9ce75fc53 100644 --- a/linphone-app/src/components/conference/ConferenceModel.hpp +++ b/linphone-app/src/components/conference/ConferenceModel.hpp @@ -56,6 +56,8 @@ signals: void participantDeviceRemoved(const std::shared_ptr & participantDevice); void participantDeviceLeft(const std::shared_ptr & participantDevice); void participantDeviceJoined(const std::shared_ptr & participantDevice); + void participantDeviceMediaChanged(const std::shared_ptr & participantDevice); + void conferenceStateChanged(linphone::Conference::State newState); private: std::shared_ptr mConference; diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp index be7e8f007..d571cd2b6 100644 --- a/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp @@ -36,14 +36,16 @@ // ============================================================================= ConferenceInfoListModel::ConferenceInfoListModel (QObject *parent) : QAbstractListModel(parent) { - auto conferenceInfos = CoreManager::getInstance()->getCore()->getConferenceInformationList(); - for(auto conferenceInfo : conferenceInfos){ - mList << ConferenceInfoModel::create( conferenceInfo ); - } + //auto conferenceInfos = CoreManager::getInstance()->getCore()->getConferenceInformationList(); + //for(auto conferenceInfo : conferenceInfos){ +// auto conferenceInfoModel = ConferenceInfoModel::create( conferenceInfo ); +// mList << conferenceInfoModel; + //mMappedList[conferenceInfoModel->getDateTime().date()].push_back(conferenceInfoModel.get()); +// } } int ConferenceInfoListModel::rowCount (const QModelIndex &) const { - return mList.count(); + return mList.size(); } QHash ConferenceInfoListModel::roleNames () const { @@ -55,35 +57,46 @@ QHash ConferenceInfoListModel::roleNames () const { QVariant ConferenceInfoListModel::data (const QModelIndex &index, int role) const { int row = index.row(); - if (!index.isValid() || row < 0 || row >= mList.count()) + if (!index.isValid() || row < 0 || row >= mList.size()) return QVariant(); + auto it = mList.begin() + row; if (role == Qt::DisplayRole) - return QVariant::fromValue(mList[row].get()); + return QVariant::fromValue(it->get()); - //return QVariant(); + return QVariant(); +} + +ConferenceInfoModel* ConferenceInfoListModel::getAt(const int& index) const { + return mList[index].get(); } // ----------------------------------------------------------------------------- - - +void ConferenceInfoListModel::add(std::shared_ptr conferenceInfoModel){ + int row = mList.size(); + beginInsertRows(QModelIndex(), row,row); + mList << conferenceInfoModel; + endInsertRows(); +} +// Should not be called as item that need to be removed are usually a cell, not a row bool ConferenceInfoListModel::removeRow (int row, const QModelIndex &parent) { return removeRows(row, 1, parent); } bool ConferenceInfoListModel::removeRows (int row, int count, const QModelIndex &parent) { +/* int limit = row + count - 1; - if (row < 0 || count < 0 || limit >= mList.count()) + if (row < 0 || count < 0 || limit >= mMappedList.count()) return false; beginRemoveRows(parent, row, limit); for (int i = 0; i < count; ++i) - mList.takeAt(row)->deleteLater(); + mMappedList.takeAt(row)->deleteLater(); endRemoveRows(); - + */ return true; } diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp index 395b42c6e..f6a5528bb 100644 --- a/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp @@ -23,6 +23,7 @@ #include #include +#include // ============================================================================= @@ -38,14 +39,16 @@ public: QHash roleNames () const override; QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; - + ConferenceInfoModel* getAt(const int& index) const; + void add(std::shared_ptr conferenceInfoModel); private: bool removeRow (int row, const QModelIndex &parent = QModelIndex()); bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override; QList> mList; + //QMap> mMappedList; }; - +Q_DECLARE_METATYPE(QList*) #endif diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.cpp new file mode 100644 index 000000000..144e1162d --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 "ConferenceInfoMapModel.hpp" + +#include +#include +#include + +#include "app/App.hpp" +#include "components/conference/ConferenceAddModel.hpp" +#include "components/conference/ConferenceHelperModel.hpp" +#include "components/core/CoreHandlers.hpp" +#include "components/core/CoreManager.hpp" +#include "components/settings/SettingsModel.hpp" +#include "utils/Utils.hpp" + +#include "ConferenceInfoListModel.hpp" +#include "ConferenceInfoModel.hpp" + +// ============================================================================= + +ConferenceInfoMapModel::ConferenceInfoMapModel (QObject *parent) : QAbstractListModel(parent) { + auto conferenceInfos = CoreManager::getInstance()->getCore()->getConferenceInformationList(); + for(auto conferenceInfo : conferenceInfos){ + auto conferenceInfoModel = ConferenceInfoModel::create( conferenceInfo ); + QDate t = conferenceInfoModel->getDateTime().date(); + if( !mMappedList.contains(t)) + mMappedList[t] = new ConferenceInfoListModel(); + mMappedList[t]->add(conferenceInfoModel); + } +} + +int ConferenceInfoMapModel::rowCount (const QModelIndex &) const { + return mMappedList.size(); +} + +QHash ConferenceInfoMapModel::roleNames () const { + QHash roles; + roles[Qt::DisplayRole] = "modelData"; + roles[Qt::DisplayRole + 1] = "date"; + return roles; +} + +QVariant ConferenceInfoMapModel::data (const QModelIndex &index, int role) const { + int row = index.row(); + + if (!index.isValid() || row < 0 || row >= mMappedList.size()) + return QVariant(); + auto it = mMappedList.begin() + row; + + if (role == Qt::DisplayRole) + return QVariant::fromValue(*it); + else if( role == Qt::DisplayRole+1) + return QVariant::fromValue(it.key()); + + return QVariant(); +} + +// ----------------------------------------------------------------------------- diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.hpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.hpp new file mode 100644 index 000000000..68d6047d6 --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoMapModel.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#ifndef _CONFERENCE_INFO_MAP_MODEL_H_ +#define _CONFERENCE_INFO_MAP_MODEL_H_ + +#include +#include +#include + +// ============================================================================= + +class ConferenceInfoListModel; + +class ConferenceInfoMapModel : public QAbstractListModel { + Q_OBJECT + +public: + ConferenceInfoMapModel (QObject *parent = Q_NULLPTR); + + int rowCount (const QModelIndex &index = QModelIndex()) const override; + + QHash roleNames () const override; + QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; + +private: + QMap mMappedList; + +}; +Q_DECLARE_METATYPE(ConferenceInfoMapModel*) +#endif diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp index d5c3f76dd..1710d484e 100644 --- a/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp @@ -45,6 +45,7 @@ #include "components/contact/ContactModel.hpp" #include "components/contact/VcardModel.hpp" #include "components/contacts/ContactsListModel.hpp" +#include "components/conferenceScheduler/ConferenceSchedulerModel.hpp" #include "components/core/CoreHandlers.hpp" #include "components/core/CoreManager.hpp" #include "components/notifier/Notifier.hpp" @@ -75,7 +76,7 @@ using namespace std; std::shared_ptr ConferenceInfoModel::create(std::shared_ptr conferenceInfo){ std::shared_ptr model = std::make_shared(conferenceInfo); if(model){ - //model->mSelf = model; + model->mSelf = model; //chatRoom->addListener(model); return model; }else @@ -85,6 +86,9 @@ std::shared_ptr ConferenceInfoModel::create(std::shared_ptr ConferenceInfoModel::ConferenceInfoModel (QObject * parent) : QObject(parent){ //App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE mConferenceInfo = linphone::Factory::get()->createConferenceInfo(); + auto accountAddress = CoreManager::getInstance()->getCore()->getDefaultAccount()->getContactAddress(); + accountAddress->clean(); + mConferenceInfo->setOrganizer(accountAddress); } ConferenceInfoModel::ConferenceInfoModel (std::shared_ptr conferenceInfo, QObject * parent) : QObject(parent){ @@ -147,6 +151,10 @@ QString ConferenceInfoModel::getUri() const{ return QString::fromStdString(mConferenceInfo->getUri()->asString()); } +bool ConferenceInfoModel::isScheduled() const{ + return mIsScheduled; +} + //------------------------------------------------------------------------------------------------ void ConferenceInfoModel::setDateTime(const QDateTime& dateTime){ @@ -178,3 +186,55 @@ void ConferenceInfoModel::setDescription(const QString& description){ void ConferenceInfoModel::setParticipants(ParticipantListModel * participants){ mConferenceInfo->setParticipants(participants->getParticipants()); } + +void ConferenceInfoModel::setIsScheduled(const bool& on){ + if( mIsScheduled != on){ + mIsScheduled = on; + emit isScheduledChanged(); + } +} + +//------------------------------------------------------------------------------------------------- + +void ConferenceInfoModel::createConference(const int& securityLevel, const int& inviteMode) { + CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = false; + shared_ptr core = CoreManager::getInstance()->getCore(); + static std::shared_ptr conference; + qInfo() << "Conference creation of " << getSubject() << " at " << securityLevel << " security, organized by " << getOrganizer();// and with " << conferenceInfo->getConferenceInfo()->getParticipants().size(); + + if( true || isScheduled()){ + mConferenceSchedulerModel = ConferenceSchedulerModel::create(this); + connect(mConferenceSchedulerModel.get(), &ConferenceSchedulerModel::invitationsSent, this, &ConferenceInfoModel::onInvitationsSent); + + mConferenceSchedulerModel->getConferenceScheduler()->setInfo(mConferenceInfo); + }else{ + auto conferenceParameters = core->createConferenceParams(); + conferenceParameters->enableAudio(true); + conferenceParameters->enableVideo(true); + conferenceParameters->setDescription(mConferenceInfo->getDescription()); + conferenceParameters->setSubject(mConferenceInfo->getSubject()); + conferenceParameters->setStartTime(mConferenceInfo->getDateTime()); + conferenceParameters->setEndTime(mConferenceInfo->getDateTime() + (mConferenceInfo->getDuration() * 60)); + conferenceParameters->enableLocalParticipant(true); + //conferenceParameters->enableOneParticipantConference(true); + /* + if(true) {//Remote + conferenceParameters->setConferenceFactoryUri(core->getDefaultAccount()->getContactAddress()->asStringUriOnly()); + }else + conferenceParameters->setConferenceFactoryUri(nullptr); + */ + conference = core->createConferenceWithParams(conferenceParameters); + + //auto parameters = CoreManager::getInstance()->getCore()->createCallParams(nullptr); + //parameters->enableVideo(true); + //conference->inviteParticipants(mConferenceInfo->getParticipants(), parameters); + } +} + +//------------------------------------------------------------------------------------------------- + + +void ConferenceInfoModel::onInvitationsSent(const std::list> & failedInvitations) { + mConferenceSchedulerModel->getConferenceScheduler()->removeListener(mConferenceSchedulerModel); + emit invitationsSent(); +} \ No newline at end of file diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp index 6cae02ad1..a947ee9ed 100644 --- a/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp @@ -26,8 +26,9 @@ #include class ParticipantListModel; +class ConferenceSchedulerModel; -class ConferenceInfoModel : public QObject{ +class ConferenceInfoModel : public QObject { Q_OBJECT public: @@ -40,6 +41,7 @@ public: Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged) Q_PROPERTY(QString displayNamesToString READ displayNamesToString NOTIFY participantsChanged) Q_PROPERTY(QString uri READ getUri NOTIFY uriChanged) + Q_PROPERTY(bool isScheduled READ isScheduled WRITE setIsScheduled NOTIFY isScheduledChanged) //Q_PROPERTY(participants READ getParticipants WRITE setParticipants NOTIFY participantsChanged) @@ -59,15 +61,25 @@ public: QString getDescription() const; Q_INVOKABLE QString displayNamesToString()const; QString getUri() const; + bool isScheduled() const; void setDateTime(const QDateTime& dateTime); void setDuration(const int& duration); void setSubject(const QString& subject); void setOrganizer(const QString& organizerAddress); void setDescription(const QString& description); + void setIsScheduled(const bool& on); Q_INVOKABLE void setParticipants(ParticipantListModel * participants); +// Tools + Q_INVOKABLE void createConference(const int& securityLevel, const int& inviteMode); + +// SCHEDULER + + //virtual void onStateChanged(const std::shared_ptr & conferenceScheduler, linphone::ConferenceSchedulerState state) override; + virtual void onInvitationsSent(const std::list> & failedInvitations); + signals: void dateTimeChanged(); @@ -77,12 +89,19 @@ signals: void descriptionChanged(); void participantsChanged(); void uriChanged(); + void isScheduledChanged(); + + void conferenceCreated(); + void invitationsSent(); private: std::shared_ptr mConferenceInfo; - + std::shared_ptr mConferenceSchedulerModel = nullptr; + std::weak_ptr mSelf; // For Linphone listener + bool mIsScheduled = true; }; Q_DECLARE_METATYPE(std::shared_ptr) +Q_DECLARE_METATYPE(ConferenceInfoModel*) #endif diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp index ed941c200..4ecda8630 100644 --- a/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp @@ -22,6 +22,7 @@ #include "components/core/CoreManager.hpp" #include "ConferenceInfoListModel.hpp" +#include "ConferenceInfoMapModel.hpp" #include "ConferenceInfoProxyModel.hpp" // ============================================================================= @@ -29,7 +30,7 @@ using namespace std; ConferenceInfoProxyModel::ConferenceInfoProxyModel (QObject *parent) : QSortFilterProxyModel(parent) { - setSourceModel(new ConferenceInfoListModel()); + setSourceModel(new ConferenceInfoMapModel()); sort(0, Qt::DescendingOrder); } @@ -38,10 +39,10 @@ bool ConferenceInfoProxyModel::filterAcceptsRow (int sourceRow, const QModelInde } bool ConferenceInfoProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { - const ConferenceInfoModel *deviceA = sourceModel()->data(left).value(); - const ConferenceInfoModel *deviceB = sourceModel()->data(right).value(); + const ConferenceInfoListModel* deviceA = sourceModel()->data(left).value(); + const ConferenceInfoListModel* deviceB = sourceModel()->data(right).value(); - return deviceA->getDateTime() < deviceB->getDateTime(); + return deviceA->getAt(0)->getDateTime() < deviceB->getAt(0)->getDateTime(); } QVariant ConferenceInfoProxyModel::getAt(int row){ diff --git a/linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.cpp b/linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.cpp new file mode 100644 index 000000000..01de9fed8 --- /dev/null +++ b/linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 "ConferenceSchedulerModel.hpp" + +#include +#include "app/App.hpp" +#include "components/core/CoreManager.hpp" + +// ============================================================================= +std::shared_ptr ConferenceSchedulerModel::create( QObject *parent){ + std::shared_ptr model = std::make_shared(parent); + if(model){ + model->mSelf = model; + model->mConferenceScheduler->addListener(model); + return model; + } + return nullptr; +} + +ConferenceSchedulerModel::ConferenceSchedulerModel (QObject * parent) : QObject(parent){ + App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE + mConferenceScheduler = CoreManager::getInstance()->getCore()->createConferenceScheduler(); +} + +ConferenceSchedulerModel::~ConferenceSchedulerModel () { +} + +std::shared_ptr ConferenceSchedulerModel::getConferenceScheduler(){ + return mConferenceScheduler; +} + +void ConferenceSchedulerModel::onStateChanged(const std::shared_ptr & conferenceScheduler, linphone::ConferenceSchedulerState state) { + emit stateChanged(state); + qWarning() << "ConferenceSchedulerModel::onStateChanged : " << (int)state; + if( state == linphone::ConferenceSchedulerState::Ready) { + std::shared_ptr params = CoreManager::getInstance()->getCore()->createDefaultChatRoomParams(); + params->setBackend(linphone::ChatRoomBackend::Basic); + mConferenceScheduler->sendInvitations(params); + } +} + +void ConferenceSchedulerModel::onInvitationsSent(const std::shared_ptr & conferenceScheduler, const std::list> & failedInvitations) { + emit invitationsSent(failedInvitations); +} \ No newline at end of file diff --git a/linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.hpp b/linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.hpp new file mode 100644 index 000000000..110dae8ad --- /dev/null +++ b/linphone-app/src/components/conferenceScheduler/ConferenceSchedulerModel.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#ifndef CONFERENCE_SCHEDULER_MODEL_H_ +#define CONFERENCE_SCHEDULER_MODEL_H_ + +#include +#include +#include + +class ConferenceSchedulerModel : public QObject + , public linphone::ConferenceSchedulerListener +{ + Q_OBJECT + +public: + static std::shared_ptr create(QObject *parent = Q_NULLPTR); + ConferenceSchedulerModel (QObject * parent = nullptr); + ~ConferenceSchedulerModel (); + std::shared_ptr getConferenceScheduler(); + + virtual void onStateChanged(const std::shared_ptr & conferenceScheduler, linphone::ConferenceSchedulerState state) override; + virtual void onInvitationsSent(const std::shared_ptr & conferenceScheduler, const std::list> & failedInvitations) override; + +signals: + void stateChanged(linphone::ConferenceSchedulerState state); + void invitationsSent(const std::list> & failedInvitations); + +private: + std::shared_ptr mConferenceScheduler; + std::weak_ptr mSelf; // Used for Linphone Listener + +}; + +Q_DECLARE_METATYPE(std::shared_ptr) + +#endif diff --git a/linphone-app/src/components/content/ContentModel.cpp b/linphone-app/src/components/content/ContentModel.cpp index 3b6b6011b..6ad886e17 100644 --- a/linphone-app/src/components/content/ContentModel.cpp +++ b/linphone-app/src/components/content/ContentModel.cpp @@ -87,6 +87,13 @@ QString ContentModel::getUtf8Text() const{ return QString::fromStdString(mContent->getUtf8Text()); } +ConferenceInfoModel * ContentModel::getConferenceInfoModel(){ + if( !mConferenceInfoModel && isIcalendar()){ + mConferenceInfoModel = ConferenceInfoModel::create(linphone::Factory::get()->createConferenceInfoFromIcalendarContent(mContent)); + } + return mConferenceInfoModel.get(); +} + void ContentModel::setFileOffset(quint64 fileOffset){ if( mFileOffset != fileOffset) { mFileOffset = fileOffset; @@ -109,6 +116,7 @@ void ContentModel::setWasDownloaded(bool wasDownloaded){ void ContentModel::setContent(std::shared_ptr content){ mContent = content; emit nameChanged(); + mConferenceInfoModel = nullptr; if(isFile() || isFileEncrypted() || isFileTransfer() ){ QString path = Utils::coreStringToAppString(mContent->getFilePath()); if (!path.isEmpty()) diff --git a/linphone-app/src/components/content/ContentModel.hpp b/linphone-app/src/components/content/ContentModel.hpp index e382c8907..386e3c90d 100644 --- a/linphone-app/src/components/content/ContentModel.hpp +++ b/linphone-app/src/components/content/ContentModel.hpp @@ -29,6 +29,8 @@ #include #include "components/chat-events/ChatMessageModel.hpp" +class ChatMessageModel; +class ConferenceInfoModel; class ContentModel : public QObject{ Q_OBJECT @@ -44,6 +46,7 @@ public: Q_PROPERTY(bool wasDownloaded MEMBER mWasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged) Q_PROPERTY(QString filePath READ getFilePath CONSTANT) Q_PROPERTY(ChatMessageModel * chatMessageModel READ getChatMessageModel CONSTANT) + Q_PROPERTY(ConferenceInfoModel * conferenceInfoModel READ getConferenceInfoModel CONSTANT) Q_PROPERTY(QString text READ getUtf8Text CONSTANT) std::shared_ptr getContent()const; @@ -54,6 +57,7 @@ public: QString getThumbnail() const; QString getFilePath() const; QString getUtf8Text() const; + ConferenceInfoModel * getConferenceInfoModel();//Create a conference Info if not set void setFileOffset(quint64 fileOffset); void setThumbnail(const QString& data); @@ -93,6 +97,7 @@ private: std::shared_ptr mContent; ChatMessageModel* mChatMessageModel; ChatMessageModel::AppDataManager mAppData; // Used if there is no Chat Message model set. + std::shared_ptr mConferenceInfoModel; }; Q_DECLARE_METATYPE(std::shared_ptr) diff --git a/linphone-app/src/components/core/CoreHandlers.cpp b/linphone-app/src/components/core/CoreHandlers.cpp index 9422428ec..2dc4af776 100644 --- a/linphone-app/src/components/core/CoreHandlers.cpp +++ b/linphone-app/src/components/core/CoreHandlers.cpp @@ -325,7 +325,32 @@ void CoreHandlers::onEcCalibrationResult( } //------------------------------ CONFERENCE INFO +void CoreHandlers::onConferenceInfoReceived(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo) { + qWarning() << "onConferenceInfoReceived"; +/* + qWarning() << "onConferenceInfoReceived : sending invitation only for known participants (API fail? this should be done from SDK)"; + qWarning() << "onConferenceInfoReceived : Duration: " << conferenceInfo->getDuration(); + + for(auto participant : conferenceInfo->getParticipants()){ + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list> participants; + std::shared_ptr chatRoom; + chatRoom = core->searchChatRoom(params, conferenceInfo->getOrganizer() + , participant + , participants); + if(chatRoom) { + auto timeLine = CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(chatRoom, true); + if(timeLine) + timeLine->sendMessage("Conference invitation : " +QString::fromStdString(conferenceInfo->getUri()->asString())); + else + qWarning() << "Cannot use a timeline for invitation"; + }else + qWarning() << "Cannot use a chatroom for invitation"; + } + */ +} +/* void CoreHandlers::onConferenceInfoCreated(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo){ qWarning() << "onConferenceInfoCreated : sending invitation only for known participants (API fail? this should be done from SDK)"; qWarning() << "onConferenceInfoCreated : Duration: " << conferenceInfo->getDuration(); @@ -358,4 +383,5 @@ void CoreHandlers::onConferenceInfoParticipantSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant, linphone::ConferenceInfoError error){ qWarning() << "onConferenceInfoParticipantError"; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/linphone-app/src/components/core/CoreHandlers.hpp b/linphone-app/src/components/core/CoreHandlers.hpp index 05c32be87..7b8952fcb 100644 --- a/linphone-app/src/components/core/CoreHandlers.hpp +++ b/linphone-app/src/components/core/CoreHandlers.hpp @@ -186,13 +186,14 @@ private: ) override; // Conference Info + virtual void onConferenceInfoReceived(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo) override; + /* virtual void onConferenceInfoCreated(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo); virtual void onConferenceInfoOnSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo); virtual void onConferenceInfoParticipantSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant); virtual void onConferenceInfoParticipantError(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant, linphone::ConferenceInfoError error); + */ - - // --------------------------------------------------------------------------- }; #endif // CORE_HANDLERS_H_ diff --git a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp index 1f284946c..f5183fd50 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp @@ -19,6 +19,7 @@ */ #include +#include #include "app/App.hpp" @@ -34,6 +35,7 @@ ParticipantDeviceListModel::ParticipantDeviceListModel (std::shared_ptr(device, false); connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged); + connect(this, &ParticipantDeviceListModel::participantDeviceMediaChanged, deviceModel.get(), &ParticipantDeviceModel::videoEnabledChanged); mList << deviceModel; } } @@ -42,26 +44,30 @@ ParticipantDeviceListModel::ParticipantDeviceListModel (CallModel * callModel, Q if(callModel && callModel->isConference()) { mCallModel = callModel; auto conferenceModel = callModel->getConferenceModel(); - auto meDevices = conferenceModel->getConference()->getMe()->getDevices(); - if(meDevices.size() > 0) - mList << std::make_shared(meDevices.front(), true);// Add Me in device list - else - mList << std::make_shared(nullptr, true); + /* + mList << std::make_shared(callModel, true);// Add Me in device list + qWarning() << "Me devices : " << conferenceModel->getConference()->getMe()->getDevices().size(); +// auto meDevices = conferenceModel->getConference()->getMe()->getDevices(); + // if(meDevices.size() > 0) + std::list> devices = conferenceModel->getConference()->getParticipantDeviceList(); - for(auto device : devices){ - auto deviceModel = std::make_shared(device, false); - connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged); - mList << deviceModel; - } + updateDevices(devices); + qWarning() << "Instanciate Participant Device list model with " << mList.size() << " devices"; + */ connect(conferenceModel.get(), &ConferenceModel::participantDeviceAdded, this, &ParticipantDeviceListModel::onParticipantDeviceAdded); + connect(conferenceModel.get(), &ConferenceModel::participantDeviceRemoved, this, &ParticipantDeviceListModel::onParticipantDeviceRemoved); + connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaChanged, this, &ParticipantDeviceListModel::onParticipantDeviceMediaChanged); + connect(conferenceModel.get(), &ConferenceModel::conferenceStateChanged, this, &ParticipantDeviceListModel::onConferenceStateChanged); } } int ParticipantDeviceListModel::rowCount (const QModelIndex &index) const{ + qWarning() << "rowCount: " << mList.count(); return mList.count(); } int ParticipantDeviceListModel::count(){ + qWarning() << "count: " << mList.count(); return mList.count(); } @@ -72,12 +78,43 @@ void ParticipantDeviceListModel::updateDevices(std::shared_ptr(device, false); connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged); + connect(this, &ParticipantDeviceListModel::participantDeviceMediaChanged, deviceModel.get(), &ParticipantDeviceModel::videoEnabledChanged); mList << deviceModel; } endResetModel(); + emit countChanged(); emit layoutChanged(); } +void ParticipantDeviceListModel::updateDevices(const std::list>& devices, const bool& isMe){ + QList> devicesToAdd; + //auto meDevices = mCallModel->getConferenceModel()->getConference()->getMe()->getDevices(); + for(auto device : devices){ + auto deviceAddress = device->getAddress(); + //bool isMe = false; + //for(auto meDevice : meDevices) + //isMe |= meDevice->getAddress() == deviceAddress; + //if( !isMe) { + auto exist = std::find_if(mList.begin(), mList.end(), [deviceAddress](const std::shared_ptr& activeDevice){ + return deviceAddress == activeDevice->getDevice()->getAddress(); + }); + if(exist == mList.end()){ + auto deviceModel = std::make_shared(device, isMe); + connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged); + connect(this, &ParticipantDeviceListModel::participantDeviceMediaChanged, deviceModel.get(), &ParticipantDeviceModel::videoEnabledChanged); + devicesToAdd << deviceModel; + } + //} + } + if(devicesToAdd.size() > 0){ + int row = mList.count(); + beginInsertRows(QModelIndex(), row, row+devicesToAdd.size()-1); + mList << devicesToAdd; + endInsertRows(); + emit countChanged(); + } +} + QHash ParticipantDeviceListModel::roleNames () const { QHash roles; roles[Qt::DisplayRole] = "$participantDevice"; @@ -124,37 +161,79 @@ void ParticipantDeviceListModel::onSecurityLevelChanged(std::shared_ptr & participantDevice){ + qWarning() << "Adding participant"; auto conferenceModel = mCallModel->getConferenceModel(); std::list> devices = conferenceModel->getConference()->getParticipantDeviceList(); for(auto realParticipantDevice : devices){ if( realParticipantDevice == participantDevice){ int row = mList.count(); beginInsertRows(QModelIndex(), row, row); - auto deviceModel = std::make_shared(realParticipantDevice, this); + auto deviceModel = std::make_shared(realParticipantDevice, false); connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged); + connect(this, &ParticipantDeviceListModel::participantDeviceMediaChanged, deviceModel.get(), &ParticipantDeviceModel::videoEnabledChanged); mList << deviceModel; endInsertRows(); - emit layoutChanged(); + emit countChanged(); + //emit layoutChanged(); return; } } qWarning() << "No participant device found from const linphone::ParticipantDevice at onParticipantDeviceAdded"; } + void ParticipantDeviceListModel::onParticipantDeviceRemoved(const std::shared_ptr & participantDevice){ + qWarning() << "Removing participant"; int row = 0; for(auto device : mList){ if( device->getDevice() == participantDevice){ removeRow(row); - emit layoutChanged(); + emit countChanged(); + //emit layoutChanged(); return; } ++row; } qWarning() << "No participant device found from const linphone::ParticipantDevice at onParticipantDeviceRemoved"; } + void ParticipantDeviceListModel::onParticipantDeviceJoined(const std::shared_ptr & participantDevice){ qWarning() << "onParticipantDeviceJoined is not yet implemented. Current participants count: " << mList.size(); } + void ParticipantDeviceListModel::onParticipantDeviceLeft(const std::shared_ptr & participantDevice){ qWarning() << "onParticipantDeviceLeft is not yet implemented. Current participants count: " << mList.size(); +} + +void ParticipantDeviceListModel::onParticipantDeviceMediaChanged(const std::shared_ptr & participantDevice) { + emit participantDeviceMediaChanged(); +} +void ParticipantDeviceListModel::onConferenceStateChanged(linphone::Conference::State newState){ + if(newState == linphone::Conference::State::Created){ + if(mCallModel && mCallModel->isConference()) { + auto conferenceModel = mCallModel->getConferenceModel(); + updateDevices(mCallModel->getConferenceModel()->getConference()->getMe()->getDevices(), true); + updateDevices(conferenceModel->getConference()->getParticipantDeviceList(), false); + } + + /* + auto devices = mCallModel->getConferenceModel()->getConference()->getMe()->getDevices(); + if(devices.size() > 0 && mList.size() == 1){ + //qWarning() << "Adding Me in list. Count=" << mList.size(); + beginInsertRows(QModelIndex(), 0, 0); + mList.push_front(std::make_shared(mCallModel, true));// Add Me in device list + endInsertRows(); + emit countChanged(); + emit layoutChanged(); + qWarning() << "M added in list. Count=" << mList.size() << ".\n\tConfVideo is enabled:" << mCallModel->getConferenceModel()->getConference()->getCurrentParams()->videoEnabled() + << "\n\tCallVideo is enabled: " << mCallModel->getVideoEnabled(); + }else + qWarning() << "Me cannot be add : no Me device."; + }else { + if(!mCallModel) + qWarning() << "Cannot add me : no call."; + else + qWarning() << "Cannot add me : No in conf."; + } + */ + } } \ No newline at end of file diff --git a/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp b/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp index 061f18580..99d31650e 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp @@ -43,6 +43,7 @@ public: int count(); void updateDevices(std::shared_ptr participant); + void updateDevices(const std::list>& devices, const bool& isMe); virtual QHash roleNames () const override; virtual QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -54,9 +55,13 @@ public slots: void onParticipantDeviceRemoved(const std::shared_ptr & participantDevice); void onParticipantDeviceJoined(const std::shared_ptr & participantDevice); void onParticipantDeviceLeft(const std::shared_ptr & participantDevice); + void onParticipantDeviceMediaChanged(const std::shared_ptr & participantDevice); + void onConferenceStateChanged(linphone::Conference::State newState); signals: void securityLevelChanged(std::shared_ptr device); + void countChanged(); + void participantDeviceMediaChanged(); private: bool removeRow (int row, const QModelIndex &parent = QModelIndex()); diff --git a/linphone-app/src/components/participant/ParticipantDeviceModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceModel.cpp index f63db4c05..4fd231596 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceModel.cpp @@ -28,8 +28,17 @@ // ============================================================================= ParticipantDeviceModel::ParticipantDeviceModel (std::shared_ptr device, const bool& isMe, QObject *parent) : QObject(parent) { + App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE mIsMe = isMe; mParticipantDevice = device; + mCall = nullptr; +} + +ParticipantDeviceModel::ParticipantDeviceModel (CallModel * call, const bool& isMe, QObject *parent) : QObject(parent) { + App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE + mIsMe = isMe; + mCall = call; + connect(call, &CallModel::statusChanged, this, &ParticipantDeviceModel::videoEnabledChanged); } // ----------------------------------------------------------------------------- @@ -60,8 +69,9 @@ std::shared_ptr ParticipantDeviceModel::getDevice( } bool ParticipantDeviceModel::isVideoEnabled() const{ - return mParticipantDevice && (mParticipantDevice->getVideoDirection() == linphone::MediaDirection::SendRecv - || mParticipantDevice->getVideoDirection() == linphone::MediaDirection::SendOnly); + if(mParticipantDevice) + qWarning() << "VideoEnabled: " << (int)mParticipantDevice->getStreamAvailability(linphone::StreamType::Video); + return mParticipantDevice && mParticipantDevice->getStreamAvailability(linphone::StreamType::Video); } bool ParticipantDeviceModel::isMe() const{ diff --git a/linphone-app/src/components/participant/ParticipantDeviceModel.hpp b/linphone-app/src/components/participant/ParticipantDeviceModel.hpp index 7542431db..98a01664d 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceModel.hpp +++ b/linphone-app/src/components/participant/ParticipantDeviceModel.hpp @@ -28,11 +28,14 @@ #include #include +class CallModel; + class ParticipantDeviceModel : public QObject { Q_OBJECT public: ParticipantDeviceModel (std::shared_ptr device, const bool& isMe = false, QObject *parent = nullptr); + ParticipantDeviceModel (CallModel * call, const bool& isMe = true, QObject *parent = nullptr); Q_PROPERTY(QString name READ getName CONSTANT) Q_PROPERTY(QString address READ getAddress CONSTANT) @@ -63,6 +66,7 @@ private: bool mIsMe = false; std::shared_ptr mParticipantDevice; + CallModel * mCall; }; diff --git a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp index a5f7e8c3a..2e77e1ff8 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp @@ -61,12 +61,26 @@ ParticipantDeviceModel *ParticipantDeviceProxyModel::getAt(int row){ CallModel * ParticipantDeviceProxyModel::getCallModel() const{ return mCallModel; } + +int ParticipantDeviceProxyModel::getCount() const{ + ParticipantDeviceListModel* devices = dynamic_cast(sourceModel()); + if(devices) + return devices->rowCount(); + else + return 0; +} void ParticipantDeviceProxyModel::setCallModel(CallModel * callModel){ mCallModel = callModel; - setSourceModel(new ParticipantDeviceListModel(mCallModel)); + auto sourceModel = new ParticipantDeviceListModel(mCallModel); + connect(sourceModel, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::countChanged); + setSourceModel(sourceModel); + emit countChanged(); } - + void ParticipantDeviceProxyModel::setParticipant(ParticipantModel * participant){ - setSourceModel(participant->getParticipantDevices().get()); + auto sourceModel = participant->getParticipantDevices().get(); + connect(sourceModel, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::countChanged); + setSourceModel(sourceModel); + emit countChanged(); } \ No newline at end of file diff --git a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp index d794eabc2..7feebd1c9 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp +++ b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp @@ -39,10 +39,12 @@ class ParticipantDeviceProxyModel : public QSortFilterProxyModel { public: Q_PROPERTY(CallModel * callModel READ getCallModel WRITE setCallModel NOTIFY callModelChanged) + Q_PROPERTY(int count READ getCount NOTIFY countChanged) ParticipantDeviceProxyModel (QObject *parent = nullptr); Q_INVOKABLE ParticipantDeviceModel* getAt(int row); CallModel * getCallModel() const; + Q_INVOKABLE int getCount() const; void setCallModel(CallModel * callModel); @@ -50,6 +52,7 @@ public: signals: void callModelChanged(); + void countChanged(); protected: virtual bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override; diff --git a/linphone-app/src/components/timeline/TimelineListModel.cpp b/linphone-app/src/components/timeline/TimelineListModel.cpp index b7af65897..b22efadcc 100644 --- a/linphone-app/src/components/timeline/TimelineListModel.cpp +++ b/linphone-app/src/components/timeline/TimelineListModel.cpp @@ -384,11 +384,11 @@ void TimelineListModel::onCallStateChanged (const std::shared_ptr &call){ - std::shared_ptr core = CoreManager::getInstance()->getCore(); - std::shared_ptr params = core->createDefaultChatRoomParams(); - std::list> participants; - -// Find all chat rooms with local address. If not, create one. + std::shared_ptr core = CoreManager::getInstance()->getCore(); + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list> participants; + if( !call->getConference() && false ){ + // Find all chat rooms with local address. If not, create one. bool isOutgoing = (call->getDir() == linphone::Call::Dir::Outgoing) ; bool found = false; auto callLog = call->getCallLog(); @@ -429,6 +429,7 @@ void TimelineListModel::onCallCreated(const std::shared_ptr &cal participants << Utils::coreStringToAppString(remoteAddress->asStringUriOnly()); CoreManager::getInstance()->getCallsListModel()->createChatRoom("", (createSecureChatRoom?1:0), callLocalAddress, participants, isOutgoing); } + } } /* diff --git a/linphone-app/ui/modules/Common/Form/Mosaic.qml b/linphone-app/ui/modules/Common/Form/Mosaic.qml index a11a0e8c4..4115100fa 100644 --- a/linphone-app/ui/modules/Common/Form/Mosaic.qml +++ b/linphone-app/ui/modules/Common/Form/Mosaic.qml @@ -164,6 +164,8 @@ ColumnLayout{ removeDisplaced: defaultTransition populate:defaultTransition + onItemCountChanged: console.log("Mosaic "+model+" itemCount: " +itemCount +" => " + (model.count ? " count="+model.count :( model.length ? " length":" no" ))) + } /* ListView{ diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml new file mode 100644 index 000000000..59348f782 --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml @@ -0,0 +1,143 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +import Clipboard 1.0 +import Common 1.0 +import Linphone 1.0 + +import Common.Styles 1.0 +import Linphone.Styles 1.0 +import TextToSpeech 1.0 +import Utils 1.0 +import Units 1.0 +import UtilsCpp 1.0 +import LinphoneEnums 1.0 + +import ColorsList 1.0 + +import 'Message.js' as Logic + +// ============================================================================= + +Loader{ + id: mainItem + property ContentModel contentModel + property ConferenceInfoModel conferenceInfoModel: contentModel && active ? contentModel.conferenceInfoModel : null + property int maxWidth : parent.width + property int fitHeight: active && item ? item.fitHeight + ChatCalendarMessageStyle.heightMargin*2 : 0 + property int fitWidth: active && item ? Math.max(item.fitWidth, maxWidth/2) + ChatCalendarMessageStyle.widthMargin*2 : 0 + width: parent.width + height: fitHeight + + property font customFont : SettingsModel.textMessageFont + active: (mainItem.contentModel && mainItem.contentModel.isIcalendar()) || (!mainItem.contentModel && mainItem.conferenceInfoModel) + + sourceComponent: MouseArea{ + id: loadedItem + property int fitHeight: layout.fitHeight + property int fitWidth: layout.fitWidth + + anchors.fill: parent + anchors.leftMargin: ChatCalendarMessageStyle.widthMargin + anchors.rightMargin: ChatCalendarMessageStyle.widthMargin + anchors.topMargin: ChatCalendarMessageStyle.heightMargin + anchors.bottomMargin: ChatCalendarMessageStyle.heightMargin + + clip: false + + cursorShape: Qt.ArrowCursor + hoverEnabled: true + onClicked: CallsListModel.launchVideoCall(mainItem.conferenceInfoModel.uri, '', 0) + + ColumnLayout{ + id: layout + property int fitHeight: Layout.minimumHeight + property int fitWidth: Layout.minimumWidth + anchors.fill: parent + spacing: 0 + RowLayout { + Layout.fillWidth: true + Layout.preferredWidth: parent.width // Need this because fillWidth is not enough... + Layout.preferredHeight: ChatCalendarMessageStyle.schedule.iconSize + spacing: 10 + RowLayout { + id: scheduleRow + Layout.fillWidth: true + Layout.preferredHeight: ChatCalendarMessageStyle.schedule.iconSize + Layout.leftMargin: 5 + spacing: ChatCalendarMessageStyle.schedule.spacing + + Icon{ + icon: ChatCalendarMessageStyle.schedule.icon + iconSize: ChatCalendarMessageStyle.schedule.iconSize + overwriteColor: ChatCalendarMessageStyle.schedule.color + } + + Text { + id: conferenceTime + Layout.fillWidth: true + Layout.minimumWidth: implicitWidth + verticalAlignment: Qt.AlignVCenter + color: ChatCalendarMessageStyle.schedule.color + elide: Text.ElideRight + font.pointSize: ChatCalendarMessageStyle.schedule.pointSize + text: Qt.formatDateTime(mainItem.conferenceInfoModel.dateTime, 'hh:mm') + +' - ' +Qt.formatDateTime(mainItem.conferenceInfoModel.endDateTime, 'hh:mm') + } + } + Item{ + Layout.fillWidth: true + Layout.fillHeight: true + } + Text{ + Layout.fillHeight: true + Layout.minimumWidth: implicitWidth + Layout.preferredWidth: implicitWidth + Layout.rightMargin: 10 + verticalAlignment: Qt.AlignVCenter + color: ChatCalendarMessageStyle.schedule.color + elide: Text.ElideRight + font.pointSize: ChatCalendarMessageStyle.schedule.pointSize + text: 'Organisateur : ' +UtilsCpp.getDisplayName(mainItem.conferenceInfoModel.organizer) + } + } + Text{ + id: title + Layout.fillWidth: true + Layout.minimumWidth: implicitWidth + Layout.topMargin: 10 + Layout.leftMargin: 10 + Layout.alignment: Qt.AlignRight + color: ChatCalendarMessageStyle.subject.color + font.pointSize: ChatCalendarMessageStyle.subject.pointSize + font.weight: Font.Bold + text: mainItem.conferenceInfoModel.subject + } + RowLayout { + id: participantsRow + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: 5 + + spacing: ChatCalendarMessageStyle.participants.spacing + + Icon{ + icon: ChatCalendarMessageStyle.participants.icon + iconSize: ChatCalendarMessageStyle.participants.iconSize + overwriteColor: ChatCalendarMessageStyle.participants.color + } + + Text { + id: participantsList + Layout.fillWidth: true + Layout.minimumWidth: implicitWidth + color: ChatCalendarMessageStyle.participants.color + elide: Text.ElideRight + font.pointSize: ChatCalendarMessageStyle.participants.pointSize + text: mainItem.conferenceInfoModel.displayNamesToString + } + } + } + } +} + diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml b/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml index c1bfe93bc..ac18f583c 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml @@ -20,8 +20,8 @@ Column{ id: mainItem property ContentModel contentModel - property int fitHeight: message.fitHeight + fileMessage.fitHeight + audioMessage.fitHeight - property int fitWidth: message.fitWidth + fileMessage.fitWidth + audioMessage.fitWidth + property int fitHeight: calendarMessage.fitHeight + message.fitHeight + fileMessage.fitHeight + audioMessage.fitHeight + property int fitWidth: calendarMessage.fitWidth + message.fitWidth + fileMessage.fitWidth + audioMessage.fitWidth property color backgroundColor property string lastTextSelected property alias textColor: message.color @@ -29,6 +29,7 @@ Column{ signal rightClicked() + property int maxWidth height: fitHeight anchors.left: parent ? parent.left : undefined anchors.right: parent ? parent.right : undefined @@ -37,6 +38,12 @@ Column{ property bool isOutgoing : contentModel && contentModel.chatMessageModel && (contentModel.chatMessageModel.isOutgoing || contentModel.chatMessageModel.state == LinphoneEnums.ChatMessageStateIdle); + ChatCalendarMessage{ + id: calendarMessage + contentModel: mainItem.contentModel + width: parent.width + maxWidth: mainItem.maxWidth + } ChatAudioMessage{ id: audioMessage contentModel: mainItem.contentModel @@ -54,4 +61,4 @@ Column{ color: isOutgoing ? ChatStyle.entry.message.outgoing.text.color : ChatStyle.entry.message.incoming.text.color onRightClicked: mainItem.rightClicked() } -} \ No newline at end of file +} diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml index f919c4241..a441239ce 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml @@ -27,7 +27,7 @@ Row { signal copySelectionDone() signal forwardClicked() height: fitHeight - visible: contentModel && (contentModel.isFile() || contentModel.isFileTransfer()) && !contentModel.isVoiceRecording() + visible: contentModel && !contentModel.isIcalendar() && (contentModel.isFile() || contentModel.isFileTransfer()) && !contentModel.isVoiceRecording() // --------------------------------------------------------------------------- // File message. // --------------------------------------------------------------------------- diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml index c2919fd75..5e68a4469 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml @@ -50,7 +50,7 @@ Item { id: headerText height: icon.height verticalAlignment: Qt.AlignVCenter - // Anonymized forward : this is wanted. + // Anonymized forward : do not get display name, this is wanted. //property string forwardInfo: mainChatMessageModel ? mainChatMessageModel.getForwardInfoDisplayName : '' //: 'Forwarded' : Header on a message that contains a forward. text: qsTr('Forwarded')// + (forwardInfo ? ' : ' +forwardInfo : '') diff --git a/linphone-app/ui/modules/Linphone/Chat/Message.qml b/linphone-app/ui/modules/Linphone/Chat/Message.qml index 96bbe341c..6281a127a 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Message.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Message.qml @@ -104,6 +104,7 @@ Item { interactive: false delegate: ChatContent{ + maxWidth: container.width contentModel: modelData onFitWidthChanged:{ rectangle.updateWidth() diff --git a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatCalendarMessageStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatCalendarMessageStyle.qml new file mode 100644 index 000000000..19ae72fad --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatCalendarMessageStyle.qml @@ -0,0 +1,82 @@ +pragma Singleton +import QtQml 2.2 + +import Units 1.0 +import ColorsList 1.0 + +// ============================================================================= + +QtObject { + property string sectionName : 'ChatCalendarMessage' + property int heightMargin: 5 + property int widthMargin: 5 + property int minWidth: 300 + + property int actionButtonsSize: 36 + property int avatarSize: 30 + property int deleteButtonSize: 22 + property int height: 50 + property int leftMargin: 40 + property int bottomMargin: 10 + property int presenceLevelSize: 12 + property int rightMargin: 25 + property int spacing: 15 + + property QtObject backgroundColor: QtObject { + property color normal: ColorsList.add(sectionName+'_conference_bg_n', 'conference_bg').color + property color hovered: ColorsList.add(sectionName+'_conference_bg_h', 'g10').color + } + + property QtObject border: QtObject { + property color color: ColorsList.add(sectionName+'_conference_border', 'f').color + property int width: 1 + } + + property QtObject indicator: QtObject { + property color color: ColorsList.add(sectionName+'_conference_indicator', 'i').color + property int width: 5 + } + + property QtObject schedule: QtObject { + property int spacing: 0 + property int pointSize: Units.dp * 10 + property string icon : 'schedule_custom' + property int iconSize: 30 + property color color: ColorsList.add(sectionName+'_schedule', 'j').color + } + property QtObject subject: QtObject { + property int spacing: 5 + property int pointSize: Units.dp * 11 + property color color: ColorsList.add(sectionName+'_subject', 'j').color + } + property QtObject participants: QtObject { + property int spacing: 5 + property int pointSize: Units.dp * 10 + property string icon : 'calendar_participants_custom' + property int iconSize: 30 + property color color: ColorsList.add(sectionName+'_participants', 'j').color + } + + property QtObject organizer: QtObject { + property color color: ColorsList.add(sectionName+'_conference_organizer', 'j').color + property int pointSize: Units.dp * 10 + property int width: 220 + } + + + + /* + property color color: ColorsList.add(sectionName, 'q').color + property QtObject header: QtObject{ + property color color: ColorsList.add(sectionName+'_header', 'h').color + property int pointSizeOffset: -3 + property QtObject forwardIcon: QtObject{ + property string icon : 'menu_forward_custom' + property int iconSize: 22 + } + } + + property int padding: 8 + */ + +} diff --git a/linphone-app/ui/modules/Linphone/Styles/qmldir b/linphone-app/ui/modules/Linphone/Styles/qmldir index b0d90c152..246137b5e 100644 --- a/linphone-app/ui/modules/Linphone/Styles/qmldir +++ b/linphone-app/ui/modules/Linphone/Styles/qmldir @@ -13,6 +13,7 @@ singleton ChatStyle 1.0 Chat/ChatStyle.qml singleton ChatAudioMessageStyle 1.0 Chat/ChatAudioMessageStyle.qml singleton ChatAudioPreviewStyle 1.0 Chat/ChatAudioPreviewStyle.qml singleton ChatFilePreviewStyle 1.0 Chat/ChatFilePreviewStyle.qml +singleton ChatCalendarMessageStyle 1.0 Chat/ChatCalendarMessageStyle.qml singleton ChatForwardMessageStyle 1.0 Chat/ChatForwardMessageStyle.qml singleton ChatReplyMessageStyle 1.0 Chat/ChatReplyMessageStyle.qml diff --git a/linphone-app/ui/modules/Linphone/qmldir b/linphone-app/ui/modules/Linphone/qmldir index d9f533348..95f2a6b98 100644 --- a/linphone-app/ui/modules/Linphone/qmldir +++ b/linphone-app/ui/modules/Linphone/qmldir @@ -17,6 +17,7 @@ CallStatistics 1.0 Calls/CallStatistics.qml Chat 1.0 Chat/Chat.qml ChatAudioMessage 1.0 Chat/ChatAudioMessage.qml ChatAudioPreview 1.0 Chat/ChatAudioPreview.qml +ChatCalendarMessage 1.0 Chat/ChatCalendarMessage.qml ChatMessagePreview 1.0 Chat/ChatMessagePreview.qml ChatForwardMessage 1.0 Chat/ChatForwardMessage.qml ChatReplyMessage 1.0 Chat/ChatReplyMessage.qml diff --git a/linphone-app/ui/views/App/Calls/EndedCall.qml b/linphone-app/ui/views/App/Calls/EndedCall.qml index 72fa5710a..128694ccb 100644 --- a/linphone-app/ui/views/App/Calls/EndedCall.qml +++ b/linphone-app/ui/views/App/Calls/EndedCall.qml @@ -68,7 +68,7 @@ Rectangle { image: _sipAddressObserver.contact && _sipAddressObserver.contact.vcard.avatar username: contactDescription.username - height: Logic.computeAvatarSize(CallStyle.container.avatar.maxSize) + height: Logic.computeAvatarSize(container, CallStyle.container.avatar.maxSize) width: height } } diff --git a/linphone-app/ui/views/App/Calls/Incall.js b/linphone-app/ui/views/App/Calls/Incall.js index 7f0b778eb..6377bc736 100644 --- a/linphone-app/ui/views/App/Calls/Incall.js +++ b/linphone-app/ui/views/App/Calls/Incall.js @@ -28,7 +28,7 @@ // ============================================================================= -function computeAvatarSize (maxSize) { +function computeAvatarSize (container, maxSize) { var height = container.height var width = container.width @@ -71,39 +71,39 @@ function handleStatusChanged (status) { } } -function handleVideoRequested () { - var call = incall.call +function handleVideoRequested (call) { + console.log("handleVideoRequested") if (window.virtualWindowVisible || !Linphone.SettingsModel.videoSupported) { call.rejectVideoRequest() return } - + /* // Close dialog after 10s. var timeout = Utils.setTimeout(incall, 10000, function () { call.statusChanged.disconnect(endedHandler) window.detachVirtualWindow() call.rejectVideoRequest() }) - + */ // Close dialog if call is ended. var endedHandler = function (status) { if (status === Linphone.CallModel.CallStatusEnded) { - Utils.clearTimeout(timeout) + Utils.clearTimeout(timeout) call.statusChanged.disconnect(endedHandler) window.detachVirtualWindow() } } - call.statusChanged.connect(endedHandler) - +console.log("D") // Ask video to user. window.attachVirtualWindow(Utils.buildDialogUri('ConfirmDialog'), { descriptionText: qsTr('acceptVideoDescription'), }, function (status) { - Utils.clearTimeout(timeout) + //Utils.clearTimeout(timeout) call.statusChanged.disconnect(endedHandler) - + console.log("E: "+status) if (status) { + console.log("TOTO") call.acceptVideoRequest() } else { call.rejectVideoRequest() diff --git a/linphone-app/ui/views/App/Calls/Incall.qml b/linphone-app/ui/views/App/Calls/Incall.qml index fb65c15a8..c06edc4f6 100644 --- a/linphone-app/ui/views/App/Calls/Incall.qml +++ b/linphone-app/ui/views/App/Calls/Incall.qml @@ -45,7 +45,7 @@ Rectangle { onCameraFirstFrameReceived: Logic.handleCameraFirstFrameReceived(width, height) onStatusChanged: Logic.handleStatusChanged (status) - onVideoRequested: Logic.handleVideoRequested() + onVideoRequested: Logic.handleVideoRequested(call) } ColumnLayout { @@ -239,7 +239,7 @@ Rectangle { IncallAvatar { call: incall.call - height: Logic.computeAvatarSize(CallStyle.container.avatar.maxSize) + height: Logic.computeAvatarSize(container, CallStyle.container.avatar.maxSize) width: height } } @@ -261,7 +261,9 @@ Rectangle { width: container.width Component.onDestruction: { resetWindowId() + console.log("Camera incall destroyed") } + Component.onCompleted: console.log("Camera incall completed") } } @@ -406,7 +408,9 @@ Rectangle { isPreview: true Component.onDestruction: { resetWindowId() + console.log("Camera preview incall destroyed") } + Component.onCompleted: console.log("Camera preview incall completed") } } } diff --git a/linphone-app/ui/views/App/Calls/IncallAvatar.qml b/linphone-app/ui/views/App/Calls/IncallAvatar.qml index b666e4407..3e8f6db39 100644 --- a/linphone-app/ui/views/App/Calls/IncallAvatar.qml +++ b/linphone-app/ui/views/App/Calls/IncallAvatar.qml @@ -14,8 +14,9 @@ Avatar { property var participantDeviceModel readonly property var _sipAddressObserver: call ? SipAddressesModel.getSipAddressObserver(call.fullPeerAddress, call.fullLocalAddress) - : SipAddressesModel.getSipAddressObserver(participantDeviceModel.address, '') - readonly property var _username: UtilsCpp.getDisplayName(_sipAddressObserver.peerAddress) + : participantDeviceModel ? SipAddressesModel.getSipAddressObserver(participantDeviceModel.address, '') + : null + readonly property var _username: _sipAddressObserver ? UtilsCpp.getDisplayName(_sipAddressObserver.peerAddress) : '' backgroundColor: CallStyle.container.avatar.backgroundColor foregroundColor: call && call.status === CallModel.CallStatusPaused @@ -30,7 +31,7 @@ Avatar { return null; } - username: call && call.status === CallModel.CallStatusPaused || !_username? '' : _username + username: call && (call.status === CallModel.CallStatusPaused) || !_username? '' : _username Text { anchors.fill: parent @@ -44,6 +45,6 @@ Avatar { text: '❙❙' textFormat: Text.RichText - visible: call && call.status === CallModel.CallStatusPaused + visible: call && (call.status === CallModel.CallStatusPaused) || false } } diff --git a/linphone-app/ui/views/App/Calls/VideoConference.qml b/linphone-app/ui/views/App/Calls/VideoConference.qml index c452267e0..a460bac2a 100644 --- a/linphone-app/ui/views/App/Calls/VideoConference.qml +++ b/linphone-app/ui/views/App/Calls/VideoConference.qml @@ -21,21 +21,31 @@ Rectangle { id: conference property CallModel callModel - + property var _fullscreen: null + /* onCallModelChanged: if(callModel) { grid.setParticipantDevicesMode() }else grid.setTestMode() + */ // --------------------------------------------------------------------------- color: VideoConferenceStyle.backgroundColor - + /* Component.onCompleted: { if(!callModel){ grid.setTestMode() }else grid.setParticipantDevicesMode() } + */ + Connections { + target: callModel + + onCameraFirstFrameReceived: Logic.handleCameraFirstFrameReceived(width, height) + onStatusChanged: Logic.handleStatusChanged (status) + onVideoRequested: Logic.handleVideoRequested(callModel) + } // --------------------------------------------------------------------------- ColumnLayout { @@ -120,6 +130,7 @@ Rectangle { id: grid anchors.fill: parent + property int radius : 8 function setTestMode(){ grid.clear() @@ -142,6 +153,7 @@ Rectangle { id: participantDevices callModel: conference.callModel } + /* property ListModel defaultList : ListModel{} Component.onCompleted: { if( conference.callModel ){ @@ -150,15 +162,20 @@ Rectangle { } } model: defaultList - - + */ + model: participantDevices + onCountChanged: {console.log("Delegate count = "+count+"/"+participantDevices.count)} delegate: Rectangle{ - color: !conference.callModel && gridModel.defaultList.get(index).color ? gridModel.defaultList.get(index).color : '' + id: avatarCell + property ParticipantDeviceModel currentDevice: gridModel.participantDevices.getAt(index) + onCurrentDeviceChanged: console.log("currentDevice changed: " +currentDevice +", me:"+currentDevice.isMe+" ["+index+"]") + color: /*!conference.callModel && gridModel.defaultList.get(index).color ? gridModel.defaultList.get(index).color : */'#AAAAAAAA' //color: gridModel.model.get(index) && gridModel.model.get(index).color ? gridModel.model.get(index).color : '' // modelIndex is a custom index because by Mosaic modelisation, it is not accessible. //color: modelData.color ? modelData.color : '' radius: grid.radius height: grid.cellHeight - 5 width: grid.cellWidth - 5 + Component.onCompleted: console.log("Completed: ["+index+"] " +currentDevice.peerAddress+", isMe:"+currentDevice.isMe) Item { id: container @@ -174,30 +191,60 @@ Rectangle { IncallAvatar { //call: gridModel.participantDevices.get(index).call - participantDeviceModel: gridModel.participantDevices.getAt(index) - height: Logic.computeAvatarSize(CallStyle.container.avatar.maxSize) + participantDeviceModel: avatarCell.currentDevice + height: Logic.computeAvatarSize(container, CallStyle.container.avatar.maxSize) width: height + Component.onCompleted: console.log("Avatar completed"+ " ["+index+"]") + Component.onDestruction: console.log("Avatar destroyed"+ " ["+index+"]") } } - + Loader { + anchors.centerIn: parent + + active: avatarCell.currentDevice && (!avatarCell.currentDevice.videoEnabled || conference._fullscreen) + sourceComponent: avatar + } Loader { id: cameraLoader - anchors.centerIn: parent + //anchors.centerIn: parent + anchors.fill: parent + property bool isVideoEnabled : avatarCell.currentDevice && avatarCell.currentDevice.videoEnabled + property bool t_fullscreen: conference._fullscreen + property bool tCallModel: conference.callModel + property bool resetActive: false + onIsVideoEnabledChanged: console.log("Video is enabled : " +isVideoEnabled + " ["+index+"]") + onT_fullscreenChanged: console.log("_fullscreen changed: " +t_fullscreen+ " ["+index+"]") + onTCallModelChanged: console.log("CallModel changed: " +tCallModel+ " ["+index+"]") - active: conference.callModel && (gridModel.participantDevices.getAt(index).videoEnabled && !_fullscreen) + active: !resetActive && avatarCell.currentDevice && (avatarCell.currentDevice.videoEnabled && !conference._fullscreen) + onActiveChanged: {console.log("Active Changed: "+active+ " ["+index+"]") + if(!active && resetActive){ + resetActive = false + active = true + } + } - sourceComponent: conference.callModel ? gridModel.participantDevices.getAt(index).isMe ? cameraPreview : camera + sourceComponent: avatarCell.currentDevice ? + avatarCell.currentDevice.isMe ? ( true ? cameraPreview : null ) + : camera : null + onSourceComponentChanged: console.log("SourceComponent Changed: "+sourceComponent+ " ["+index+"]") + Component { id: camera Camera { //call: grid.get(modelIndex).call - participantDeviceModel: gridModel.participantDevices.getAt(index) - height: container.height - width: container.width + participantDeviceModel: avatarCell.currentDevice + //height: container.height + //width: container.width + anchors.fill: parent + onRequestNewRenderer: {cameraLoader.resetActive = true} + + Component.onCompleted: console.log("Camera completed"+ " ["+index+"]") + Component.onDestruction: console.log("Camera destroyed"+ " ["+index+"]") } } Component { @@ -205,18 +252,15 @@ Rectangle { Camera { anchors.fill: parent - call: incall.call + //call: incall.call isPreview: true + onRequestNewRenderer: {cameraLoader.resetActive = true} + + Component.onCompleted: console.log("Preview completed"+ " ["+index+"]") + Component.onDestruction: console.log("Preview destroyed"+ " ["+index+"]") } } } - - Loader { - anchors.centerIn: parent - - active: conference.callModel && (!gridModel.participantDevices.getAt(index).videoEnabled || _fullscreen) - sourceComponent: avatar - } } MouseArea{ anchors.fill: parent diff --git a/linphone-app/ui/views/App/Main/Conferences.qml b/linphone-app/ui/views/App/Main/Conferences.qml index 4c32dced7..5f12bcebc 100644 --- a/linphone-app/ui/views/App/Main/Conferences.qml +++ b/linphone-app/ui/views/App/Main/Conferences.qml @@ -27,8 +27,7 @@ ColumnLayout { color: ConferencesStyle.bar.backgroundColor Text{ anchors.verticalCenter: parent.center - anchors.left: parent.left - anchors.right: parent.right + anchors.fill: parent anchors.leftMargin: 40 @@ -77,25 +76,11 @@ ColumnLayout { section { criteria: ViewSection.FullString delegate: sectionHeading - property: 'dateTime' + property: 'date' } model: ConferenceInfoProxyModel{} - - /* ListModel{ - ListElement{date: '2020/12/01'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - ListElement{date: '2020/12/01'; time: '14:00:00';duration: 30;organizerName: 'Moi';subject:'TOTO';participantes: 'Julien' } - ListElement{date: '2020/12/01'; time: '10:10:00';duration: 120;organizerName: 'Henri';subject:'Eskimirbief, mais ou est donc Willy?';participantes: 'Julien'} - ListElement{date: '2020/12/04'; time: '09:00:00';duration: 300;organizerName: 'Houlahoup';subject:'Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam'} - ListElement{date: '2020/12/05'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'1. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - ListElement{date: '2020/12/05'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'2. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - - ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'1. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'2. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'3. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'4. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' } - }*/ // ----------------------------------------------------------------------- // Heading. // ----------------------------------------------------------------------- @@ -144,92 +129,39 @@ ColumnLayout { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - delegate: Rectangle { - id: entry - + delegate: Item { + implicitHeight: calendarGrid.height + ConferencesStyle.conference.bottomMargin anchors { - left: parent ? parent.left : undefined - leftMargin: 0 - right: parent ? parent.right : undefined - rightMargin: 0 - } - radius: 6 - color: ConferencesStyle.conference.backgroundColor.normal - implicitHeight: layout.height + ConferencesStyle.conference.bottomMargin - - // --------------------------------------------------------------------- - MouseArea { - id: mouseArea - - cursorShape: Qt.ArrowCursor - hoverEnabled: true - implicitHeight: layout.height - width: parent.width + parent.anchors.rightMargin - //acceptedButtons: Qt.NoButton - onClicked: CallsListModel.launchVideoCall(modelData.uri, '', 0) - ColumnLayout{ - id: layout - spacing: 0 - width: entry.width + left: parent ? parent.left : undefined + leftMargin: 10 + right: parent ? parent.right : undefined + rightMargin: 10 + } + GridView{ + id: calendarGrid + //anchors.fill: parent + cellWidth: (container.width-20)/2 + cellHeight: 112 + model: modelData + height: cellHeight * ( (count+1) /2) + width: container.width - 20 + delegate:Rectangle { + id: entry + width: calendarGrid.cellWidth -10 + height: calendarGrid.cellHeight -10 + radius: 6 + color: ConferencesStyle.conference.backgroundColor.normal - RowLayout { - RowLayout { - id: scheduleRow - spacing: ConferencesStyle.conference.spacing - - Icon{ - icon: ConferencesStyle.conference.schedule.icon - iconSize: ConferencesStyle.conference.schedule.iconSize - overwriteColor: ConferencesStyle.conference.schedule.color - } - - Text { - Layout.fillWidth: true - color: ConferencesStyle.conference.schedule.color - elide: Text.ElideRight - font.pointSize: ConferencesStyle.conference.schedule.pointSize - text: Qt.formatDateTime(modelData.dateTime, 'yyyy/MM/dd hh:mm') - +', end at: ' +Qt.formatDateTime(modelData.endDateTime, 'yyyy/MM/dd hh:mm') - } - } - Text{ - Layout.fillWidth: true - Layout.alignment: Qt.AlignRight - color: ConferencesStyle.conference.schedule.color - font.pointSize: ConferencesStyle.conference.schedule.pointSize - text: 'Organisateur : ' +UtilsCpp.getDisplayName(modelData.organizer) - } + ChatCalendarMessage{ + id: calendarMessage + conferenceInfoModel: modelData + width: calendarGrid.cellWidth + maxWidth: calendarGrid.cellWidth } - Text{ - Layout.fillWidth: true - Layout.alignment: Qt.AlignRight - color: ConferencesStyle.conference.schedule.color - font.pointSize: ConferencesStyle.conference.schedule.pointSize - text: modelData.subject - } - RowLayout { - id: participantsRow - spacing: ConferencesStyle.conference.spacing - - Icon{ - icon: ConferencesStyle.conference.participants.icon - iconSize: ConferencesStyle.conference.participants.iconSize - overwriteColor: ConferencesStyle.conference.participants.color - } - - Text { - Layout.fillWidth: true - color: ConferencesStyle.conference.participants.color - elide: Text.ElideRight - font.pointSize: ConferencesStyle.conference.participants.pointSize - text: modelData.displayNamesToString - } - } } } } - } } } diff --git a/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml b/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml index 8cc1b228d..195311d4d 100644 --- a/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml +++ b/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml @@ -17,7 +17,13 @@ import ColorsList 1.0 DialogPlus { id: conferenceManager - property ConferenceInfoModel conferenceInfoModel: ConferenceInfoModel{} + property ConferenceInfoModel conferenceInfoModel: ConferenceInfoModel{ + onConferenceCreated: console.log("Conference has been created.") + onInvitationsSent: { + console.log("Conference => invitations sent. Check in log for invite states.") + exit(1) + } + } readonly property int minParticipants: 1 @@ -98,6 +104,7 @@ DialogPlus { } onClicked: { + conferenceInfoModel.isScheduled = scheduledSwitch.checked if( scheduledSwitch.checked){ var startDateTime = new Date() startDateTime.setDate(dateField.getDate()) @@ -110,11 +117,11 @@ DialogPlus { conferenceInfoModel.setParticipants(selectedParticipants.participantListModel) - var callsWindow = App.getCallsWindow() - App.smartShowWindow(callsWindow) - callsWindow.openConference() - CallsListModel.createConference(conferenceInfoModel, secureSwitch.checked, getInviteMode(), false ) - exit(1) + //var callsWindow = App.getCallsWindow() + //App.smartShowWindow(callsWindow) + //callsWindow.openConference() + //CallsListModel.createConference(conferenceInfoModel, secureSwitch.checked, getInviteMode(), false ) + conferenceInfoModel.createConference(secureSwitch.checked, getInviteMode()) } TooltipArea{ visible: AccountSettingsModel.conferenceURI == '' || subject.text == '' || selectedParticipants.count < conferenceManager.minParticipants @@ -205,7 +212,7 @@ DialogPlus { checked: true onClicked: { - //checked = !checked + checked = !checked } indicatorStyle: SwitchStyle.aux } diff --git a/linphone-app/ui/views/App/Settings/Dialogs/SettingsVideoPreview.qml b/linphone-app/ui/views/App/Settings/Dialogs/SettingsVideoPreview.qml index 96e6efdb4..30940ed81 100644 --- a/linphone-app/ui/views/App/Settings/Dialogs/SettingsVideoPreview.qml +++ b/linphone-app/ui/views/App/Settings/Dialogs/SettingsVideoPreview.qml @@ -8,23 +8,32 @@ import App.Styles 1.0 // ============================================================================= DialogPlus { - id: dialog - - buttons: [ - TextButtonB { - text: qsTr('confirm') - - onClicked: exit(1) - } - ] - - buttonsAlignment: Qt.AlignCenter - height: SettingsVideoPreviewStyle.height - width: SettingsVideoPreviewStyle.width - - // --------------------------------------------------------------------------- - - CameraPreview { - anchors.fill: parent - } + id: dialog + + buttons: [ + TextButtonB { + text: qsTr('confirm') + + onClicked: exit(1) + } + ] + + buttonsAlignment: Qt.AlignCenter + height: SettingsVideoPreviewStyle.height + width: SettingsVideoPreviewStyle.width + + // --------------------------------------------------------------------------- + Loader{ + id: previewLoader + anchors.fill: parent + sourceComponent: CameraPreview { + anchors.fill: parent + onRequestNewRenderer: previewLoader.active = false + } + active: true + onActiveChanged: { + console.log("Active changed : " +active) + if(!active) active = true + } + } }