Country, start conference, dates, combobox, calendar, popup, effectimage, meeting details, conference scheduler

This commit is contained in:
Gaelle Braud 2024-02-22 17:56:22 +01:00 committed by Julien Wadel
parent 893c3d7485
commit c824bd6c83
102 changed files with 8876 additions and 483 deletions

View file

@ -41,17 +41,23 @@
#include "core/call/CallProxy.hpp"
#include "core/camera/CameraGui.hpp"
#include "core/fps-counter/FPSCounter.hpp"
#include "core/conference/ConferenceInfoGui.hpp"
#include "core/conference/ConferenceInfoProxy.hpp"
#include "core/friend/FriendCore.hpp"
#include "core/friend/FriendGui.hpp"
#include "core/friend/FriendInitialProxy.hpp"
#include "core/logger/QtLogger.hpp"
#include "core/login/LoginPage.hpp"
#include "core/notifier/Notifier.hpp"
#include "core/participant/ParticipantDeviceCore.hpp"
#include "core/participant/ParticipantGui.hpp"
#include "core/participant/ParticipantProxy.hpp"
#include "core/phone-number/PhoneNumber.hpp"
#include "core/phone-number/PhoneNumberProxy.hpp"
#include "core/search/MagicSearchProxy.hpp"
#include "core/setting/SettingsCore.hpp"
#include "core/singleapplication/singleapplication.h"
#include "core/timezone/TimeZone.hpp"
#include "core/timezone/TimeZoneProxy.hpp"
#include "core/variant/VariantList.hpp"
#include "model/object/VariantObject.hpp"
#include "tool/Constants.hpp"
@ -184,7 +190,14 @@ void App::initCppInterfaces() {
qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList");
qmlRegisterType<ParticipantProxy>(Constants::MainQmlUri, 1, 0, "ParticipantProxy");
qmlRegisterType<ParticipantGui>(Constants::MainQmlUri, 1, 0, "ParticipantGui");
qmlRegisterType<ConferenceInfoProxy>(Constants::MainQmlUri, 1, 0, "ConferenceInfoProxy");
qmlRegisterType<ConferenceInfoGui>(Constants::MainQmlUri, 1, 0, "ConferenceInfoGui");
qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable"));
qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy");
qmlRegisterType<AccountGui>(Constants::MainQmlUri, 1, 0, "AccountGui");
@ -192,15 +205,14 @@ void App::initCppInterfaces() {
qmlRegisterUncreatableType<CallCore>(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable"));
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy");
qmlRegisterType<CallHistoryProxy>(Constants::MainQmlUri, 1, 0, "CallHistoryProxy");
qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList");
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
qmlRegisterType<FriendGui>(Constants::MainQmlUri, 1, 0, "FriendGui");
qmlRegisterUncreatableType<FriendCore>(Constants::MainQmlUri, 1, 0, "FriendCore", QLatin1String("Uncreatable"));
qmlRegisterType<MagicSearchProxy>(Constants::MainQmlUri, 1, 0, "MagicSearchProxy");
qmlRegisterType<FriendInitialProxy>(Constants::MainQmlUri, 1, 0, "FriendInitialProxy");
qmlRegisterType<CameraGui>(Constants::MainQmlUri, 1, 0, "CameraGui");
qmlRegisterType<FPSCounter>(Constants::MainQmlUri, 1, 0, "FPSCounter");
qmlRegisterType<TimeZoneProxy>(Constants::MainQmlUri, 1, 0, "TimeZoneProxy");
LinphoneEnums::registerMetaTypes();
}
@ -208,12 +220,13 @@ void App::initCppInterfaces() {
void App::clean() {
// Wait 500ms to let time for log te be stored.
delete mNotifier;
mNotifier = nullptr;
// mNotifier destroyed in mEngine deletion as it is its parent
delete mEngine;
mEngine = nullptr;
mSettings.reset();
mSettings = nullptr;
if (mSettings) {
mSettings.reset();
mSettings = nullptr;
}
mLinphoneThread->wait(250);
qApp->processEvents(QEventLoop::AllEvents, 250);
mLinphoneThread->exit();

View file

@ -17,7 +17,6 @@ list(APPEND _LINPHONEAPP_SOURCES
core/fps-counter/FPSCounter.cpp
core/friend/FriendCore.cpp
core/friend/FriendGui.cpp
core/friend/FriendInitialProxy.cpp
core/logger/QtLogger.cpp
core/login/LoginPage.cpp
core/notifier/Notifier.cpp
@ -36,6 +35,24 @@ list(APPEND _LINPHONEAPP_SOURCES
core/proxy/SortFilterProxy.cpp
core/variant/VariantList.cpp
core/conference/ConferenceCore.cpp
core/conference/ConferenceInfoCore.cpp
core/conference/ConferenceInfoGui.cpp
core/conference/ConferenceInfoList.cpp
core/conference/ConferenceInfoProxy.cpp
core/timezone/TimeZoneList.cpp
core/timezone/TimeZoneProxy.cpp
core/timezone/TimeZone.cpp
core/participant/ParticipantCore.cpp
core/participant/ParticipantGui.cpp
core/participant/ParticipantDeviceCore.cpp
# core/participant/ParticipantDeviceList.cpp
# core/participant/ParticipantDeviceProxy.cpp
core/participant/ParticipantList.cpp
core/participant/ParticipantProxy.cpp
)
## Single Application

View file

@ -42,6 +42,7 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr<linphone::CallLog> &callL
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
// Should be call from model Thread
mustBeInLinphoneThread(getClassName());
mCallHistoryModel = std::make_shared<CallHistoryModel>(callLog);
auto addr = callLog->getRemoteAddress()->clone();
addr->clean();
@ -49,7 +50,6 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr<linphone::CallLog> &callL
// mRemoteAddress->clean();
mStatus = LinphoneEnums::fromLinphone(callLog->getStatus());
mDate = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
mCallHistoryModel = std::make_shared<CallHistoryModel>(callLog);
mIsOutgoing = callLog->getDir() == linphone::Call::Dir::Outgoing;
mDuration = QString::number(callLog->getDuration());
}

View file

@ -22,7 +22,6 @@
#include "CallHistoryGui.hpp"
#include "core/App.hpp"
#include "model/object/VariantObject.hpp"
#include "tool/Utils.hpp"
#include <QSharedPointer>
#include <linphone++/linphone.hh>
@ -81,7 +80,7 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
mModelConnection->makeConnectToModel(&CoreModel::callLogUpdated,
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
lUpdate();
emit lUpdate();
}
void CallHistoryList::removeAllEntries() {

View file

@ -21,7 +21,6 @@
#include "CallHistoryProxy.hpp"
#include "CallHistoryGui.hpp"
#include "CallHistoryList.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(CallHistoryProxy)

View file

@ -0,0 +1,481 @@
// /*
// * Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
// */
// #include "CallCore.hpp"
// #include "core/App.hpp"
// #include "model/tool/ToolModel.hpp"
// #include "tool/Utils.hpp"
// #include "tool/thread/SafeConnection.hpp"
// DEFINE_ABSTRACT_OBJECT(CallCore)
// QVariant createDeviceVariant(const QString &id, const QString &name) {
// QVariantMap map;
// map.insert("id", id);
// map.insert("name", name);
// return map;
// }
// QSharedPointer<CallCore> CallCore::create(const std::shared_ptr<linphone::Call> &call) {
// auto sharedPointer = QSharedPointer<CallCore>(new CallCore(call), &QObject::deleteLater);
// sharedPointer->setSelf(sharedPointer);
// sharedPointer->moveToThread(App::getInstance()->thread());
// return sharedPointer;
// }
// CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullptr) {
// qDebug() << "[CallCore] new" << this;
// App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
// // Should be call from model Thread
// mustBeInLinphoneThread(getClassName());
// mDir = LinphoneEnums::fromLinphone(call->getDir());
// mCallModel = Utils::makeQObject_ptr<CallModel>(call);
// mCallModel->setSelf(mCallModel);
// mDuration = call->getDuration();
// mMicrophoneMuted = call->getMicrophoneMuted();
// mSpeakerMuted = call->getSpeakerMuted();
// mCameraEnabled = call->cameraEnabled();
// mState = LinphoneEnums::fromLinphone(call->getState());
// mPeerAddress = Utils::coreStringToAppString(call->getRemoteAddress()->asStringUriOnly());
// mStatus = LinphoneEnums::fromLinphone(call->getCallLog()->getStatus());
// mTransferState = LinphoneEnums::fromLinphone(call->getTransferState());
// auto token = Utils::coreStringToAppString(mCallModel->getAuthenticationToken());
// auto localToken = mDir == LinphoneEnums::CallDir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper();
// auto remoteToken = mDir == LinphoneEnums::CallDir::Outgoing ? token.left(2).toUpper() : token.right(2).toUpper();
// mEncryption = LinphoneEnums::fromLinphone(call->getParams()->getMediaEncryption());
// auto tokenVerified = call->getAuthenticationTokenVerified();
// mLocalSas = localToken;
// mRemoteSas = remoteToken;
// mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
// mEncryption == LinphoneEnums::MediaEncryption::Srtp ||
// mEncryption == LinphoneEnums::MediaEncryption::Dtls;
// mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
// mState == LinphoneEnums::CallState::PausedByRemote;
// mRemoteVideoEnabled = call->getRemoteParams() && call->getRemoteParams()->videoEnabled();
// mRecording = call->getParams() && call->getParams()->isRecording();
// mRemoteRecording = call->getRemoteParams() && call->getRemoteParams()->isRecording();
// mSpeakerVolumeGain = mCallModel->getSpeakerVolumeGain();
// // TODO : change this with settings value when settings done
// if (mSpeakerVolumeGain < 0) {
// call->setSpeakerVolumeGain(0.5);
// mSpeakerVolumeGain = 0.5;
// }
// mMicrophoneVolumeGain = call->getMicrophoneVolumeGain();
// // TODO : change this with settings value when settings done
// if (mMicrophoneVolumeGain < 0) {
// call->setMicrophoneVolumeGain(0.5);
// mMicrophoneVolumeGain = 0.5;
// }
// mMicrophoneVolume = call->getRecordVolume();
// mRecordable = mState == LinphoneEnums::CallState::StreamsRunning;
// }
// CallCore::~CallCore() {
// qDebug() << "[CallCore] delete" << this;
// mustBeInMainThread("~" + getClassName());
// emit mCallModel->removeListener();
// }
// void CallCore::setSelf(QSharedPointer<CallCore> me) {
// mCallModelConnection = QSharedPointer<SafeConnection<CallCore, CallModel>>(
// new SafeConnection<CallCore, CallModel>(me, mCallModel), &QObject::deleteLater);
// mCallModelConnection->makeConnectToCore(&CallCore::lSetMicrophoneMuted, [this](bool isMuted) {
// mCallModelConnection->invokeToModel([this, isMuted]() { mCallModel->setMicrophoneMuted(isMuted); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::microphoneMutedChanged, [this](bool isMuted) {
// mCallModelConnection->invokeToCore([this, isMuted]() { setMicrophoneMuted(isMuted); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::remoteVideoEnabledChanged, [this](bool enabled) {
// mCallModelConnection->invokeToCore([this, enabled]() { setRemoteVideoEnabled(enabled); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetSpeakerMuted, [this](bool isMuted) {
// mCallModelConnection->invokeToModel([this, isMuted]() { mCallModel->setSpeakerMuted(isMuted); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::speakerMutedChanged, [this](bool isMuted) {
// mCallModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) {
// mCallModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() {
// mCallModelConnection->invokeToModel([this]() { mCallModel->startRecording(); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lStopRecording, [this]() {
// mCallModelConnection->invokeToModel([this]() { mCallModel->stopRecording(); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::recordingChanged, [this](bool recording) {
// mCallModelConnection->invokeToCore([this, recording]() { setRecording(recording); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lVerifyAuthenticationToken, [this](bool verified) {
// mCallModelConnection->invokeToModel(
// [this, verified]() { mCallModel->setAuthenticationTokenVerified(verified); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::authenticationTokenVerifiedChanged, [this](bool verified) {
// mCallModelConnection->invokeToCore([this, verified]() { setIsSecured(verified); });
// });
// mCallModelConnection->makeConnectToModel(
// &CallModel::remoteRecording, [this](const std::shared_ptr<linphone::Call> &call, bool recording) {
// mCallModelConnection->invokeToCore([this, recording]() { setRemoteRecording(recording); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::cameraEnabledChanged, [this](bool enabled) {
// mCallModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) {
// mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::microphoneVolumeChanged, [this](float volume) {
// mCallModelConnection->invokeToCore([this, volume]() { setMicrophoneVolume(volume); });
// });
// mCallModelConnection->makeConnectToModel(
// &CallModel::stateChanged, [this](linphone::Call::State state, const std::string &message) {
// mCallModelConnection->invokeToCore([this, state, message]() {
// setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message));
// });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) {
// mCallModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::stateChanged,
// [this](linphone::Call::State state, const std::string &message) {
// mCallModelConnection->invokeToCore([this, state]() {
// setRecordable(state == linphone::Call::State::StreamsRunning);
// });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) {
// mCallModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::pausedChanged, [this](bool paused) {
// mCallModelConnection->invokeToCore([this, paused]() { setPaused(paused); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lTransferCall, [this](const QString &address) {
// mCallModelConnection->invokeToModel(
// [this, address]() { mCallModel->transferTo(ToolModel::interpretUrl(address)); });
// });
// mCallModelConnection->makeConnectToModel(
// &CallModel::transferStateChanged,
// [this](const std::shared_ptr<linphone::Call> &call, linphone::Call::State state) {
// mCallModelConnection->invokeToCore([this, state]() {
// QString message;
// if (state == linphone::Call::State::Error) {
// message = "L'appel n'a pas pu être transféré.";
// }
// setTransferState(LinphoneEnums::fromLinphone(state), message);
// });
// });
// mCallModelConnection->makeConnectToModel(
// &CallModel::encryptionChanged,
// [this](const std::shared_ptr<linphone::Call> &call, bool on, const std::string &authenticationToken) {
// auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption());
// auto tokenVerified = mCallModel->getAuthenticationTokenVerified();
// auto token = Utils::coreStringToAppString(mCallModel->getAuthenticationToken());
// mCallModelConnection->invokeToCore([this, call, encryption, tokenVerified, token]() {
// if (token.size() == 4) {
// auto localToken =
// mDir == LinphoneEnums::CallDir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper();
// auto remoteToken =
// mDir == LinphoneEnums::CallDir::Outgoing ? token.left(2).toUpper() : token.right(2).toUpper();
// setLocalSas(localToken);
// setRemoteSas(remoteToken);
// }
// setEncryption(encryption);
// setIsSecured((encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
// encryption == LinphoneEnums::MediaEncryption::Srtp ||
// encryption == LinphoneEnums::MediaEncryption::Dtls);
// });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetSpeakerVolumeGain, [this](float gain) {
// mCallModelConnection->invokeToModel([this, gain]() { mCallModel->setSpeakerVolumeGain(gain); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::speakerVolumeGainChanged, [this](float gain) {
// mCallModelConnection->invokeToCore([this, gain]() { setSpeakerVolumeGain(gain); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetMicrophoneVolumeGain, [this](float gain) {
// mCallModelConnection->invokeToModel([this, gain]() { mCallModel->setMicrophoneVolumeGain(gain); });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::microphoneVolumeGainChanged, [this](float gain) {
// mCallModelConnection->invokeToCore([this, gain]() { setMicrophoneVolumeGain(gain); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetInputAudioDevice, [this](const QString &id) {
// mCallModelConnection->invokeToModel([this, id]() {
// if (auto device = ToolModel::findAudioDevice(id)) {
// mCallModel->setInputAudioDevice(device);
// }
// });
// });
// mCallModelConnection->makeConnectToModel(&CallModel::inputAudioDeviceChanged, [this](const std::string &id) {
// mCallModelConnection->invokeToCore([this, id]() {});
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lSetOutputAudioDevice, [this](const QString &id) {
// mCallModelConnection->invokeToModel([this, id]() {
// if (auto device = ToolModel::findAudioDevice(id)) {
// mCallModel->setOutputAudioDevice(device);
// }
// });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lAccept, [this](bool withVideo) {
// mCallModelConnection->invokeToModel([this, withVideo]() { mCallModel->accept(withVideo); });
// });
// mCallModelConnection->makeConnectToCore(
// &CallCore::lDecline, [this]() { mCallModelConnection->invokeToModel([this]() { mCallModel->decline(); }); });
// mCallModelConnection->makeConnectToCore(&CallCore::lTerminate, [this]() {
// mCallModelConnection->invokeToModel([this]() { mCallModel->terminate(); });
// });
// mCallModelConnection->makeConnectToCore(&CallCore::lTerminateAllCalls, [this]() {
// mCallModelConnection->invokeToModel([this]() { mCallModel->terminateAllCalls(); });
// });
// }
// QString CallCore::getPeerAddress() const {
// return mPeerAddress;
// }
// LinphoneEnums::CallStatus CallCore::getStatus() const {
// return mStatus;
// }
// void CallCore::setStatus(LinphoneEnums::CallStatus status) {
// mustBeInMainThread(log().arg(Q_FUNC_INFO));
// if (mStatus != status) {
// mStatus = status;
// emit statusChanged(mStatus);
// }
// }
// LinphoneEnums::CallDir CallCore::getDir() const {
// return mDir;
// }
// void CallCore::setDir(LinphoneEnums::CallDir dir) {
// mustBeInMainThread(log().arg(Q_FUNC_INFO));
// if (mDir != dir) {
// mDir = dir;
// emit dirChanged(mDir);
// }
// }
// LinphoneEnums::CallState CallCore::getState() const {
// return mState;
// }
// void CallCore::setState(LinphoneEnums::CallState state, const QString &message) {
// mustBeInMainThread(log().arg(Q_FUNC_INFO));
// if (mState != state) {
// mState = state;
// if (state == LinphoneEnums::CallState::Error) setLastErrorMessage(message);
// emit stateChanged(mState);
// }
// }
// QString CallCore::getLastErrorMessage() const {
// return mLastErrorMessage;
// }
// void CallCore::setLastErrorMessage(const QString &message) {
// if (mLastErrorMessage != message) {
// mLastErrorMessage = message;
// emit lastErrorMessageChanged();
// }
// }
// int CallCore::getDuration() {
// return mDuration;
// }
// void CallCore::setDuration(int duration) {
// if (mDuration != duration) {
// mDuration = duration;
// emit durationChanged(mDuration);
// }
// }
// bool CallCore::getSpeakerMuted() const {
// return mSpeakerMuted;
// }
// void CallCore::setSpeakerMuted(bool isMuted) {
// if (mSpeakerMuted != isMuted) {
// mSpeakerMuted = isMuted;
// emit speakerMutedChanged();
// }
// }
// bool CallCore::getMicrophoneMuted() const {
// return mMicrophoneMuted;
// }
// void CallCore::setMicrophoneMuted(bool isMuted) {
// if (mMicrophoneMuted != isMuted) {
// mMicrophoneMuted = isMuted;
// emit microphoneMutedChanged();
// }
// }
// bool CallCore::getCameraEnabled() const {
// return mCameraEnabled;
// }
// void CallCore::setCameraEnabled(bool enabled) {
// if (mCameraEnabled != enabled) {
// mCameraEnabled = enabled;
// emit cameraEnabledChanged();
// }
// }
// bool CallCore::getPaused() const {
// return mPaused;
// }
// void CallCore::setPaused(bool paused) {
// if (mPaused != paused) {
// mPaused = paused;
// emit pausedChanged();
// }
// }
// bool CallCore::isSecured() const {
// return mIsSecured;
// }
// void CallCore::setIsSecured(bool secured) {
// if (mIsSecured != secured) {
// mIsSecured = secured;
// emit securityUpdated();
// }
// }
// QString CallCore::getLocalSas() {
// return mLocalSas;
// }
// QString CallCore::getRemoteSas() {
// return mRemoteSas;
// }
// void CallCore::setLocalSas(const QString &sas) {
// if (mLocalSas != sas) {
// mLocalSas = sas;
// emit localSasChanged();
// }
// }
// void CallCore::setRemoteSas(const QString &sas) {
// if (mRemoteSas != sas) {
// mRemoteSas = sas;
// emit remoteSasChanged();
// }
// }
// LinphoneEnums::MediaEncryption CallCore::getEncryption() const {
// return mEncryption;
// }
// void CallCore::setEncryption(LinphoneEnums::MediaEncryption encryption) {
// if (mEncryption != encryption) {
// mEncryption = encryption;
// emit securityUpdated();
// }
// }
// bool CallCore::getRemoteVideoEnabled() const {
// return mRemoteVideoEnabled;
// }
// void CallCore::setRemoteVideoEnabled(bool enabled) {
// if (mRemoteVideoEnabled != enabled) {
// mRemoteVideoEnabled = enabled;
// emit remoteVideoEnabledChanged(mRemoteVideoEnabled);
// }
// }
// bool CallCore::getRecording() const {
// return mRecording;
// }
// void CallCore::setRecording(bool recording) {
// if (mRecording != recording) {
// mRecording = recording;
// emit recordingChanged();
// }
// }
// bool CallCore::getRemoteRecording() const {
// return mRemoteRecording;
// }
// void CallCore::setRemoteRecording(bool recording) {
// if (mRemoteRecording != recording) {
// mRemoteRecording = recording;
// emit remoteRecordingChanged();
// }
// }
// bool CallCore::getRecordable() const {
// return mRecordable;
// }
// void CallCore::setRecordable(bool recordable) {
// if (mRecordable != recordable) {
// mRecordable = recordable;
// emit recordableChanged();
// }
// }
// float CallCore::getSpeakerVolumeGain() const {
// return mSpeakerVolumeGain;
// }
// void CallCore::setSpeakerVolumeGain(float gain) {
// if (mSpeakerVolumeGain != gain) {
// mSpeakerVolumeGain = gain;
// emit speakerVolumeGainChanged();
// }
// }
// float CallCore::getMicrophoneVolume() const {
// return mMicrophoneVolume;
// }
// void CallCore::setMicrophoneVolume(float vol) {
// if (mMicrophoneVolume != vol) {
// mMicrophoneVolume = vol;
// emit microphoneVolumeChanged();
// }
// }
// float CallCore::getMicrophoneVolumeGain() const {
// return mMicrophoneVolumeGain;
// }
// void CallCore::setMicrophoneVolumeGain(float gain) {
// if (mMicrophoneVolumeGain != gain) {
// mMicrophoneVolumeGain = gain;
// emit microphoneVolumeGainChanged();
// }
// }
// LinphoneEnums::CallState CallCore::getTransferState() const {
// return mTransferState;
// }
// void CallCore::setTransferState(LinphoneEnums::CallState state, const QString &message) {
// if (mTransferState != state) {
// mTransferState = state;
// if (state == LinphoneEnums::CallState::Error) setLastErrorMessage(message);
// emit transferStateChanged();
// }
// }
// std::shared_ptr<CallModel> CallCore::getModel() const {
// return mCallModel;
// }

View file

@ -0,0 +1,224 @@
// /*
// * Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
// */
// #ifndef CONFERENCE_CORE_H_
// #define CONFERENCE_CORE_H_
// #include "model/conference/ConferenceModel.hpp"
// #include "tool/LinphoneEnums.hpp"
// #include "tool/thread/SafeConnection.hpp"
// #include <QObject>
// #include <QSharedPointer>
// #include <linphone++/linphone.hh>
// class ConferenceCore : public QObject, public AbstractObject {
// Q_OBJECT
// // Q_PROPERTY(QString peerDisplayName MEMBER mPeerDisplayName)
// Q_PROPERTY(LinphoneEnums::ConferenceStatus status READ getStatus NOTIFY statusChanged)
// Q_PROPERTY(LinphoneEnums::ConferenceDir dir READ getDir NOTIFY dirChanged)
// Q_PROPERTY(LinphoneEnums::ConferenceState state READ getState NOTIFY stateChanged)
// Q_PROPERTY(QString lastErrorMessage READ getLastErrorMessage NOTIFY lastErrorMessageChanged)
// Q_PROPERTY(int duration READ getDuration NOTIFY durationChanged)
// Q_PROPERTY(bool speakerMuted READ getSpeakerMuted WRITE lSetSpeakerMuted NOTIFY speakerMutedChanged)
// Q_PROPERTY(bool microphoneMuted READ getMicrophoneMuted WRITE lSetMicrophoneMuted NOTIFY microphoneMutedChanged)
// Q_PROPERTY(bool cameraEnabled READ getCameraEnabled WRITE lSetCameraEnabled NOTIFY cameraEnabledChanged)
// Q_PROPERTY(bool paused READ getPaused WRITE lSetPaused NOTIFY pausedChanged)
// Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT)
// Q_PROPERTY(bool isSecured READ isSecured NOTIFY securityUpdated)
// Q_PROPERTY(LinphoneEnums::MediaEncryption encryption READ getEncryption NOTIFY securityUpdated)
// Q_PROPERTY(QString localSas READ getLocalSas WRITE setLocalSas MEMBER mLocalSas NOTIFY localSasChanged)
// Q_PROPERTY(QString remoteSas WRITE setRemoteSas MEMBER mRemoteSas NOTIFY remoteSasChanged)
// Q_PROPERTY(
// bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged)
// Q_PROPERTY(bool recording READ getRecording WRITE setRecording NOTIFY recordingChanged)
// Q_PROPERTY(bool remoteRecording READ getRemoteRecording WRITE setRemoteRecording NOTIFY remoteRecordingChanged)
// Q_PROPERTY(bool recordable READ getRecordable WRITE setRecordable NOTIFY recordableChanged)
// Q_PROPERTY(
// float speakerVolumeGain READ getSpeakerVolumeGain WRITE setSpeakerVolumeGain NOTIFY speakerVolumeGainChanged)
// Q_PROPERTY(float microphoneVolumeGain READ getMicrophoneVolumeGain WRITE setMicrophoneVolumeGain NOTIFY
// microphoneVolumeGainChanged)
// Q_PROPERTY(float microVolume READ getMicrophoneVolume WRITE setMicrophoneVolume NOTIFY microphoneVolumeChanged)
// Q_PROPERTY(LinphoneEnums::ConferenceState transferState READ getTransferState NOTIFY transferStateChanged)
// public:
// // Should be call from model Thread. Will be automatically in App thread after initialization
// static QSharedPointer<ConferenceCore> create(const std::shared_ptr<linphone::Conference> &call);
// ConferenceCore(const std::shared_ptr<linphone::Conference> &call);
// ~ConferenceCore();
// void setSelf(QSharedPointer<ConferenceCore> me);
// QString getPeerAddress() const;
// LinphoneEnums::ConferenceStatus getStatus() const;
// void setStatus(LinphoneEnums::ConferenceStatus status);
// LinphoneEnums::ConferenceDir getDir() const;
// void setDir(LinphoneEnums::ConferenceDir dir);
// LinphoneEnums::ConferenceState getState() const;
// void setState(LinphoneEnums::ConferenceState state, const QString &message);
// QString getLastErrorMessage() const;
// void setLastErrorMessage(const QString &message);
// int getDuration();
// void setDuration(int duration);
// bool getSpeakerMuted() const;
// void setSpeakerMuted(bool isMuted);
// bool getMicrophoneMuted() const;
// void setMicrophoneMuted(bool isMuted);
// bool getCameraEnabled() const;
// void setCameraEnabled(bool enabled);
// bool getPaused() const;
// void setPaused(bool paused);
// bool isSecured() const;
// void setIsSecured(bool secured);
// QString getLocalSas();
// void setLocalSas(const QString &sas);
// QString getRemoteSas();
// void setRemoteSas(const QString &sas);
// LinphoneEnums::MediaEncryption getEncryption() const;
// void setEncryption(LinphoneEnums::MediaEncryption encryption);
// bool getRemoteVideoEnabled() const;
// void setRemoteVideoEnabled(bool enabled);
// bool getRecording() const;
// void setRecording(bool recording);
// bool getRemoteRecording() const;
// void setRemoteRecording(bool recording);
// bool getRecordable() const;
// void setRecordable(bool recordable);
// float getSpeakerVolumeGain() const;
// void setSpeakerVolumeGain(float gain);
// float getMicrophoneVolumeGain() const;
// void setMicrophoneVolumeGain(float gain);
// float getMicrophoneVolume() const;
// void setMicrophoneVolume(float vol);
// QString getInputDeviceName() const;
// void setInputDeviceName(const QString &id);
// LinphoneEnums::ConferenceState getTransferState() const;
// void setTransferState(LinphoneEnums::ConferenceState state, const QString &message);
// std::shared_ptr<ConferenceModel> getModel() const;
// signals:
// void statusChanged(LinphoneEnums::ConferenceStatus status);
// void stateChanged(LinphoneEnums::ConferenceState state);
// void dirChanged(LinphoneEnums::ConferenceDir dir);
// void lastErrorMessageChanged();
// void durationChanged(int duration);
// void speakerMutedChanged();
// void microphoneMutedChanged();
// void cameraEnabledChanged();
// void pausedChanged();
// void transferStateChanged();
// void securityUpdated();
// void localSasChanged();
// void remoteSasChanged();
// void remoteVideoEnabledChanged(bool remoteVideoEnabled);
// void recordingChanged();
// void remoteRecordingChanged();
// void recordableChanged();
// void speakerVolumeGainChanged();
// void microphoneVolumeChanged();
// void microphoneVolumeGainChanged();
// // Linphone commands
// void lAccept(bool withVideo); // Accept an incoming call
// void lDecline(); // Decline an incoming call
// void lTerminate(); // Hangup a call
// void lTerminateAllConferences(); // Hangup all calls
// void lSetSpeakerMuted(bool muted);
// void lSetMicrophoneMuted(bool isMuted);
// void lSetCameraEnabled(bool enabled);
// void lSetPaused(bool paused);
// void lTransferConference(const QString &dest);
// void lStartRecording();
// void lStopRecording();
// void lVerifyAuthenticationToken(bool verified);
// void lSetSpeakerVolumeGain(float gain);
// void lSetMicrophoneVolumeGain(float gain);
// void lSetInputAudioDevice(const QString &id);
// void lSetOutputAudioDevice(const QString &id);
// /* TODO
// Q_INVOKABLE void acceptWithVideo();
// Q_INVOKABLE void askForTransfer();
// Q_INVOKABLE void askForAttendedTransfer();
// Q_INVOKABLE bool transferTo(const QString &sipAddress);
// Q_INVOKABLE bool transferToAnother(const QString &peerAddress);
// Q_INVOKABLE bool getRemoteVideoEnabled() const;
// Q_INVOKABLE void acceptVideoRequest();
// Q_INVOKABLE void rejectVideoRequest();
// Q_INVOKABLE void takeSnapshot();
// Q_INVOKABLE void sendDtmf(const QString &dtmf);
// Q_INVOKABLE void verifyAuthenticationToken(bool verify);
// Q_INVOKABLE void updateStreams();
// */
// private:
// std::shared_ptr<ConferenceModel> mConferenceModel;
// LinphoneEnums::ConferenceStatus mStatus;
// LinphoneEnums::ConferenceState mState;
// LinphoneEnums::ConferenceState mTransferState;
// LinphoneEnums::ConferenceDir mDir;
// LinphoneEnums::MediaEncryption mEncryption;
// QString mLastErrorMessage;
// QString mPeerAddress;
// bool mIsSecured;
// int mDuration = 0;
// bool mSpeakerMuted;
// bool mMicrophoneMuted;
// bool mCameraEnabled;
// bool mPaused = false;
// bool mRemoteVideoEnabled = false;
// bool mRecording = false;
// bool mRemoteRecording = false;
// bool mRecordable = false;
// QString mLocalSas;
// QString mRemoteSas;
// float mSpeakerVolumeGain;
// float mMicrophoneVolume;
// float mMicrophoneVolumeGain;
// QSharedPointer<SafeConnection<ConferenceCore, ConferenceModel>> mConferenceModelConnection;
// DECLARE_ABSTRACT_OBJECT
// };
// Q_DECLARE_METATYPE(ConferenceCore *)
// #endif

View file

@ -0,0 +1,576 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceInfoCore.hpp"
#include "core/App.hpp"
#include "core/proxy/ListProxy.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp"
DEFINE_ABSTRACT_OBJECT(ConferenceInfoCore)
QSharedPointer<ConferenceInfoCore>
ConferenceInfoCore::create(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo) {
auto sharedPointer =
QSharedPointer<ConferenceInfoCore>(new ConferenceInfoCore(conferenceInfo), &QObject::deleteLater);
sharedPointer->setSelf(sharedPointer);
if (isInLinphoneThread()) sharedPointer->moveToThread(App::getInstance()->thread());
return sharedPointer;
}
ConferenceInfoCore::ConferenceInfoCore(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo, QObject *parent)
: QObject(parent) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mTimeZoneModel = QSharedPointer<TimeZoneModel>(new TimeZoneModel(
QTimeZone::systemTimeZone())); // Always return system timezone because this info is not stored in database.
if (conferenceInfo) {
mustBeInLinphoneThread(getClassName());
mConferenceInfoModel = Utils::makeQObject_ptr<ConferenceInfoModel>(conferenceInfo);
auto confSchedulerModel = mConferenceInfoModel->getConferenceScheduler();
if (!confSchedulerModel) {
auto confScheduler = CoreModel::getInstance()->getCore()->createConferenceScheduler();
confSchedulerModel = Utils::makeQObject_ptr<ConferenceSchedulerModel>(confScheduler);
mConferenceInfoModel->setConferenceScheduler(confSchedulerModel);
}
auto address = conferenceInfo->getUri();
mUri = address && address->isValid() && !address->getDomain().empty()
? Utils::coreStringToAppString(address->asStringUriOnly())
: "";
mDateTime = QDateTime::fromMSecsSinceEpoch(conferenceInfo->getDateTime() * 1000, Qt::LocalTime);
mDuration = conferenceInfo->getDuration();
mEndDateTime = mDateTime.addSecs(mDuration * 60);
mOrganizerAddress = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->asStringUriOnly());
mOrganizerName = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->getDisplayName());
if (mOrganizerName.isEmpty()) {
mOrganizerName = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->getUsername());
mOrganizerName.replace(".", " ");
}
mSubject = Utils::coreStringToAppString(conferenceInfo->getSubject());
mDescription = Utils::coreStringToAppString(conferenceInfo->getDescription());
mIsEnded = getDateTimeUtc().addSecs(mDuration * 60) < QDateTime::currentDateTimeUtc();
for (auto item : conferenceInfo->getParticipantInfos()) {
QVariantMap participant;
auto address = item->getAddress();
auto name = Utils::coreStringToAppString(address->getDisplayName());
if (name.isEmpty()) {
name = Utils::coreStringToAppString(address->getUsername());
name.replace(".", " ");
}
participant["displayName"] = name;
participant["address"] = Utils::coreStringToAppString(address->asStringUriOnly());
participant["role"] = (int)LinphoneEnums::fromLinphone(item->getRole());
mParticipants.append(participant);
}
mConferenceInfoState = LinphoneEnums::fromLinphone(conferenceInfo->getState());
} else {
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
if (defaultAccount) {
auto accountAddress = defaultAccount->getContactAddress();
if (accountAddress) {
auto cleanedClonedAddress = accountAddress->clone();
cleanedClonedAddress->clean();
mOrganizerAddress = Utils::coreStringToAppString(cleanedClonedAddress->asStringUriOnly());
qDebug() << "set organizer address" << mOrganizerAddress;
}
}
}
connect(this, &ConferenceInfoCore::endDateTimeChanged,
[this] { setDuration(mDateTime.secsTo(mEndDateTime) / 60.0); });
connect(this, &ConferenceInfoCore::durationChanged, [this] { setEndDateTime(mDateTime.addSecs(mDuration * 60)); });
}
ConferenceInfoCore::ConferenceInfoCore(const ConferenceInfoCore &conferenceInfoCore) {
mDateTime = conferenceInfoCore.mDateTime;
mEndDateTime = conferenceInfoCore.mEndDateTime;
mDuration = conferenceInfoCore.mDuration;
mOrganizerAddress = conferenceInfoCore.mOrganizerAddress;
mOrganizerName = conferenceInfoCore.mOrganizerName;
mSubject = conferenceInfoCore.mSubject;
mDescription = conferenceInfoCore.mDescription;
mUri = conferenceInfoCore.mUri;
mParticipants = conferenceInfoCore.mParticipants;
mTimeZoneModel = conferenceInfoCore.mTimeZoneModel;
mIsScheduled = conferenceInfoCore.mIsScheduled;
mIsEnded = conferenceInfoCore.mIsEnded;
mInviteMode = conferenceInfoCore.mInviteMode;
mConferenceInfoState = conferenceInfoCore.mConferenceInfoState;
}
ConferenceInfoCore::~ConferenceInfoCore() {
mustBeInMainThread("~" + getClassName());
mCheckEndTimer.stop();
}
void ConferenceInfoCore::reset(const ConferenceInfoCore &conf) {
setDateTime(conf.getDateTimeSystem());
setDuration(conf.getDuration());
setOrganizerAddress(conf.getOrganizerAddress());
setOrganizerName(conf.getOrganizerName());
setSubject(conf.getSubject());
setDescription(conf.getDescription());
setUri(conf.getUri());
resetParticipants(conf.getParticipants());
setTimeZoneModel(conf.getTimeZoneModel());
setIsScheduled(conf.isScheduled());
setIsEnded(conf.isEnded());
setInviteMode(conf.getInviteMode());
setConferenceInfoState(conf.getConferenceInfoState());
}
void ConferenceInfoCore::setSelf(SafeSharedPointer<ConferenceInfoCore> me) {
setSelf(me.mQDataWeak.lock());
}
void ConferenceInfoCore::setSelf(QSharedPointer<ConferenceInfoCore> me) {
if (me) {
if (mConferenceInfoModel) {
mCoreModelConnection = nullptr;
mConfInfoModelConnection = QSharedPointer<SafeConnection<ConferenceInfoCore, ConferenceInfoModel>>(
new SafeConnection<ConferenceInfoCore, ConferenceInfoModel>(me, mConferenceInfoModel),
&QObject::deleteLater);
mConfInfoModelConnection->makeConnectToModel(&ConferenceInfoModel::dateTimeChanged,
[this](const QDateTime &date) {
mConfInfoModelConnection->invokeToCore([this, date] {
setDateTime(date);
setIsEnded(computeIsEnded());
});
});
mConfInfoModelConnection->makeConnectToModel(&ConferenceInfoModel::durationChanged, [this](int duration) {
mConfInfoModelConnection->invokeToCore([this, duration] {
setDuration(duration);
setIsEnded(computeIsEnded());
});
});
mConfInfoModelConnection->makeConnectToModel(
&ConferenceInfoModel::stateChanged, [this](linphone::ConferenceScheduler::State state) {
qDebug() << "conf state changed" << LinphoneEnums::fromLinphone(state);
mConfInfoModelConnection->invokeToCore([this] {});
});
mConfInfoModelConnection->makeConnectToCore(&ConferenceInfoCore::lDeleteConferenceInfo,
[this]() { mConferenceInfoModel->deleteConferenceInfo(); });
mConfInfoModelConnection->makeConnectToModel(&ConferenceInfoModel::conferenceInfoDeleted,
&ConferenceInfoCore::removed);
mConfInfoModelConnection->makeConnectToModel(
&ConferenceInfoModel::stateChanged,
[this](linphone::ConferenceScheduler::State state) { qDebug() << "conf state changed"; });
mConfInfoModelConnection->makeConnectToModel(
&ConferenceInfoModel::invitationsSent,
[this](const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) {
qDebug() << "invitations sent";
});
} else { // Create
mCoreModelConnection = QSharedPointer<SafeConnection<ConferenceInfoCore, CoreModel>>(
new SafeConnection<ConferenceInfoCore, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
}
}
}
//------------------------------------------------------------------------------------------------
// Note conferenceInfo->getDateTime uses UTC
QDateTime ConferenceInfoCore::getDateTimeUtc() const {
return getDateTimeSystem().toUTC();
}
QDateTime ConferenceInfoCore::getDateTimeSystem() const {
return mDateTime;
}
int ConferenceInfoCore::getDuration() const {
return mDuration;
}
QDateTime ConferenceInfoCore::getEndDateTime() const {
return mDateTime.addSecs(mDuration * 60);
}
QDateTime ConferenceInfoCore::getEndDateTimeUtc() const {
return getEndDateTime().toUTC();
}
QString ConferenceInfoCore::getOrganizerName() const {
return mOrganizerName;
}
QString ConferenceInfoCore::getOrganizerAddress() const {
return mOrganizerAddress;
}
QString ConferenceInfoCore::getSubject() const {
return mSubject;
}
QString ConferenceInfoCore::getDescription() const {
return mDescription;
}
void ConferenceInfoCore::setDateTime(const QDateTime &date) {
if (date != mDateTime) {
mDateTime = date;
emit dateTimeChanged();
}
}
void ConferenceInfoCore::setEndDateTime(const QDateTime &date) {
if (date != mEndDateTime) {
mEndDateTime = date;
emit endDateTimeChanged();
}
}
void ConferenceInfoCore::setDuration(int duration) {
if (duration != mDuration) {
mDuration = duration;
emit durationChanged();
}
}
void ConferenceInfoCore::setSubject(const QString &subject) {
if (subject != mSubject) {
mSubject = subject;
emit subjectChanged();
}
}
void ConferenceInfoCore::setOrganizerName(const QString &organizer) {
if (organizer != mOrganizerName) {
mOrganizerName = organizer;
emit organizerNameChanged();
}
}
void ConferenceInfoCore::setOrganizerAddress(const QString &organizer) {
if (organizer != mOrganizerAddress) {
mOrganizerAddress = organizer;
emit organizerAddressChanged();
}
}
void ConferenceInfoCore::setUri(const QString &uri) {
if (uri != mUri) {
mUri = uri;
emit uriChanged();
}
}
void ConferenceInfoCore::setTimeZoneModel(TimeZoneModel *model) {
if (mTimeZoneModel->getDisplayName() != model->getDisplayName() ||
mTimeZoneModel->getCountryName() != model->getCountryName() ||
mTimeZoneModel->getOffsetFromUtc() != model->getOffsetFromUtc() ||
mTimeZoneModel->getStandardTimeOffset() != model->getStandardTimeOffset() ||
mTimeZoneModel->getTimeZone() != model->getTimeZone()) {
mTimeZoneModel = QSharedPointer<TimeZoneModel>(model);
emit timeZoneModelChanged();
}
}
void ConferenceInfoCore::setDescription(const QString &description) {
if (description != mDescription) {
mDescription = description;
emit descriptionChanged();
}
}
QString ConferenceInfoCore::getUri() const {
return mUri;
}
bool ConferenceInfoCore::isScheduled() const {
return mIsScheduled;
}
bool ConferenceInfoCore::computeIsEnded() const {
return getEndDateTimeUtc() < QDateTime::currentDateTimeUtc();
}
bool ConferenceInfoCore::isEnded() const {
return mIsEnded;
}
int ConferenceInfoCore::getInviteMode() const {
return mInviteMode;
}
QVariantList ConferenceInfoCore::getParticipants() const {
return mParticipants;
}
int ConferenceInfoCore::getParticipantCount() const {
return mParticipants.size();
}
void ConferenceInfoCore::addParticipant(const QString &address) {
for (auto &participant : mParticipants) {
auto map = participant.toMap();
if (map["address"].toString() == address) return;
}
QVariantMap participant;
auto displayNameObj = Utils::getDisplayName(address);
if (displayNameObj) participant["displayName"] = displayNameObj->getValue();
participant["address"] = address;
participant["role"] = (int)LinphoneEnums::ParticipantRole::Listener;
mParticipants.append(participant);
emit participantsChanged();
}
void ConferenceInfoCore::removeParticipant(const QString &address) {
for (int i = 0; i < mParticipants.size(); ++i) {
auto map = mParticipants[i].toMap();
if (map["address"].toString() == address) {
mParticipants.remove(i);
emit participantsChanged();
return;
}
}
}
void ConferenceInfoCore::removeParticipant(const int &index) {
mParticipants.remove(index);
emit participantsChanged();
}
QString ConferenceInfoCore::getParticipantAddressAt(const int &index) {
if (index < 0 || index >= mParticipants.size()) return QString();
auto map = mParticipants[index].toMap();
return map["address"].toString();
}
void ConferenceInfoCore::clearParticipants() {
mParticipants.clear();
emit participantsChanged();
}
void ConferenceInfoCore::resetParticipants(QVariantList participants) {
mParticipants = participants;
}
void ConferenceInfoCore::resetParticipants(const QStringList &adresses) {
mParticipants.clear();
for (auto &address : adresses) {
QVariantMap participant;
QString name;
auto nameObj = Utils::getDisplayName(address);
if (nameObj) name = nameObj->getValue().toString();
participant["displayName"] = name;
participant["address"] = address;
participant["role"] = (int)LinphoneEnums::ParticipantRole::Listener;
mParticipants.append(participant);
}
emit participantsChanged();
}
int ConferenceInfoCore::getParticipantIndex(const QString &address) {
for (int i = 0; i < mParticipants.count(); ++i) {
auto map = mParticipants[i].toMap();
if (map["address"].toString() == address) {
return i;
}
}
return -1;
}
TimeZoneModel *ConferenceInfoCore::getTimeZoneModel() const {
return mTimeZoneModel.get();
}
// QString ConferenceInfoCore::getIcalendarString() const {
// return Utils::coreStringToAppString(mConferenceInfoModel->getIcalendarString());
// }
LinphoneEnums::ConferenceInfoState ConferenceInfoCore::getConferenceInfoState() const {
return mConferenceInfoState;
}
// LinphoneEnums::ConferenceSchedulerState ConferenceInfoCore::getConferenceSchedulerState() const {
// return LinphoneEnums::fromLinphone(mLastConferenceSchedulerState);
// }
//------------------------------------------------------------------------------------------------
// Datetime is in Custom (Locale/UTC/System). Convert into UTC for conference info
void ConferenceInfoCore::setIsScheduled(const bool &on) {
if (mIsScheduled != on) {
mIsScheduled = on;
emit isScheduledChanged();
}
}
void ConferenceInfoCore::setIsEnded(bool ended) {
if (mIsEnded != ended) {
mIsEnded = ended;
if (mIsEnded) mCheckEndTimer.stop(); // No need to run the timer.
else mCheckEndTimer.start();
emit isEndedChanged();
}
}
void ConferenceInfoCore::setInviteMode(const int &mode) {
if (mode != mInviteMode) {
mInviteMode = mode;
emit inviteModeChanged();
}
}
void ConferenceInfoCore::setConferenceInfoState(LinphoneEnums::ConferenceInfoState state) {
if (state != mConferenceInfoState) {
mConferenceInfoState = state;
emit conferenceInfoStateChanged();
}
}
void ConferenceInfoCore::writeFromModel(const std::shared_ptr<ConferenceInfoModel> &model) {
mustBeInLinphoneThread(getClassName() + "::writeFromModel()");
setDateTime(model->getDateTime());
setDuration(model->getDuration());
setSubject(model->getSubject());
setOrganizerName(model->getOrganizerName());
setOrganizerAddress(model->getOrganizerAddress());
setDescription(model->getDescription());
QStringList participantAddresses;
for (auto &infos : model->getParticipantInfos()) {
participantAddresses.append(Utils::coreStringToAppString(infos->getAddress()->asStringUriOnly()));
}
resetParticipants(participantAddresses);
}
void ConferenceInfoCore::writeIntoModel(std::shared_ptr<ConferenceInfoModel> model) {
mustBeInLinphoneThread(getClassName() + "::writeIntoModel()");
model->setDateTime(mDateTime);
model->setDuration(mDuration);
model->setSubject(mSubject);
model->setOrganizer(mOrganizerAddress);
model->setDescription(mDescription);
std::list<std::shared_ptr<linphone::ParticipantInfo>> participantInfos;
for (auto &p : mParticipants) {
auto map = p.toMap();
auto address = map["address"].toString();
auto linAddr = ToolModel::interpretUrl(address);
auto infos = linphone::Factory::get()->createParticipantInfo(linAddr);
participantInfos.push_back(infos);
}
model->setParticipantInfos(participantInfos);
}
void ConferenceInfoCore::save() {
mustBeInMainThread(getClassName() + "::save()");
ConferenceInfoCore *thisCopy = new ConferenceInfoCore(*this); // Pointer to avoid multiple copies in lambdas
if (mConferenceInfoModel) {
mConfInfoModelConnection->invokeToModel([this, thisCopy]() { // Copy values to avoid concurrency
mustBeInLinphoneThread(getClassName() + "::save()");
thisCopy->writeIntoModel(mConferenceInfoModel);
thisCopy->deleteLater();
});
} else {
mCoreModelConnection->invokeToModel([this, thisCopy]() {
auto linphoneConf =
CoreModel::getInstance()->getCore()->findConferenceInformationFromUri(ToolModel::interpretUrl(mUri));
if (linphoneConf == nullptr) {
linphoneConf = linphone::Factory::get()->createConferenceInfo();
}
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
if (defaultAccount) {
auto accountAddress = defaultAccount->getContactAddress();
if (accountAddress) {
auto cleanedClonedAddress = accountAddress->clone();
cleanedClonedAddress->clean();
if (!linphoneConf->getOrganizer()) linphoneConf->setOrganizer(cleanedClonedAddress);
if (mOrganizerAddress.isEmpty())
mOrganizerAddress = Utils::coreStringToAppString(accountAddress->asStringUriOnly());
}
}
mConferenceInfoModel = Utils::makeQObject_ptr<ConferenceInfoModel>(linphoneConf);
// mConferenceInfoModel->createConferenceScheduler();
auto confSchedulerModel = mConferenceInfoModel->getConferenceScheduler();
if (!confSchedulerModel) {
auto confScheduler = CoreModel::getInstance()->getCore()->createConferenceScheduler();
confSchedulerModel = Utils::makeQObject_ptr<ConferenceSchedulerModel>(confScheduler);
mConferenceInfoModel->setConferenceScheduler(confSchedulerModel);
}
thisCopy->writeIntoModel(mConferenceInfoModel);
thisCopy->deleteLater();
confSchedulerModel->setInfo(linphoneConf);
mCoreModelConnection->invokeToCore([this]() { setSelf(mCoreModelConnection->mCore); });
});
}
}
void ConferenceInfoCore::undo() {
if (mConferenceInfoModel) {
mConfInfoModelConnection->invokeToModel([this]() {
ConferenceInfoCore *conf = new ConferenceInfoCore(*this);
conf->writeFromModel(mConferenceInfoModel);
conf->moveToThread(App::getInstance()->thread());
mConfInfoModelConnection->invokeToCore([this, conf]() mutable {
this->reset(*conf);
conf->deleteLater();
});
});
}
}
void ConferenceInfoCore::cancelConference() {
if (!mConferenceInfoModel) return;
mConferenceInfoModel->cancelConference();
}
//-------------------------------------------------------------------------------------------------
// void ConferenceInfoCore::createConference(const int &securityLevel) {
// CoreModel::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = false;
// shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
// static std::shared_ptr<linphone::Conference> conference;
// qInfo() << "Conference creation of " << getSubject() << " at " << securityLevel << " security, organized by "
// << getOrganizer() << " for " << getDateTimeSystem().toString();
// qInfo() << "Participants:";
// for (auto p : mConferenceInfoModel->getParticipants())
// qInfo() << "\t" << p->asString().c_str();
// mConferenceScheduler = ConferenceScheduler::create();
// mConferenceScheduler->mSendInvite = mInviteMode;
// connect(mConferenceScheduler.get(), &ConferenceScheduler::invitationsSent, this,
// &ConferenceInfoCore::onInvitationsSent);
// connect(mConferenceScheduler.get(), &ConferenceScheduler::stateChanged, this,
// &ConferenceInfoCore::onConferenceSchedulerStateChanged);
// mConferenceScheduler->getConferenceScheduler()->setInfo(mConferenceInfoModel);
// }
//-------------------------------------------------------------------------------------------------
// void ConferenceInfoCore::onConferenceSchedulerStateChanged(linphone::ConferenceScheduler::State state) {
// qDebug() << "ConferenceInfoCore::onConferenceSchedulerStateChanged: " << (int)state;
// mLastConferenceSchedulerState = state;
// if (state == linphone::ConferenceScheduler::State::Ready) emit conferenceCreated();
// else if (state == linphone::ConferenceScheduler::State::Error) emit conferenceCreationFailed();
// emit conferenceInfoChanged();
// }
void ConferenceInfoCore::onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) {
qDebug() << "ConferenceInfoCore::onInvitationsSent";
emit invitationsSent();
}

View file

@ -0,0 +1,187 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_INFO_CORE_H_
#define CONFERENCE_INFO_CORE_H_
#include "core/timezone/TimeZone.hpp"
#include "model/conference/ConferenceInfoModel.hpp"
#include "tool/LinphoneEnums.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <linphone++/linphone.hh>
#include <QDateTime>
#include <QObject>
#include <QSharedPointer>
#include <QTimeZone>
#include <QTimer>
class ParticipantListModel;
// class TimeZoneModel;
class ConferenceInfoCore : public QObject, public AbstractObject {
Q_OBJECT
public:
Q_PROPERTY(TimeZoneModel *timeZoneModel READ getTimeZoneModel WRITE setTimeZoneModel NOTIFY timeZoneModelChanged)
Q_PROPERTY(QDateTime dateTime READ getDateTimeSystem WRITE setDateTime NOTIFY dateTimeChanged)
Q_PROPERTY(QDateTime endDateTime READ getEndDateTime WRITE setEndDateTime NOTIFY endDateTimeChanged)
Q_PROPERTY(QDateTime dateTimeUtc READ getDateTimeUtc NOTIFY dateTimeChanged)
Q_PROPERTY(int duration READ getDuration WRITE setDuration NOTIFY durationChanged)
Q_PROPERTY(
QString organizerAddress READ getOrganizerAddress WRITE setOrganizerAddress NOTIFY organizerAddressChanged)
Q_PROPERTY(QString organizerName READ getOrganizerName WRITE setOrganizerName NOTIFY organizerNameChanged)
Q_PROPERTY(QString subject READ getSubject WRITE setSubject NOTIFY subjectChanged)
Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged)
Q_PROPERTY(QString uri READ getUri NOTIFY uriChanged)
Q_PROPERTY(bool isScheduled READ isScheduled WRITE setIsScheduled NOTIFY isScheduledChanged)
Q_PROPERTY(bool isEnded READ isEnded WRITE setIsEnded NOTIFY isEndedChanged)
Q_PROPERTY(int inviteMode READ getInviteMode WRITE setInviteMode NOTIFY inviteModeChanged)
Q_PROPERTY(int participantCount READ getParticipantCount NOTIFY participantsChanged)
Q_PROPERTY(QVariantList participants READ getParticipants NOTIFY participantsChanged)
Q_PROPERTY(LinphoneEnums::ConferenceInfoState state READ getConferenceInfoState NOTIFY conferenceInfoStateChanged)
// Q_PROPERTY(LinphoneEnums::ConferenceSchedulerState conferenceSchedulerState READ getConferenceSchedulerState
// NOTIFY
// conferenceSchedulerStateChanged)
static QSharedPointer<ConferenceInfoCore> create(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo);
ConferenceInfoCore(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo, QObject *parent = nullptr);
ConferenceInfoCore(const ConferenceInfoCore &conferenceInfoCore);
~ConferenceInfoCore();
void reset(const ConferenceInfoCore &contact);
void setSelf(SafeSharedPointer<ConferenceInfoCore> me);
void setSelf(QSharedPointer<ConferenceInfoCore> me);
QDateTime getDateTimeUtc() const;
QDateTime getDateTimeSystem() const;
int getDuration() const;
QDateTime getEndDateTime() const;
QDateTime getEndDateTimeUtc() const;
QString getOrganizerName() const;
QString getOrganizerAddress() const;
QString getSubject() const;
QString getDescription() const;
QString getUri() const;
bool isScheduled() const;
void setIsScheduled(const bool &on);
bool computeIsEnded() const;
bool isEnded() const;
void setIsEnded(bool ended);
int getInviteMode() const;
QVariantList getParticipants() const;
// Q_INVOKABLE QVariantList getAllParticipants() const;
int getParticipantCount() const;
TimeZoneModel *getTimeZoneModel() const;
// QString getIcalendarString() const;
LinphoneEnums::ConferenceInfoState getConferenceInfoState() const;
// LinphoneEnums::ConferenceSchedulerState getConferenceSchedulerState() const;
void setDateTime(const QDateTime &date);
void setEndDateTime(const QDateTime &date);
void setDuration(int duration);
void setSubject(const QString &subject);
void setOrganizerName(const QString &organizer);
void setOrganizerAddress(const QString &organizer);
void setUri(const QString &uri);
void setTimeZoneModel(TimeZoneModel *model);
void setDescription(const QString &description);
void setInviteMode(const int &mode);
void setConferenceInfoState(LinphoneEnums::ConferenceInfoState state);
Q_INVOKABLE void addParticipant(const QString &address);
Q_INVOKABLE void removeParticipant(const QString &address);
Q_INVOKABLE void removeParticipant(const int &index);
Q_INVOKABLE QString getParticipantAddressAt(const int &index);
Q_INVOKABLE void clearParticipants();
void resetParticipants(QVariantList participants);
Q_INVOKABLE void resetParticipants(const QStringList &adresses);
Q_INVOKABLE int getParticipantIndex(const QString &address);
void writeFromModel(const std::shared_ptr<ConferenceInfoModel> &model);
void writeIntoModel(std::shared_ptr<ConferenceInfoModel> model);
Q_INVOKABLE void save();
Q_INVOKABLE void cancelConference();
Q_INVOKABLE void undo();
// Tools
// Q_INVOKABLE void resetConferenceInfo(); // Recreate a new conference info from factory
// SCHEDULER
// virtual void onConferenceSchedulerStateChanged(linphone::ConferenceScheduler::State state);
virtual void onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations);
signals:
void dateTimeChanged();
void endDateTimeChanged();
void durationChanged();
void organizerAddressChanged();
void organizerNameChanged();
void subjectChanged();
void descriptionChanged();
void participantsChanged();
void uriChanged();
void isScheduledChanged();
void isEndedChanged();
void inviteModeChanged();
void conferenceInfoStateChanged();
void timeZoneModelChanged();
// void conferenceSchedulerStateChanged();
void invitationsSent();
void removed();
// void lCreateConference(const int &securityLevel);
// void lCancelConference();
void lDeleteConferenceInfo(); // Remove completly this conference info from DB
private:
std::shared_ptr<ConferenceInfoModel> mConferenceInfoModel = nullptr;
QSharedPointer<SafeConnection<ConferenceInfoCore, ConferenceInfoModel>> mConfInfoModelConnection;
QSharedPointer<SafeConnection<ConferenceInfoCore, ConferenceSchedulerModel>> mConfSchedulerModelConnection;
QSharedPointer<SafeConnection<ConferenceInfoCore, CoreModel>> mCoreModelConnection;
QDateTime mDateTime;
QDateTime mEndDateTime;
int mDuration;
QString mOrganizerAddress;
QString mOrganizerName;
QString mSubject;
QString mDescription;
QString mUri;
QVariantList mParticipants;
QSharedPointer<TimeZoneModel> mTimeZoneModel;
LinphoneEnums::ConferenceInfoState mConferenceInfoState =
LinphoneEnums::ConferenceInfoState::ConferenceInfoStateNew;
bool mIsScheduled = true;
bool mIsEnded = false;
QTimer mCheckEndTimer;
int mInviteMode = 0;
// bool mRemoveRequested = false; // true if user has request its deletion from DB
// linphone::ConferenceScheduler::State mLastConferenceSchedulerState =
// linphone::ConferenceScheduler::State::Idle; // Workaround for missing getter in scheduler.
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(ConferenceInfoCore *)
#endif

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceInfoGui.hpp"
#include "ConferenceInfoCore.hpp"
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(ConferenceInfoGui)
ConferenceInfoGui::ConferenceInfoGui() {
qDebug() << "[ConferenceInfoGui] new" << this;
mCore = ConferenceInfoCore::create(nullptr);
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
}
ConferenceInfoGui::ConferenceInfoGui(QSharedPointer<ConferenceInfoCore> core) {
qDebug() << "[ConferenceInfoGui] new" << this;
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
mCore = core;
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
}
ConferenceInfoGui::~ConferenceInfoGui() {
mustBeInMainThread("~" + getClassName());
qDebug() << "[ConferenceInfoGui] delete" << this;
}
ConferenceInfoCore *ConferenceInfoGui::getCore() const {
return mCore.get();
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_INFO_GUI_H_
#define CONFERENCE_INFO_GUI_H_
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <QSharedPointer>
class ConferenceInfoCore;
class ConferenceInfoGui : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(ConferenceInfoCore *core READ getCore CONSTANT)
public:
ConferenceInfoGui();
ConferenceInfoGui(QSharedPointer<ConferenceInfoCore> core);
~ConferenceInfoGui();
ConferenceInfoCore *getCore() const;
QSharedPointer<ConferenceInfoCore> mCore;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceInfoList.hpp"
#include "ConferenceInfoCore.hpp"
#include "ConferenceInfoGui.hpp"
#include "core/App.hpp"
#include "model/object/VariantObject.hpp"
#include "tool/Utils.hpp"
#include <QSharedPointer>
#include <linphone++/linphone.hh>
// =============================================================================
DEFINE_ABSTRACT_OBJECT(ConferenceInfoList)
QSharedPointer<ConferenceInfoList> ConferenceInfoList::create() {
auto model = QSharedPointer<ConferenceInfoList>(new ConferenceInfoList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
model->setSelf(model);
return model;
}
ConferenceInfoList::ConferenceInfoList(QObject *parent) : ListProxy(parent) {
mustBeInMainThread(getClassName());
}
ConferenceInfoList::~ConferenceInfoList() {
mustBeInMainThread("~" + getClassName());
mCoreModelConnection = nullptr;
}
void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
mCoreModelConnection = QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>>(
new SafeConnection<ConferenceInfoList, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
mCoreModelConnection->makeConnectToCore(&ConferenceInfoList::lUpdate, [this]() {
mCoreModelConnection->invokeToModel([this]() {
QList<QSharedPointer<ConferenceInfoCore>> *items = new QList<QSharedPointer<ConferenceInfoCore>>();
mustBeInLinphoneThread(getClassName());
std::list<std::shared_ptr<linphone::ConferenceInfo>> conferenceInfos =
CoreModel::getInstance()->getCore()->getDefaultAccount()->getConferenceInformationList();
for (auto conferenceInfo : conferenceInfos) {
auto confInfoCore = build(conferenceInfo);
if (confInfoCore) items->push_back(confInfoCore);
}
mCoreModelConnection->invokeToCore([this, items]() {
mustBeInMainThread(getClassName());
resetData();
add(*items);
delete items;
});
});
});
// mCoreModelConnection->makeConnectToModel(
// &CoreModel::conferenceInfoReceived,
// [this](const std::shared_ptr<linphone::Core> core,
// const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
// auto realConferenceInfo = CoreModel::getInstance()->getCore()->findConferenceInformationFromUri(
// conferenceInfo->getUri()->clone());
// // auto realConferenceInfo = ConferenceInfoModel::findConferenceInfo(conferenceInfo);
// if (realConferenceInfo) {
// auto model = get(realConferenceInfo);
// if (model) {
// // model->setConferenceInfo(realConferenceInfo);
// } else {
// auto confInfo = build(realConferenceInfo);
// if (confInfo) add(confInfo);
// }
// } else
// qWarning() << "No ConferenceInfo have beend found for " << conferenceInfo->getUri()->asString().c_str();
// });
mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceInfoReceived, &ConferenceInfoList::lUpdate);
mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceStateChanged, [this] {
qDebug() << "list: conf state changed";
lUpdate();
});
mCoreModelConnection->makeConnectToModel(
&CoreModel::conferenceInfoReceived,
[this](const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
qDebug() << "info received" << conferenceInfo->getOrganizer()->asStringUriOnly()
<< conferenceInfo->getSubject();
});
emit lUpdate();
}
QSharedPointer<ConferenceInfoCore>
ConferenceInfoList::get(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo) const {
auto uri = Utils::coreStringToAppString(conferenceInfo->getUri()->asStringUriOnly());
for (auto item : mList) {
auto model = item.objectCast<ConferenceInfoCore>();
auto confUri = model->getUri();
if (confUri == uri) {
return model;
}
}
return nullptr;
}
QSharedPointer<ConferenceInfoCore>
ConferenceInfoList::build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo) const {
auto me = CoreModel::getInstance()->getCore()->getDefaultAccount()->getParams()->getIdentityAddress();
qDebug() << "[CONFERENCEINFOLIST] looking for me " << me->asStringUriOnly();
std::list<std::shared_ptr<linphone::ParticipantInfo>> participants = conferenceInfo->getParticipantInfos();
bool haveMe = conferenceInfo->getOrganizer()->weakEqual(me);
if (!haveMe)
haveMe = (std::find_if(participants.begin(), participants.end(),
[me](const std::shared_ptr<linphone::ParticipantInfo> &p) {
// qDebug()
// << "[CONFERENCEINFOLIST] participant " << p->getAddress()->asStringUriOnly();
return me->weakEqual(p->getAddress());
}) != participants.end());
if (haveMe) {
auto conferenceModel = ConferenceInfoCore::create(conferenceInfo);
connect(conferenceModel.get(), &ConferenceInfoCore::removed, this, &ConferenceInfoList::lUpdate);
return conferenceModel;
} else return nullptr;
}
void ConferenceInfoList::remove(const int &row) {
// beginRemoveRows(QModelIndex(), row, row);
auto item = mList[row].objectCast<ConferenceInfoCore>();
emit item->lDeleteConferenceInfo();
// endRemoveRows();
}
QHash<int, QByteArray> ConferenceInfoList::roleNames() const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$modelData";
roles[Qt::DisplayRole + 1] = "$sectionMonth";
return roles;
}
QVariant ConferenceInfoList::data(const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
if (role == Qt::DisplayRole) {
return QVariant::fromValue(new ConferenceInfoGui(mList[row].objectCast<ConferenceInfoCore>()));
} else if (role == Qt::DisplayRole + 1) {
return Utils::toDateMonthString(mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc());
}
return QVariant();
}

View file

@ -0,0 +1,58 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_INFO_LIST_H_
#define CONFERENCE_INFO_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <linphone++/linphone.hh>
class CoreModel;
class ConferenceInfoCore;
class ConferenceInfoList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<ConferenceInfoList> create();
// Create a ConferenceInfoCore and make connections to List.
ConferenceInfoList(QObject *parent = Q_NULLPTR);
~ConferenceInfoList();
void setSelf(QSharedPointer<ConferenceInfoList> me);
QSharedPointer<ConferenceInfoCore> get(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo) const;
QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo) const;
void remove(const int &row);
QHash<int, QByteArray> roleNames() const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void lUpdate();
private:
QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection;
DECLARE_ABSTRACT_OBJECT
};
#endif // CONFERENCE_INFO_LIST_H_

View file

@ -0,0 +1,74 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceInfoProxy.hpp"
#include "ConferenceInfoCore.hpp"
#include "ConferenceInfoGui.hpp"
#include "ConferenceInfoList.hpp"
DEFINE_ABSTRACT_OBJECT(ConferenceInfoProxy)
ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(parent) {
mList = ConferenceInfoList::create();
setSourceModel(mList.get());
connect(this, &ConferenceInfoProxy::searchTextChanged, [this] { invalidate(); });
}
ConferenceInfoProxy::~ConferenceInfoProxy() {
setSourceModel(nullptr);
}
QString ConferenceInfoProxy::getSearchText() const {
return mSearchText;
}
void ConferenceInfoProxy::setSearchText(const QString &search) {
mSearchText = search;
emit searchTextChanged();
}
bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
const ConferenceInfoGui *gui =
sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value<ConferenceInfoGui *>();
if (gui) {
auto ciCore = gui->getCore();
assert(ciCore);
if (!ciCore->getSubject().contains(mSearchText)) return false;
if (ciCore->getDuration() == 0) return false;
QDateTime currentDateTime = QDateTime::currentDateTimeUtc();
if (mFilterType == 0) {
// auto res = ciCore->getEndDateTimeUtc() < currentDateTime;
return true;
} else if (mFilterType == 1) {
auto res = ciCore->getEndDateTimeUtc() >= currentDateTime;
return res;
// } else if (mFilterType == 2) {
// return !Utils::isMe(ciCore->getOrganizer());
} else return mFilterType == -1;
}
return false;
}
bool ConferenceInfoProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = getItemAt<ConferenceInfoList, ConferenceInfoGui>(left.row())->getCore();
auto r = getItemAt<ConferenceInfoList, ConferenceInfoGui>(right.row())->getCore();
return l->getDateTimeUtc() < r->getDateTimeUtc();
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_INFO_PROXY_H_
#define CONFERENCE_INFO_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "tool/AbstractObject.hpp"
class ConferenceInfoList;
class ConferenceInfoProxy : public SortFilterProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
public:
ConferenceInfoProxy(QObject *parent = Q_NULLPTR);
~ConferenceInfoProxy();
QString getSearchText() const;
void setSearchText(const QString &search);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
signals:
void searchTextChanged();
private:
QString mSearchText;
QSharedPointer<ConferenceInfoList> mList;
DECLARE_ABSTRACT_OBJECT
};
#endif // CONFERENCE_INFO_PROXY_H_

View file

@ -459,6 +459,7 @@ void FriendCore::remove() {
}
void FriendCore::save() { // Save Values to model
mustBeInMainThread(getClassName() + "::save()");
if (mAddressList.size() > 0) {
auto it = std::find_if(mAddressList.begin(), mAddressList.end(), [this](const QVariant &a) {
return a.toMap()["address"].toString() == mDefaultAddress;
@ -472,9 +473,9 @@ void FriendCore::save() { // Save Values to model
emit defaultAddressChanged();
}
FriendCore *thisCopy = new FriendCore(*this); // Pointer to avoid multiple copies in lambdas
if (mFriendModel) {
mFriendModelConnection->invokeToModel([this, thisCopy]() { // Copy values to avoid concurrency
mustBeInLinphoneThread(getClassName() + "::save()");
thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater();
mFriendModelConnection->invokeToCore([this]() { saved(); });
@ -491,18 +492,17 @@ void FriendCore::save() { // Save Values to model
if (contact) break;
}
if (contact != nullptr) {
auto friendModel = Utils::makeQObject_ptr<FriendModel>(contact);
friendModel->setSelf(friendModel);
thisCopy->writeIntoModel(friendModel);
mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact);
mFriendModel->setSelf(mFriendModel);
thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater();
if (mFriendModelConnection) mFriendModelConnection->invokeToCore([this] { saved(); });
else mCoreModelConnection->invokeToCore([this] { saved(); });
} else {
auto contact = core->createFriend();
std::shared_ptr<FriendModel> friendModel;
friendModel = Utils::makeQObject_ptr<FriendModel>(contact);
friendModel->setSelf(friendModel);
thisCopy->writeIntoModel(friendModel);
mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact);
mFriendModel->setSelf(mFriendModel);
thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater();
bool created = (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK);
if (created) {

View file

@ -24,6 +24,7 @@
DEFINE_ABSTRACT_OBJECT(FriendGui)
FriendGui::FriendGui(QObject *parent) : QObject(parent) {
mustBeInMainThread(getClassName());
mCore = FriendCore::create(nullptr);
}
FriendGui::FriendGui(QSharedPointer<FriendCore> core) {

View file

@ -21,7 +21,6 @@
#include "FriendInitialProxy.hpp"
#include "FriendCore.hpp"
#include "FriendGui.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(FriendInitialProxy)

View file

@ -0,0 +1,172 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <QQmlApplicationEngine>
#include "core/App.hpp"
#include "ParticipantCore.hpp"
// #include "ParticipantDeviceList.hpp"
#include "model/participant/ParticipantModel.hpp"
#include "tool/Utils.hpp"
// =============================================================================
DEFINE_ABSTRACT_OBJECT(ParticipantCore)
QSharedPointer<ParticipantCore> ParticipantCore::create(const std::shared_ptr<linphone::Participant> &participant) {
auto sharedPointer = QSharedPointer<ParticipantCore>(new ParticipantCore(participant), &QObject::deleteLater);
sharedPointer->setSelf(sharedPointer);
sharedPointer->moveToThread(App::getInstance()->thread());
return sharedPointer;
}
ParticipantCore::ParticipantCore(const std::shared_ptr<linphone::Participant> &participant) : QObject(nullptr) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mParticipantModel = Utils::makeQObject_ptr<ParticipantModel>(participant);
mAdminStatus = participant->isAdmin();
mSipAddress = Utils::coreStringToAppString(participant->getAddress()->asStringUriOnly());
mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime());
mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getDisplayName());
if (mDisplayName.isEmpty()) mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getUsername());
for (auto &device : participant->getDevices()) {
auto name = Utils::coreStringToAppString(device->getName());
auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly());
QVariantMap map;
map.insert("name", name);
map.insert("address", address);
mParticipantDevices.append(map);
}
// App::getInstance()->mEngine->setObjectOwnership(mParticipantDevices.get(),
// QQmlEngine::CppOwnership); // Managed by QSharedPointer
// connect(this, &ParticipantCore::deviceSecurityLevelChanged, mParticipantDevices.get(),
// &ParticipantDeviceListModel::securityLevelChanged);
}
ParticipantCore::~ParticipantCore() {
mustBeInMainThread("~" + getClassName());
}
void ParticipantCore::setSelf(QSharedPointer<ParticipantCore> me) {
mParticipantConnection = QSharedPointer<SafeConnection<ParticipantCore, ParticipantModel>>(
new SafeConnection<ParticipantCore, ParticipantModel>(me, mParticipantModel), &QObject::deleteLater);
mParticipantConnection->makeConnectToCore(&ParticipantCore::lStartInvitation, [this](const int &secs) {
QTimer::singleShot(secs * 1000, this, &ParticipantCore::onEndOfInvitation);
});
// mParticipantConnection->makeConnectToModel(&ParticipantModel::)
}
// FriendCore *ParticipantCore::getFriendCore() const {
// return nullptr;
// // return CoreModel::getInstance()->getContactsListModel()->findContactModelFromSipAddress(getSipAddress()).get();
// }
int ParticipantCore::getSecurityLevel() const {
return mSecurityLevel;
}
int ParticipantCore::getDeviceCount() const {
return mParticipantDevices.size();
}
bool ParticipantCore::isMe() const {
return true; // Utils::isMe(getSipAddress());
}
QString ParticipantCore::getSipAddress() const {
return mSipAddress;
}
void ParticipantCore::setSipAddress(const QString &address) {
if (mSipAddress != address) {
mSipAddress = address;
emit sipAddressChanged();
}
}
void ParticipantCore::setDisplayName(const QString &name) {
if (mDisplayName != name) {
mDisplayName = name;
emit displayNameChanged();
}
}
QString ParticipantCore::getDisplayName() const {
return mDisplayName;
}
QDateTime ParticipantCore::getCreationTime() const {
return mCreationTime;
}
void ParticipantCore::setCreationTime(const QDateTime &date) {
if (date != mCreationTime) {
mCreationTime = date;
emit creationTimeChanged();
}
}
bool ParticipantCore::getAdminStatus() const {
return mAdminStatus;
}
bool ParticipantCore::isFocus() const {
return mIsFocus;
}
void ParticipantCore::setAdminStatus(const bool &status) {
if (status != mAdminStatus) {
mAdminStatus = status;
emit adminStatusChanged();
}
}
void ParticipantCore::setIsFocus(const bool &focus) {
if (focus != mIsFocus) {
mIsFocus = focus;
emit isFocusChanged();
}
}
void ParticipantCore::setSecurityLevel(int level) {
if (level != mSecurityLevel) {
mSecurityLevel = level;
emit securityLevelChanged();
}
}
void ParticipantCore::onSecurityLevelChanged() {
emit securityLevelChanged();
}
void ParticipantCore::onDeviceSecurityLevelChanged(std::shared_ptr<const linphone::Address> device) {
emit deviceSecurityLevelChanged(device);
}
// ParticipantDeviceProxyModel *ParticipantCore::getProxyDevices() {
// ParticipantDeviceProxyModel *devices = new ParticipantDeviceProxyModel();
// devices->setParticipant(this);
// return devices;
// }
QList<QVariant> ParticipantCore::getParticipantDevices() {
return mParticipantDevices;
}
void ParticipantCore::onEndOfInvitation() {
emit invitationTimeout(this);
}

View file

@ -0,0 +1,126 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_CORE_H_
#define PARTICIPANT_CORE_H_
#include "tool/thread/SafeConnection.hpp"
#include <linphone++/linphone.hh>
#include <QDateTime>
#include <QMap>
#include <QObject>
#include <QSharedPointer>
#include <QString>
class FriendCore;
class ParticipantDeviceProxy;
class ParticipantDeviceList;
class ParticipantModel;
class ParticipantCore : public QObject, public AbstractObject {
Q_OBJECT
// Q_PROPERTY(FriendCore *friendCore READ getFriendCore CONSTANT)
Q_PROPERTY(QString sipAddress READ getSipAddress WRITE setSipAddress NOTIFY sipAddressChanged)
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName NOTIFY displayNameChanged)
Q_PROPERTY(bool adminStatus READ getAdminStatus WRITE setAdminStatus NOTIFY adminStatusChanged)
Q_PROPERTY(bool isMe READ isMe CONSTANT)
Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT)
Q_PROPERTY(bool focus READ isFocus CONSTANT)
Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
Q_PROPERTY(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged)
Q_PROPERTY(QList<QVariant> devices READ getParticipantDevices NOTIFY deviceChanged)
// Q_PROPERTY(bool inviting READ getInviting NOTIFY invitingChanged)
public:
static QSharedPointer<ParticipantCore> create(const std::shared_ptr<linphone::Participant> &participant);
ParticipantCore(const std::shared_ptr<linphone::Participant> &participant);
~ParticipantCore();
void setSelf(QSharedPointer<ParticipantCore> me);
// FriendCore *getFriendCore() const;
QString getDisplayName() const;
QString getSipAddress() const;
QDateTime getCreationTime() const;
bool getAdminStatus() const;
bool isFocus() const;
int getSecurityLevel() const;
int getDeviceCount() const;
bool isMe() const;
void setSipAddress(const QString &address);
void setDisplayName(const QString &name);
void setCreationTime(const QDateTime &date);
void setAdminStatus(const bool &status);
void setIsFocus(const bool &focus);
void setSecurityLevel(int level);
// Q_INVOKABLE ParticipantDeviceProxy *getProxyDevices();
QList<QVariant> getParticipantDevices();
public slots:
void onSecurityLevelChanged();
void onDeviceSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
void onEndOfInvitation();
signals:
void securityLevelChanged();
void deviceSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
void sipAddressChanged();
void updateAdminStatus(
const std::shared_ptr<linphone::Participant> participant,
const bool &isAdmin); // Split in two signals in order to sequancialize execution between SDK and GUI
void adminStatusChanged();
void isFocusChanged();
void deviceCountChanged();
void invitingChanged();
void creationTimeChanged();
void displayNameChanged();
void lStartInvitation(const int &secs);
void invitationTimeout(ParticipantCore *model);
void deviceChanged();
private:
std::shared_ptr<ParticipantModel> mParticipantModel;
QSharedPointer<SafeConnection<ParticipantCore, ParticipantModel>> mParticipantConnection;
// QSharedPointer<ParticipantDeviceList> mParticipantDevices;
QList<QVariant> mParticipantDevices;
QString mDisplayName;
QString mSipAddress;
QDateTime mCreationTime;
bool mAdminStatus;
bool mIsFocus;
int mSecurityLevel;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<ParticipantCore>);
#endif // PARTICIPANT_CORE_H_

View file

@ -0,0 +1,250 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantDeviceCore.hpp"
#include "core/App.hpp"
#include "tool/Utils.hpp"
#include <QQmlApplicationEngine>
DEFINE_ABSTRACT_OBJECT(ParticipantDeviceCore)
QSharedPointer<ParticipantDeviceCore>
ParticipantDeviceCore::create(std::shared_ptr<linphone::ParticipantDevice> device, const bool &isMe, QObject *parent) {
auto sharedPointer =
QSharedPointer<ParticipantDeviceCore>(new ParticipantDeviceCore(device, isMe, parent), &QObject::deleteLater);
sharedPointer->setSelf(sharedPointer);
sharedPointer->moveToThread(App::getInstance()->thread());
return nullptr;
}
ParticipantDeviceCore::ParticipantDeviceCore(const std::shared_ptr<linphone::ParticipantDevice> &device,
const bool &isMe,
QObject *parent)
: QObject(parent) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mustBeInLinphoneThread(getClassName());
mName = Utils::coreStringToAppString(device->getName());
mDisplayName = Utils::coreStringToAppString(device->getAddress()->getDisplayName());
mAddress = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly());
mIsMuted = device->getIsMuted();
mIsMe = isMe;
mParticipantDeviceModel = Utils::makeQObject_ptr<ParticipantDeviceModel>(device);
mParticipantDeviceModel->setSelf(mParticipantDeviceModel);
mState = LinphoneEnums::fromLinphone(device->getState());
// mCall = callModel;
// if (mCall) connect(mCall, &CallModel::statusChanged, this, &ParticipantDeviceCore::onCallStatusChanged);
mIsVideoEnabled = mParticipantDeviceModel->isVideoEnabled();
// if (mCall && mParticipantDeviceModel) updateIsLocal();
}
ParticipantDeviceCore::~ParticipantDeviceCore() {
mParticipantDeviceModel->removeListener();
}
void ParticipantDeviceCore::setSelf(QSharedPointer<ParticipantDeviceCore> me) {
mParticipantDeviceModelConnection = QSharedPointer<SafeConnection<ParticipantDeviceCore, ParticipantDeviceModel>>(
new SafeConnection<ParticipantDeviceCore, ParticipantDeviceModel>(me, mParticipantDeviceModel),
&QObject::deleteLater);
mParticipantDeviceModelConnection->makeConnectToModel(
&ParticipantDeviceModel::isPausedChanged, [this](bool paused) {
mParticipantDeviceModelConnection->invokeToCore([this, paused] { setPaused(paused); });
});
mParticipantDeviceModelConnection->makeConnectToModel(
&ParticipantDeviceModel::isSpeakingChanged, [this](bool speaking) {
mParticipantDeviceModelConnection->invokeToCore([this, speaking] { setIsSpeaking(speaking); });
});
mParticipantDeviceModelConnection->makeConnectToModel(&ParticipantDeviceModel::isMutedChanged, [this](bool muted) {
mParticipantDeviceModelConnection->invokeToCore([this, muted] { setIsMuted(muted); });
});
mParticipantDeviceModelConnection->makeConnectToModel(
&ParticipantDeviceModel::stateChanged, [this](LinphoneEnums::ParticipantDeviceState state) {
mParticipantDeviceModelConnection->invokeToCore([this, state] { setState(state); });
});
mParticipantDeviceModelConnection->makeConnectToModel(
&ParticipantDeviceModel::streamCapabilityChanged, [this](linphone::StreamType) {
auto videoEnabled = mParticipantDeviceModel->isVideoEnabled();
mParticipantDeviceModelConnection->invokeToCore([this, videoEnabled] { setIsVideoEnabled(videoEnabled); });
});
mParticipantDeviceModelConnection->makeConnectToModel(
&ParticipantDeviceModel::streamAvailabilityChanged, [this](linphone::StreamType) {
auto videoEnabled = mParticipantDeviceModel->isVideoEnabled();
mParticipantDeviceModelConnection->invokeToCore([this, videoEnabled] { setIsVideoEnabled(videoEnabled); });
});
}
QString ParticipantDeviceCore::getName() const {
return mName;
}
QString ParticipantDeviceCore::getDisplayName() const {
return mDisplayName;
}
int ParticipantDeviceCore::getSecurityLevel() const {
if (mParticipantDeviceModel) {
int security = (int)mParticipantDeviceModel->getSecurityLevel();
return security;
} else return 0;
}
time_t ParticipantDeviceCore::getTimeOfJoining() const {
return mParticipantDeviceModel ? mParticipantDeviceModel->getTimeOfJoining() : 0;
}
QString ParticipantDeviceCore::getAddress() const {
return mAddress;
}
bool ParticipantDeviceCore::getPaused() const {
return mIsPaused;
}
bool ParticipantDeviceCore::getIsSpeaking() const {
return mIsSpeaking;
}
bool ParticipantDeviceCore::getIsMuted() const {
return mIsMuted;
}
LinphoneEnums::ParticipantDeviceState ParticipantDeviceCore::getState() const {
return mState;
}
bool ParticipantDeviceCore::isVideoEnabled() const {
return mIsVideoEnabled;
}
void ParticipantDeviceCore::setPaused(bool paused) {
if (mIsPaused != paused) {
mIsPaused = paused;
emit isPausedChanged();
}
}
void ParticipantDeviceCore::setIsSpeaking(bool speaking) {
if (mIsSpeaking != speaking) {
mIsSpeaking = speaking;
emit isSpeakingChanged();
}
}
void ParticipantDeviceCore::setIsMuted(bool muted) {
if (mIsMuted != muted) {
mIsMuted = muted;
emit isMutedChanged();
}
}
void ParticipantDeviceCore::setIsLocal(bool local) {
if (mIsLocal != local) {
mIsLocal = local;
emit isLocalChanged();
}
}
void ParticipantDeviceCore::setState(LinphoneEnums::ParticipantDeviceState state) {
if (mState != state) {
mState = state;
emit stateChanged();
}
}
void ParticipantDeviceCore::setIsVideoEnabled(bool enabled) {
if (mIsVideoEnabled != enabled) {
mIsVideoEnabled = enabled;
emit videoEnabledChanged();
}
}
bool ParticipantDeviceCore::isMe() const {
return mIsMe;
}
bool ParticipantDeviceCore::isLocal() const {
return mIsLocal;
}
// void ParticipantDeviceCore::updateIsLocal() {
// auto deviceAddress = mParticipantDeviceModel->getAddress();
// auto callAddress = mCall->getConferenceSharedModel()->getConference()->getMe()->getAddress();
// auto gruuAddress =
// CoreManager::getInstance()->getAccountSettingsModel()->findAccount(callAddress)->getContactAddress();
// setIsLocal(deviceAddress->equal(gruuAddress));
// }
// void ParticipantDeviceCore::onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device) {
// if (!device || mParticipantDeviceModel && mParticipantDeviceModel->getAddress()->weakEqual(device))
// emit securityLevelChanged();
// }
// void ParticipantDeviceCore::onCallStatusChanged() {
// if (mCall->getCall()->getState() == linphone::Call::State::StreamsRunning) {
// updateVideoEnabled();
// }
// }
//--------------------------------------------------------------------
void ParticipantDeviceCore::onIsSpeakingChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isSpeaking) {
setIsSpeaking(isSpeaking);
}
void ParticipantDeviceCore::onIsMuted(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isMuted) {
emit isMutedChanged();
}
void ParticipantDeviceCore::onStateChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::ParticipantDevice::State state) {
switch (state) {
case linphone::ParticipantDevice::State::Joining:
break;
case linphone::ParticipantDevice::State::Present:
setPaused(false);
break;
case linphone::ParticipantDevice::State::Leaving:
break;
case linphone::ParticipantDevice::State::Left:
break;
case linphone::ParticipantDevice::State::ScheduledForJoining:
break;
case linphone::ParticipantDevice::State::ScheduledForLeaving:
break;
case linphone::ParticipantDevice::State::OnHold:
setPaused(true);
break;
case linphone::ParticipantDevice::State::Alerting:
break;
case linphone::ParticipantDevice::State::MutedByFocus:
break;
default: {
}
}
setState(LinphoneEnums::fromLinphone(state));
}
void ParticipantDeviceCore::onStreamCapabilityChanged(
const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::MediaDirection direction,
linphone::StreamType streamType) {
}
void ParticipantDeviceCore::onStreamAvailabilityChanged(
const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool available,
linphone::StreamType streamType) {
}

View file

@ -0,0 +1,130 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_DEVICE_CORE_H_
#define PARTICIPANT_DEVICE_CORE_H_
#include "model/participant/ParticipantDeviceModel.hpp"
#include "tool/LinphoneEnums.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <linphone++/linphone.hh>
#include <QDateTime>
#include <QObject>
#include <QSharedPointer>
#include <QString>
class ParticipantDeviceCore : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString displayName READ getDisplayName CONSTANT)
Q_PROPERTY(QString name READ getName CONSTANT)
Q_PROPERTY(QString address READ getAddress CONSTANT)
Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
Q_PROPERTY(time_t timeOfJoining READ getTimeOfJoining CONSTANT)
Q_PROPERTY(bool videoEnabled READ isVideoEnabled NOTIFY videoEnabledChanged)
Q_PROPERTY(bool isMe READ isMe CONSTANT)
Q_PROPERTY(bool isLocal READ isLocal WRITE setIsLocal NOTIFY
isLocalChanged) // Can change on call update. Not really used but it just in case as Object can be
// initialized with empty call/device.
Q_PROPERTY(bool isPaused READ getPaused WRITE setPaused NOTIFY isPausedChanged)
Q_PROPERTY(bool isSpeaking READ getIsSpeaking WRITE setIsSpeaking NOTIFY isSpeakingChanged)
Q_PROPERTY(bool isMuted READ getIsMuted NOTIFY isMutedChanged)
Q_PROPERTY(LinphoneEnums::ParticipantDeviceState state READ getState WRITE setState NOTIFY stateChanged)
public:
// static QSharedPointer<ParticipantDeviceCore> create(const std::shared_ptr<linphone::ParticipantDevice> &device);
static QSharedPointer<ParticipantDeviceCore>
create(std::shared_ptr<linphone::ParticipantDevice> device, const bool &isMe = false, QObject *parent = nullptr);
ParticipantDeviceCore(const std::shared_ptr<linphone::ParticipantDevice> &device,
const bool &isMe = false,
QObject *parent = nullptr);
virtual ~ParticipantDeviceCore();
void setSelf(QSharedPointer<ParticipantDeviceCore> me);
QString getName() const;
QString getDisplayName() const;
QString getAddress() const;
int getSecurityLevel() const;
time_t getTimeOfJoining() const;
bool isVideoEnabled() const;
bool isMe() const;
bool isLocal() const;
bool getPaused() const;
bool getIsSpeaking() const;
bool getIsMuted() const;
LinphoneEnums::ParticipantDeviceState getState() const;
std::shared_ptr<linphone::ParticipantDevice> getDevice();
void setPaused(bool paused);
void setIsSpeaking(bool speaking);
void setIsMuted(bool muted);
void setIsLocal(bool local);
void setIsVideoEnabled(bool enabled);
void setState(LinphoneEnums::ParticipantDeviceState state);
virtual void onIsSpeakingChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isSpeaking);
virtual void onIsMuted(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice, bool isMuted);
virtual void onStateChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::ParticipantDevice::State state);
virtual void onStreamCapabilityChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::MediaDirection direction,
linphone::StreamType streamType);
virtual void onStreamAvailabilityChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool available,
linphone::StreamType streamType);
// void updateIsLocal();
// public slots:
// void onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
// void onCallStatusChanged();
signals:
void securityLevelChanged();
void videoEnabledChanged();
void isPausedChanged();
void isSpeakingChanged();
void isMutedChanged();
void isLocalChanged();
void stateChanged();
private:
QString mName;
QString mDisplayName;
QString mAddress;
bool mIsMe = false;
bool mIsLocal = false;
bool mIsVideoEnabled;
bool mIsMuted = false;
bool mIsPaused = false;
bool mIsSpeaking = false;
LinphoneEnums::ParticipantDeviceState mState;
std::shared_ptr<ParticipantDeviceModel> mParticipantDeviceModel;
QSharedPointer<SafeConnection<ParticipantDeviceCore, ParticipantDeviceModel>> mParticipantDeviceModelConnection;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<ParticipantDeviceCore>)
#endif // PARTICIPANT_CORE_H_

View file

@ -0,0 +1,343 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantDeviceList.hpp"
#include "core/App.hpp"
#include "core/participant/ParticipantCore.hpp"
#include <QQmlApplicationEngine>
#include <algorithm>
DEFINE_ABSTRACT_OBJECT(ParticipantDeviceList)
QSharedPointer<ParticipantDeviceList>
ParticipantDeviceList::create(const std::shared_ptr<linphone::Participant> &participant) {
auto model = QSharedPointer<ParticipantDeviceList>(new ParticipantDeviceList(participant), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
model->setSelf(model);
return model;
}
QSharedPointer<ParticipantDeviceList> ParticipantDeviceList::create() {
auto model = QSharedPointer<ParticipantDeviceList>(new ParticipantDeviceList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
model->setSelf(model);
return model;
}
ParticipantDeviceList::ParticipantDeviceList(const std::shared_ptr<linphone::Participant> &participant, QObject *parent)
: ListProxy(parent) {
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices();
for (auto device : devices) {
auto deviceModel = ParticipantDeviceCore::create(device, isMe(device));
// connect(this, &ParticipantDeviceList::securityLevelChanged, deviceModel.get(),
// &ParticipantDeviceCore::onSecurityLevelChanged);
connect(deviceModel.get(), &ParticipantDeviceCore::isSpeakingChanged, this,
&ParticipantDeviceList::onParticipantDeviceSpeaking);
mList << deviceModel;
}
mInitialized = true;
}
ParticipantDeviceList::ParticipantDeviceList(QObject *parent) {
mustBeInMainThread(getClassName());
}
// ParticipantDeviceList::ParticipantDeviceList(CallModel *callModel, QObject *parent) : ProxyListModel(parent) {
// if (callModel && callModel->isConference()) {
// mCallModel = callModel;
// connect(mCallModel, &CallModel::conferenceModelChanged, this, &ParticipantDeviceList::onConferenceModelChanged);
// initConferenceModel();
// }
// }
ParticipantDeviceList::~ParticipantDeviceList() {
mustBeInMainThread(getClassName());
}
void ParticipantDeviceList::setSelf(QSharedPointer<ParticipantDeviceList> me) {
}
void ParticipantDeviceList::initConferenceModel() {
// if (!mInitialized && mCallModel) {
// auto conferenceModel = mCallModel->getConferenceSharedModel();
// if (conferenceModel) {
// updateDevices(conferenceModel->getConference()->getMe()->getDevices(), true);
// updateDevices(conferenceModel->getConference()->getParticipantDeviceList(), false);
// qDebug() << "Conference have " << mList.size() << " devices";
// connect(conferenceModel.get(), &ConferenceModel::activeSpeakerParticipantDevice, this,
// &ParticipantDeviceList::onActiveSpeakerParticipantDevice);
// connect(conferenceModel.get(), &ConferenceModel::participantAdded, this,
// &ParticipantDeviceList::onParticipantAdded);
// connect(conferenceModel.get(), &ConferenceModel::participantRemoved, this,
// &ParticipantDeviceList::onParticipantRemoved);
// connect(conferenceModel.get(), &ConferenceModel::participantDeviceAdded, this,
// &ParticipantDeviceList::onParticipantDeviceAdded);
// connect(conferenceModel.get(), &ConferenceModel::participantDeviceRemoved, this,
// &ParticipantDeviceList::onParticipantDeviceRemoved);
// connect(conferenceModel.get(), &ConferenceModel::conferenceStateChanged, this,
// &ParticipantDeviceList::onConferenceStateChanged);
// connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaCapabilityChanged, this,
// &ParticipantDeviceList::onParticipantDeviceMediaCapabilityChanged);
// connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaAvailabilityChanged, this,
// &ParticipantDeviceList::onParticipantDeviceMediaAvailabilityChanged);
// connect(conferenceModel.get(), &ConferenceModel::participantDeviceIsSpeakingChanged, this,
// &ParticipantDeviceList::onParticipantDeviceIsSpeakingChanged);
// mActiveSpeaker = get(conferenceModel->getConference()->getActiveSpeakerParticipantDevice());
// mInitialized = true;
// }
// }
}
void ParticipantDeviceList::updateDevices(std::shared_ptr<linphone::Participant> participant) {
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices();
bool meAdded = false;
beginResetModel();
qDebug() << "Update devices from participant";
mList.clear();
for (auto device : devices) {
bool addMe = isMe(device);
auto deviceModel = ParticipantDeviceCore::create(device, addMe);
// connect(this, &ParticipantDeviceList::securityLevelChanged, deviceModel.get(),
// &ParticipantDeviceCore::onSecurityLevelChanged);
connect(deviceModel.get(), &ParticipantDeviceCore::isSpeakingChanged, this,
&ParticipantDeviceList::onParticipantDeviceSpeaking);
mList << deviceModel;
if (addMe) meAdded = true;
}
endResetModel();
if (meAdded) emit meChanged();
}
void ParticipantDeviceList::updateDevices(const std::list<QSharedPointer<ParticipantDeviceCore>> &devices,
const bool &isMe) {
for (auto device : devices) {
add(device);
}
}
bool ParticipantDeviceList::add(const QSharedPointer<ParticipantDeviceCore> &deviceToAdd) {
auto deviceToAddAddr = deviceToAdd->getAddress();
int row = 0;
qDebug() << "Adding device " << deviceToAdd->getAddress();
for (auto item : mList) {
auto deviceCore = item.objectCast<ParticipantDeviceCore>();
if (deviceCore == deviceToAdd) {
qDebug() << "Device already exist. Send video update event";
// deviceCore->updateVideoEnabled();
return false;
} else if (deviceToAddAddr == deviceCore->getAddress()) { // Address is the same (same device) but the model
// is using another linphone object. Replace it.
qDebug() << "Replacing device : Device exists but the model is using another linphone object.";
// deviceCore->updateVideoEnabled();
removeRow(row);
break;
}
++row;
}
bool addMe = isMe(deviceToAdd);
auto deviceModel = ParticipantDeviceCore::create(deviceToAdd, addMe);
// connect(this, &ParticipantDeviceList::securityLevelChanged, deviceModel.get(),
// &ParticipantDeviceCore::onSecurityLevelChanged);
connect(deviceModel.get(), &ParticipantDeviceCore::isSpeakingChanged, this,
&ParticipantDeviceList::onParticipantDeviceSpeaking);
ListProxy::add<ParticipantDeviceCore>(deviceModel);
qDebug() << "Device added. Count=" << mList.count();
QStringList debugDevices;
for (auto i : mList) {
auto item = i.objectCast<ParticipantDeviceCore>();
debugDevices.push_back(item->getAddress());
}
qDebug() << debugDevices.join("\n");
if (addMe) {
qDebug() << "Added a me device";
emit meChanged();
} else if (mList.size() == 1 ||
(mList.size() == 2 && isMe(mList.front().objectCast<ParticipantDeviceCore>()->getDevice()))) {
mActiveSpeaker = mList.back().objectCast<ParticipantDeviceCore>();
emit activeSpeakerChanged();
}
return true;
}
bool ParticipantDeviceList::remove(std::shared_ptr<const linphone::ParticipantDevice> deviceToRemove) {
int row = 0;
for (auto item : mList) {
auto device = item.objectCast<ParticipantDeviceCore>();
if (device->getDevice() == deviceToRemove) {
// device->updateVideoEnabled();
removeRow(row);
return true;
} else ++row;
}
return false;
}
QSharedPointer<ParticipantDeviceCore>
ParticipantDeviceList::get(std::shared_ptr<const linphone::ParticipantDevice> deviceToGet, int *index) {
int row = 0;
for (auto item : mList) {
auto device = item.objectCast<ParticipantDeviceCore>();
if (device->getDevice() == deviceToGet) {
if (index) *index = row;
return device;
} else ++row;
}
return nullptr;
}
QSharedPointer<ParticipantDeviceCore> ParticipantDeviceList::getMe(int *index) const {
int row = 0;
for (auto item : mList) {
auto device = item.objectCast<ParticipantDeviceCore>();
if (device->isMe() && device->isLocal()) {
if (index) *index = row;
return device;
} else ++row;
}
return nullptr;
}
ParticipantDeviceCore *ParticipantDeviceList::getActiveSpeakerModel() const {
return mActiveSpeaker.get();
}
bool ParticipantDeviceList::isMe(std::shared_ptr<linphone::ParticipantDevice> deviceToCheck) const {
// if (mCallModel) {
// auto devices = mCallModel->getConferenceSharedModel()->getConference()->getMe()->getDevices();
// auto deviceToCheckAddress = deviceToCheck->getAddress();
// for (auto device : devices) {
// if (deviceToCheckAddress == device->getAddress()) return true;
// }
// }
return false;
}
bool ParticipantDeviceList::isMeAlone() const {
for (auto item : mList) {
auto device = item.objectCast<ParticipantDeviceCore>();
if (!isMe(device->getDevice())) return false;
}
return true;
}
void ParticipantDeviceList::onConferenceModelChanged() {
if (!mInitialized) {
initConferenceModel();
}
}
void ParticipantDeviceList::onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device) {
emit securityLevelChanged(device);
}
//----------------------------------------------------------------------------------------------------------
void ParticipantDeviceList::onParticipantAdded(const std::shared_ptr<const linphone::Participant> &participant) {
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices();
if (devices.size() == 0)
qDebug() << "Participant has no device. It will not be added : "
<< participant->getAddress()->asString().c_str();
else
for (auto device : devices)
add(device);
}
void ParticipantDeviceList::onParticipantRemoved(const std::shared_ptr<const linphone::Participant> &participant) {
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices();
for (auto device : devices)
remove(device);
}
void ParticipantDeviceList::onParticipantDeviceAdded(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "Adding new device : " << mList.count();
// auto conferenceModel = mCallModel->getConferenceSharedModel();
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices;
for (int i = 0; i < 2; ++i) {
// if (i == 0) devices = conferenceModel->getConference()->getParticipantDeviceList(); // Active devices.
// else devices = conferenceModel->getConference()->getMe()->getDevices();
for (auto realParticipantDevice : devices) {
if (realParticipantDevice == participantDevice) {
add(realParticipantDevice);
return;
}
}
}
qDebug() << "No participant device found from linphone::ParticipantDevice at onParticipantDeviceAdded";
}
void ParticipantDeviceList::onParticipantDeviceRemoved(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "Removing participant device : " << mList.count();
if (!remove(participantDevice))
qDebug() << "No participant device found from linphone::ParticipantDevice at onParticipantDeviceRemoved";
}
void ParticipantDeviceList::onConferenceStateChanged(linphone::Conference::State newState) {
// if (newState == linphone::Conference::State::Created) {
// if (mCallModel && mCallModel->isConference()) {
// auto conferenceModel = mCallModel->getConferenceSharedModel();
// updateDevices(conferenceModel->getConference()->getMe()->getDevices(), true);
// updateDevices(conferenceModel->getConference()->getParticipantDeviceList(), false);
// }
// emit conferenceCreated();
// }
}
void ParticipantDeviceList::onParticipantDeviceMediaCapabilityChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
// auto device = get(participantDevice);
// if (device) device->updateVideoEnabled();
// else onParticipantDeviceAdded(participantDevice);
// device = get(participantDevice);
// if (device && device->isMe()) { // Capability change for me. Update all videos.
// for (auto item : mList) {
// auto device = item.objectCast<ParticipantDeviceCore>();
// device->updateVideoEnabled();
// }
// }
}
void ParticipantDeviceList::onParticipantDeviceMediaAvailabilityChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
// auto device = get(participantDevice);
// if (device) device->updateVideoEnabled();
// else onParticipantDeviceAdded(participantDevice);
}
void ParticipantDeviceList::onActiveSpeakerParticipantDevice(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
// auto device = get(participantDevice);
// if (device) {
// mActiveSpeaker = device;
// emit activeSpeakerChanged();
// }
}
void ParticipantDeviceList::onParticipantDeviceIsSpeakingChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice, bool isSpeaking) {
auto device = get(participantDevice);
if (device) emit participantSpeaking(device.get());
}
void ParticipantDeviceList::onParticipantDeviceSpeaking() {
}

View file

@ -0,0 +1,94 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_DEVICE_LIST_H_
#define PARTICIPANT_DEVICE_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "core/call/CallCore.hpp"
#include "core/participant/ParticipantDeviceCore.hpp"
#include <QDateTime>
#include <QObject>
#include <QString>
class ParticipantDeviceList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<ParticipantDeviceList> create(const std::shared_ptr<linphone::Participant> &participant);
static QSharedPointer<ParticipantDeviceList> create();
ParticipantDeviceList(const std::shared_ptr<linphone::Participant> &participant, QObject *parent = nullptr);
// ParticipantDeviceList(CallCore *callCore, QObject *parent = nullptr);
ParticipantDeviceList(QObject *parent = Q_NULLPTR);
~ParticipantDeviceList();
void setSelf(QSharedPointer<ParticipantDeviceList> me);
void initConferenceModel();
void updateDevices(std::shared_ptr<linphone::Participant> participant);
void updateDevices(const std::list<QSharedPointer<ParticipantDeviceCore>> &devices, const bool &isMe);
bool add(const QSharedPointer<ParticipantDeviceCore> &deviceToAdd);
bool remove(std::shared_ptr<const linphone::ParticipantDevice> deviceToAdd);
QSharedPointer<ParticipantDeviceCore> get(std::shared_ptr<const linphone::ParticipantDevice> deviceToGet,
int *index = nullptr);
QSharedPointer<ParticipantDeviceCore> getMe(int *index = nullptr) const;
ParticipantDeviceCore *getActiveSpeakerModel() const;
bool isMe(std::shared_ptr<linphone::ParticipantDevice> device) const;
bool isMeAlone() const;
public slots:
void onActiveSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void onConferenceModelChanged();
void onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
void onParticipantAdded(const std::shared_ptr<const linphone::Participant> &participant);
void onParticipantRemoved(const std::shared_ptr<const linphone::Participant> &participant);
void onParticipantDeviceAdded(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void onParticipantDeviceRemoved(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void onConferenceStateChanged(linphone::Conference::State newState);
void onParticipantDeviceMediaCapabilityChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void onParticipantDeviceMediaAvailabilityChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void onParticipantDeviceIsSpeakingChanged(const std::shared_ptr<const linphone::ParticipantDevice> &device,
bool isSpeaking);
void onParticipantDeviceSpeaking();
signals:
void activeSpeakerChanged();
void securityLevelChanged(std::shared_ptr<const linphone::Address> device);
void participantSpeaking(ParticipantDeviceCore *speakingDevice);
void conferenceCreated();
void meChanged();
private:
CallCore *mCallCore = nullptr;
QSharedPointer<ParticipantDeviceCore> mActiveSpeaker;
// QList<ParticipantDeviceCore*> mActiveSpeakers;// First item is last speaker
bool mInitialized = false;
QSharedPointer<SafeConnection<ParticipantDeviceList, CallModel>> mModelConnection;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<ParticipantDeviceList>);
#endif // PARTICIPANT_DEVICE_LIST_H_

View file

@ -0,0 +1,121 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantDeviceProxy.hpp"
#include "ParticipantDeviceList.hpp"
#include "core/App.hpp"
#include <QQmlApplicationEngine>
// =============================================================================
ParticipantDeviceProxy::ParticipantDeviceProxy(QObject *parent) : SortFilterProxy(parent) {
mDeleteSourceModel = true;
mList = ParticipantDeviceList::create();
setSourceModel(mList.get());
}
ParticipantDeviceProxy::~ParticipantDeviceProxy() {
}
bool ParticipantDeviceProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = mList->index(sourceRow, 0, sourceParent);
const ParticipantDeviceCore *device = index.data().value<ParticipantDeviceCore *>();
return device && (isShowMe() /*|| !(device->isMe() && device->isLocal())*/);
}
bool ParticipantDeviceProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
const ParticipantDeviceCore *deviceA = sourceModel()->data(left).value<ParticipantDeviceCore *>();
const ParticipantDeviceCore *deviceB = sourceModel()->data(right).value<ParticipantDeviceCore *>();
// 'me' at end (for grid).
return /*deviceB->isLocal() || !deviceA->isLocal() && deviceB->isMe() ||*/ left.row() < right.row();
}
//---------------------------------------------------------------------------------
ParticipantDeviceCore *ParticipantDeviceProxy::getAt(int row) {
if (row >= 0) {
QModelIndex sourceIndex = mapToSource(this->index(row, 0));
return sourceModel()->data(sourceIndex).value<ParticipantDeviceCore *>();
} else return nullptr;
}
ParticipantDeviceCore *ParticipantDeviceProxy::getActiveSpeakerModel() {
return mList->getActiveSpeakerModel();
}
CallModel *ParticipantDeviceProxy::getCallModel() const {
return mCallModel;
}
ParticipantDeviceCore *ParticipantDeviceProxy::getMe() const {
return mList->getMe().get();
}
bool ParticipantDeviceProxy::isShowMe() const {
return mShowMe;
}
void ParticipantDeviceProxy::connectTo(ParticipantDeviceList *model) {
connect(model, &ParticipantDeviceList::countChanged, this, &ParticipantDeviceProxy::onCountChanged);
connect(model, &ParticipantDeviceList::participantSpeaking, this, &ParticipantDeviceProxy::onParticipantSpeaking);
connect(model, &ParticipantDeviceList::conferenceCreated, this, &ParticipantDeviceProxy::conferenceCreated);
connect(model, &ParticipantDeviceList::meChanged, this, &ParticipantDeviceProxy::meChanged);
connect(model, &ParticipantDeviceList::activeSpeakerChanged, this, &ParticipantDeviceProxy::activeSpeakerChanged);
}
void ParticipantDeviceProxy::setCallModel(CallModel *callModel) {
setFilterType(1);
mCallModel = callModel;
deleteSourceModel();
auto newSourceModel = new ParticipantDeviceList(mCallModel);
connectTo(newSourceModel);
setSourceModel(newSourceModel);
mDeleteSourceModel = true;
sort(0);
emit countChanged();
emit meChanged();
}
// void ParticipantDeviceProxy::setParticipant(ParticipantCore *participantCore) {
// setFilterType(0);
// deleteSourceModel();
// auto newSourceModel = participant->getParticipantDevices().get();
// connectTo(newSourceModel);
// setSourceModel(newSourceModel);
// mDeleteSourceModel = false;
// sort(0);
// emit countChanged();
// emit meChanged();
// }
void ParticipantDeviceProxy::setShowMe(const bool &show) {
if (mShowMe != show) {
mShowMe = show;
emit showMeChanged();
invalidate();
}
}
void ParticipantDeviceProxy::onCountChanged() {
qDebug() << "Count changed : " << getCount();
}
void ParticipantDeviceProxy::onParticipantSpeaking(ParticipantDeviceCore *speakingDevice) {
emit participantSpeaking(speakingDevice);
}

View file

@ -0,0 +1,84 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_DEVICE_PROXY_MODEL_H_
#define PARTICIPANT_DEVICE_PROXY_MODEL_H_
#include <linphone++/linphone.hh>
// =============================================================================
#include "../proxy/SortFilterProxy.hpp"
#include <QDateTime>
#include <QObject>
#include <QSharedPointer>
#include <QString>
class ParticipantDeviceList;
class ParticipantDeviceCore;
class ParticipantCore;
class CallModel;
class ParticipantDeviceProxy : public SortFilterProxy {
Q_OBJECT
public:
Q_PROPERTY(CallModel *callModel READ getCallModel WRITE setCallModel NOTIFY callModelChanged)
Q_PROPERTY(bool showMe READ isShowMe WRITE setShowMe NOTIFY showMeChanged)
Q_PROPERTY(ParticipantDeviceCore *me READ getMe NOTIFY meChanged)
Q_PROPERTY(ParticipantDeviceCore *activeSpeaker READ getActiveSpeakerModel NOTIFY activeSpeakerChanged)
ParticipantDeviceProxy(QObject *parent = nullptr);
~ParticipantDeviceProxy();
Q_INVOKABLE ParticipantDeviceCore *getAt(int row);
ParticipantDeviceCore *getActiveSpeakerModel();
ParticipantDeviceCore *getMe() const;
CallModel *getCallModel() const;
bool isShowMe() const;
void setCallModel(CallModel *callModel);
// void setParticipant(ParticipantCore *participantCore);
void setShowMe(const bool &show);
void connectTo(ParticipantDeviceList *model);
public slots:
void onCountChanged();
void onParticipantSpeaking(ParticipantDeviceCore *speakingDevice);
signals:
void activeSpeakerChanged();
void callModelChanged();
void showMeChanged();
void meChanged();
void participantSpeaking(ParticipantDeviceCore *speakingDevice);
void conferenceCreated();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
CallModel *mCallModel;
bool mShowMe = true;
QSharedPointer<ParticipantDeviceList> mList;
};
#endif

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantGui.hpp"
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(ParticipantGui)
ParticipantGui::ParticipantGui(QObject *parent) : QObject(parent) {
mCore = ParticipantCore::create(nullptr);
}
ParticipantGui::ParticipantGui(QSharedPointer<ParticipantCore> core) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
mCore = core;
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
}
ParticipantGui::~ParticipantGui() {
mustBeInMainThread("~" + getClassName());
}
ParticipantCore *ParticipantGui::getCore() const {
return mCore.get();
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_GUI_H_
#define PARTICIPANT_GUI_H_
#include "ParticipantCore.hpp"
#include <QObject>
#include <QSharedPointer>
class ParticipantGui : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(ParticipantCore *core READ getCore CONSTANT)
public:
ParticipantGui(QSharedPointer<ParticipantCore> core);
ParticipantGui(QObject *parent = nullptr);
~ParticipantGui();
ParticipantCore *getCore() const;
QSharedPointer<ParticipantCore> mCore;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,406 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantList.hpp"
#include "core/App.hpp"
#include "core/participant/ParticipantGui.hpp"
#include "model/core/CoreModel.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
#include <QDebug>
DEFINE_ABSTRACT_OBJECT(ParticipantList)
QSharedPointer<ParticipantList> ParticipantList::create() {
auto model = QSharedPointer<ParticipantList>(new ParticipantList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
model->setSelf(model);
return model;
}
// ParticipantList::ParticipantList(ChatRoomModel *chatRoomModel, QObject *parent) : ProxyListModel(parent) {
// if (chatRoomModel) {
// mChatRoomModel = chatRoomModel;
// connect(mChatRoomModel, &ChatRoomModel::securityEvent, this, &ParticipantList::onSecurityEvent);
// connect(mChatRoomModel, &ChatRoomModel::conferenceJoined, this, &ParticipantList::onConferenceJoined);
// connect(mChatRoomModel, &ChatRoomModel::participantAdded, this,
// QOverload<const std::shared_ptr<const linphone::EventLog> &>::of(
// &ParticipantList::onParticipantAdded));
// connect(mChatRoomModel, &ChatRoomModel::participantRemoved, this,
// QOverload<const std::shared_ptr<const linphone::EventLog> &>::of(
// &ParticipantList::onParticipantRemoved));
// connect(mChatRoomModel, &ChatRoomModel::participantAdminStatusChanged, this,
// QOverload<const std::shared_ptr<const linphone::EventLog> &>::of(
// &ParticipantList::onParticipantAdminStatusChanged));
// connect(mChatRoomModel, &ChatRoomModel::participantDeviceAdded, this,
// &ParticipantList::onParticipantDeviceAdded);
// connect(mChatRoomModel, &ChatRoomModel::participantDeviceRemoved, this,
// &ParticipantList::onParticipantDeviceRemoved);
// connect(mChatRoomModel, &ChatRoomModel::participantRegistrationSubscriptionRequested, this,
// &ParticipantList::onParticipantRegistrationSubscriptionRequested);
// connect(mChatRoomModel, &ChatRoomModel::participantRegistrationUnsubscriptionRequested, this,
// &ParticipantList::onParticipantRegistrationUnsubscriptionRequested);
// updateParticipants();
// }
// }
// ParticipantList::ParticipantList(ConferenceModel *conferenceModel, QObject *parent) : ListProxy(parent) {
// if (conferenceModel) {
// mConferenceModel = conferenceModel;
// connect(mConferenceModel, &ConferenceModel::participantAdded, this,
// QOverload<const std::shared_ptr<const linphone::Participant> &>::of(
// &ParticipantList::onParticipantAdded));
// connect(mConferenceModel, &ConferenceModel::participantRemoved, this,
// QOverload<const std::shared_ptr<const linphone::Participant> &>::of(
// &ParticipantList::onParticipantRemoved));
// connect(mConferenceModel, &ConferenceModel::participantAdminStatusChanged, this,
// QOverload<const std::shared_ptr<const linphone::Participant> &>::of(
// &ParticipantList::onParticipantAdminStatusChanged));
// connect(mConferenceModel, &ConferenceModel::conferenceStateChanged, this,
// &ParticipantList::onStateChanged);
// updateParticipants();
// }
// }
ParticipantList::ParticipantList(QObject *parent) : ListProxy(parent) {
}
ParticipantList::~ParticipantList() {
mList.clear();
// mChatRoomModel = nullptr;
// mConferenceModel = nullptr;
}
void ParticipantList::setSelf(QSharedPointer<ParticipantList> me) {
mModelConnection = QSharedPointer<SafeConnection<ParticipantList, ConferenceModel>>(
new SafeConnection<ParticipantList, ConferenceModel>(me, mConferenceModel), &QObject::deleteLater);
mModelConnection->makeConnectToCore(&ParticipantList::lUpdateParticipants, [this] {
mModelConnection->invokeToModel([this]() {
QList<QSharedPointer<ParticipantCore>> *participantList = new QList<QSharedPointer<ParticipantCore>>();
mustBeInLinphoneThread(getClassName());
std::list<std::shared_ptr<linphone::Participant>> participants;
participants = mConferenceModel->getMonitor()->getParticipantList();
for (auto it : participants) {
auto model = ParticipantCore::create(it);
participantList->push_back(model);
}
mModelConnection->invokeToCore([this, participantList]() {
mustBeInMainThread(getClassName());
resetData();
add(*participantList);
delete participantList;
});
});
});
mModelConnection->makeConnectToModel(&ConferenceModel::participantAdded, &ParticipantList::lUpdateParticipants);
mModelConnection->makeConnectToModel(&ConferenceModel::participantRemoved, &ParticipantList::lUpdateParticipants);
emit lUpdateParticipants();
}
QVariant ParticipantList::data(const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
if (role == Qt::DisplayRole) {
return QVariant::fromValue(new ParticipantGui(mList[row].objectCast<ParticipantCore>()));
}
return QVariant();
}
std::list<std::shared_ptr<linphone::Address>> ParticipantList::getParticipants() const {
std::list<std::shared_ptr<linphone::Address>> participants;
for (auto participant : mList) {
participants.push_back(ToolModel::interpretUrl(participant.objectCast<ParticipantCore>()->getSipAddress()));
}
return participants;
}
QString ParticipantList::addressesToString() const {
QStringList txt;
for (auto item : mList) {
auto participant = item.objectCast<ParticipantCore>();
if (participant) {
// chat room yet.
txt << participant->getSipAddress();
// txt << Utils::toDisplayString(Utils::coreStringToAppString(address->asStringUriOnly()),
// CoreModel::getInstance()->getSettingsModel()->getSipDisplayMode());
}
}
if (txt.size() > 0) txt.removeFirst(); // Remove me
return txt.join(", ");
}
QString ParticipantList::displayNamesToString() const {
QStringList txt;
for (auto item : mList) {
auto participant = item.objectCast<ParticipantCore>();
if (participant) {
QString displayName = participant->getSipAddress();
if (displayName != "") txt << displayName;
}
}
if (txt.size() > 0) txt.removeFirst(); // Remove me
return txt.join(", ");
}
QString ParticipantList::usernamesToString() const {
QStringList txt;
for (auto item : mList) {
auto participant = item.objectCast<ParticipantCore>();
if (participant) {
auto username = participant->getDisplayName();
txt << username;
}
}
if (txt.size() > 0) txt.removeFirst(); // Remove me
return txt.join(", ");
}
bool ParticipantList::contains(const QString &address) const {
auto testAddress = ToolModel::interpretUrl(address);
bool exists = false;
for (auto itParticipant = mList.begin(); !exists && itParticipant != mList.end(); ++itParticipant)
exists = testAddress->weakEqual(
ToolModel::interpretUrl(itParticipant->objectCast<ParticipantCore>()->getSipAddress()));
return exists;
}
// void ParticipantList::updateParticipants() {
// if (/*mChatRoomModel ||*/ mConferenceModel) {
// bool changed = false;
// mConferenceModel->getMonitor()->getParticipantList();
// // auto dbParticipants = (/*mChatRoomModel ? mChatRoomModel->getParticipants() :*/ mConferenceModel->get());
// // Remove left participants
// auto itParticipant = mList.begin();
// while (itParticipant != mList.end()) {
// auto itDbParticipant = dbParticipants.begin();
// while (
// itDbParticipant != dbParticipants.end() &&
// (itParticipant->objectCast<ParticipantCore>()->getParticipant() &&
// !(*itDbParticipant)
// ->getAddress()
// ->weakEqual(itParticipant->objectCast<ParticipantCore>()->getParticipant()->getAddress()) ||
// !itParticipant->objectCast<ParticipantCore>()->getParticipant() &&
// !(*itDbParticipant)
// ->getAddress()
// ->weakEqual(
// Utils::interpretUrl(itParticipant->objectCast<ParticipantCore>()->getSipAddress())))) {
// ++itDbParticipant;
// }
// if (itDbParticipant == dbParticipants.end()) {
// int row = itParticipant - mList.begin();
// if (!changed) emit layoutAboutToBeChanged();
// beginRemoveRows(QModelIndex(), row, row);
// itParticipant = mList.erase(itParticipant);
// endRemoveRows();
// changed = true;
// } else ++itParticipant;
// }
// // Add new
// for (auto dbParticipant : dbParticipants) {
// auto itParticipant = mList.begin();
// while (itParticipant != mList.end() &&
// ((itParticipant->objectCast<ParticipantCore>()->getParticipant() &&
// !dbParticipant->getAddress()->weakEqual(
// itParticipant->objectCast<ParticipantCore>()->getParticipant()->getAddress()))
// || (!itParticipant->objectCast<ParticipantCore>()->getParticipant() &&
// !dbParticipant->getAddress()->weakEqual(
// Utils::interpretUrl(itParticipant->objectCast<ParticipantCore>()->getSipAddress()))))) {
// ++itParticipant;
// }
// if (itParticipant == mList.end()) {
// auto participant = QSharedPointer<ParticipantCore>::create(dbParticipant);
// add(participant);
// changed = true;
// } else if (!itParticipant->objectCast<ParticipantCore>()->getParticipant() ||
// itParticipant->objectCast<ParticipantCore>()->getParticipant() != dbParticipant) {
// itParticipant->objectCast<ParticipantCore>()->setParticipant(dbParticipant);
// changed = true;
// }
// }
// if (changed) {
// emit layoutChanged();
// emit participantsChanged();
// emit countChanged();
// }
// }
// }
// void ParticipantList::add(QSharedPointer<ParticipantCore> participant) {
// int row = mList.count();
// connect(this, &ParticipantList::deviceSecurityLevelChanged, participant.get(),
// &ParticipantCore::onDeviceSecurityLevelChanged);
// connect(this, &ParticipantList::securityLevelChanged, participant.get(), &ParticipantCore::onSecurityLevelChanged);
// connect(participant.get(), &ParticipantCore::updateAdminStatus, this, &ParticipantList::setAdminStatus);
// ProxyListModel::add(participant);
// emit participantsChanged();
// }
// void ParticipantList::add(const std::shared_ptr<const linphone::Participant> &participant) {
// updateParticipants();
// }
// void ParticipantList::add(const std::shared_ptr<const linphone::Address> &participantAddress) {
// add((mChatRoomModel ? mChatRoomModel->getChatRoom()->findParticipant(participantAddress->clone())
// : mConferenceModel->getConference()->findParticipant(participantAddress)));
// }
void ParticipantList::remove(ParticipantCore *participant) {
QString address = participant->getSipAddress();
int index = 0;
bool found = false;
auto itParticipant = mList.begin();
while (!found && itParticipant != mList.end()) {
if (itParticipant->objectCast<ParticipantCore>()->getSipAddress() == address) found = true;
else {
++itParticipant;
++index;
}
}
if (found) {
mConferenceModel->removeParticipant(ToolModel::interpretUrl(address));
}
}
// const QSharedPointer<ParticipantCore>
// ParticipantList::getParticipant(const std::shared_ptr<const linphone::Address> &address) const {
// if (address) {
// auto itParticipant =
// std::find_if(mList.begin(), mList.end(), [address](const QSharedPointer<QObject> &participant) {
// return
// participant.objectCast<ParticipantCore>()->getParticipant()->getAddress()->weakEqual(address);
// });
// if (itParticipant == mList.end()) return nullptr;
// else return itParticipant->objectCast<ParticipantCore>();
// } else return nullptr;
// }
// const QSharedPointer<ParticipantCore>
// ParticipantList::getParticipant(const std::shared_ptr<const linphone::Participant> &pParticipant) const {
// if (pParticipant) {
// auto itParticipant =
// std::find_if(mList.begin(), mList.end(), [pParticipant](const QSharedPointer<QObject> &participant) {
// return participant.objectCast<ParticipantCore>()->getParticipant() == pParticipant;
// });
// if (itParticipant == mList.end()) return nullptr;
// else return itParticipant->objectCast<ParticipantCore>();
// } else return nullptr;
// }
//-------------------------------------------------------------
void ParticipantList::setAdminStatus(const std::shared_ptr<linphone::Participant> participant, const bool &isAdmin) {
// if (mChatRoomModel) mChatRoomModel->getChatRoom()->setParticipantAdminStatus(participant, isAdmin);
// if (mConferenceModel) mConferenceModel->getConference()->setParticipantAdminStatus(participant, isAdmin);
}
void ParticipantList::onSecurityEvent(const std::shared_ptr<const linphone::EventLog> &eventLog) {
auto address = eventLog->getParticipantAddress();
if (address) {
// auto participant = getParticipant(address);
// if (participant) {
// emit participant->securityLevelChanged();
// }
} else {
address = eventLog->getDeviceAddress();
// Looping on all participant ensure to get all devices. Can be optimized if Device address is unique : Gain
// 2n operations.
if (address) emit deviceSecurityLevelChanged(address);
}
}
void ParticipantList::onConferenceJoined() {
// updateParticipants();
}
void ParticipantList::onParticipantAdded(const std::shared_ptr<const linphone::EventLog> &eventLog) {
qDebug() << "onParticipantAdded event: " << eventLog->getParticipantAddress()->asString().c_str();
// add(eventLog->getParticipantAddress());
}
void ParticipantList::onParticipantAdded(const std::shared_ptr<const linphone::Participant> &participant) {
qDebug() << "onParticipantAdded part: " << participant->getAddress()->asString().c_str();
// add(participant);
}
void ParticipantList::onParticipantAdded(const std::shared_ptr<const linphone::Address> &address) {
qDebug() << "onParticipantAdded addr: " << address->asString().c_str();
// add(address);
}
void ParticipantList::onParticipantRemoved(const std::shared_ptr<const linphone::EventLog> &eventLog) {
onParticipantRemoved(eventLog->getParticipantAddress());
}
void ParticipantList::onParticipantRemoved(const std::shared_ptr<const linphone::Participant> &participant) {
// auto p = getParticipant(participant);
// if (p) remove(p.get());
}
void ParticipantList::onParticipantRemoved(const std::shared_ptr<const linphone::Address> &address) {
// auto participant = getParticipant(address);
// if (participant) remove(participant.get());
}
void ParticipantList::onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::EventLog> &eventLog) {
onParticipantAdminStatusChanged(eventLog->getParticipantAddress());
}
void ParticipantList::onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> &participant) {
// auto p = getParticipant(participant);
// if (participant) emit p->adminStatusChanged(); // Request to participant to update its status from its data
}
void ParticipantList::onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Address> &address) {
// auto participant = getParticipant(address);
// if (participant)
// emit participant->adminStatusChanged(); // Request to participant to update its status from its data
}
void ParticipantList::onParticipantDeviceAdded(const std::shared_ptr<const linphone::EventLog> &eventLog) {
// auto participant = getParticipant(eventLog->getParticipantAddress());
// if (participant) {
// emit participant->deviceCountChanged();
// }
}
void ParticipantList::onParticipantDeviceRemoved(const std::shared_ptr<const linphone::EventLog> &eventLog) {
// auto participant = getParticipant(eventLog->getParticipantAddress());
// if (participant) {
// emit participant->deviceCountChanged();
// }
}
void ParticipantList::onParticipantRegistrationSubscriptionRequested(
const std::shared_ptr<const linphone::Address> &participantAddress) {
}
void ParticipantList::onParticipantRegistrationUnsubscriptionRequested(
const std::shared_ptr<const linphone::Address> &participantAddress) {
}
void ParticipantList::onStateChanged() {
// if (mConferenceModel) {
// if (mConferenceModel->getConference()->getState() == linphone::Conference::State::Created) {
// updateParticipants();
// }
// }
}

View file

@ -0,0 +1,106 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_LIST_H_
#define PARTICIPANT_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "core/participant/ParticipantCore.hpp"
#include "model/conference/ConferenceModel.hpp"
class ConferenceModel;
// =============================================================================
class ParticipantList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<ParticipantList> create();
// ParticipantList(ChatRoomModel *chatRoomModel, QObject *parent = Q_NULLPTR);
// ParticipantList(ConferenceModel *conferenceModel, QObject *parent = Q_NULLPTR);
ParticipantList(QObject *parent = Q_NULLPTR);
virtual ~ParticipantList();
void setSelf(QSharedPointer<ParticipantList> me);
// Q_PROPERTY(ChatRoomModel *chatRoomModel READ getChatRoomModel CONSTANT)
Q_PROPERTY(QString addressesToString READ addressesToString NOTIFY participantsChanged)
Q_PROPERTY(QString displayNamesToString READ displayNamesToString NOTIFY participantsChanged)
Q_PROPERTY(QString usernamesToString READ usernamesToString NOTIFY participantsChanged)
void reset();
// void updateParticipants(); // Update list from Chat Room
// const QSharedPointer<ParticipantCore>
// getParticipant(const std::shared_ptr<const linphone::Address> &address) const;
// const QSharedPointer<ParticipantCore> const QSharedPointer<ParticipantCore>
// getParticipant(const std::shared_ptr<const linphone::Participant> &participant) const;
Q_INVOKABLE void remove(ParticipantCore *participant);
std::list<std::shared_ptr<linphone::Address>> getParticipants() const;
Q_INVOKABLE QString addressesToString() const;
Q_INVOKABLE QString displayNamesToString() const;
Q_INVOKABLE QString usernamesToString() const;
bool contains(const QString &address) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
public slots:
void setAdminStatus(const std::shared_ptr<linphone::Participant> participant, const bool &isAdmin);
void onSecurityEvent(const std::shared_ptr<const linphone::EventLog> &eventLog);
void onConferenceJoined();
void onParticipantAdded(const std::shared_ptr<const linphone::Participant> &participant);
void onParticipantAdded(const std::shared_ptr<const linphone::EventLog> &eventLog);
void onParticipantAdded(const std::shared_ptr<const linphone::Address> &address);
void onParticipantRemoved(const std::shared_ptr<const linphone::Participant> &participant);
void onParticipantRemoved(const std::shared_ptr<const linphone::EventLog> &eventLog);
void onParticipantRemoved(const std::shared_ptr<const linphone::Address> &address);
void onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> &participant);
void onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::EventLog> &eventLog);
void onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Address> &address);
void onParticipantDeviceAdded(const std::shared_ptr<const linphone::EventLog> &eventLog);
void onParticipantDeviceRemoved(const std::shared_ptr<const linphone::EventLog> &eventLog);
void
onParticipantRegistrationSubscriptionRequested(const std::shared_ptr<const linphone::Address> &participantAddress);
void onParticipantRegistrationUnsubscriptionRequested(
const std::shared_ptr<const linphone::Address> &participantAddress);
void onStateChanged();
signals:
void securityLevelChanged();
void deviceSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
void participantsChanged();
void lUpdateParticipants();
private:
std::shared_ptr<ConferenceModel> mConferenceModel;
QSharedPointer<SafeConnection<ParticipantList, ConferenceModel>> mModelConnection;
// ChatRoomModel *mChatRoomModel = nullptr;
// ConferenceCore *mConferenceCore = nullptr;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<ParticipantList>);
#endif // PARTICIPANT_LIST_H_

View file

@ -0,0 +1,196 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantProxy.hpp"
// #include "core/conference/ConferenceCore.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include "ParticipantList.hpp"
#include "core/participant/ParticipantCore.hpp"
#include <QDebug>
// =============================================================================
// -----------------------------------------------------------------------------
ParticipantProxy::ParticipantProxy(QObject *parent) : SortFilterProxy(parent) {
mList = ParticipantList::create();
setSourceModel(mList.get());
connect(this, &ParticipantProxy::chatRoomModelChanged, this, &ParticipantProxy::countChanged);
connect(this, &ParticipantProxy::conferenceModelChanged, this, &ParticipantProxy::countChanged);
}
ParticipantProxy::~ParticipantProxy() {
setSourceModel(nullptr);
}
// ChatRoomModel *ParticipantProxy::getChatRoomModel() const {
// return mChatRoomModel;
// }
// ConferenceModel *ParticipantProxy::getConferenceModel() const {
// return mConferenceModel;
// }
QStringList ParticipantProxy::getSipAddresses() const {
QStringList participants;
for (int i = 0; i < mList->rowCount(); ++i)
participants << mList->getAt<ParticipantCore>(i)->getSipAddress();
return participants;
}
QVariantList ParticipantProxy::getParticipants() const {
QVariantList participants;
ParticipantList *list = qobject_cast<ParticipantList *>(sourceModel());
for (int i = 0; i < list->rowCount(); ++i)
participants << QVariant::fromValue(list->getAt<ParticipantCore>(i).get());
return participants;
}
bool ParticipantProxy::getShowMe() const {
return mShowMe;
}
// -----------------------------------------------------------------------------
// void ParticipantProxy::setChatRoomModel(ChatRoomModel *chatRoomModel) {
// if (!mChatRoomModel || mChatRoomModel != chatRoomModel) {
// mChatRoomModel = chatRoomModel;
// if (mChatRoomModel) {
// auto participants = mChatRoomModel->getParticipantList();
// connect(participants, &ParticipantList::countChanged, this, &ParticipantProxy::countChanged);
// setSourceModel(participants);
// emit participantListChanged();
// for (int i = 0; i < participants->getCount(); ++i) {
// auto participant = participants->getAt<ParticipantCore>(i);
// connect(participant.get(), &ParticipantCore::invitationTimeout, this, &ParticipantProxy::removeModel);
// emit addressAdded(participant->getSipAddress());
// }
// } else if (!sourceModel()) {
// auto model = new ParticipantList((ChatRoomModel *)nullptr, this);
// connect(model, &ParticipantList::countChanged, this, &ParticipantProxy::countChanged);
// setSourceModel(model);
// emit participantListChanged();
// }
// sort(0);
// emit chatRoomModelChanged();
// }
// }
void ParticipantProxy::setConferenceModel(ConferenceModel *conferenceModel) {
// if (!mConferenceModel || mConferenceModel != conferenceModel) {
// mConferenceModel = conferenceModel;
// if (mConferenceModel) {
// auto participants = mConferenceModel->getParticipantList();
// connect(participants, &ParticipantList::countChanged, this, &ParticipantProxy::countChanged);
// setSourceModel(participants);
// emit participantListChanged();
// for (int i = 0; i < participants->getCount(); ++i) {
// auto participant = participants->getAt<ParticipantCore>(i);
// connect(participant.get(), &ParticipantCore::invitationTimeout, this, &ParticipantProxy::removeModel);
// emit addressAdded(participant->getSipAddress());
// }
// } else if (!sourceModel()) {
// auto model = new ParticipantList((ConferenceModel *)nullptr, this);
// connect(model, &ParticipantList::countChanged, this, &ParticipantProxy::countChanged);
// setSourceModel(model);
// emit participantListChanged();
// }
// sort(0);
// emit conferenceModelChanged();
// }
}
void ParticipantProxy::setAddresses(ConferenceInfoModel *conferenceInfoModel) {
// if (conferenceInfoModel && conferenceInfoModel->getConferenceInfo())
// for (auto address : conferenceInfoModel->getConferenceInfo()->getParticipants())
// addAddress(QString::fromStdString(address->asString()));
}
void ParticipantProxy::setShowMe(const bool &show) {
if (mShowMe != show) {
mShowMe = show;
emit showMeChanged();
invalidate();
}
}
// void ParticipantProxy::addAddress(const QString &address) {
// if (!participantsModel->contains(address)) {
// QSharedPointer<ParticipantCore> participant = QSharedPointer<ParticipantCore>::create(nullptr);
// connect(participant.get(), &ParticipantCore::invitationTimeout, this, &ParticipantProxy::removeModel);
// participant->setSipAddress(address);
// participantsModel->add(participant);
// if (mChatRoomModel && mChatRoomModel->getChatRoom()) { // Invite and wait for its creation
// participant->startInvitation();
// mChatRoomModel->getChatRoom()->addParticipant(Utils::interpretUrl(address));
// }
// if (mConferenceModel && mConferenceModel->getConference()) {
// auto addressToInvite = Utils::interpretUrl(address);
// std::list<std::shared_ptr<linphone::Call>> runningCallsToAdd;
// auto currentCalls = CoreManager::getInstance()->getCore()->getCalls();
// auto haveCall = std::find_if(currentCalls.begin(), currentCalls.end(),
// [addressToInvite](const std::shared_ptr<linphone::Call> &call) {
// return call->getRemoteAddress()->weakEqual(addressToInvite);
// });
// participant->startInvitation();
// if (haveCall == currentCalls.end()) mConferenceModel->getConference()->addParticipant(addressToInvite);
// else {
// runningCallsToAdd.push_back(*haveCall);
// mConferenceModel->getConference()->addParticipants(runningCallsToAdd);
// }
// /*
// std::list<std::shared_ptr<linphone::Address>> addressesToInvite;
// addressesToInvite.push_back(addressToInvite);
// auto callParameters =
// CoreManager::getInstance()->getCore()->createCallParams(mConferenceModel->getConference()->getCall());
// mConferenceModel->getConference()->inviteParticipants(addressesToInvite, callParameters);*/
// }
// emit countChanged();
// emit addressAdded(address);
// }
// }
void ParticipantProxy::removeParticipant(ParticipantCore *participant) {
if (participant) {
mList->remove(participant);
}
}
// -----------------------------------------------------------------------------
bool ParticipantProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
if (mShowMe) return true;
else {
const ParticipantCore *a =
sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value<ParticipantCore *>();
return !a->isMe();
}
}
bool ParticipantProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
const ParticipantCore *a = sourceModel()->data(left).value<ParticipantCore *>();
const ParticipantCore *b = sourceModel()->data(right).value<ParticipantCore *>();
return a->getCreationTime() > b->getCreationTime() || b->isMe();
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_PROXY_H_
#define PARTICIPANT_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include <memory>
class ParticipantCore;
class ChatRoomModel;
class ParticipantList;
class ConferenceModel;
class ConferenceInfoModel;
// =============================================================================
class QWindow;
class ParticipantProxy : public SortFilterProxy {
Q_OBJECT
Q_PROPERTY(bool showMe READ getShowMe WRITE setShowMe NOTIFY showMeChanged)
public:
ParticipantProxy(QObject *parent = Q_NULLPTR);
~ParticipantProxy();
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
// ChatRoomModel *getChatRoomModel() const;
// ConferenceModel *getConferenceModel() const;
Q_INVOKABLE QStringList getSipAddresses() const;
Q_INVOKABLE QVariantList getParticipants() const;
bool getShowMe() const;
// void setChatRoomModel(ChatRoomModel *chatRoomModel);
void setConferenceModel(ConferenceModel *conferenceModel);
void setShowMe(const bool &show);
// Q_INVOKABLE void addAddress(const QString &address);
Q_INVOKABLE void removeParticipant(ParticipantCore *participant);
Q_INVOKABLE void setAddresses(ConferenceInfoModel *conferenceInfoModel);
signals:
void chatRoomModelChanged();
void conferenceModelChanged();
void participantListChanged();
void countChanged();
void showMeChanged();
void addressAdded(QString sipAddress);
void addressRemoved(QString sipAddress);
private:
// ChatRoomModel *mChatRoomModel = nullptr;
// ConferenceModel *mConferenceModel = nullptr;
bool mShowMe = true;
QSharedPointer<ParticipantList> mList;
};
#endif // PARTICIPANT_PROXY_H_

View file

@ -0,0 +1,56 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TimeZone.hpp"
#include "core/App.hpp"
#include <QQmlApplicationEngine>
// =============================================================================
TimeZoneModel::TimeZoneModel(const QTimeZone &timeZone, QObject *parent) : QObject(parent) {
App::getInstance()->mEngine->setObjectOwnership(
this, QQmlEngine::CppOwnership); // Avoid QML to destroy it when passing by Q_INVOKABLE
mTimeZone = timeZone;
}
TimeZoneModel::~TimeZoneModel() {
}
QTimeZone TimeZoneModel::getTimeZone() const {
return mTimeZone;
}
int TimeZoneModel::getOffsetFromUtc() const {
return mTimeZone.offsetFromUtc(QDateTime::currentDateTime());
}
int TimeZoneModel::getStandardTimeOffset() const {
return mTimeZone.standardTimeOffset(QDateTime::currentDateTime());
}
QString TimeZoneModel::getCountryName() const {
return QLocale::countryToString(mTimeZone.country());
}
QString TimeZoneModel::getDisplayName() const {
return mTimeZone.displayName(QTimeZone::TimeType::GenericTime, QTimeZone::NameType::LongName);
}

View file

@ -0,0 +1,53 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TIME_ZONE_MODEL_H_
#define TIME_ZONE_MODEL_H_
#include <QObject>
#include <QTimeZone>
#include <linphone++/linphone.hh>
// =============================================================================
class TimeZoneModel : public QObject {
Q_OBJECT
Q_PROPERTY(QTimeZone timezone MEMBER mTimeZone CONSTANT)
Q_PROPERTY(int offsetFromUtc READ getOffsetFromUtc CONSTANT)
Q_PROPERTY(int standardTimeOffset READ getStandardTimeOffset CONSTANT)
Q_PROPERTY(QString countryName READ getCountryName CONSTANT)
Q_PROPERTY(QString displayName READ getDisplayName CONSTANT)
public:
TimeZoneModel(const QTimeZone &timeZone, QObject *parent = nullptr);
virtual ~TimeZoneModel();
QTimeZone getTimeZone() const;
int getOffsetFromUtc() const;
int getStandardTimeOffset() const;
QString getCountryName() const;
QString getDisplayName() const;
private:
QTimeZone mTimeZone;
};
Q_DECLARE_METATYPE(TimeZoneModel *);
#endif

View file

@ -0,0 +1,105 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TimeZoneList.hpp"
#include "core/App.hpp"
#include <QTimeZone>
// =============================================================================
DEFINE_ABSTRACT_OBJECT(TimeZoneList)
using namespace std;
QSharedPointer<TimeZoneList> TimeZoneList::create() {
auto model = QSharedPointer<TimeZoneList>(new TimeZoneList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
return model;
}
TimeZoneList::TimeZoneList(QObject *parent) : ListProxy(parent) {
initTimeZones();
}
TimeZoneList::~TimeZoneList() {
mustBeInMainThread("~" + getClassName());
}
// -----------------------------------------------------------------------------
void TimeZoneList::initTimeZones() {
resetData();
for (auto id : QTimeZone::availableTimeZoneIds()) {
auto model = QSharedPointer<TimeZoneModel>::create(QTimeZone(id));
if (std::find_if(mList.begin(), mList.end(), [id](const QSharedPointer<QObject> &a) {
return a.objectCast<TimeZoneModel>()->getTimeZone() == QTimeZone(id);
}) == mList.end()) {
if (model->getCountryName().toUpper() != "DEFAULT") {
add(model);
}
}
}
}
QHash<int, QByteArray> TimeZoneList::roleNames() const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "modelData";
roles[Qt::DisplayRole + 1] = "timeZoneModel";
return roles;
}
QVariant TimeZoneList::data(const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
auto timeZoneModel = getAt<TimeZoneModel>(row);
if (!timeZoneModel) return QVariant();
if (role == Qt::DisplayRole) {
int offset = timeZoneModel->getStandardTimeOffset() / 3600;
int absOffset = std::abs(offset);
return QStringLiteral("(GMT%1%2%3:00) %4 %5")
.arg(offset >= 0 ? "+" : "-")
.arg(absOffset < 10 ? "0" : "")
.arg(absOffset)
.arg(timeZoneModel->getCountryName())
.arg(timeZoneModel->getTimeZone().comment().isEmpty() ? ""
: (" - " + timeZoneModel->getTimeZone().comment()));
} else {
return QVariant::fromValue(timeZoneModel.get());
}
return QVariant();
}
int TimeZoneList::get(const QTimeZone &timeZone) const {
auto it = find_if(mList.cbegin(), mList.cend(), [&timeZone](QSharedPointer<QObject> item) {
return item.objectCast<TimeZoneModel>()->getTimeZone() == timeZone;
});
if (it == mList.cend()) {
auto today = QDateTime::currentDateTime();
it = find_if(mList.cbegin(), mList.cend(), [&timeZone, today](QSharedPointer<QObject> item) {
auto tz = item.objectCast<TimeZoneModel>()->getTimeZone();
return (timeZone.country() == QLocale::AnyCountry || tz.country() == timeZone.country()) &&
tz.standardTimeOffset(today) == timeZone.standardTimeOffset(today);
});
}
return it != mList.cend() ? int(distance(mList.cbegin(), it)) : 0;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TIME_ZONE_LIST_MODEL_H_
#define TIME_ZONE_LIST_MODEL_H_
#include "../proxy/ListProxy.hpp"
#include "core/timezone/TimeZone.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class TimeZoneList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<TimeZoneList> create();
TimeZoneList(QObject *parent = Q_NULLPTR);
~TimeZoneList();
void initTimeZones();
int get(const QTimeZone &timeZone = QTimeZone::systemTimeZone()) const;
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,51 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TimeZoneProxy.hpp"
#include "TimeZoneList.hpp"
#include "core/timezone/TimeZone.hpp"
// -----------------------------------------------------------------------------
TimeZoneProxy::TimeZoneProxy(QObject *parent) : SortFilterProxy(parent) {
mDeleteSourceModel = true;
mList = TimeZoneList::create();
setSourceModel(mList.get());
sort(0);
}
// -----------------------------------------------------------------------------
bool TimeZoneProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto test = sourceModel()->data(left);
auto l = getItemAt<TimeZoneList, TimeZoneModel>(left.row());
auto r = getItemAt<TimeZoneList, TimeZoneModel>(right.row());
if (!l || !r) return true;
auto timeA = l->getStandardTimeOffset() / 3600;
auto timeB = r->getStandardTimeOffset() / 3600;
return timeA < timeB || (timeA == timeB && l->getCountryName() < r->getCountryName());
}
int TimeZoneProxy::getIndex(TimeZoneModel *model) const {
int index = 0;
index = mList->get(model ? model->getTimeZone() : QTimeZone::systemTimeZone());
return mapFromSource(mList->index(index, 0)).row();
}

View file

@ -0,0 +1,44 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TIME_ZONE_PROXY_MODEL_H_
#define TIME_ZONE_PROXY_MODEL_H_
#include "../proxy/SortFilterProxy.hpp"
// =============================================================================
class TimeZoneModel;
class TimeZoneList;
class TimeZoneProxy : public SortFilterProxy {
Q_OBJECT
public:
TimeZoneProxy(QObject *parent = Q_NULLPTR);
Q_PROPERTY(int defaultIndex READ getIndex CONSTANT)
Q_INVOKABLE int getIndex(TimeZoneModel *model = nullptr) const;
protected:
QSharedPointer<TimeZoneList> mList;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
#endif

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 12C11 11.7348 11.1054 11.4804 11.2929 11.2929C11.4804 11.1054 11.7348 11 12 11H20C20.2652 11 20.5196 11.1054 20.7071 11.2929C20.8946 11.4804 21 11.7348 21 12C21 12.2652 20.8946 12.5196 20.7071 12.7071C20.5196 12.8946 20.2652 13 20 13H12C11.7348 13 11.4804 12.8946 11.2929 12.7071C11.1054 12.5196 11 12.2652 11 12ZM12 17H20C20.2652 17 20.5196 16.8946 20.7071 16.7071C20.8946 16.5196 21 16.2652 21 16C21 15.7348 20.8946 15.4804 20.7071 15.2929C20.5196 15.1054 20.2652 15 20 15H12C11.7348 15 11.4804 15.1054 11.2929 15.2929C11.1054 15.4804 11 15.7348 11 16C11 16.2652 11.1054 16.5196 11.2929 16.7071C11.4804 16.8946 11.7348 17 12 17ZM16 19H12C11.7348 19 11.4804 19.1054 11.2929 19.2929C11.1054 19.4804 11 19.7348 11 20C11 20.2652 11.1054 20.5196 11.2929 20.7071C11.4804 20.8946 11.7348 21 12 21H16C16.2652 21 16.5196 20.8946 16.7071 20.7071C16.8946 20.5196 17 20.2652 17 20C17 19.7348 16.8946 19.4804 16.7071 19.2929C16.5196 19.1054 16.2652 19 16 19ZM28 6V19.5863C28.0008 19.849 27.9494 20.1093 27.8488 20.352C27.7482 20.5947 27.6003 20.815 27.4137 21L21 27.4137C20.815 27.6003 20.5947 27.7482 20.352 27.8488C20.1093 27.9494 19.849 28.0008 19.5863 28H6C5.46957 28 4.96086 27.7893 4.58579 27.4142C4.21071 27.0391 4 26.5304 4 26V6C4 5.46957 4.21071 4.96086 4.58579 4.58579C4.96086 4.21071 5.46957 4 6 4H26C26.5304 4 27.0391 4.21071 27.4142 4.58579C27.7893 4.96086 28 5.46957 28 6ZM6 26H19V20C19 19.7348 19.1054 19.4804 19.2929 19.2929C19.4804 19.1054 19.7348 19 20 19H26V6H6V26ZM21 21V24.5875L24.5863 21H21Z" fill="#343330"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 3C13.4288 3 10.9154 3.76244 8.77759 5.1909C6.63975 6.61935 4.97351 8.64968 3.98957 11.0251C3.00563 13.4006 2.74819 16.0144 3.2498 18.5362C3.75141 21.0579 4.98953 23.3743 6.80762 25.1924C8.6257 27.0105 10.9421 28.2486 13.4638 28.7502C15.9856 29.2518 18.5995 28.9944 20.9749 28.0104C23.3503 27.0265 25.3807 25.3603 26.8091 23.2224C28.2376 21.0846 29 18.5712 29 16C28.9964 12.5533 27.6256 9.24882 25.1884 6.81163C22.7512 4.37445 19.4467 3.00364 16 3ZM16 27C13.8244 27 11.6977 26.3549 9.88873 25.1462C8.07979 23.9375 6.66989 22.2195 5.83733 20.2095C5.00477 18.1995 4.78693 15.9878 5.21137 13.854C5.63581 11.7202 6.68345 9.7602 8.22183 8.22183C9.76021 6.68345 11.7202 5.6358 13.854 5.21136C15.9878 4.78692 18.1995 5.00476 20.2095 5.83733C22.2195 6.66989 23.9375 8.07979 25.1462 9.88873C26.3549 11.6977 27 13.8244 27 16C26.9967 18.9164 25.8367 21.7123 23.7745 23.7745C21.7123 25.8367 18.9164 26.9967 16 27ZM10 13.5C10 13.2033 10.088 12.9133 10.2528 12.6666C10.4176 12.42 10.6519 12.2277 10.926 12.1142C11.2001 12.0006 11.5017 11.9709 11.7926 12.0288C12.0836 12.0867 12.3509 12.2296 12.5607 12.4393C12.7704 12.6491 12.9133 12.9164 12.9712 13.2074C13.0291 13.4983 12.9994 13.7999 12.8858 14.074C12.7723 14.3481 12.58 14.5824 12.3334 14.7472C12.0867 14.912 11.7967 15 11.5 15C11.1022 15 10.7206 14.842 10.4393 14.5607C10.158 14.2794 10 13.8978 10 13.5ZM22 13.5C22 13.7967 21.912 14.0867 21.7472 14.3334C21.5824 14.58 21.3481 14.7723 21.074 14.8858C20.7999 14.9994 20.4983 15.0291 20.2074 14.9712C19.9164 14.9133 19.6491 14.7704 19.4393 14.5607C19.2296 14.3509 19.0867 14.0836 19.0288 13.7926C18.971 13.5017 19.0007 13.2001 19.1142 12.926C19.2277 12.6519 19.42 12.4176 19.6667 12.2528C19.9133 12.088 20.2033 12 20.5 12C20.8978 12 21.2794 12.158 21.5607 12.4393C21.842 12.7206 22 13.1022 22 13.5ZM21.865 21.5C21.9374 21.6138 21.9859 21.7411 22.0078 21.8742C22.0297 22.0073 22.0245 22.1434 21.9924 22.2744C21.9603 22.4054 21.902 22.5285 21.8211 22.6364C21.7402 22.7443 21.6383 22.8348 21.5215 22.9022C21.4048 22.9697 21.2756 23.0129 21.1417 23.0292C21.0078 23.0454 20.872 23.0345 20.7425 22.9969C20.6129 22.9593 20.4924 22.8959 20.388 22.8105C20.2836 22.7251 20.1975 22.6195 20.135 22.5C19.2013 20.8862 17.7338 20 16 20C14.2663 20 12.7988 20.8875 11.865 22.5C11.8025 22.6195 11.7164 22.7251 11.6121 22.8105C11.5077 22.8959 11.3871 22.9593 11.2575 22.9969C11.128 23.0345 10.9922 23.0454 10.8583 23.0292C10.7245 23.0129 10.5952 22.9697 10.4785 22.9022C10.3617 22.8348 10.2598 22.7443 10.1789 22.6364C10.098 22.5285 10.0397 22.4054 10.0076 22.2744C9.97555 22.1434 9.97029 22.0073 9.99218 21.8742C10.0141 21.7411 10.0627 21.6138 10.135 21.5C11.4213 19.2762 13.5588 18 16 18C18.4413 18 20.5788 19.275 21.865 21.5Z" fill="#343330"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216ZM80,108a12,12,0,1,1,12,12A12,12,0,0,1,80,108Zm96,0a12,12,0,1,1-12-12A12,12,0,0,1,176,108Zm-1.07,48c-10.29,17.79-27.4,28-46.93,28s-36.63-10.2-46.92-28a8,8,0,1,1,13.84-8c7.47,12.91,19.21,20,33.08,20s25.61-7.1,33.07-20a8,8,0,0,1,13.86,8Z"></path></svg>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 3C13.4288 3 10.9154 3.76244 8.77759 5.1909C6.63975 6.61935 4.97351 8.64968 3.98957 11.0251C3.00563 13.4006 2.74819 16.0144 3.2498 18.5362C3.75141 21.0579 4.98953 23.3743 6.80762 25.1924C8.6257 27.0105 10.9421 28.2486 13.4638 28.7502C15.9856 29.2518 18.5995 28.9944 20.9749 28.0104C23.3503 27.0265 25.3807 25.3603 26.8091 23.2224C28.2376 21.0846 29 18.5712 29 16C28.9964 12.5533 27.6256 9.24882 25.1884 6.81163C22.7512 4.37445 19.4467 3.00364 16 3ZM16 27C13.8244 27 11.6977 26.3549 9.88873 25.1462C8.07979 23.9375 6.66989 22.2195 5.83733 20.2095C5.00477 18.1995 4.78693 15.9878 5.21137 13.854C5.63581 11.7202 6.68345 9.7602 8.22183 8.22183C9.76021 6.68345 11.7202 5.6358 13.854 5.21136C15.9878 4.78692 18.1995 5.00476 20.2095 5.83733C22.2195 6.66989 23.9375 8.07979 25.1462 9.88873C26.3549 11.6977 27 13.8244 27 16C26.9967 18.9164 25.8367 21.7123 23.7745 23.7745C21.7123 25.8367 18.9164 26.9967 16 27ZM10 13.5C10 13.2033 10.088 12.9133 10.2528 12.6666C10.4176 12.42 10.6519 12.2277 10.926 12.1142C11.2001 12.0006 11.5017 11.9709 11.7926 12.0288C12.0836 12.0867 12.3509 12.2296 12.5607 12.4393C12.7704 12.6491 12.9133 12.9164 12.9712 13.2074C13.0291 13.4983 12.9994 13.7999 12.8858 14.074C12.7723 14.3481 12.58 14.5824 12.3334 14.7472C12.0867 14.912 11.7967 15 11.5 15C11.1022 15 10.7206 14.842 10.4393 14.5607C10.158 14.2794 10 13.8978 10 13.5ZM22 13.5C22 13.7967 21.912 14.0867 21.7472 14.3334C21.5824 14.58 21.3481 14.7723 21.074 14.8858C20.7999 14.9994 20.4983 15.0291 20.2074 14.9712C19.9164 14.9133 19.6491 14.7704 19.4393 14.5607C19.2296 14.3509 19.0867 14.0836 19.0288 13.7926C18.971 13.5017 19.0007 13.2001 19.1142 12.926C19.2277 12.6519 19.42 12.4176 19.6667 12.2528C19.9133 12.088 20.2033 12 20.5 12C20.8978 12 21.2794 12.158 21.5607 12.4393C21.842 12.7206 22 13.1022 22 13.5ZM21.8663 19.5C20.58 21.7238 18.4413 23 16 23C13.5588 23 11.4213 21.725 10.135 19.5C10.0627 19.3862 10.0141 19.2589 9.99218 19.1258C9.97029 18.9927 9.97555 18.8566 10.0076 18.7256C10.0397 18.5946 10.098 18.4715 10.1789 18.3636C10.2598 18.2557 10.3617 18.1652 10.4785 18.0978C10.5952 18.0303 10.7245 17.9871 10.8583 17.9708C10.9922 17.9546 11.128 17.9655 11.2575 18.0031C11.3871 18.0407 11.5077 18.1041 11.6121 18.1895C11.7164 18.2749 11.8025 18.3805 11.865 18.5C12.7988 20.1138 14.2663 21 16 21C17.7338 21 19.2013 20.1125 20.1338 18.5C20.2664 18.2703 20.4848 18.1026 20.741 18.0339C20.9972 17.9652 21.2703 18.0011 21.5 18.1338C21.7297 18.2664 21.8974 18.4848 21.9661 18.741C22.0348 18.9972 21.9989 19.2703 21.8663 19.5Z" fill="#343330"/>
</svg>

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27 5H5C4.46957 5 3.96086 5.21071 3.58579 5.58579C3.21071 5.96086 3 6.46957 3 7V25C3 25.5304 3.21071 26.0391 3.58579 26.4142C3.96086 26.7893 4.46957 27 5 27H27C27.5304 27 28.0391 26.7893 28.4142 26.4142C28.7893 26.0391 29 25.5304 29 25V7C29 6.46957 28.7893 5.96086 28.4142 5.58579C28.0391 5.21071 27.5304 5 27 5ZM12 15C12 14.2089 12.2346 13.4355 12.6741 12.7777C13.1136 12.1199 13.7384 11.6072 14.4693 11.3045C15.2002 11.0017 16.0044 10.9225 16.7804 11.0769C17.5563 11.2312 18.269 11.6122 18.8284 12.1716C19.3878 12.731 19.7688 13.4437 19.9231 14.2196C20.0775 14.9956 19.9983 15.7998 19.6955 16.5307C19.3928 17.2616 18.8801 17.8864 18.2223 18.3259C17.5645 18.7654 16.7911 19 16 19C14.9391 19 13.9217 18.5786 13.1716 17.8284C12.4214 17.0783 12 16.0609 12 15ZM9.07125 25C9.77332 23.7836 10.7833 22.7734 11.9995 22.0711C13.2158 21.3688 14.5955 20.9991 16 20.9991C17.4045 20.9991 18.7842 21.3688 20.0005 22.0711C21.2167 22.7734 22.2267 23.7836 22.9287 25H9.07125ZM27 25H25.1663C24.1107 22.5894 22.1489 20.6909 19.705 19.715C20.6866 18.9444 21.4035 17.8868 21.7559 16.6896C22.1082 15.4924 22.0785 14.2151 21.6708 13.0355C21.2631 11.856 20.4978 10.833 19.4814 10.1088C18.4649 9.38473 17.248 8.99557 16 8.99557C14.752 8.99557 13.5351 9.38473 12.5186 10.1088C11.5022 10.833 10.7369 11.856 10.3292 13.0355C9.92149 14.2151 9.89175 15.4924 10.2441 16.6896C10.5965 17.8868 11.3134 18.9444 12.295 19.715C9.85107 20.6909 7.88932 22.5894 6.83375 25H5V7H27V25Z" fill="#343330"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -5,6 +5,13 @@ list(APPEND _LINPHONEAPP_SOURCES
model/call/CallModel.cpp
model/call-history/CallHistoryModel.cpp
model/conference/ConferenceInfoModel.cpp
model/conference/ConferenceModel.cpp
model/conference/ConferenceSchedulerModel.cpp
model/participant/ParticipantDeviceModel.cpp
model/participant/ParticipantModel.cpp
model/core/CoreModel.cpp

View file

@ -23,7 +23,6 @@
#include <QDebug>
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(CallHistoryModel)
@ -37,5 +36,6 @@ CallHistoryModel::~CallHistoryModel() {
}
void CallHistoryModel::removeCallHistory() {
mustBeInLinphoneThread(getClassName() + "::removeCallHistory");
CoreModel::getInstance()->getCore()->removeCallLog(callLog);
}

View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceInfoModel.hpp"
#include <QDebug>
#include "core/participant/ParticipantList.hpp"
#include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(ConferenceInfoModel)
ConferenceInfoModel::ConferenceInfoModel(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo,
QObject *parent)
: mConferenceInfo(conferenceInfo) {
mustBeInLinphoneThread(getClassName());
}
ConferenceInfoModel::~ConferenceInfoModel() {
mustBeInLinphoneThread("~" + getClassName());
if (mConferenceSchedulerModel) mConferenceSchedulerModel->removeListener();
}
void ConferenceInfoModel::createConferenceScheduler() {
mustBeInLinphoneThread(getClassName() + "::createConferenceScheduler()");
}
std::shared_ptr<ConferenceSchedulerModel> ConferenceInfoModel::getConferenceScheduler() const {
return mConferenceSchedulerModel;
}
void ConferenceInfoModel::setConferenceScheduler(const std::shared_ptr<ConferenceSchedulerModel> &model) {
if (mConferenceSchedulerModel != model) {
if (mConferenceSchedulerModel) {
disconnect(mConferenceSchedulerModel.get(), &ConferenceSchedulerModel::stateChanged, this, nullptr);
disconnect(mConferenceSchedulerModel.get(), &ConferenceSchedulerModel::invitationsSent, this, nullptr);
mConferenceSchedulerModel->removeListener();
}
mConferenceSchedulerModel = model;
connect(mConferenceSchedulerModel.get(), &ConferenceSchedulerModel::stateChanged, this,
&ConferenceInfoModel::stateChanged);
connect(mConferenceSchedulerModel.get(), &ConferenceSchedulerModel::invitationsSent, this,
&ConferenceInfoModel::invitationsSent);
mConferenceSchedulerModel->setSelf(mConferenceSchedulerModel);
}
}
QDateTime ConferenceInfoModel::getDateTime() const {
return QDateTime::fromMSecsSinceEpoch(mConferenceInfo->getDateTime() * 1000, Qt::LocalTime);
}
int ConferenceInfoModel::getDuration() const {
return mConferenceInfo->getDuration();
}
QDateTime ConferenceInfoModel::getEndTime() const {
return getDateTime().addSecs(mConferenceInfo->getDuration());
}
QString ConferenceInfoModel::getSubject() const {
return Utils::coreStringToAppString(mConferenceInfo->getSubject());
}
QString ConferenceInfoModel::getOrganizerName() const {
auto organizer = mConferenceInfo->getOrganizer();
auto name = Utils::coreStringToAppString(organizer->getDisplayName());
if (name.isEmpty()) name = ToolModel::getDisplayName(Utils::coreStringToAppString(organizer->asStringUriOnly()));
return name;
}
QString ConferenceInfoModel::getOrganizerAddress() const {
return Utils::coreStringToAppString(mConferenceInfo->getOrganizer()->asStringUriOnly());
}
QString ConferenceInfoModel::getDescription() const {
return Utils::coreStringToAppString(mConferenceInfo->getSubject());
}
std::list<std::shared_ptr<linphone::ParticipantInfo>> ConferenceInfoModel::getParticipantInfos() const {
return mConferenceInfo->getParticipantInfos();
}
void ConferenceInfoModel::setDateTime(const QDateTime &date) {
mConferenceInfo->setDateTime(date.toMSecsSinceEpoch() / 1000); // toMSecsSinceEpoch() is UTC
emit dateTimeChanged(date);
}
void ConferenceInfoModel::setDuration(int duration) {
mConferenceInfo->setDuration(duration);
emit durationChanged(duration);
}
void ConferenceInfoModel::setSubject(const QString &subject) {
mConferenceInfo->setSubject(Utils::appStringToCoreString(subject));
emit subjectChanged(subject);
}
void ConferenceInfoModel::setOrganizer(const QString &organizerAddress) {
auto linAddr = ToolModel::interpretUrl(organizerAddress);
if (linAddr) {
mConferenceInfo->setOrganizer(linAddr);
emit organizerChanged(organizerAddress);
}
}
void ConferenceInfoModel::setDescription(const QString &description) {
mConferenceInfo->setDescription(Utils::appStringToCoreString(description));
emit descriptionChanged(description);
}
void ConferenceInfoModel::setParticipantInfos(
const std::list<std::shared_ptr<linphone::ParticipantInfo>> &participantInfos) {
mConferenceInfo->setParticipantInfos(participantInfos);
emit participantsChanged();
}
void ConferenceInfoModel::deleteConferenceInfo() {
CoreModel::getInstance()->getCore()->deleteConferenceInformation(mConferenceInfo);
emit conferenceInfoDeleted();
}
void ConferenceInfoModel::cancelConference() {
if (!mConferenceSchedulerModel) return;
mConferenceSchedulerModel->cancelConference(mConferenceInfo);
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_INFO_MODEL_H_
#define CONFERENCE_INFO_MODEL_H_
#include "model/conference/ConferenceSchedulerModel.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <QTimer>
#include <linphone++/linphone.hh>
class ConferenceInfoModel : public QObject, public AbstractObject {
Q_OBJECT
public:
ConferenceInfoModel(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo, QObject *parent = nullptr);
~ConferenceInfoModel();
void createConferenceScheduler();
std::shared_ptr<ConferenceSchedulerModel> getConferenceScheduler() const;
void setConferenceScheduler(const std::shared_ptr<ConferenceSchedulerModel> &model);
QDateTime getDateTime() const;
int getDuration() const;
QDateTime getEndTime() const;
QString getSubject() const;
QString getOrganizerName() const;
QString getOrganizerAddress() const;
QString getDescription() const;
std::list<std::shared_ptr<linphone::ParticipantInfo>> getParticipantInfos() const;
void setDateTime(const QDateTime &date);
void setDuration(int duration);
void setSubject(const QString &subject);
void setOrganizer(const QString &organizerAddress);
void setDescription(const QString &description);
void setParticipantInfos(const std::list<std::shared_ptr<linphone::ParticipantInfo>> &participantInfos);
void deleteConferenceInfo();
void cancelConference();
signals:
void dateTimeChanged(const QDateTime &date);
void durationChanged(int duration);
void organizerChanged(const QString &organizer);
void subjectChanged(const QString &subject);
void descriptionChanged(const QString &description);
void participantsChanged();
void conferenceInfoDeleted();
void stateChanged(linphone::ConferenceScheduler::State state);
void invitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations);
private:
std::shared_ptr<linphone::ConferenceInfo> mConferenceInfo;
std::shared_ptr<ConferenceSchedulerModel> mConferenceSchedulerModel = nullptr;
DECLARE_ABSTRACT_OBJECT
// LINPHONE
//--------------------------------------------------------------------------------
};
#endif

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceModel.hpp"
#include <QDebug>
#include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp"
DEFINE_ABSTRACT_OBJECT(ConferenceModel)
ConferenceModel::ConferenceModel(const std::shared_ptr<linphone::Conference> &conference, QObject *parent)
: ::Listener<linphone::Conference, linphone::ConferenceListener>(conference, parent) {
mustBeInLinphoneThread(getClassName());
}
ConferenceModel::~ConferenceModel() {
mustBeInLinphoneThread("~" + getClassName());
}
void ConferenceModel::terminate() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->terminate();
}
void ConferenceModel::setPaused(bool paused) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
}
void ConferenceModel::removeParticipant(std::shared_ptr<linphone::Participant> p) {
mMonitor->removeParticipant(p);
}
void ConferenceModel::removeParticipant(std::shared_ptr<linphone::Address> address) {
for (auto &p : mMonitor->getParticipantList()) {
if (address->asStringUriOnly() == p->getAddress()->asStringUriOnly()) {
mMonitor->removeParticipant(p);
}
}
}
void ConferenceModel::setMicrophoneMuted(bool isMuted) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->setMicrophoneMuted(isMuted);
emit microphoneMutedChanged(isMuted);
}
void ConferenceModel::startRecording() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
// mMonitor->startRecording(mMonitor->getCurrentParams()->getRecordFile());
// emit recordingChanged(mMonitor->getParams()->isRecording());
}
void ConferenceModel::stopRecording() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->stopRecording();
// emit recordingChanged(mMonitor->getParams()->isRecording());
// TODO : display notification
}
void ConferenceModel::setRecordFile(const std::string &path) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
// auto params = core->createCallParams(mMonitor);
// params->setRecordFile(path);
// mMonitor->update(params);
}
// void ConferenceModel::setSpeakerVolumeGain(float gain) {
// mMonitor->setSpeakerVolumeGain(gain);
// emit speakerVolumeGainChanged(gain);
// }
// float ConferenceModel::getSpeakerVolumeGain() const {
// auto gain = mMonitor->getSpeakerVolumeGain();
// if (gain < 0) gain = CoreModel::getInstance()->getCore()->getPlaybackGainDb();
// return gain;
// }
// void ConferenceModel::setMicrophoneVolumeGain(float gain) {
// mMonitor->setMicrophoneVolumeGain(gain);
// emit microphoneVolumeGainChanged(gain);
// }
// float ConferenceModel::getMicrophoneVolumeGain() const {
// auto gain = mMonitor->getMicrophoneVolumeGain();
// return gain;
// }
// float ConferenceModel::getMicrophoneVolume() const {
// auto volume = mMonitor->getRecordVolume();
// return volume;
// }
void ConferenceModel::setInputAudioDevice(const std::shared_ptr<linphone::AudioDevice> &device) {
mMonitor->setInputAudioDevice(device);
std::string deviceName;
if (device) deviceName = device->getDeviceName();
emit inputAudioDeviceChanged(deviceName);
}
std::shared_ptr<const linphone::AudioDevice> ConferenceModel::getInputAudioDevice() const {
return mMonitor->getInputAudioDevice();
}
void ConferenceModel::setOutputAudioDevice(const std::shared_ptr<linphone::AudioDevice> &device) {
mMonitor->setOutputAudioDevice(device);
std::string deviceName;
if (device) deviceName = device->getDeviceName();
emit outputAudioDeviceChanged(deviceName);
}
std::shared_ptr<const linphone::AudioDevice> ConferenceModel::getOutputAudioDevice() const {
return mMonitor->getOutputAudioDevice();
}
void ConferenceModel::onActiveSpeakerParticipantDevice(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "onActiveSpeakerParticipantDevice: " << participantDevice->getAddress()->asString().c_str();
emit activeSpeakerParticipantDevice(participantDevice);
}
void ConferenceModel::onParticipantAdded(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::Participant> &participant) {
qDebug() << "onParticipantAdded: " << participant->getAddress()->asString().c_str();
emit participantAdded(participant);
}
void ConferenceModel::onParticipantRemoved(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::Participant> &participant) {
qDebug() << "onParticipantRemoved";
emit participantRemoved(participant);
}
void ConferenceModel::onParticipantDeviceAdded(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "onParticipantDeviceAdded";
qDebug() << "Me devices : " << conference->getMe()->getDevices().size();
if (conference->getMe()->getDevices().size() > 1)
for (auto d : conference->getMe()->getDevices())
qDebug() << "\t--> " << d->getAddress()->asString().c_str();
emit participantDeviceAdded(participantDevice);
}
void ConferenceModel::onParticipantDeviceRemoved(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "onParticipantDeviceRemoved: " << participantDevice->getAddress()->asString().c_str() << " isInConf?["
<< participantDevice->isInConference() << "]";
qDebug() << "Me devices : " << conference->getMe()->getDevices().size();
emit participantDeviceRemoved(participantDevice);
}
void ConferenceModel::onParticipantDeviceStateChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &device,
linphone::ParticipantDevice::State state) {
qDebug() << "onParticipantDeviceStateChanged: " << device->getAddress()->asString().c_str() << " isInConf?["
<< device->isInConference() << "] " << (int)state;
emit participantDeviceStateChanged(conference, device, state);
}
void ConferenceModel::onParticipantAdminStatusChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::Participant> &participant) {
qDebug() << "onParticipantAdminStatusChanged";
emit participantAdminStatusChanged(participant);
}
void ConferenceModel::onParticipantDeviceMediaCapabilityChanged(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "onParticipantDeviceMediaCapabilityChanged: "
<< (int)participantDevice->getStreamCapability(linphone::StreamType::Video)
<< ". Device: " << participantDevice->getAddress()->asString().c_str();
emit participantDeviceMediaCapabilityChanged(participantDevice);
}
void ConferenceModel::onParticipantDeviceMediaAvailabilityChanged(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
qDebug() << "onParticipantDeviceMediaAvailabilityChanged: "
<< (int)participantDevice->getStreamAvailability(linphone::StreamType::Video)
<< ". Device: " << participantDevice->getAddress()->asString().c_str();
emit participantDeviceMediaAvailabilityChanged(participantDevice);
}
void ConferenceModel::onParticipantDeviceIsSpeakingChanged(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice,
bool isSpeaking) {
// qDebug() << "onParticipantDeviceIsSpeakingChanged: " << participantDevice->getAddress()->asString().c_str() <<
// ". Speaking:" << isSpeaking;
emit participantDeviceIsSpeakingChanged(participantDevice, isSpeaking);
}
void ConferenceModel::onStateChanged(const std::shared_ptr<linphone::Conference> &conference,
linphone::Conference::State newState) {
qDebug() << "onStateChanged:" << (int)newState;
emit conferenceStateChanged(newState);
}
void ConferenceModel::onSubjectChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::string &subject) {
qDebug() << "onSubjectChanged";
emit subjectChanged(subject);
}
void ConferenceModel::onAudioDeviceChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::AudioDevice> &audioDevice) {
qDebug() << "onAudioDeviceChanged is not yet implemented.";
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_MODEL_H_
#define CONFERENCE_MODEL_H_
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <QTimer>
#include <linphone++/linphone.hh>
class ConferenceModel : public ::Listener<linphone::Conference, linphone::ConferenceListener>,
public linphone::ConferenceListener,
public AbstractObject {
Q_OBJECT
public:
ConferenceModel(const std::shared_ptr<linphone::Conference> &conference, QObject *parent = nullptr);
~ConferenceModel();
void terminate();
void setMicrophoneMuted(bool isMuted);
void startRecording();
void stopRecording();
void setRecordFile(const std::string &path);
void setInputAudioDevice(const std::shared_ptr<linphone::AudioDevice> &id);
std::shared_ptr<const linphone::AudioDevice> getInputAudioDevice() const;
void setOutputAudioDevice(const std::shared_ptr<linphone::AudioDevice> &id);
std::shared_ptr<const linphone::AudioDevice> getOutputAudioDevice() const;
void setPaused(bool paused);
void removeParticipant(std::shared_ptr<linphone::Participant> p);
void removeParticipant(std::shared_ptr<linphone::Address> address);
signals:
void microphoneMutedChanged(bool isMuted);
void speakerMutedChanged(bool isMuted);
void cameraEnabledChanged(bool enabled);
void durationChanged(int);
void microphoneVolumeChanged(float);
void pausedChanged(bool paused);
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
void recordingChanged(bool recording);
void speakerVolumeGainChanged(float volume);
void microphoneVolumeGainChanged(float volume);
void inputAudioDeviceChanged(const std::string &id);
void outputAudioDeviceChanged(const std::string &id);
private:
// LINPHONE LISTENERS
virtual void onActiveSpeakerParticipantDevice(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) override;
virtual void onParticipantAdded(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::Participant> &participant) override;
virtual void onParticipantRemoved(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::Participant> &participant) override;
virtual void
onParticipantAdminStatusChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::Participant> &participant) override;
virtual void
onParticipantDeviceAdded(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) override;
virtual void
onParticipantDeviceRemoved(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) override;
virtual void onParticipantDeviceStateChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &device,
linphone::ParticipantDevice::State state) override;
virtual void onParticipantDeviceMediaCapabilityChanged(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &device) override;
virtual void onParticipantDeviceMediaAvailabilityChanged(
const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &device) override;
virtual void
onParticipantDeviceIsSpeakingChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice,
bool isSpeaking) override;
virtual void onStateChanged(const std::shared_ptr<linphone::Conference> &conference,
linphone::Conference::State newState) override;
virtual void onSubjectChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::string &subject) override;
virtual void onAudioDeviceChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::AudioDevice> &audioDevice) override;
signals:
void activeSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void participantAdded(const std::shared_ptr<const linphone::Participant> &participant);
void participantRemoved(const std::shared_ptr<const linphone::Participant> &participant);
void participantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> &participant);
void participantDeviceAdded(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void participantDeviceRemoved(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void participantDeviceStateChanged(const std::shared_ptr<linphone::Conference> &conference,
const std::shared_ptr<const linphone::ParticipantDevice> &device,
linphone::ParticipantDevice::State state);
void participantDeviceMediaCapabilityChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void participantDeviceMediaAvailabilityChanged(
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
void participantDeviceIsSpeakingChanged(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice,
bool isSpeaking);
void conferenceStateChanged(linphone::Conference::State newState);
void subjectChanged(const std::string &subject);
private:
QTimer mDurationTimer;
QTimer mMicroVolumeTimer;
DECLARE_ABSTRACT_OBJECT
// LINPHONE
//--------------------------------------------------------------------------------
};
#endif

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#include "ConferenceSchedulerModel.hpp"
#include <QDebug>
#include "model/core/CoreModel.hpp"
DEFINE_ABSTRACT_OBJECT(ConferenceSchedulerModel)
ConferenceSchedulerModel::ConferenceSchedulerModel(
const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler, QObject *parent)
: ::Listener<linphone::ConferenceScheduler, linphone::ConferenceSchedulerListener>(conferenceScheduler, parent) {
mustBeInLinphoneThread(getClassName());
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
assert(defaultAccount);
mMonitor->setAccount(CoreModel::getInstance()->getCore()->getDefaultAccount());
}
ConferenceSchedulerModel::~ConferenceSchedulerModel() {
mustBeInLinphoneThread("~" + getClassName());
}
void ConferenceSchedulerModel::setInfo(const std::shared_ptr<linphone::ConferenceInfo> &confInfo) {
mMonitor->setInfo(confInfo);
}
void ConferenceSchedulerModel::cancelConference(const std::shared_ptr<linphone::ConferenceInfo> &confInfo) {
mMonitor->cancelConference(confInfo);
}
void ConferenceSchedulerModel::onStateChanged(const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler,
linphone::ConferenceScheduler::State state) {
emit stateChanged(state);
}
void ConferenceSchedulerModel::onInvitationsSent(
const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler,
const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) {
emit invitationsSent(failedInvitations);
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFERENCE_SCHEDULER_MODEL_H_
#define CONFERENCE_SCHEDULER_MODEL_H_
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <QTimer>
#include <linphone++/linphone.hh>
class ConferenceSchedulerModel
: public ::Listener<linphone::ConferenceScheduler, linphone::ConferenceSchedulerListener>,
public linphone::ConferenceSchedulerListener,
public AbstractObject {
Q_OBJECT
public:
ConferenceSchedulerModel(const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler,
QObject *parent = nullptr);
~ConferenceSchedulerModel();
void setInfo(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
void cancelConference(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
signals:
void stateChanged(linphone::ConferenceScheduler::State state);
void invitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations);
private:
DECLARE_ABSTRACT_OBJECT
//--------------------------------------------------------------------------------
// LINPHONE
//--------------------------------------------------------------------------------
virtual void onStateChanged(const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler,
linphone::ConferenceScheduler::State state) override;
virtual void onInvitationsSent(const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler,
const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) override;
};
#endif

View file

@ -220,8 +220,13 @@ void CoreModel::onConferenceInfoReceived(const std::shared_ptr<linphone::Core> &
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
emit conferenceInfoReceived(core, conferenceInfo);
}
void CoreModel::onConferenceStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Conference> &conference,
linphone::Conference::State state) {
emit conferenceStateChanged(core, conference, state);
}
void CoreModel::onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::ConfiguringState status,
linphone::Config::ConfiguringState status,
const std::string &message) {
emit configuringStatus(core, status, message);
}

View file

@ -108,8 +108,12 @@ private:
virtual void
onConferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) override;
virtual void onConferenceStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Conference> &conference,
linphone::Conference::State state) override;
virtual void onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::ConfiguringState status,
linphone::Config::ConfiguringState status,
const std::string &message) override;
virtual void onDefaultAccountChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Account> &account) override;
@ -192,8 +196,11 @@ signals:
linphone::ChatRoom::State state);
void conferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo);
void conferenceStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Conference> &conference,
linphone::Conference::State state);
void configuringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::ConfiguringState status,
linphone::Config::ConfiguringState status,
const std::string &message);
void defaultAccountChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Account> &account);

View file

@ -0,0 +1,122 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantDeviceModel.hpp"
#include "core/App.hpp"
#include "tool/Utils.hpp"
#include <QQmlApplicationEngine>
DEFINE_ABSTRACT_OBJECT(ParticipantDeviceModel)
ParticipantDeviceModel::ParticipantDeviceModel(const std::shared_ptr<linphone::ParticipantDevice> &device,
QObject *parent)
: ::Listener<linphone::ParticipantDevice, linphone::ParticipantDeviceListener>(device, parent) {
mustBeInLinphoneThread(getClassName());
}
ParticipantDeviceModel::~ParticipantDeviceModel() {
}
QString ParticipantDeviceModel::getName() const {
return Utils::coreStringToAppString(mMonitor->getName());
}
QString ParticipantDeviceModel::getDisplayName() const {
return Utils::coreStringToAppString(mMonitor->getAddress()->getDisplayName());
}
int ParticipantDeviceModel::getSecurityLevel() const {
return (int)mMonitor->getSecurityLevel();
}
time_t ParticipantDeviceModel::getTimeOfJoining() const {
return mMonitor->getTimeOfJoining();
}
QString ParticipantDeviceModel::getAddress() const {
return Utils::coreStringToAppString(mMonitor->getAddress()->asStringUriOnly());
}
bool ParticipantDeviceModel::getPaused() const {
return !mMonitor->isInConference() || mMonitor->getState() == linphone::ParticipantDevice::State::OnHold;
}
bool ParticipantDeviceModel::getIsSpeaking() const {
return mMonitor->getIsSpeaking();
}
bool ParticipantDeviceModel::getIsMuted() const {
return mMonitor->getIsMuted();
}
LinphoneEnums::ParticipantDeviceState ParticipantDeviceModel::getState() const {
return LinphoneEnums::fromLinphone(mMonitor->getState());
}
bool ParticipantDeviceModel::isVideoEnabled() const {
return mMonitor->isInConference() && mMonitor->getStreamAvailability(linphone::StreamType::Video) &&
(mMonitor->getStreamCapability(linphone::StreamType::Video) == linphone::MediaDirection::SendRecv ||
mMonitor->getStreamCapability(linphone::StreamType::Video) == linphone::MediaDirection::SendOnly);
}
// void ParticipantDeviceModel::updateIsLocal() {
// auto deviceAddress = mMonitor->getAddress();
// auto callAddress = mCall->getConferenceSharedModel()->getConference()->getMe()->getAddress();
// auto gruuAddress =
// CoreManager::getInstance()->getAccountSettingsModel()->findAccount(callAddress)->getContactAddress();
// setIsLocal(deviceAddress->equal(gruuAddress));
// }
// void ParticipantDeviceModel::onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device) {
// if (!device || mMonitor && mMonitor->getAddress()->weakEqual(device)) emit securityLevelChanged();
// }
// void ParticipantDeviceModel::onCallStatusChanged() {
// if (mCall->getCall()->getState() == linphone::Call::State::StreamsRunning) {
// updateVideoEnabled();
// }
// }
//--------------------------------------------------------------------
void ParticipantDeviceModel::onIsSpeakingChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isSpeaking) {
emit isSpeakingChanged(isSpeaking);
}
void ParticipantDeviceModel::onIsMuted(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isMuted) {
emit isMutedChanged(isMuted);
}
void ParticipantDeviceModel::onStateChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::ParticipantDevice::State state) {
emit stateChanged(LinphoneEnums::fromLinphone(state));
}
void ParticipantDeviceModel::onStreamCapabilityChanged(
const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::MediaDirection direction,
linphone::StreamType streamType) {
emit streamCapabilityChanged(streamType);
}
void ParticipantDeviceModel::onStreamAvailabilityChanged(
const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool available,
linphone::StreamType streamType) {
emit streamAvailabilityChanged(streamType);
}

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_DEVICE_MODEL_H_
#define PARTICIPANT_DEVICE_MODEL_H_
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/LinphoneEnums.hpp"
#include <linphone++/linphone.hh>
#include <QDateTime>
#include <QObject>
#include <QSharedPointer>
#include <QString>
class ParticipantDeviceModel : public ::Listener<linphone::ParticipantDevice, linphone::ParticipantDeviceListener>,
public linphone::ParticipantDeviceListener,
public AbstractObject {
Q_OBJECT
public:
ParticipantDeviceModel(const std::shared_ptr<linphone::ParticipantDevice> &device, QObject *parent = nullptr);
virtual ~ParticipantDeviceModel();
QString getName() const;
QString getDisplayName() const;
QString getAddress() const;
int getSecurityLevel() const;
time_t getTimeOfJoining() const;
bool isVideoEnabled() const;
// bool isLocal() const;
bool getPaused() const;
bool getIsSpeaking() const;
bool getIsMuted() const;
LinphoneEnums::ParticipantDeviceState getState() const;
virtual void onIsSpeakingChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isSpeaking) override;
virtual void onIsMuted(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool isMuted) override;
virtual void onStateChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::ParticipantDevice::State state) override;
virtual void onStreamCapabilityChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
linphone::MediaDirection direction,
linphone::StreamType streamType) override;
virtual void onStreamAvailabilityChanged(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice,
bool available,
linphone::StreamType streamType) override;
// void updateVideoEnabled();
// void updateIsLocal();
signals:
// void securityLevelChanged();
// void videoEnabledChanged();
void isPausedChanged(bool paused);
void isSpeakingChanged(bool speaking);
void isMutedChanged(bool muted);
void stateChanged(LinphoneEnums::ParticipantDeviceState state);
void streamCapabilityChanged(linphone::StreamType streamType);
void streamAvailabilityChanged(linphone::StreamType streamType);
private:
DECLARE_ABSTRACT_OBJECT
};
#endif // PARTICIPANT_DEVICE_MODEL_H_

View file

@ -0,0 +1,65 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ParticipantModel.hpp"
#include "tool/Utils.hpp"
#include <QTimer>
DEFINE_ABSTRACT_OBJECT(ParticipantModel)
ParticipantModel::ParticipantModel(std::shared_ptr<linphone::Participant> linphoneParticipant, QObject *parent)
: QObject(parent) {
assert(mParticipant);
mParticipant = linphoneParticipant;
}
ParticipantModel::~ParticipantModel() {
mustBeInLinphoneThread("~" + getClassName());
}
int ParticipantModel::getSecurityLevel() const {
return (int)mParticipant->getSecurityLevel();
}
std::list<std::shared_ptr<linphone::ParticipantDevice>> ParticipantModel::getDevices() const {
return mParticipant->getDevices();
}
int ParticipantModel::getDeviceCount() {
return mParticipant->getDevices().size();
}
QString ParticipantModel::getSipAddress() const {
return Utils::coreStringToAppString(mParticipant->getAddress()->asString());
}
QDateTime ParticipantModel::getCreationTime() const {
return QDateTime::fromSecsSinceEpoch(mParticipant->getCreationTime());
}
bool ParticipantModel::getAdminStatus() const {
return mParticipant->isAdmin();
}
bool ParticipantModel::isFocus() const {
return mParticipant->isFocus();
}

View file

@ -0,0 +1,56 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_MODEL_H_
#define PARTICIPANT_MODEL_H_
#include "tool/AbstractObject.hpp"
#include <linphone++/linphone.hh>
#include <QDateTime>
#include <QObject>
#include <QSharedPointer>
#include <QString>
class ParticipantDeviceProxyModel;
class ParticipantDeviceListModel;
class ParticipantModel : public QObject, public AbstractObject {
Q_OBJECT
public:
ParticipantModel(std::shared_ptr<linphone::Participant> linphoneParticipant, QObject *parent = nullptr);
~ParticipantModel();
QString getSipAddress() const;
QDateTime getCreationTime() const;
bool getAdminStatus() const;
bool isFocus() const;
int getSecurityLevel() const;
int getDeviceCount();
std::list<std::shared_ptr<linphone::ParticipantDevice>> getDevices() const;
private:
std::shared_ptr<linphone::Participant> mParticipant;
DECLARE_ABSTRACT_OBJECT
};
#endif // PARTICIPANT_MODEL_H_

View file

@ -37,7 +37,7 @@ public:
//----------------------------------------------------------------------------------
static constexpr char DefaultLocale[] = "en";
static constexpr char DefaultLocale[] = "en_EN";
static constexpr char DefaultFont[] = "Noto Sans";
static constexpr int DefaultFontPointSize = 10;

View file

@ -221,6 +221,14 @@ LinphoneEnums::ParticipantDeviceState LinphoneEnums::fromLinphone(const linphone
return static_cast<LinphoneEnums::ParticipantDeviceState>(state);
}
linphone::Participant::Role LinphoneEnums::toLinphone(const LinphoneEnums::ParticipantRole &role) {
return static_cast<linphone::Participant::Role>(role);
}
LinphoneEnums::ParticipantRole LinphoneEnums::fromLinphone(const linphone::Participant::Role &role) {
return static_cast<LinphoneEnums::ParticipantRole>(role);
}
linphone::Tunnel::Mode LinphoneEnums::toLinphone(const LinphoneEnums::TunnelMode &data) {
return static_cast<linphone::Tunnel::Mode>(data);
}

View file

@ -256,6 +256,15 @@ Q_ENUM_NS(ParticipantDeviceState)
linphone::ParticipantDevice::State toLinphone(const LinphoneEnums::ParticipantDeviceState &state);
LinphoneEnums::ParticipantDeviceState fromLinphone(const linphone::ParticipantDevice::State &state);
enum class ParticipantRole {
Speaker = int(linphone::Participant::Role::Speaker),
Listener = int(linphone::Participant::Role::Listener),
Unknown = int(linphone::Participant::Role::Unknown)
};
Q_ENUM_NS(ParticipantRole)
linphone::Participant::Role toLinphone(const LinphoneEnums::ParticipantRole &role);
LinphoneEnums::ParticipantRole fromLinphone(const linphone::Participant::Role &role);
enum class RegistrationState {
None = int(linphone::RegistrationState::None),
Progress = int(linphone::RegistrationState::Progress),

View file

@ -141,6 +141,12 @@ QQuickWindow *Utils::getMainWindow() {
return win;
}
void Utils::showInformationPopup(const QString &title, const QString &description, bool isSuccess) {
auto win = App::getInstance()->getMainWindow();
QMetaObject::invokeMethod(win, "showInformationPopup", Q_ARG(QVariant, title), Q_ARG(QVariant, description),
Q_ARG(QVariant, isSuccess));
}
VariantObject *Utils::haveAccount() {
VariantObject *result = new VariantObject();
if (!result) return nullptr;
@ -274,6 +280,15 @@ QString Utils::generateLinphoneSipAddress(const QString &uri) {
return ret;
}
QString Utils::findAvatarByAddress(const QString &address) {
auto defaultFriendList = CoreModel::getInstance()->getCore()->getDefaultFriendList();
if (!defaultFriendList) return QString();
auto linphoneAddr = ToolModel::interpretUrl(address);
auto linFriend = CoreModel::getInstance()->getCore()->findFriend(linphoneAddr);
if (linFriend) return Utils::coreStringToAppString(linFriend->getPhoto());
return QString();
}
QString Utils::generateSavedFilename(const QString &from, const QString &to) {
auto escape = [](const QString &str) {
constexpr char ReservedCharacters[] = "[<|>|:|\"|/|\\\\|\\?|\\*|\\+|\\||_|-]+";
@ -340,3 +355,842 @@ QString Utils::computeUserAgent() {
.arg(qVersion());
*/
}
QString Utils::getCountryName(const QLocale::Country &p_country) {
QString countryName;
switch (p_country) {
case QLocale::Afghanistan:
if ((countryName = QCoreApplication::translate("country", "Afghanistan")) == "Afghanistan")
countryName = "";
break;
case QLocale::Albania:
if ((countryName = QCoreApplication::translate("country", "Albania")) == "Albania") countryName = "";
break;
case QLocale::Algeria:
if ((countryName = QCoreApplication::translate("country", "Algeria")) == "Algeria") countryName = "";
break;
case QLocale::AmericanSamoa:
if ((countryName = QCoreApplication::translate("country", "AmericanSamoa")) == "AmericanSamoa")
countryName = "";
break;
case QLocale::Andorra:
if ((countryName = QCoreApplication::translate("country", "Andorra")) == "Andorra") countryName = "";
break;
case QLocale::Angola:
if ((countryName = QCoreApplication::translate("country", "Angola")) == "Angola") countryName = "";
break;
case QLocale::Anguilla:
if ((countryName = QCoreApplication::translate("country", "Anguilla")) == "Anguilla") countryName = "";
break;
case QLocale::AntiguaAndBarbuda:
if ((countryName = QCoreApplication::translate("country", "AntiguaAndBarbuda")) == "AntiguaAndBarbuda")
countryName = "";
break;
case QLocale::Argentina:
if ((countryName = QCoreApplication::translate("country", "Argentina")) == "Argentina") countryName = "";
break;
case QLocale::Armenia:
if ((countryName = QCoreApplication::translate("country", "Armenia")) == "Armenia") countryName = "";
break;
case QLocale::Aruba:
if ((countryName = QCoreApplication::translate("country", "Aruba")) == "Aruba") countryName = "";
break;
case QLocale::Australia:
if ((countryName = QCoreApplication::translate("country", "Australia")) == "Australia") countryName = "";
break;
case QLocale::Austria:
if ((countryName = QCoreApplication::translate("country", "Austria")) == "Austria") countryName = "";
break;
case QLocale::Azerbaijan:
if ((countryName = QCoreApplication::translate("country", "Azerbaijan")) == "Azerbaijan") countryName = "";
break;
case QLocale::Bahamas:
if ((countryName = QCoreApplication::translate("country", "Bahamas")) == "Bahamas") countryName = "";
break;
case QLocale::Bahrain:
if ((countryName = QCoreApplication::translate("country", "Bahrain")) == "Bahrain") countryName = "";
break;
case QLocale::Bangladesh:
if ((countryName = QCoreApplication::translate("country", "Bangladesh")) == "Bangladesh") countryName = "";
break;
case QLocale::Barbados:
if ((countryName = QCoreApplication::translate("country", "Barbados")) == "Barbados") countryName = "";
break;
case QLocale::Belarus:
if ((countryName = QCoreApplication::translate("country", "Belarus")) == "Belarus") countryName = "";
break;
case QLocale::Belgium:
if ((countryName = QCoreApplication::translate("country", "Belgium")) == "Belgium") countryName = "";
break;
case QLocale::Belize:
if ((countryName = QCoreApplication::translate("country", "Belize")) == "Belize") countryName = "";
break;
case QLocale::Benin:
if ((countryName = QCoreApplication::translate("country", "Benin")) == "Benin") countryName = "";
break;
case QLocale::Bermuda:
if ((countryName = QCoreApplication::translate("country", "Bermuda")) == "Bermuda") countryName = "";
break;
case QLocale::Bhutan:
if ((countryName = QCoreApplication::translate("country", "Bhutan")) == "Bhutan") countryName = "";
break;
case QLocale::Bolivia:
if ((countryName = QCoreApplication::translate("country", "Bolivia")) == "Bolivia") countryName = "";
break;
case QLocale::BosniaAndHerzegowina:
if ((countryName = QCoreApplication::translate("country", "BosniaAndHerzegowina")) ==
"BosniaAndHerzegowina")
countryName = "";
break;
case QLocale::Botswana:
if ((countryName = QCoreApplication::translate("country", "Botswana")) == "Botswana") countryName = "";
break;
case QLocale::Brazil:
if ((countryName = QCoreApplication::translate("country", "Brazil")) == "Brazil") countryName = "";
break;
case QLocale::Brunei:
if ((countryName = QCoreApplication::translate("country", "Brunei")) == "Brunei") countryName = "";
break;
case QLocale::Bulgaria:
if ((countryName = QCoreApplication::translate("country", "Bulgaria")) == "Bulgaria") countryName = "";
break;
case QLocale::BurkinaFaso:
if ((countryName = QCoreApplication::translate("country", "BurkinaFaso")) == "BurkinaFaso")
countryName = "";
break;
case QLocale::Burundi:
if ((countryName = QCoreApplication::translate("country", "Burundi")) == "Burundi") countryName = "";
break;
case QLocale::Cambodia:
if ((countryName = QCoreApplication::translate("country", "Cambodia")) == "Cambodia") countryName = "";
break;
case QLocale::Cameroon:
if ((countryName = QCoreApplication::translate("country", "Cameroon")) == "Cameroon") countryName = "";
break;
case QLocale::Canada:
if ((countryName = QCoreApplication::translate("country", "Canada")) == "Canada") countryName = "";
break;
case QLocale::CapeVerde:
if ((countryName = QCoreApplication::translate("country", "CapeVerde")) == "CapeVerde") countryName = "";
break;
case QLocale::CaymanIslands:
if ((countryName = QCoreApplication::translate("country", "CaymanIslands")) == "CaymanIslands")
countryName = "";
break;
case QLocale::CentralAfricanRepublic:
if ((countryName = QCoreApplication::translate("country", "CentralAfricanRepublic")) ==
"CentralAfricanRepublic")
countryName = "";
break;
case QLocale::Chad:
if ((countryName = QCoreApplication::translate("country", "Chad")) == "Chad") countryName = "";
break;
case QLocale::Chile:
if ((countryName = QCoreApplication::translate("country", "Chile")) == "Chile") countryName = "";
break;
case QLocale::China:
if ((countryName = QCoreApplication::translate("country", "China")) == "China") countryName = "";
break;
case QLocale::Colombia:
if ((countryName = QCoreApplication::translate("country", "Colombia")) == "Colombia") countryName = "";
break;
case QLocale::Comoros:
if ((countryName = QCoreApplication::translate("country", "Comoros")) == "Comoros") countryName = "";
break;
case QLocale::PeoplesRepublicOfCongo:
if ((countryName = QCoreApplication::translate("country", "PeoplesRepublicOfCongo")) ==
"PeoplesRepublicOfCongo")
countryName = "";
break;
case QLocale::DemocraticRepublicOfCongo:
if ((countryName = QCoreApplication::translate("country", "DemocraticRepublicOfCongo")) ==
"DemocraticRepublicOfCongo")
countryName = "";
break;
case QLocale::CookIslands:
if ((countryName = QCoreApplication::translate("country", "CookIslands")) == "CookIslands")
countryName = "";
break;
case QLocale::CostaRica:
if ((countryName = QCoreApplication::translate("country", "CostaRica")) == "CostaRica") countryName = "";
break;
case QLocale::IvoryCoast:
if ((countryName = QCoreApplication::translate("country", "IvoryCoast")) == "IvoryCoast") countryName = "";
break;
case QLocale::Croatia:
if ((countryName = QCoreApplication::translate("country", "Croatia")) == "Croatia") countryName = "";
break;
case QLocale::Cuba:
if ((countryName = QCoreApplication::translate("country", "Cuba")) == "Cuba") countryName = "";
break;
case QLocale::Cyprus:
if ((countryName = QCoreApplication::translate("country", "Cyprus")) == "Cyprus") countryName = "";
break;
case QLocale::CzechRepublic:
if ((countryName = QCoreApplication::translate("country", "CzechRepublic")) == "CzechRepublic")
countryName = "";
break;
case QLocale::Denmark:
if ((countryName = QCoreApplication::translate("country", "Denmark")) == "Denmark") countryName = "";
break;
case QLocale::Djibouti:
if ((countryName = QCoreApplication::translate("country", "Djibouti")) == "Djibouti") countryName = "";
break;
case QLocale::Dominica:
if ((countryName = QCoreApplication::translate("country", "Dominica")) == "Dominica") countryName = "";
break;
case QLocale::DominicanRepublic:
if ((countryName = QCoreApplication::translate("country", "DominicanRepublic")) == "DominicanRepublic")
countryName = "";
break;
case QLocale::Ecuador:
if ((countryName = QCoreApplication::translate("country", "Ecuador")) == "Ecuador") countryName = "";
break;
case QLocale::Egypt:
if ((countryName = QCoreApplication::translate("country", "Egypt")) == "Egypt") countryName = "";
break;
case QLocale::ElSalvador:
if ((countryName = QCoreApplication::translate("country", "ElSalvador")) == "ElSalvador") countryName = "";
break;
case QLocale::EquatorialGuinea:
if ((countryName = QCoreApplication::translate("country", "EquatorialGuinea")) == "EquatorialGuinea")
countryName = "";
break;
case QLocale::Eritrea:
if ((countryName = QCoreApplication::translate("country", "Eritrea")) == "Eritrea") countryName = "";
break;
case QLocale::Estonia:
if ((countryName = QCoreApplication::translate("country", "Estonia")) == "Estonia") countryName = "";
break;
case QLocale::Ethiopia:
if ((countryName = QCoreApplication::translate("country", "Ethiopia")) == "Ethiopia") countryName = "";
break;
case QLocale::FalklandIslands:
if ((countryName = QCoreApplication::translate("country", "FalklandIslands")) == "FalklandIslands")
countryName = "";
break;
case QLocale::FaroeIslands:
if ((countryName = QCoreApplication::translate("country", "FaroeIslands")) == "FaroeIslands")
countryName = "";
break;
case QLocale::Fiji:
if ((countryName = QCoreApplication::translate("country", "Fiji")) == "Fiji") countryName = "";
break;
case QLocale::Finland:
if ((countryName = QCoreApplication::translate("country", "Finland")) == "Finland") countryName = "";
break;
case QLocale::France:
if ((countryName = QCoreApplication::translate("country", "France")) == "France") countryName = "";
break;
case QLocale::FrenchGuiana:
if ((countryName = QCoreApplication::translate("country", "FrenchGuiana")) == "FrenchGuiana")
countryName = "";
break;
case QLocale::FrenchPolynesia:
if ((countryName = QCoreApplication::translate("country", "FrenchPolynesia")) == "FrenchPolynesia")
countryName = "";
break;
case QLocale::Gabon:
if ((countryName = QCoreApplication::translate("country", "Gabon")) == "Gabon") countryName = "";
break;
case QLocale::Gambia:
if ((countryName = QCoreApplication::translate("country", "Gambia")) == "Gambia") countryName = "";
break;
case QLocale::Georgia:
if ((countryName = QCoreApplication::translate("country", "Georgia")) == "Georgia") countryName = "";
break;
case QLocale::Germany:
if ((countryName = QCoreApplication::translate("country", "Germany")) == "Germany") countryName = "";
break;
case QLocale::Ghana:
if ((countryName = QCoreApplication::translate("country", "Ghana")) == "Ghana") countryName = "";
break;
case QLocale::Gibraltar:
if ((countryName = QCoreApplication::translate("country", "Gibraltar")) == "Gibraltar") countryName = "";
break;
case QLocale::Greece:
if ((countryName = QCoreApplication::translate("country", "Greece")) == "Greece") countryName = "";
break;
case QLocale::Greenland:
if ((countryName = QCoreApplication::translate("country", "Greenland")) == "Greenland") countryName = "";
break;
case QLocale::Grenada:
if ((countryName = QCoreApplication::translate("country", "Grenada")) == "Grenada") countryName = "";
break;
case QLocale::Guadeloupe:
if ((countryName = QCoreApplication::translate("country", "Guadeloupe")) == "Guadeloupe") countryName = "";
break;
case QLocale::Guam:
if ((countryName = QCoreApplication::translate("country", "Guam")) == "Guam") countryName = "";
break;
case QLocale::Guatemala:
if ((countryName = QCoreApplication::translate("country", "Guatemala")) == "Guatemala") countryName = "";
break;
case QLocale::Guinea:
if ((countryName = QCoreApplication::translate("country", "Guinea")) == "Guinea") countryName = "";
break;
case QLocale::GuineaBissau:
if ((countryName = QCoreApplication::translate("country", "GuineaBissau")) == "GuineaBissau")
countryName = "";
break;
case QLocale::Guyana:
if ((countryName = QCoreApplication::translate("country", "Guyana")) == "Guyana") countryName = "";
break;
case QLocale::Haiti:
if ((countryName = QCoreApplication::translate("country", "Haiti")) == "Haiti") countryName = "";
break;
case QLocale::Honduras:
if ((countryName = QCoreApplication::translate("country", "Honduras")) == "Honduras") countryName = "";
break;
case QLocale::HongKong:
if ((countryName = QCoreApplication::translate("country", "HongKong")) == "HongKong") countryName = "";
break;
case QLocale::Hungary:
if ((countryName = QCoreApplication::translate("country", "Hungary")) == "Hungary") countryName = "";
break;
case QLocale::Iceland:
if ((countryName = QCoreApplication::translate("country", "Iceland")) == "Iceland") countryName = "";
break;
case QLocale::India:
if ((countryName = QCoreApplication::translate("country", "India")) == "India") countryName = "";
break;
case QLocale::Indonesia:
if ((countryName = QCoreApplication::translate("country", "Indonesia")) == "Indonesia") countryName = "";
break;
case QLocale::Iran:
if ((countryName = QCoreApplication::translate("country", "Iran")) == "Iran") countryName = "";
break;
case QLocale::Iraq:
if ((countryName = QCoreApplication::translate("country", "Iraq")) == "Iraq") countryName = "";
break;
case QLocale::Ireland:
if ((countryName = QCoreApplication::translate("country", "Ireland")) == "Ireland") countryName = "";
break;
case QLocale::Israel:
if ((countryName = QCoreApplication::translate("country", "Israel")) == "Israel") countryName = "";
break;
case QLocale::Italy:
if ((countryName = QCoreApplication::translate("country", "Italy")) == "Italy") countryName = "";
break;
case QLocale::Jamaica:
if ((countryName = QCoreApplication::translate("country", "Jamaica")) == "Jamaica") countryName = "";
break;
case QLocale::Japan:
if ((countryName = QCoreApplication::translate("country", "Japan")) == "Japan") countryName = "";
break;
case QLocale::Jordan:
if ((countryName = QCoreApplication::translate("country", "Jordan")) == "Jordan") countryName = "";
break;
case QLocale::Kazakhstan:
if ((countryName = QCoreApplication::translate("country", "Kazakhstan")) == "Kazakhstan") countryName = "";
break;
case QLocale::Kenya:
if ((countryName = QCoreApplication::translate("country", "Kenya")) == "Kenya") countryName = "";
break;
case QLocale::Kiribati:
if ((countryName = QCoreApplication::translate("country", "Kiribati")) == "Kiribati") countryName = "";
break;
case QLocale::DemocraticRepublicOfKorea:
if ((countryName = QCoreApplication::translate("country", "DemocraticRepublicOfKorea")) ==
"DemocraticRepublicOfKorea")
countryName = "";
break;
case QLocale::RepublicOfKorea:
if ((countryName = QCoreApplication::translate("country", "RepublicOfKorea")) == "RepublicOfKorea")
countryName = "";
break;
case QLocale::Kuwait:
if ((countryName = QCoreApplication::translate("country", "Kuwait")) == "Kuwait") countryName = "";
break;
case QLocale::Kyrgyzstan:
if ((countryName = QCoreApplication::translate("country", "Kyrgyzstan")) == "Kyrgyzstan") countryName = "";
break;
case QLocale::Laos:
if ((countryName = QCoreApplication::translate("country", "Laos")) == "Laos") countryName = "";
break;
case QLocale::Latvia:
if ((countryName = QCoreApplication::translate("country", "Latvia")) == "Latvia") countryName = "";
break;
case QLocale::Lebanon:
if ((countryName = QCoreApplication::translate("country", "Lebanon")) == "Lebanon") countryName = "";
break;
case QLocale::Lesotho:
if ((countryName = QCoreApplication::translate("country", "Lesotho")) == "Lesotho") countryName = "";
break;
case QLocale::Liberia:
if ((countryName = QCoreApplication::translate("country", "Liberia")) == "Liberia") countryName = "";
break;
case QLocale::Libya:
if ((countryName = QCoreApplication::translate("country", "Libya")) == "Libya") countryName = "";
break;
case QLocale::Liechtenstein:
if ((countryName = QCoreApplication::translate("country", "Liechtenstein")) == "Liechtenstein")
countryName = "";
break;
case QLocale::Lithuania:
if ((countryName = QCoreApplication::translate("country", "Lithuania")) == "Lithuania") countryName = "";
break;
case QLocale::Luxembourg:
if ((countryName = QCoreApplication::translate("country", "Luxembourg")) == "Luxembourg") countryName = "";
break;
case QLocale::Macau:
if ((countryName = QCoreApplication::translate("country", "Macau")) == "Macau") countryName = "";
break;
case QLocale::Macedonia:
if ((countryName = QCoreApplication::translate("country", "Macedonia")) == "Macedonia") countryName = "";
break;
case QLocale::Madagascar:
if ((countryName = QCoreApplication::translate("country", "Madagascar")) == "Madagascar") countryName = "";
break;
case QLocale::Malawi:
if ((countryName = QCoreApplication::translate("country", "Malawi")) == "Malawi") countryName = "";
break;
case QLocale::Malaysia:
if ((countryName = QCoreApplication::translate("country", "Malaysia")) == "Malaysia") countryName = "";
break;
case QLocale::Maldives:
if ((countryName = QCoreApplication::translate("country", "Maldives")) == "Maldives") countryName = "";
break;
case QLocale::Mali:
if ((countryName = QCoreApplication::translate("country", "Mali")) == "Mali") countryName = "";
break;
case QLocale::Malta:
if ((countryName = QCoreApplication::translate("country", "Malta")) == "Malta") countryName = "";
break;
case QLocale::MarshallIslands:
if ((countryName = QCoreApplication::translate("country", "MarshallIslands")) == "MarshallIslands")
countryName = "";
break;
case QLocale::Martinique:
if ((countryName = QCoreApplication::translate("country", "Martinique")) == "Martinique") countryName = "";
break;
case QLocale::Mauritania:
if ((countryName = QCoreApplication::translate("country", "Mauritania")) == "Mauritania") countryName = "";
break;
case QLocale::Mauritius:
if ((countryName = QCoreApplication::translate("country", "Mauritius")) == "Mauritius") countryName = "";
break;
case QLocale::Mayotte:
if ((countryName = QCoreApplication::translate("country", "Mayotte")) == "Mayotte") countryName = "";
break;
case QLocale::Mexico:
if ((countryName = QCoreApplication::translate("country", "Mexico")) == "Mexico") countryName = "";
break;
case QLocale::Micronesia:
if ((countryName = QCoreApplication::translate("country", "Micronesia")) == "Micronesia") countryName = "";
break;
case QLocale::Moldova:
if ((countryName = QCoreApplication::translate("country", "Moldova")) == "Moldova") countryName = "";
break;
case QLocale::Monaco:
if ((countryName = QCoreApplication::translate("country", "Monaco")) == "Monaco") countryName = "";
break;
case QLocale::Mongolia:
if ((countryName = QCoreApplication::translate("country", "Mongolia")) == "Mongolia") countryName = "";
break;
case QLocale::Montenegro:
if ((countryName = QCoreApplication::translate("country", "Montenegro")) == "Montenegro") countryName = "";
break;
case QLocale::Montserrat:
if ((countryName = QCoreApplication::translate("country", "Montserrat")) == "Montserrat") countryName = "";
break;
case QLocale::Morocco:
if ((countryName = QCoreApplication::translate("country", "Morocco")) == "Morocco") countryName = "";
break;
case QLocale::Mozambique:
if ((countryName = QCoreApplication::translate("country", "Mozambique")) == "Mozambique") countryName = "";
break;
case QLocale::Myanmar:
if ((countryName = QCoreApplication::translate("country", "Myanmar")) == "Myanmar") countryName = "";
break;
case QLocale::Namibia:
if ((countryName = QCoreApplication::translate("country", "Namibia")) == "Namibia") countryName = "";
break;
case QLocale::NauruCountry:
if ((countryName = QCoreApplication::translate("country", "NauruCountry")) == "NauruCountry")
countryName = "";
break;
case QLocale::Nepal:
if ((countryName = QCoreApplication::translate("country", "Nepal")) == "Nepal") countryName = "";
break;
case QLocale::Netherlands:
if ((countryName = QCoreApplication::translate("country", "Netherlands")) == "Netherlands")
countryName = "";
break;
case QLocale::NewCaledonia:
if ((countryName = QCoreApplication::translate("country", "NewCaledonia")) == "NewCaledonia")
countryName = "";
break;
case QLocale::NewZealand:
if ((countryName = QCoreApplication::translate("country", "NewZealand")) == "NewZealand") countryName = "";
break;
case QLocale::Nicaragua:
if ((countryName = QCoreApplication::translate("country", "Nicaragua")) == "Nicaragua") countryName = "";
break;
case QLocale::Niger:
if ((countryName = QCoreApplication::translate("country", "Niger")) == "Niger") countryName = "";
break;
case QLocale::Nigeria:
if ((countryName = QCoreApplication::translate("country", "Nigeria")) == "Nigeria") countryName = "";
break;
case QLocale::Niue:
if ((countryName = QCoreApplication::translate("country", "Niue")) == "Niue") countryName = "";
break;
case QLocale::NorfolkIsland:
if ((countryName = QCoreApplication::translate("country", "NorfolkIsland")) == "NorfolkIsland")
countryName = "";
break;
case QLocale::NorthernMarianaIslands:
if ((countryName = QCoreApplication::translate("country", "NorthernMarianaIslands")) ==
"NorthernMarianaIslands")
countryName = "";
break;
case QLocale::Norway:
if ((countryName = QCoreApplication::translate("country", "Norway")) == "Norway") countryName = "";
break;
case QLocale::Oman:
if ((countryName = QCoreApplication::translate("country", "Oman")) == "Oman") countryName = "";
break;
case QLocale::Pakistan:
if ((countryName = QCoreApplication::translate("country", "Pakistan")) == "Pakistan") countryName = "";
break;
case QLocale::Palau:
if ((countryName = QCoreApplication::translate("country", "Palau")) == "Palau") countryName = "";
break;
case QLocale::PalestinianTerritories:
if ((countryName = QCoreApplication::translate("country", "PalestinianTerritories")) ==
"PalestinianTerritories")
countryName = "";
break;
case QLocale::Panama:
if ((countryName = QCoreApplication::translate("country", "Panama")) == "Panama") countryName = "";
break;
case QLocale::PapuaNewGuinea:
if ((countryName = QCoreApplication::translate("country", "PapuaNewGuinea")) == "PapuaNewGuinea")
countryName = "";
break;
case QLocale::Paraguay:
if ((countryName = QCoreApplication::translate("country", "Paraguay")) == "Paraguay") countryName = "";
break;
case QLocale::Peru:
if ((countryName = QCoreApplication::translate("country", "Peru")) == "Peru") countryName = "";
break;
case QLocale::Philippines:
if ((countryName = QCoreApplication::translate("country", "Philippines")) == "Philippines")
countryName = "";
break;
case QLocale::Poland:
if ((countryName = QCoreApplication::translate("country", "Poland")) == "Poland") countryName = "";
break;
case QLocale::Portugal:
if ((countryName = QCoreApplication::translate("country", "Portugal")) == "Portugal") countryName = "";
break;
case QLocale::PuertoRico:
if ((countryName = QCoreApplication::translate("country", "PuertoRico")) == "PuertoRico") countryName = "";
break;
case QLocale::Qatar:
if ((countryName = QCoreApplication::translate("country", "Qatar")) == "Qatar") countryName = "";
break;
case QLocale::Reunion:
if ((countryName = QCoreApplication::translate("country", "Reunion")) == "Reunion") countryName = "";
break;
case QLocale::Romania:
if ((countryName = QCoreApplication::translate("country", "Romania")) == "Romania") countryName = "";
break;
case QLocale::RussianFederation:
if ((countryName = QCoreApplication::translate("country", "RussianFederation")) == "RussianFederation")
countryName = "";
break;
case QLocale::Rwanda:
if ((countryName = QCoreApplication::translate("country", "Rwanda")) == "Rwanda") countryName = "";
break;
case QLocale::SaintHelena:
if ((countryName = QCoreApplication::translate("country", "SaintHelena")) == "SaintHelena")
countryName = "";
break;
case QLocale::SaintKittsAndNevis:
if ((countryName = QCoreApplication::translate("country", "SaintKittsAndNevis")) == "SaintKittsAndNevis")
countryName = "";
break;
case QLocale::SaintLucia:
if ((countryName = QCoreApplication::translate("country", "SaintLucia")) == "SaintLucia") countryName = "";
break;
case QLocale::SaintPierreAndMiquelon:
if ((countryName = QCoreApplication::translate("country", "SaintPierreAndMiquelon")) ==
"SaintPierreAndMiquelon")
countryName = "";
break;
case QLocale::SaintVincentAndTheGrenadines:
if ((countryName = QCoreApplication::translate("country", "SaintVincentAndTheGrenadines")) ==
"SaintVincentAndTheGrenadines")
countryName = "";
break;
case QLocale::Samoa:
if ((countryName = QCoreApplication::translate("country", "Samoa")) == "Samoa") countryName = "";
break;
case QLocale::SanMarino:
if ((countryName = QCoreApplication::translate("country", "SanMarino")) == "SanMarino") countryName = "";
break;
case QLocale::SaoTomeAndPrincipe:
if ((countryName = QCoreApplication::translate("country", "SaoTomeAndPrincipe")) == "SaoTomeAndPrincipe")
countryName = "";
break;
case QLocale::SaudiArabia:
if ((countryName = QCoreApplication::translate("country", "SaudiArabia")) == "SaudiArabia")
countryName = "";
break;
case QLocale::Senegal:
if ((countryName = QCoreApplication::translate("country", "Senegal")) == "Senegal") countryName = "";
break;
case QLocale::Serbia:
if ((countryName = QCoreApplication::translate("country", "Serbia")) == "Serbia") countryName = "";
break;
case QLocale::Seychelles:
if ((countryName = QCoreApplication::translate("country", "Seychelles")) == "Seychelles") countryName = "";
break;
case QLocale::SierraLeone:
if ((countryName = QCoreApplication::translate("country", "SierraLeone")) == "SierraLeone")
countryName = "";
break;
case QLocale::Singapore:
if ((countryName = QCoreApplication::translate("country", "Singapore")) == "Singapore") countryName = "";
break;
case QLocale::Slovakia:
if ((countryName = QCoreApplication::translate("country", "Slovakia")) == "Slovakia") countryName = "";
break;
case QLocale::Slovenia:
if ((countryName = QCoreApplication::translate("country", "Slovenia")) == "Slovenia") countryName = "";
break;
case QLocale::SolomonIslands:
if ((countryName = QCoreApplication::translate("country", "SolomonIslands")) == "SolomonIslands")
countryName = "";
break;
case QLocale::Somalia:
if ((countryName = QCoreApplication::translate("country", "Somalia")) == "Somalia") countryName = "";
break;
case QLocale::SouthAfrica:
if ((countryName = QCoreApplication::translate("country", "SouthAfrica")) == "SouthAfrica")
countryName = "";
break;
case QLocale::Spain:
if ((countryName = QCoreApplication::translate("country", "Spain")) == "Spain") countryName = "";
break;
case QLocale::SriLanka:
if ((countryName = QCoreApplication::translate("country", "SriLanka")) == "SriLanka") countryName = "";
break;
case QLocale::Sudan:
if ((countryName = QCoreApplication::translate("country", "Sudan")) == "Sudan") countryName = "";
break;
case QLocale::Suriname:
if ((countryName = QCoreApplication::translate("country", "Suriname")) == "Suriname") countryName = "";
break;
case QLocale::Swaziland:
if ((countryName = QCoreApplication::translate("country", "Swaziland")) == "Swaziland") countryName = "";
break;
case QLocale::Sweden:
if ((countryName = QCoreApplication::translate("country", "Sweden")) == "Sweden") countryName = "";
break;
case QLocale::Switzerland:
if ((countryName = QCoreApplication::translate("country", "Switzerland")) == "Switzerland")
countryName = "";
break;
case QLocale::Syria:
if ((countryName = QCoreApplication::translate("country", "Syria")) == "Syria") countryName = "";
break;
case QLocale::Taiwan:
if ((countryName = QCoreApplication::translate("country", "Taiwan")) == "Taiwan") countryName = "";
break;
case QLocale::Tajikistan:
if ((countryName = QCoreApplication::translate("country", "Tajikistan")) == "Tajikistan") countryName = "";
break;
case QLocale::Tanzania:
if ((countryName = QCoreApplication::translate("country", "Tanzania")) == "Tanzania") countryName = "";
break;
case QLocale::Thailand:
if ((countryName = QCoreApplication::translate("country", "Thailand")) == "Thailand") countryName = "";
break;
case QLocale::Togo:
if ((countryName = QCoreApplication::translate("country", "Togo")) == "Togo") countryName = "";
break;
case QLocale::TokelauCountry:
if ((countryName = QCoreApplication::translate("country", "Tokelau")) == "Tokelau") countryName = "";
break;
case QLocale::Tonga:
if ((countryName = QCoreApplication::translate("country", "Tonga")) == "Tonga") countryName = "";
break;
case QLocale::TrinidadAndTobago:
if ((countryName = QCoreApplication::translate("country", "TrinidadAndTobago")) == "TrinidadAndTobago")
countryName = "";
break;
case QLocale::Tunisia:
if ((countryName = QCoreApplication::translate("country", "Tunisia")) == "Tunisia") countryName = "";
break;
case QLocale::Turkey:
if ((countryName = QCoreApplication::translate("country", "Turkey")) == "Turkey") countryName = "";
break;
case QLocale::Turkmenistan:
if ((countryName = QCoreApplication::translate("country", "Turkmenistan")) == "Turkmenistan")
countryName = "";
break;
case QLocale::TurksAndCaicosIslands:
if ((countryName = QCoreApplication::translate("country", "TurksAndCaicosIslands")) ==
"TurksAndCaicosIslands")
countryName = "";
break;
case QLocale::TuvaluCountry:
if ((countryName = QCoreApplication::translate("country", "Tuvalu")) == "Tuvalu") countryName = "";
break;
case QLocale::Uganda:
if ((countryName = QCoreApplication::translate("country", "Uganda")) == "Uganda") countryName = "";
break;
case QLocale::Ukraine:
if ((countryName = QCoreApplication::translate("country", "Ukraine")) == "Ukraine") countryName = "";
break;
case QLocale::UnitedArabEmirates:
if ((countryName = QCoreApplication::translate("country", "UnitedArabEmirates")) == "UnitedArabEmirates")
countryName = "";
break;
case QLocale::UnitedKingdom:
if ((countryName = QCoreApplication::translate("country", "UnitedKingdom")) == "UnitedKingdom")
countryName = "";
break;
case QLocale::UnitedStates:
if ((countryName = QCoreApplication::translate("country", "UnitedStates")) == "UnitedStates")
countryName = "";
break;
case QLocale::Uruguay:
if ((countryName = QCoreApplication::translate("country", "Uruguay")) == "Uruguay") countryName = "";
break;
case QLocale::Uzbekistan:
if ((countryName = QCoreApplication::translate("country", "Uzbekistan")) == "Uzbekistan") countryName = "";
break;
case QLocale::Vanuatu:
if ((countryName = QCoreApplication::translate("country", "Vanuatu")) == "Vanuatu") countryName = "";
break;
case QLocale::Venezuela:
if ((countryName = QCoreApplication::translate("country", "Venezuela")) == "Venezuela") countryName = "";
break;
case QLocale::Vietnam:
if ((countryName = QCoreApplication::translate("country", "Vietnam")) == "Vietnam") countryName = "";
break;
case QLocale::WallisAndFutunaIslands:
if ((countryName = QCoreApplication::translate("country", "WallisAndFutunaIslands")) ==
"WallisAndFutunaIslands")
countryName = "";
break;
case QLocale::Yemen:
if ((countryName = QCoreApplication::translate("country", "Yemen")) == "Yemen") countryName = "";
break;
case QLocale::Zambia:
if ((countryName = QCoreApplication::translate("country", "Zambia")) == "Zambia") countryName = "";
break;
case QLocale::Zimbabwe:
if ((countryName = QCoreApplication::translate("country", "Zimbabwe")) == "Zimbabwe") countryName = "";
break;
default: {
countryName = QLocale::countryToString(p_country);
}
}
if (countryName == "") countryName = QLocale::countryToString(p_country);
return countryName;
}
QString Utils::toDateString(QDateTime date, const QString &format) {
return QLocale().toString(date, (!format.isEmpty() ? format : "ddd d MMMM yyyy"));
}
QString Utils::toDateString(QDate date, const QString &format) {
return QLocale().toString(date, (!format.isEmpty() ? format : "ddd d, MMMM"));
}
QString Utils::toDateDayString(const QDateTime &date) {
auto res = QLocale().toString(date, "d");
return res;
}
QString Utils::toDateHourString(const QDateTime &date) {
return QLocale().toString(date, "hh:mm");
}
QString Utils::toDateDayNameString(const QDateTime &date) {
return QLocale().toString(date, "ddd");
}
QString Utils::toDateMonthString(const QDateTime &date) {
return QLocale().toString(date, "MMMM");
}
bool Utils::isCurrentDay(QDateTime date) {
auto dateDayNum = date.date().day();
auto currentDate = QDateTime::currentDateTime();
auto currentDayNum = currentDate.date().day();
auto daysTo = date.daysTo(currentDate);
return (dateDayNum == currentDayNum && daysTo == 0);
}
bool Utils::isCurrentDay(QDate date) {
auto currentDate = QDate::currentDate();
return date.month() == currentDate.month() && date.year() == currentDate.year() && date.day() == currentDate.day();
}
bool Utils::isCurrentMonth(QDate date) {
auto currentDate = QDate::currentDate();
return date.month() == currentDate.month() && date.year() == currentDate.year();
}
bool Utils::isBeforeToday(QDate date) {
auto currentDate = QDate::currentDate();
auto res = date.daysTo(currentDate) > 0;
return res;
}
bool Utils::datesAreEqual(const QDate &a, const QDate &b) {
return a.month() == b.month() && a.year() == b.year() && a.day() == b.day();
}
QDateTime Utils::createDateTime(const QDate &date, int hour, int min) {
QTime time(hour, min);
return QDateTime(date, time);
}
int Utils::secsTo(const QString &startTime, const QString &endTime) {
QDateTime startDate(QDateTime::fromString(startTime, "hh:mm"));
QDateTime endDate(QDateTime::fromString(endTime, "hh:mm"));
auto res = startDate.secsTo(endDate);
return res;
}
QDateTime Utils::addSecs(QDateTime date, int secs) {
date = date.addSecs(secs);
return date;
}
int Utils::getYear(const QDate &date) {
return date.year();
}
bool Utils::isMe(const QString &address) {
auto linAddr = ToolModel::interpretUrl(address);
if (!CoreModel::getInstance()->getCore()->getDefaultAccount()) {
for (auto &account : CoreModel::getInstance()->getCore()->getAccountList()) {
if (account->getContactAddress()->weakEqual(linAddr)) return true;
}
return false;
} else {
auto accountAddr = CoreModel::getInstance()->getCore()->getDefaultAccount()->getContactAddress();
return linAddr && accountAddr ? accountAddr->weakEqual(linAddr) : false;
}
}
// QDateTime dateTime(QDateTime::fromString(date, "yyyy-MM-dd hh:mm:ss"));
// bool Utils::isMe(const QString &address) {
// return !address.isEmpty() ? isMe(Utils::interpretUrl(address)) : false;
// }
// bool Utils::isMe(const std::shared_ptr<const linphone::Address> &address) {
// if (!CoreModel::getInstance()
// ->getCore()
// ->getDefaultAccount()) { // Default account is selected : Me is all local accounts.
// return CoreModel::getInstance()->getAccountSettingsModel()->findAccount(address) != nullptr;
// } else
// return address ? CoreModel::getInstance()->getAccountSettingsModel()->getUsedSipAddress()->weakEqual(address)
// : false;
// }

View file

@ -62,6 +62,8 @@ public:
const QHash<QString, QString> &headers = {});
Q_INVOKABLE static void openCallsWindow(CallGui *call);
Q_INVOKABLE static QQuickWindow *getMainWindow();
Q_INVOKABLE static void
showInformationPopup(const QString &title, const QString &description, bool isSuccess = true);
Q_INVOKABLE static QQuickWindow *getCallsWindow(CallGui *callGui);
Q_INVOKABLE static void closeCallsWindow();
Q_INVOKABLE static VariantObject *haveAccount();
@ -74,8 +76,26 @@ public:
Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode);
Q_INVOKABLE static int getRandomIndex(int size);
Q_INVOKABLE static void copyToClipboard(const QString &text);
static QString generateSavedFilename(const QString &from, const QString &to);
Q_INVOKABLE static QString toDateString(QDateTime date, const QString &format = "");
Q_INVOKABLE static QString toDateString(QDate date, const QString &format = "");
Q_INVOKABLE static QString toDateDayString(const QDateTime &date);
Q_INVOKABLE static QString toDateHourString(const QDateTime &date);
Q_INVOKABLE static QString toDateDayNameString(const QDateTime &date);
Q_INVOKABLE static QString toDateMonthString(const QDateTime &date);
Q_INVOKABLE static bool isCurrentDay(QDateTime date);
Q_INVOKABLE static bool isCurrentDay(QDate date);
Q_INVOKABLE static bool isCurrentMonth(QDate date);
Q_INVOKABLE static bool isBeforeToday(QDate date);
Q_INVOKABLE static bool datesAreEqual(const QDate &a, const QDate &b);
Q_INVOKABLE static QDateTime createDateTime(const QDate &date, int hour, int min);
Q_INVOKABLE static int getYear(const QDate &date);
Q_INVOKABLE static int secsTo(const QString &start, const QString &end);
Q_INVOKABLE static QDateTime addSecs(QDateTime date, int secs);
Q_INVOKABLE static QString generateLinphoneSipAddress(const QString &uri);
Q_INVOKABLE static QString findAvatarByAddress(const QString &address);
static QString generateSavedFilename(const QString &from, const QString &to);
Q_INVOKABLE static bool isMe(const QString &address);
static QString getCountryName(const QLocale::Country &p_country);
static QString getApplicationProduct();
static QString getOsProduct();

View file

@ -345,8 +345,9 @@ Item {
id: callPage
}
ContactPage{}
Item{}
//ConversationPage{}
//MeetingPage{}
MeetingPage{}
}
}
}

View file

@ -24,6 +24,121 @@ Window {
mainWindowStackView.currentItem.transferCallSucceed()
}
function showInformationPopup(title, description, isSuccess) {
var infoPopup = popupComp.createObject(popupLayout, {"title": title, "description": description, "isSuccess": isSuccess})
// informationPopup.title = title
// informationPopup.description = description
// informationPopup.isSuccess = isSuccess
// infoPopup.y = popupLayout.nextY - infoPopup.height
infoPopup.index = popupLayout.popupList.length
popupLayout.popupList.push(infoPopup)
infoPopup.open()
}
Component {
id: popupComp
Popup {
id: informationPopup
property bool isSuccess: true
property string title
property string description
property int index
onAboutToShow: {
autoClosePopup.restart()
}
onAboutToHide: {
popupLayout.popupList.splice(informationPopup.index, 1)
}
closePolicy: Popup.NoAutoClose
x : parent.x + parent.width - width
// y : parent.y + parent.height - height
rightMargin: 20 * DefaultStyle.dp
bottomMargin: 20 * DefaultStyle.dp
padding: 20 * DefaultStyle.dp
underlineColor: informationPopup.isSuccess ? DefaultStyle.success_500main : DefaultStyle.danger_500main
radius: 0
onHoveredChanged: {
if (hovered) autoClosePopup.stop()
else autoClosePopup.restart()
}
Timer {
id: autoClosePopup
interval: 5000
onTriggered: {
informationPopup.close()
}
}
contentItem: RowLayout {
spacing: 15 * DefaultStyle.dp
EffectImage {
imageSource: informationPopup.isSuccess ? AppIcons.smiley : AppIcons.smileySad
colorizationColor: informationPopup.isSuccess ? DefaultStyle.success_500main : DefaultStyle.danger_500main
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
width: 32 * DefaultStyle.dp
height: 32 * DefaultStyle.dp
}
Rectangle {
Layout.preferredWidth: 1 * DefaultStyle.dp
Layout.preferredHeight: parent.height
color: DefaultStyle.main2_200
}
ColumnLayout {
RowLayout {
Layout.fillWidth: true
Text {
Layout.fillWidth: true
text: informationPopup.title
color: informationPopup.isSuccess ? DefaultStyle.success_500main : DefaultStyle.danger_500main
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
Button {
Layout.preferredWidth: 20 * DefaultStyle.dp
Layout.preferredHeight: 20 * DefaultStyle.dp
Layout.alignment: Qt.AlignTop | Qt.AlignRight
visible: informationPopup.hovered || hovered
background: Item{}
icon.source: AppIcons.closeX
onClicked: informationPopup.close()
}
}
Text {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.maximumWidth: 300 * DefaultStyle.dp
text: informationPopup.description
wrapMode: Text.WordWrap
color: DefaultStyle.main2_500main
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
}
}
}
ColumnLayout {
id: popupLayout
anchors.fill: parent
Layout.alignment: Qt.AlignBottom
property int nextY: mainWindow.height
property list<Popup> popupList
property int popupCount: popupList.length
spacing: 15
onPopupCountChanged: {
nextY = mainWindow.height
for(var i = 0; i < popupCount; ++i) {
popupList[i].y = nextY - popupList[i].height
nextY = nextY - popupList[i].height - 15
}
}
}
AccountProxy {
// TODO : change this so it does not display the main page for one second
// when we fail trying to connect the first account (account is added and

View file

@ -2,10 +2,17 @@
list(APPEND _LINPHONEAPP_QML_FILES
view/App/Main.qml
view/App/CallsWindow.qml
view/App/Layout/ContactLayout.qml
view/App/Layout/LoginLayout.qml
view/App/Layout/MainLayout.qml
view/Layout/Conference/IncallGrid.qml
view/Layout/Contact/ContactLayout.qml
view/Layout/Meeting/AddParticipantsLayout.qml
view/Layout/FormItemLayout.qml
view/Layout/Mosaic.qml
view/Layout/Section.qml
view/Item/Account/Accounts.qml
view/Item/Call/CallContactsLists.qml
@ -22,9 +29,14 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/Contact/ContactEdition.qml
view/Item/Contact/ContactsList.qml
view/Item/Contact/Sticker.qml
view/Item/Meeting/MeetingList.qml
view/Item/Meeting/NewMeeting.qml
view/Item/BusyIndicator.qml
view/Item/Button.qml
view/Item/Calendar.qml
view/Item/CalendarComboBox.qml
view/Item/Carousel.qml
view/Item/CheckBox.qml
view/Item/ComboBox.qml
@ -45,9 +57,12 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/RoundedBackgroundControl.qml
view/Item/SearchBar.qml
view/Item/Slider.qml
view/Item/Switch.qml
view/Item/TabBar.qml
view/Item/Text.qml
view/Item/TextInput.qml
view/Item/TextArea.qml
view/Item/TextField.qml
view/Item/TimeComboBox.qml
view/Item/ToolTip.qml
view/Item/VerticalTabBar.qml
view/Item/ZrtpTokenAuthenticationDialog.qml
@ -66,6 +81,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Page/Main/AbstractMainPage.qml
view/Page/Main/CallPage.qml
view/Page/Main/ContactPage.qml
view/Page/Main/MeetingPage.qml
view/Tool/utils.js
# Prototypes

View file

@ -15,6 +15,7 @@ Control.Button {
property bool underline: false
property bool shadowEnabled: false
property var contentImageColor
property alias contentText: contentText
hoverEnabled: true
icon.width: width
icon.height: height
@ -69,6 +70,7 @@ Control.Button {
? 1
: 2
width: mainItem.width
Text {
id: contentText
horizontalAlignment: Text.AlignHCenter
@ -76,10 +78,10 @@ Control.Button {
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
Layout.fillHeight: true
width: implicitWidth
height: implicitHeight
wrapMode: Text.WordWrap
wrapMode: Text.WrapAnywhere
text: mainItem.text
maximumLineCount: 1
color: inversedColors ? mainItem.color : DefaultStyle.grey_0
font {
pixelSize: mainItem.textSize

View file

@ -0,0 +1,117 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls as Control
import QtQuick.Effects
import Linphone
import ConstantsCpp 1.0
import UtilsCpp 1.0
ListView {
id: mainItem
// width: 400 * DefaultStyle.dp
// height: 400 * DefaultStyle.dp
snapMode: ListView.SnapOneItem
orientation: Qt.Horizontal
clip: true
property int maxYears: 5
readonly property var currentDate: new Date()
Layout.fillWidth: true
Layout.fillHeight: true
highlightMoveDuration: 100
property var selectedDate: new Date()
model: Control.CalendarModel {
id: calendarModel
from: new Date()
to: new Date(2025, 12, 31)
}
delegate: ColumnLayout {
width: mainItem.width
height: mainItem.height
RowLayout {
Layout.fillWidth: true
Text {
text: new Date(model.year, model.month, 15).toLocaleString(Qt.locale(ConstantsCpp.DefaultLocale), 'MMMM yyyy')// 15 because of timezones that can change the date for localeString
font {
pixelSize: 14 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
Item {
Layout.fillWidth: true
}
Button {
Layout.preferredWidth: 10 * DefaultStyle.dp
Layout.preferredHeight: 20 * DefaultStyle.dp
background: Item{}
icon.source: AppIcons.leftArrow
onClicked: if (mainItem.currentIndex > 0) --mainItem.currentIndex
}
Button {
Layout.preferredWidth: 20 * DefaultStyle.dp
Layout.preferredHeight: 20 * DefaultStyle.dp
background: Item{}
icon.source: AppIcons.rightArrow
onClicked: if (mainItem.currentIndex < mainItem.count) ++mainItem.currentIndex
}
}
Control.DayOfWeekRow {
locale: monthGrid.locale
Layout.column: 1
Layout.fillWidth: true
delegate: Text {
text: model.shortName
color: DefaultStyle.main2_400
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
Control.MonthGrid {
id: monthGrid
Layout.fillWidth: true
Layout.fillHeight: true
year: model.year
month: model.month
// locale: Qt.locale("en_US")
delegate: Item {
property bool isSelectedDay: UtilsCpp.datesAreEqual(mainItem.selectedDate, model.date)
Rectangle {
anchors.centerIn: parent
width: 30 * DefaultStyle.dp
height: 30 * DefaultStyle.dp
radius: 50 * DefaultStyle.dp
color: isSelectedDay ? DefaultStyle.main1_500_main : "transparent"
}
Text {
anchors.centerIn: parent
text: monthGrid.locale.toString(model.date, "d")
color: isSelectedDay
? DefaultStyle.grey_0
: UtilsCpp.isCurrentDay(model.date)
? DefaultStyle.main1_500_main
: UtilsCpp.isCurrentMonth(model.date)
? DefaultStyle.main2_700
: DefaultStyle.main2_400
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
onClicked: (date) => {
if (UtilsCpp.isBeforeToday(date)) return;
mainItem.selectedDate = date
}
}
}
}

View file

@ -0,0 +1,45 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Effects
import Linphone
ComboBox {
id: mainItem
property var selectedDate: calendar.selectedDate
property alias calendar: calendar
contentItem: Text {
text: Qt.formatDate(calendar.selectedDate, "ddd d, MMMM")
anchors.fill: parent
anchors.leftMargin: 15 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
font {
pixelSize: 14 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
popup: Control.Popup {
y: mainItem.height
width: 321 * DefaultStyle.dp
height: 270 * DefaultStyle.dp
closePolicy: Popup.NoAutoClose
background: Item {
Rectangle {
id: calendarBg
anchors.fill: parent
color: DefaultStyle.grey_0
radius: 16 * DefaultStyle.dp
}
MultiEffect {
anchors.fill: calendarBg
source: calendarBg
shadowEnabled: true
shadowBlur: 1
shadowOpacity: 0.1
}
}
contentItem: Calendar {
id: calendar
}
}
}

View file

@ -235,12 +235,26 @@ Item {
onContactSelected: (contact) => {
if (contact.core.allAddresses.length > 1) {
startCallPopup.contact = contact
startCallPopup.open()
onSelectedContactChanged: {
if (selectedContact) {
if (selectedContact.core.allAddresses.length > 1) {
startCallPopup.selectedContact = selectedContact
startCallPopup.open()
} else {
mainItem.callButtonPressed(contact.core.defaultAddress)
} else {
mainItem.callButtonPressed(selectedContact.core.defaultAddress)
}
}
}
// onContactSelected: (contact) => {
// if (contact.core.allAddresses.length > 1) {
// startCallPopup.contact = contact
// startCallPopup.open()
// } else {
// mainItem.callButtonPressed(contact.core.defaultAddress)
// }
// }
}
}
ColumnLayout {
@ -264,20 +278,36 @@ Item {
sourceFlags: LinphoneEnums.MagicSearchSource.All
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
}
onContactSelected: (contact) => {
if (contact.core.allAddresses.length > 1) {
startCallPopup.contact = contact
startCallPopup.open()
onSelectedContactChanged: {
if (selectedContact) {
if (selectedContact.core.allAddresses.length > 1) {
startCallPopup.selectedContact = selectedContact
startCallPopup.open()
} else {
var addressToCall = contact.core.defaultAddress.length === 0
? contact.core.phoneNumbers.length === 0
? ""
: contact.core.phoneNumbers[0].address
: contact.core.defaultAddress
if (addressToCall.length != 0) mainItem.callButtonPressed(addressToCall)
} else {
var addressToCall = selectedContact.core.defaultAddress.length === 0
? selectedContact.core.phoneNumbers.length === 0
? ""
: selectedContact.core.phoneNumbers[0].address
: selectedContact.core.defaultAddress
if (addressToCall.length != 0) mainItem.callButtonPressed(addressToCall)
}
}
}
// onContactSelected: (contact) => {
// if (contact.core.allAddresses.length > 1) {
// startCallPopup.contact = contact
// startCallPopup.open()
// } else {
// var addressToCall = contact.core.defaultAddress.length === 0
// ? contact.core.phoneNumbers.length === 0
// ? ""
// : contact.core.phoneNumbers[0].address
// : contact.core.defaultAddress
// if (addressToCall.length != 0) mainItem.callButtonPressed(addressToCall)
// }
// }
}
}
Item {

View file

@ -4,196 +4,198 @@ import QtQuick.Layouts 1.0
import QtQuick.Effects
import Linphone
ColumnLayout {
Control.ComboBox {
id: mainItem
property string label: ""
// Usage : each item of the model list must be {text: ..., img: ...}
// If string list, only text part of the delegate will be filled
property var model: []
property alias combobox: combobox
readonly property string currentText: selectedItemText.text
property bool enableBackgroundColors: true
readonly property bool hasActiveFocus: combobox.activeFocus
// readonly property string currentText: selectedItemText.text
// Layout.preferredWidth: mainItem.width
// Layout.preferredHeight: mainItem.height
property alias listView: listView
property string constantImageSource
property int pixelSize: 14 * DefaultStyle.dp
property int weight: 400 * DefaultStyle.dp
property int leftMargin: 10 * DefaultStyle.dp
Text {
visible: label.length > 0
verticalAlignment: Text.AlignVCenter
text: mainItem.label
color: combobox.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_600
font {
pixelSize: 13 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
onConstantImageSourceChanged: if (constantImageSource) selectedItemImg.source = constantImageSource
onCurrentIndexChanged: {
var item = model[currentIndex]
if (!item) item = model.getAt(currentIndex)
selectedItemText.text = item.text
? item.text
: item
? item
: ""
selectedItemImg.source = constantImageSource
? constantImageSource
: item.img
? item.img
: ""
console.log("const", constantImageSource, item.img)
}
Control.ComboBox {
id: combobox
model: mainItem.model
Layout.preferredWidth: mainItem.width
background: Rectangle {
implicitWidth: mainItem.width
implicitHeight: 49 * DefaultStyle.dp
radius: 63 * DefaultStyle.dp
color: combobox.enabled ? DefaultStyle.grey_100 : DefaultStyle.grey_200
border.color: combobox.enabled ? DefaultStyle.grey_200 : DefaultStyle.grey_400
}
contentItem: Item {
background: Rectangle {
anchors.fill: mainItem
radius: 63 * DefaultStyle.dp
color: mainItem.enabled ? DefaultStyle.grey_100 : DefaultStyle.grey_200
border.color: mainItem.enabled ? DefaultStyle.grey_200 : DefaultStyle.grey_400
}
contentItem: Item {
Image {
id: selectedItemImg
source: mainItem.constantImageSource ? mainItem.constantImageSource : ""
visible: source != ""
sourceSize.width: 24 * DefaultStyle.dp
width: visible ? 24 * DefaultStyle.dp : 0
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: indicImage.right
Image {
id: selectedItemImg
visible: source != ""
sourceSize.width: 20 * DefaultStyle.dp
width: visible ? 20 * DefaultStyle.dp : 0
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: visible ? 10 * DefaultStyle.dp : 0
}
anchors.leftMargin: visible ? mainItem.leftMargin : 0
}
Text {
id: selectedItemText
color: combobox.enabled ? DefaultStyle.main2_600 : DefaultStyle.grey_400
elide: Text.ElideRight
maximumLineCount: 1
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
anchors.left: selectedItemImg.right
anchors.leftMargin: selectedItemImg.visible ? 5 * DefaultStyle.dp : 10 * DefaultStyle.dp
anchors.right: parent.right
anchors.rightMargin: 20 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
Text {
id: selectedItemText
color: mainItem.enabled ? DefaultStyle.main2_600 : DefaultStyle.grey_400
elide: Text.ElideRight
maximumLineCount: 2
wrapMode: Text.WrapAnywhere
font {
pixelSize: mainItem.pixelSize
weight: mainItem.weight
}
anchors.left: selectedItemImg.right
anchors.leftMargin: selectedItemImg.visible ? 5 * DefaultStyle.dp : 10 * DefaultStyle.dp
anchors.right: parent.right
anchors.rightMargin: 20 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
}
Component.onCompleted: {
var index = combobox.currentIndex < 0 ? 0 : combobox.currentIndex
Component.onCompleted: {
var index = mainItem.currentIndex < 0 ? 0 : mainItem.currentIndex
if (mainItem.model && mainItem.model[index]) {
if (mainItem.model[index] && mainItem.model[index].img) {
selectedItemImg.source = mainItem.model[index].img
}
if (mainItem.model[index] && mainItem.model[index].text)
else if (mainItem.model[index] && mainItem.model[index].text)
selectedItemText.text = mainItem.model[index].text
else if (mainItem.model[index])
else
selectedItemText.text = mainItem.model[index]
}
}
}
indicator: Image {
id: indicImage
anchors.right: parent.right
anchors.rightMargin: 10 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
source: AppIcons.downArrow
}
indicator: Image {
id: indicImage
z: 1
anchors.right: parent.right
anchors.rightMargin: 10 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
source: AppIcons.downArrow
}
popup: Control.Popup {
id: listPopup
y: combobox.height - 1
width: combobox.width
implicitHeight: contentItem.implicitHeight
padding: 1 * DefaultStyle.dp
popup: Control.Popup {
id: popup
y: mainItem.height - 1
width: mainItem.width
implicitHeight: contentItem.implicitHeight
padding: 1 * DefaultStyle.dp
contentItem: ListView {
id: listView
clip: true
implicitHeight: contentHeight
model: combobox.model
currentIndex: combobox.highlightedIndex >= 0 ? combobox.highlightedIndex : 0
highlightFollowsCurrentItem: true
highlight: Rectangle {
width: listView.width
color: DefaultStyle.main2_300
radius: 15 * DefaultStyle.dp
y: listView.currentItem? listView.currentItem.y : 0
}
contentItem: ListView {
id: listView
clip: true
implicitHeight: contentHeight
height: contentHeight
model: mainItem.model
currentIndex: mainItem.highlightedIndex >= 0 ? mainItem.highlightedIndex : 0
highlightFollowsCurrentItem: true
highlightMoveDuration: -1
highlightMoveVelocity: -1
highlight: Rectangle {
width: listView.width
color: DefaultStyle.main2_200
radius: 15 * DefaultStyle.dp
y: listView.currentItem? listView.currentItem.y : 0
}
delegate: Item {
width:combobox.width
height: combobox.height
delegate: Item {
width:mainItem.width
height: mainItem.height
// anchors.left: listView.left
// anchors.right: listView.right
Image {
id: delegateImg
visible: source != ""
width: visible ? 20 * DefaultStyle.dp : 0
sourceSize.width: 20 * DefaultStyle.dp
source: modelData.img ? modelData.img : ""
fillMode: Image.PreserveAspectFit
anchors.left: parent.left
anchors.leftMargin: visible ? 10 * DefaultStyle.dp : 0
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: modelData.text
? modelData.text
: modelData
? modelData
: ""
elide: Text.ElideRight
maximumLineCount: 1
wrapMode: Text.WrapAnywhere
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
anchors.verticalCenter: parent.verticalCenter
anchors.left: delegateImg.right
anchors.leftMargin: delegateImg.visible ? 5 * DefaultStyle.dp : 10 * DefaultStyle.dp
anchors.right: parent.right
Image {
id: delegateImg
visible: source != ""
width: visible ? 20 * DefaultStyle.dp : 0
sourceSize.width: 20 * DefaultStyle.dp
source: modelData.img ? modelData.img : ""
fillMode: Image.PreserveAspectFit
anchors.left: parent.left
anchors.leftMargin: visible ? 10 * DefaultStyle.dp : 0
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: modelData.text
? modelData.text
: modelData
? modelData
: ""
elide: Text.ElideRight
maximumLineCount: 1
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
anchors.verticalCenter: parent.verticalCenter
anchors.left: delegateImg.right
anchors.leftMargin: delegateImg.visible ? 5 * DefaultStyle.dp : 10 * DefaultStyle.dp
anchors.right: parent.right
anchors.rightMargin: 20 * DefaultStyle.dp
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
Rectangle {
anchors.fill: parent
opacity: 0.1
radius: 15 * DefaultStyle.dp
color: DefaultStyle.main2_500main
visible: parent.containsMouse
}
onPressed: {
combobox.state = ""
selectedItemText.text = modelData.text
? modelData.text
: modelData
? modelData
: ""
selectedItemImg.source = modelData.img ? modelData.img : ""
combobox.currentIndex = index
listPopup.close()
}
}
anchors.rightMargin: 20 * DefaultStyle.dp
}
Control.ScrollIndicator.vertical: Control.ScrollIndicator { }
}
onOpened: {
listView.positionViewAtIndex(listView.currentIndex, ListView.Center)
}
background: Item {
implicitWidth: mainItem.width
implicitHeight: 30 * DefaultStyle.dp
Rectangle {
id: cboxBg
MouseArea {
anchors.fill: parent
radius: 15 * DefaultStyle.dp
hoverEnabled: true
Rectangle {
anchors.fill: parent
opacity: 0.1
radius: 15 * DefaultStyle.dp
color: DefaultStyle.main2_500main
visible: parent.containsMouse
}
onClicked: {
mainItem.currentIndex = index
popup.close()
}
}
MultiEffect {
anchors.fill: cboxBg
source: cboxBg
shadowEnabled: true
shadowColor: DefaultStyle.grey_1000
shadowBlur: 1
shadowOpacity: 0.1
}
}
}
Control.ScrollIndicator.vertical: Control.ScrollIndicator { }
}
onOpened: {
listView.positionViewAtIndex(listView.currentIndex, ListView.Center)
}
background: Item {
implicitWidth: mainItem.width
implicitHeight: 30 * DefaultStyle.dp
Rectangle {
id: cboxBg
anchors.fill: parent
radius: 15 * DefaultStyle.dp
}
MultiEffect {
anchors.fill: cboxBg
source: cboxBg
shadowEnabled: true
shadowColor: DefaultStyle.grey_1000
shadowBlur: 1
shadowOpacity: 0.1
}
}
}
}

View file

@ -26,7 +26,9 @@ StackView {
property string displayNameVal: displayNameObj ? displayNameObj.value : ""
property bool haveAvatar: (account && account.core.pictureUri )
|| (contact && contact.core.pictureUri)
|| computedAvatarUri.length != 0
property string computedAvatarUri: UtilsCpp.findAvatarByAddress(address)
onHaveAvatarChanged: replace(haveAvatar ? avatar : initials, StackView.Immediate)
property bool secured: false
@ -134,7 +136,7 @@ StackView {
anchors.centerIn: parent
source: mainItem.account && mainItem.account.core.pictureUri
|| mainItem.contact && mainItem.contact.core.pictureUri
|| ""
|| computedAvatarUri
mipmap: true
}
ShaderEffect {

View file

@ -103,29 +103,37 @@ ColumnLayout {
Layout.bottomMargin: 50 * DefaultStyle.dp
ColumnLayout {
spacing: 20 * DefaultStyle.dp
TextInput {
FormItemLayout {
label: qsTr("Prénom")
initialText: contact.core.givenName
onEditingFinished: contact.core.givenName = text
backgroundColor: DefaultStyle.grey_0
contentItem: TextField {
initialText: contact.core.givenName
onEditingFinished: contact.core.givenName = text
backgroundColor: DefaultStyle.grey_0
}
}
TextInput {
FormItemLayout {
label: qsTr("Nom")
initialText: contact.core.familyName
onEditingFinished: contact.core.familyName = text
backgroundColor: DefaultStyle.grey_0
contentItem: TextField {
initialText: contact.core.familyName
onEditingFinished: contact.core.familyName = text
backgroundColor: DefaultStyle.grey_0
}
}
TextInput {
FormItemLayout {
label: qsTr("Entreprise")
initialText: contact.core.organization
onEditingFinished: contact.core.organization = text
backgroundColor: DefaultStyle.grey_0
contentItem: TextField {
initialText: contact.core.organization
onEditingFinished: contact.core.organization = text
backgroundColor: DefaultStyle.grey_0
}
}
TextInput {
FormItemLayout {
label: qsTr("Fonction")
initialText: contact.core.job
onEditingFinished: contact.core.job = text
backgroundColor: DefaultStyle.grey_0
contentItem: TextField {
initialText: contact.core.job
onEditingFinished: contact.core.job = text
backgroundColor: DefaultStyle.grey_0
}
}
Item{Layout.fillHeight: true}
}
@ -141,13 +149,15 @@ ColumnLayout {
model: mainItem.contact && mainItem.contact.core.addresses || []
}
delegate: RowLayout {
TextInput {
FormItemLayout {
label: modelData.label
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.setAddressAt(index, qsTr("Address SIP"), text)
contentItem: TextField {
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.setAddressAt(index, qsTr("Address SIP"), text)
}
initialText: modelData.address
backgroundColor: DefaultStyle.grey_0
}
initialText: modelData.address
backgroundColor: DefaultStyle.grey_0
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
@ -161,12 +171,14 @@ ColumnLayout {
}
}
RowLayout {
TextInput {
FormItemLayout {
label: qsTr("Adresse SIP")
backgroundColor: DefaultStyle.grey_0
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.appendAddress(text)
setText("")
contentItem: TextField {
backgroundColor: DefaultStyle.grey_0
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.appendAddress(text)
text = ""
}
}
}
Item {
@ -180,13 +192,15 @@ ColumnLayout {
model: mainItem.contact && mainItem.contact.core.phoneNumbers || []
}
delegate: RowLayout {
TextInput {
FormItemLayout {
label: modelData.label
initialText: modelData.address
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.setPhoneNumberAt(index, qsTr("Téléphone"), text)
contentItem: TextField {
initialText: modelData.address
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.setPhoneNumberAt(index, qsTr("Téléphone"), text)
}
backgroundColor: DefaultStyle.grey_0
}
backgroundColor: DefaultStyle.grey_0
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
@ -200,12 +214,14 @@ ColumnLayout {
}
}
RowLayout {
TextInput {
FormItemLayout {
label: qsTr("Phone")
backgroundColor: DefaultStyle.grey_0
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.appendPhoneNumber(label, text)
setText("")
contentItem: TextField {
backgroundColor: DefaultStyle.grey_0
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.appendPhoneNumber(label, text)
setText("")
}
}
}
Item {

View file

@ -18,6 +18,19 @@ ListView {
property bool initialHeadersVisible: true
property bool displayNameCapitalization: true
property bool showOnlyFavourites: false
property ConferenceInfoGui confInfoGui
property bool multiSelectionEnabled: false
property list<string> selectedContacts
property int selectedContactCount: selectedContacts.length
Component.onCompleted: {
if (confInfoGui) {
for(var i = 0; i < confInfoGui.core.participants.length; ++i) {
selectedContacts.push(confInfoGui.core.getParticipantAddressAt(i));
}
}
}
property int delegateLeftMargin: 0
currentIndex: -1
@ -30,10 +43,11 @@ ListView {
selectedContact = model.getAt(currentIndex) || null
}
signal contactSelected(var contact)
// signal contactSelected(var contact)
signal contactStarredChanged()
signal contactDeletionRequested(FriendGui contact)
signal contactAddedToSelection()
model: MagicSearchProxy {
searchText: searchBarText.length === 0 ? "*" : searchBarText
}
@ -89,13 +103,29 @@ ListView {
maximumLineCount: 1
Layout.fillWidth: true
}
RowLayout {
id: buttonsLayout
z: 1
height: parent.height
children: mainItem.delegateButtons || []
EffectImage {
id: isSelectedCheck
// visible: mainItem.multiSelectionEnabled && (mainItem.confInfoGui.core.getParticipantIndex(modelData.core.defaultAddress) != -1)
visible: mainItem.multiSelectionEnabled && (mainItem.selectedContacts.indexOf(modelData.core.defaultAddress) != -1)
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
imageSource: AppIcons.check
colorizationColor: DefaultStyle.main1_500_main
Connections {
target: mainItem
// onParticipantsChanged: isSelectedCheck.visible = mainItem.confInfoGui.core.getParticipantIndex(modelData.core.defaultAddress) != -1
onSelectedContactCountChanged: isSelectedCheck.visible = (mainItem.selectedContacts.indexOf(modelData.core.defaultAddress) != -1)
}
}
}
RowLayout {
z: 1
height: parent.height
anchors.right: parent.right
anchors.rightMargin: 5 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
children: mainItem.delegateButtons || []
PopupButton {
id: friendPopup
z: 1
@ -159,6 +189,7 @@ ListView {
}
}
}
MouseArea {
id: contactArea
@ -169,11 +200,29 @@ ListView {
anchors.fill: contactArea
opacity: 0.7
color: DefaultStyle.main2_100
visible: contactArea.containsMouse || friendPopup.hovered || mainItem.currentIndex === index
visible: contactArea.containsMouse || friendPopup.hovered || (!mainItem.multiSelectionEnabled && mainItem.currentIndex === index)
}
onClicked: {
mainItem.currentIndex = index
mainItem.contactSelected(modelData)
// mainItem.contactSelected(modelData)
// if (mainItem.multiSelectionEnabled && mainItem.confInfoGui) {
// var indexInSelection = mainItem.confInfoGui.core.getParticipantIndex(modelData.core.defaultAddress)
// if (indexInSelection == -1) {
// mainItem.confInfoGui.core.addParticipant(modelData.core.defaultAddress)
// } else {
// mainItem.confInfoGui.core.removeParticipant(indexInSelection)
// }
// }
if (mainItem.multiSelectionEnabled) {
var indexInSelection = mainItem.selectedContacts.indexOf(modelData.core.defaultAddress)
if (indexInSelection == -1) {
mainItem.selectedContacts.push(modelData.core.defaultAddress)
mainItem.contactAddedToSelection()
}
else {
mainItem.selectedContacts.splice(indexInSelection, 1)
}
}
}
}
}

View file

@ -9,43 +9,51 @@ ColumnLayout {
spacing: 15 * DefaultStyle.dp
signal connectionSucceed()
TextInput {
FormItemLayout {
id: username
label: "Username"
mandatory: true
enableErrorText: true
Binding on background.border.color {
when: errorText.opacity != 0
value: DefaultStyle.danger_500main
}
Binding on textField.color {
when: errorText.opacity != 0
value: DefaultStyle.danger_500main
}
}
Item {
Layout.preferredHeight: password.implicitHeight
TextInput {
id: password
label: "Password"
mandatory: true
hidden: true
enableErrorText: true
Binding on background.border.color {
contentItem: TextField {
id: usernameEdit
Layout.preferredWidth: 360 * DefaultStyle.dp
Layout.preferredHeight: 49 * DefaultStyle.dp
Binding on backgroundBorderColor {
when: errorText.opacity != 0
value: DefaultStyle.danger_500main
}
Binding on textField.color {
Binding on color {
when: errorText.opacity != 0
value: DefaultStyle.danger_500main
}
}
}
Item {
Layout.preferredHeight: password.implicitHeight
FormItemLayout {
id: password
label: "Password"
mandatory: true
enableErrorText: true
contentItem: TextField {
id: passwordEdit
Layout.preferredWidth: 360 * DefaultStyle.dp
Layout.preferredHeight: 49 * DefaultStyle.dp
hidden: true
Binding on backgroundBorderColor {
when: errorText.opacity != 0
value: DefaultStyle.danger_500main
}
Binding on color {
when: errorText.opacity != 0
value: DefaultStyle.danger_500main
}
}
}
ErrorText {
anchors.bottom: password.bottom
anchors.top: password.bottom
anchors.topMargin: 15 * DefaultStyle.dp
id: errorText
Connections {
target: LoginPageCpp
@ -106,14 +114,14 @@ ColumnLayout {
password.errorMessage = ""
errorText.text = ""
if (username.text.length == 0 || password.text.length == 0) {
if (username.text.length == 0)
if (usernameEdit.text.length == 0 || passwordEdit.text.length == 0) {
if (usernameEdit.text.length == 0)
username.errorMessage = qsTr("You must enter a username")
if (password.text.length == 0)
if (passwordEdit.text.length == 0)
password.errorMessage = qsTr("You must enter a password")
return
}
LoginPageCpp.login(username.text, password.text)
LoginPageCpp.login(usernameEdit.text, passwordEdit.text)
connectionButton.currentIndex = 1
}
}

View file

@ -0,0 +1,155 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Effects
import Linphone
import QtQml
import UtilsCpp 1.0
ListView {
id: mainItem
height: contentHeight
visible: count > 0
clip: true
property string searchBarText
property bool hoverEnabled: true
property int delegateLeftMargin: 0
currentIndex: -1
property var delegateButtons
property ConferenceInfoGui selectedConference: model.getAt(currentIndex) || null
onCountChanged: selectedConference = model.getAt(currentIndex) || null
onCurrentIndexChanged: selectedConference = model.getAt(currentIndex) || null
signal conferenceSelected(var contact)
model: ConferenceInfoProxy {
searchText: searchBarText.length === 0 ? "" : searchBarText
}
section {
criteria: ViewSection.FullString
delegate: Text {
text: section
height: 29 * DefaultStyle.dp
font {
pixelSize: 20 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
property: '$sectionMonth'
}
delegate: Item {
id: itemDelegate
height: 80 * DefaultStyle.dp
width: mainItem.width
property var previousItem : mainItem.model.count > 0 && index > 0 ? mainItem.model.getAt(index-1) : null
property var previousDateTime: previousItem ? previousItem.core.dateTimeUtc : null
property var dateTime: $modelData.core.dateTime
property var endDateTime: $modelData.core.endDateTime
ColumnLayout {
id: dateDay
width: 32 * DefaultStyle.dp
height: 51 * DefaultStyle.dp
visible: !previousDateTime || previousDateTime != dateTime
anchors.verticalCenter: parent.verticalCenter
Text {
verticalAlignment: Text.AlignVCenter
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 19 * DefaultStyle.dp
// opacity: (!previousItem || !previousDateTime.startsWith(displayName[0])) ? 1 : 0
text: UtilsCpp.toDateDayNameString(dateTime)
color: DefaultStyle.main2_500main
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
Rectangle {
id: dayNum
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
radius: 50 * DefaultStyle.dp
property var isCurrentDay: UtilsCpp.isCurrentDay(dateTime)
color: isCurrentDay ? DefaultStyle.main1_500_main : "transparent"
Text {
anchors.centerIn: parent
text: UtilsCpp.toDateDayString(dateTime)
color: dayNum.isCurrentDay ? DefaultStyle.grey_0 : DefaultStyle.main2_500main
font {
pixelSize: 20 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
}
}
Rectangle {
id: conferenceInfoDelegate
anchors.left: dateDay.visible ? dateDay.right : parent.left
anchors.leftMargin: 10 * DefaultStyle.dp + mainItem.delegateLeftMargin
anchors.rightMargin: 10 * DefaultStyle.dp + mainItem.delegateLeftMargin
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
radius: 10 * DefaultStyle.dp
// width: 265 * DefaultStyle.dp
height: 63 * DefaultStyle.dp
color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.grey_0
ColumnLayout {
anchors.fill: parent
anchors.left: parent.left
anchors.leftMargin: 15 * DefaultStyle.dp
spacing: 2 * DefaultStyle.dp
RowLayout {
spacing: 8 * DefaultStyle.dp
Image {
source: AppIcons.usersThree
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
text: $modelData.core.subject
font {
pixelSize: 13 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
}
Text {
text: UtilsCpp.toDateHourString(dateTime) + " - " + UtilsCpp.toDateHourString(endDateTime)
color: DefaultStyle.main2_500main
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
}
}
MultiEffect {
source: conferenceInfoDelegate
anchors.fill: conferenceInfoDelegate
shadowEnabled: true
shadowBlur: 1.0
shadowOpacity: 0.1
}
MouseArea {
id: confArea
hoverEnabled: mainItem.hoverEnabled
anchors.fill: dateDay.visible ? conferenceInfoDelegate : parent
cursorShape: Qt.PointingHandCursor
onClicked: {
mainItem.currentIndex = index
mainItem.conferenceSelected($modelData)
}
}
}
}

View file

@ -0,0 +1,377 @@
import QtQuick 2.15
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
ColumnLayout {
id: mainItem
spacing: 8 * DefaultStyle.dp
property ConferenceInfoGui conferenceInfoGui
signal addParticipantsRequested()
signal returnRequested()
RowLayout {
Button {
background: Item{}
icon.source: AppIcons.leftArrow
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
onClicked: mainItem.returnRequested()
}
Text {
text: qsTr("Nouvelle réunion")
color: DefaultStyle.main2_700
font {
pixelSize: 22 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
Layout.fillWidth: true
}
Button {
topPadding: 6 * DefaultStyle.dp
bottomPadding: 6 * DefaultStyle.dp
leftPadding: 12 * DefaultStyle.dp
rightPadding: 12 * DefaultStyle.dp
text: qsTr("Créer")
textSize: 13 * DefaultStyle.dp
onClicked: {
if (mainItem.conferenceInfoGui.core.subject.length === 0) {
UtilsCpp.showInformationPopup(qsTr("Erreur lors de la création"), qsTr("La conférence doit contenir un sujet"), false)
} else if (mainItem.conferenceInfoGui.core.duration <= 0) {
UtilsCpp.showInformationPopup(qsTr("Erreur lors de la création"), qsTr("La fin de la conférence doit être plus récente que son début"), false)
} else if (mainItem.conferenceInfoGui.core.participantCount === 0) {
UtilsCpp.showInformationPopup(qsTr("Erreur lors de la création"), qsTr("La conférence doit contenir au moins un participant"), false)
} else {
mainItem.conferenceInfoGui.core.save()
mainItem.returnRequested()
}
}
}
}
component CheckableButton: Button {
id: checkableButton
checkable: true
autoExclusive: true
contentImageColor: checked ? DefaultStyle.grey_0 : DefaultStyle.main1_500_main
inversedColors: !checked
topPadding: 10 * DefaultStyle.dp
bottomPadding: 10 * DefaultStyle.dp
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
contentItem: RowLayout {
EffectImage {
imageSource: checkableButton.icon.source
colorizationColor: checkableButton.checked ? DefaultStyle.grey_0 : DefaultStyle.main1_500_main
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
}
Text {
text: checkableButton.text
color: checkableButton.checked ? DefaultStyle.grey_0 : DefaultStyle.main1_500_main
font {
pixelSize: 16 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
}
}
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 20 * DefaultStyle.dp
Layout.bottomMargin: 20 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
spacing: 20 * DefaultStyle.dp
CheckableButton {
Layout.preferredWidth: 151 * DefaultStyle.dp
icon.source: AppIcons.usersThree
text: qsTr("Réunion")
checked: true
}
CheckableButton {
Layout.preferredWidth: 151 * DefaultStyle.dp
icon.source: AppIcons.slide
text: qsTr("Broadcast")
}
}
Section {
content: RowLayout {
EffectImage {
imageSource: AppIcons.usersThree
colorizationColor: DefaultStyle.main2_600
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
TextInput {
id: confTitle
text: qsTr("Ajouter un titre")
color: DefaultStyle.main2_600
font {
pixelSize: 20 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
onActiveFocusChanged: if(activeFocus==true) selectAll()
onEditingFinished: mainItem.conferenceInfoGui.core.subject = text
}
}
}
Section {
Layout.topMargin: 10 * DefaultStyle.dp
content: ColumnLayout {
spacing: 15 * DefaultStyle.dp
anchors.left: parent.left
anchors.right: parent.right
RowLayout {
Layout.fillWidth: true
EffectImage {
imageSource: AppIcons.clock
colorizationColor: DefaultStyle.main2_600
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
CalendarComboBox {
id: startDate
Layout.fillWidth: true
Layout.preferredHeight: 30 * DefaultStyle.dp
onSelectedDateChanged: {
mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(selectedDate, startHour.selectedHour, startHour.selectedMin)
endDate.calendar.selectedDate = selectedDate
}
}
}
RowLayout {
Item {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
StackLayout {
currentIndex: allDaySwitch.position
RowLayout {
TimeComboBox {
id: startHour
onSelectedHourChanged: {
mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, selectedHour, selectedMin)
console.log("selected hour", selectedHour, selectedMin)
endHour.selectedTimeString = Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), selectedHour == 23 ? 0 : selectedHour + 1, selectedMin), "hh:mm")
}
onSelectedMinChanged: {
mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, selectedHour, selectedMin)
console.log("selected min", selectedHour, selectedMin)
endHour.selectedTimeString = Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), selectedHour == 23 ? 0 : selectedHour + 1, selectedMin), "hh:mm")
}
Layout.preferredWidth: 94 * DefaultStyle.dp
Layout.preferredHeight: 30 * DefaultStyle.dp
}
TimeComboBox {
id: endHour
property date startTime: new Date()
onSelectedHourChanged: mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, selectedHour, selectedMin)
onSelectedMinChanged: mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, selectedHour, selectedMin)
Layout.preferredWidth: 94 * DefaultStyle.dp
Layout.preferredHeight: 30 * DefaultStyle.dp
Component.onCompleted: selectedTimeString = Qt.formatDateTime(UtilsCpp.addSecs(startTime, 3600), "hh:mm")
}
Item {
Layout.fillWidth: true
}
Text {
property int durationSec: UtilsCpp.secsTo(startHour.selectedTime, endHour.selectedTime)
property int hour: durationSec/3600
property int min: (durationSec - hour*3600)/60
text: (hour > 0 ? hour + "h" : "") + (min > 0 ? min + "mn" : "")
font {
pixelSize: 14 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
}
CalendarComboBox {
id: endDate
Layout.fillWidth: true
Layout.preferredHeight: 30 * DefaultStyle.dp
onSelectedDateChanged: mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(selectedDate, 23, 59)
}
}
}
RowLayout {
Item {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
RowLayout {
Switch {
id: allDaySwitch
text: qsTr("Toute la journée")
}
}
}
ComboBox {
id: timeZoneCbox
Layout.fillWidth: true
Layout.preferredHeight: 30 * DefaultStyle.dp
hoverEnabled: true
listView.implicitHeight: 152 * DefaultStyle.dp
constantImageSource: AppIcons.globe
weight: 700 * DefaultStyle.dp
leftMargin: 0
currentIndex: mainItem.conferenceInfoGui ? model.getIndex(mainItem.conferenceInfoGui.core.timeZoneModel) : -1
background: Rectangle {
visible: parent.hovered || parent.down
anchors.fill: parent
color: DefaultStyle.grey_100
}
model: TimeZoneProxy{
}
onCurrentIndexChanged: {
var modelIndex = timeZoneCbox.model.index(currentIndex, 0)
mainItem.conferenceInfoGui.core.timeZoneModel = timeZoneCbox.model.data(modelIndex, Qt.DisplayRole + 1)
}
}
ComboBox {
id: repeaterCbox
enabled: false
Component.onCompleted: console.log("TODO : handle conf repetition")
constantImageSource: AppIcons.reloadArrow
Layout.fillWidth: true
Layout.preferredHeight: height
height: 30 * DefaultStyle.dp
width: 307 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
leftMargin: 0
currentIndex: 0
background: Rectangle {
visible: parent.hovered || parent.down
anchors.fill: parent
color: DefaultStyle.grey_100
}
model: [
{text: qsTr("Une fois")},
{text: qsTr("Tous les jours")},
{text: qsTr("Tous les jours de la semaine (Lun-Ven)")},
{text: qsTr("Toutes les semaines")},
{text: qsTr("Tous les mois")}
]
}
}
}
Section {
content: RowLayout {
anchors.left: parent.left
anchors.right: parent.right
EffectImage {
imageSource: AppIcons.note
colorizationColor: DefaultStyle.main2_600
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
TextArea {
id: descriptionEdit
Layout.fillWidth: true
Layout.preferredWidth: 275 * DefaultStyle.dp
leftPadding: 8 * DefaultStyle.dp
rightPadding: 8 * DefaultStyle.dp
hoverEnabled: true
placeholderText: qsTr("Ajouter une description")
placeholderTextColor: DefaultStyle.main2_600
placeholderWeight: 700 * DefaultStyle.dp
color: DefaultStyle.main2_600
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
background: Rectangle {
anchors.fill: parent
color: descriptionEdit.hovered || descriptionEdit.activeFocus ? DefaultStyle.grey_100 : "transparent"
radius: 4 * DefaultStyle.dp
}
onEditingFinished: mainItem.conferenceInfoGui.core.description = text
}
}
}
Section {
content: ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
Button {
id: addParticipantsButton
Layout.fillWidth: true
Layout.preferredHeight: 30 * DefaultStyle.dp
background: Rectangle {
anchors.fill: parent
color: addParticipantsButton.hovered ? DefaultStyle.grey_100 : "transparent"
radius: 4 * DefaultStyle.dp
}
contentItem: RowLayout {
EffectImage {
imageSource: AppIcons.usersThree
colorizationColor: DefaultStyle.main2_600
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
Layout.fillWidth: true
text: qsTr("Ajouter des participants")
font {
pixelSize: 14 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
}
onClicked: mainItem.addParticipantsRequested()
}
ListView {
id: participantList
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: contentHeight
Layout.maximumHeight: 250 * DefaultStyle.dp
clip: true
model: mainItem.conferenceInfoGui.core.participants
delegate: Item {
height: 56 * DefaultStyle.dp
width: parent.width
RowLayout {
anchors.fill: parent
Avatar {
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
address: modelData.address
}
Text {
text: modelData.displayName
font.pixelSize: 14 * DefaultStyle.dp
font.capitalization: Font.Capitalize
}
Item {
Layout.fillWidth: true
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.rightMargin: 10 * DefaultStyle.dp
background: Item{}
icon.source: AppIcons.closeX
contentImageColor: DefaultStyle.main1_500_main
onClicked: mainItem.conferenceInfoGui.core.removeParticipant(index)
}
}
}
}
}
}
Switch {
text: qsTr("Send invitation to participants")
Component.onCompleted: {
console.log("TODO : handle send invitation to participants")
toggle()
}
}
Item {
Layout.fillHeight: true
}
}

View file

@ -49,12 +49,11 @@ ColumnLayout {
Layout.bottomMargin: 10 * DefaultStyle.dp
color: DefaultStyle.main2_600
}
TextInput {
TextField {
id: textField
Layout.fillWidth: true
placeholderText: mainItem.placeholderText
enableBackgroundColors: false
fillWidth: true
background: Item{}
initialText: initialPhoneNumber
validator: IntValidator{}
}

View file

@ -8,6 +8,7 @@ Control.Popup{
padding: 0
property color underlineColor
property int radius: 16 * DefaultStyle.dp
property bool hovered: mouseArea.containsMouse
background: Item{
Rectangle {
visible: mainItem.underlineColor != undefined
@ -32,5 +33,10 @@ Control.Popup{
shadowBlur: 1.0
shadowOpacity: 0.1
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
}
}

View file

@ -6,25 +6,35 @@ import Linphone
Button {
id: mainItem
property alias popup: popup
property var contentImageColor
checked: popup.visible
implicitWidth: 24 * DefaultStyle.dp
implicitHeight: 24 * DefaultStyle.dp
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
icon.source: AppIcons.more
icon.width: width
icon.height: height
function close() {
popup.close()
}
background: Rectangle {
anchors.fill: mainItem
visible: mainItem.checked
color: DefaultStyle.main2_300
radius: 40 * DefaultStyle.dp
}
icon.source: AppIcons.more
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
contentItem: EffectImage {
imageSource: mainItem.icon.source
imageWidth: mainItem.icon.width
imageHeight: mainItem.icon.height
colorizationColor: mainItem.contentImageColor
}
onPressed: {
if (popup.visible) popup.close()
else popup.open()
@ -33,7 +43,7 @@ Button {
id: popup
x: - width
y: mainItem.height
closePolicy: Popup.CloseOnPressOutsideParent |Popup.CloseOnPressOutside
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside
parent: mainItem // Explicit define for coordinates references.
onAboutToShow: {
@ -67,4 +77,4 @@ Button {
}
}
}
}
}

View file

@ -0,0 +1,41 @@
import QtQuick 2.12
import QtQuick.Controls as Control
import Linphone
Control.Switch {
id: mainItem
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
indicator: Rectangle {
implicitWidth: 32 * DefaultStyle.dp
implicitHeight: 20 * DefaultStyle.dp
x: mainItem.leftPadding
y: parent.height / 2 - height / 2
radius: 10 * DefaultStyle.dp
color: mainItem.checked ? DefaultStyle.success_500main : DefaultStyle.main2_400
Rectangle {
anchors.verticalCenter: parent.verticalCenter
property int margin: 4 * DefaultStyle.dp
x: mainItem.checked ? parent.width - width - margin : margin
width: 12 * DefaultStyle.dp
height: 12 * DefaultStyle.dp
radius: 10 * DefaultStyle.dp
color: DefaultStyle.grey_0
Behavior on x {
NumberAnimation{duration: 100}
}
}
}
contentItem: Text {
text: mainItem.text
font: mainItem.font
opacity: enabled ? 1.0 : 0.3
verticalAlignment: Text.AlignVCenter
leftPadding: mainItem.indicator.width + mainItem.spacing
}
}

View file

@ -102,22 +102,22 @@ Window {
text: "scaled text"
}
RowLayout {
TextInput {
TextField {
label: "mandatory text input"
placeholderText: "default text"
mandatory: true
// mandatory: true
}
TextInput {
TextField {
label: "password text input"
placeholderText: "default text"
hidden: true
}
TextInput {
TextField {
id: next
label: "text input with long long looooooooooooooooooooooooooooooooooooooooooooooooooooooooong label"
placeholderText: "long long long default text"
}
TextInput {
TextField {
label: "number text input"
validator: IntValidator{}
}

View file

@ -0,0 +1,46 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Layouts 1.0
import Linphone
TextEdit {
id: mainItem
property string placeholderText
property int placeholderPixelSize: 14 * DefaultStyle.dp
property int placeholderWeight: 400 * DefaultStyle.dp
property color placeholderTextColor: color
property alias background: background.data
property bool hoverEnabled: false
property bool hovered: mouseArea.hoverEnabled && mouseArea.containsMouse
topPadding: 5 * DefaultStyle.dp
bottomPadding: 5 * DefaultStyle.dp
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: mainItem.hoverEnabled
// onPressed: mainItem.forceActiveFocus()
acceptedButtons: Qt.NoButton
cursorShape: mainItem.hovered ? Qt.PointingHandCursor : Qt.ArrowCursor
}
Item {
id: background
anchors.fill: parent
z: -1
}
Text {
anchors.verticalCenter: mainItem.verticalCenter
text: mainItem.placeholderText
color: mainItem.placeholderTextColor
visible: mainItem.text.length == 0 && !mainItem.activeFocus
x: mainItem.leftPadding
font {
pixelSize: mainItem.placeholderPixelSize
weight: mainItem.placeholderWeight
}
}
}

View file

@ -0,0 +1,115 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Layouts 1.0
import Linphone
Control.TextField {
id: mainItem
width: 360 * DefaultStyle.dp
height: 49 * DefaultStyle.dp
leftPadding: 15 * DefaultStyle.dp
rightPadding: eyeButton.visible ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin : 15 * DefaultStyle.dp
echoMode: (hidden && !eyeButton.checked) ? TextInput.Password : TextInput.Normal
color: DefaultStyle.main2_600
font {
family: DefaultStyle.defaultFont
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
selectByMouse: true
property bool controlIsDown: false
property bool hidden: false
property bool backgroundVisible: true
property color backgroundColor: DefaultStyle.grey_100
property color backgroundBorderColor: DefaultStyle.grey_200
property string initialText
property int pixelSize: 14 * DefaultStyle.dp
property int weight: 400 * DefaultStyle.dp
Component.onCompleted: {
text = initialText
}
function resetText() {
text = initialText
}
signal enterPressed()
background: Rectangle {
id: inputBackground
visible: mainItem.backgroundVisible
anchors.fill: parent
radius: 79 * DefaultStyle.dp
color: mainItem.backgroundColor
border.color: activeFocus
? DefaultStyle.main1_500_main
: mainItem.backgroundBorderColor
}
cursorDelegate: Rectangle {
id: cursor
color: DefaultStyle.main1_500_main
width: 1 * DefaultStyle.dp
SequentialAnimation {
loops: Animation.Infinite
running: mainItem.cursorVisible
PropertyAction {
target: cursor
property: 'visible'
value: true
}
PauseAnimation {
duration: 600
}
PropertyAction {
target: cursor
property: 'visible'
value: false
}
PauseAnimation {
duration: 600
}
onStopped: {
cursor.visible = false
}
}
}
Keys.onPressed: (event) => {
if (event.jey == Qt.Key_Control) mainItem.controlIsDown = true
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
enterPressed()
if (mainItem.controlIsDown) {
}
}
}
Keys.onReleased: (event) => {
if (event.jey == Qt.Key_Control) mainItem.controlIsDown = false
}
Button {
id: eyeButton
property int rightMargin: 15 * DefaultStyle.dp
z: 1
visible: mainItem.hidden
checkable: true
background: Rectangle {
color: "transparent"
}
icon.source: eyeButton.checked ? AppIcons.eyeShow : AppIcons.eyeHide
width: 20 * DefaultStyle.dp
height: 20 * DefaultStyle.dp
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: rightMargin
}
}

View file

@ -1,132 +0,0 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Layouts
import Linphone
ColumnLayout {
id: mainItem
property string label: ""
property string errorMessage: ""
property string placeholderText: ""
property bool mandatory: false
property bool hidden: false
property int textInputWidth: 346 * DefaultStyle.dp
property var validator: RegularExpressionValidator{}
property bool fillWidth: false
property bool enableBackgroundColors: true
property color backgroundColor: DefaultStyle.grey_100
property color backgroundBorderColor: DefaultStyle.grey_200
property string initialText
property bool enableErrorText: false
property bool errorTextVisible: errorText.opacity > 0
property alias textField: textField
property alias background: input
readonly property string text: textField.text
readonly property bool hasActiveFocus: textField.activeFocus
signal editingFinished()
Component.onCompleted: {
setText(initialText)
}
function setText(text) {
textField.text = text
}
function resetText() {
setText(initialText)
}
Text {
visible: mainItem.label.length > 0
verticalAlignment: Text.AlignVCenter
text: mainItem.label + (mainItem.mandatory ? "*" : "")
color: textField.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_600
elide: Text.ElideRight
wrapMode: Text.Wrap
maximumLineCount: 1
font {
pixelSize: 13 * DefaultStyle.dp
family: DefaultStyle.defaultFont
weight: 700 * DefaultStyle.dp
}
Layout.preferredWidth: mainItem.textInputWidth
}
Rectangle {
id: input
Component.onCompleted: {
if (mainItem.fillWidth)
Layout.fillWidth = true
}
Layout.preferredWidth: mainItem.textInputWidth
Layout.preferredHeight: 49 * DefaultStyle.dp
radius: 79 * DefaultStyle.dp
color: mainItem.backgroundColor
border.color: mainItem.errorTextVisible
? DefaultStyle.danger_500main
: textField.activeFocus
? DefaultStyle.main1_500_main
: mainItem.backgroundBorderColor
Control.TextField {
id: textField
anchors.left: parent.left
anchors.leftMargin: 10 * DefaultStyle.dp
anchors.right: eyeButton.visible ? eyeButton.left : parent.right
anchors.rightMargin: eyeButton.visible ? 0 : 10 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
placeholderText: mainItem.placeholderText
echoMode: (mainItem.hidden && !eyeButton.checked) ? TextInput.Password : TextInput.Normal
font.family: DefaultStyle.defaultFont
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
color: mainItem.errorTextVisible ? DefaultStyle.danger_500main : DefaultStyle.main2_600
selectByMouse: true
validator: mainItem.validator
background: Item {
opacity: 0.
}
cursorDelegate: Rectangle {
visible: textField.activeFocus
color: DefaultStyle.main1_500_main
width: 2 * DefaultStyle.dp
}
onEditingFinished: {
mainItem.editingFinished()
}
Keys.onPressed: (event)=> {
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
textField.focus = false
}
}
}
Button {
id: eyeButton
visible: mainItem.hidden
checkable: true
background: Rectangle {
color: "transparent"
}
icon.source: eyeButton.checked ? AppIcons.eyeShow : AppIcons.eyeHide
width: 20 * DefaultStyle.dp
height: 20 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 15 * DefaultStyle.dp
}
}
ErrorText {
id: errorText
visible: mainItem.enableErrorText
text: mainItem.errorMessage
Layout.preferredWidth: implicitWidth
}
}

View file

@ -0,0 +1,83 @@
import QtQuick
import Linphone
import UtilsCpp 1.0
ComboBox {
id: mainItem
property string selectedTimeString: Qt.formatDateTime(new Date(), "hh:mm")
property int selectedHour: input.hour*1
property int selectedMin: input.min*1
popup.width: 73 * DefaultStyle.dp
listView.model: 48
listView.implicitHeight: 204 * DefaultStyle.dp
editable: true
popup.closePolicy: Popup.PressOutsideParent | Popup.CloseOnPressOutside
onCurrentTextChanged: input.text = currentText
popup.onOpened: {
input.forceActiveFocus()
}
contentItem: TextInput {
id: input
anchors.right: indicator.left
validator: IntValidator{}
// activeFocusOnPress: false
inputMask: "00:00"
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignHCenter
property string hour: text.split(":")[0]
property string min: text.split(":")[1]
color: DefaultStyle.main2_600
onActiveFocusChanged: {
if (activeFocus) {
selectAll()
mainItem.popup.open()
} else {
listView.currentIndex = -1
mainItem.selectedTimeString = Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), hour, min), "hh:mm")
}
}
font {
pixelSize: 14 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
text: mainItem.selectedTimeString
Keys.onPressed: (event) => {
if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) {
focus = false
}
}
onEditingFinished: {
console.log("set time", hour, min)
mainItem.selectedTimeString = Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), hour, min), "hh:mm")
}
}
listView.delegate: Text {
id: hourDelegate
property int hour: modelData /2
property int min: modelData%2 === 0 ? 0 : 30
text: Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), hour, min), "hh:mm")
width: mainItem.width
height: 25 * DefaultStyle.dp
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignHCenter
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
// mainItem.text = parent.text
mainItem.listView.currentIndex = index
mainItem.selectedTimeString = hourDelegate.text
mainItem.popup.close()
}
Rectangle {
visible: parent.containsMouse
color: DefaultStyle.main2_200
}
}
}
}

View file

@ -0,0 +1,67 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQml.Models 2.12
import QtGraphicalEffects 1.12
import Common 1.0
import Common.Styles 1.0
import Linphone 1.0
import LinphoneEnums 1.0
import UtilsCpp 1.0
import App.Styles 1.0
import ConstantsCpp 1.0
// Temp
import 'Incall.js' as Logic
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
// =============================================================================
Mosaic {
id: grid
property alias callModel: participantDevices.callModel
property bool cameraEnabled: true
property int participantCount: gridModel.count
// On grid view, we limit the quality if there are enough participants// The vga mode has been activated from the factory rc
//onParticipantCountChanged: participantCount > ConstantsCpp.maxMosaicParticipants ? SettingsModel.setLimitedMosaicQuality() : SettingsModel.setHighMosaicQuality()
delegateModel: DelegateModel{
id: gridModel
property ParticipantDeviceProxyModel participantDevices : ParticipantDeviceProxyModel {
id: participantDevices
showMe: true
}
model: participantDevices
delegate: Item{
id: avatarCell
property ParticipantDeviceModel currentDevice: gridModel.participantDevices.getAt(index)
onCurrentDeviceChanged: {
if(index < 0) cameraView.enabled = false // this is a delegate destruction. We need to stop camera before Qt change its currentDevice (and then, let CameraView to delete wrong renderer)
}
height: grid.cellHeight - 10
width: grid.cellWidth - 10
Sticker{
id: cameraView
anchors.fill: parent
cameraQmlName: 'G_'+index
callModel: index >= 0 ? participantDevices.callModel : null // do this before to prioritize changing call on remove
deactivateCamera: index <0 || !grid.cameraEnabled || grid.callModel.pausedByUser
currentDevice: gridModel.participantDevices.getAt(index)
isCameraFromDevice: true
isPaused: !isPreview && avatarCell.currentDevice && avatarCell.currentDevice.isPaused
showCloseButton: false
showCustomButton: false
avatarStickerBackgroundColor: isPreview? IncallStyle.container.avatar.stickerPreviewBackgroundColor.color : IncallStyle.container.avatar.stickerBackgroundColor.color
avatarBackgroundColor: IncallStyle.container.avatar.backgroundColor.color
//onCloseRequested: participantDevices.showMe = false
}
}
}
}

View file

@ -0,0 +1,44 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Layouts 1.0
import QtQuick.Effects
import Linphone
ColumnLayout {
id: mainItem
property alias contentItem: contentItem.data
property string label: ""
property bool mandatory: false
property string errorMessage: ""
property bool enableErrorText: false
property bool errorTextVisible: errorText.opacity > 0
Text {
visible: label.length > 0
verticalAlignment: Text.AlignVCenter
text: mainItem.label + (mainItem.mandatory ? "*" : "")
color: contentItem.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_600
elide: Text.ElideRight
wrapMode: Text.Wrap
maximumLineCount: 1
font {
pixelSize: 13 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
Item {
id: contentItem
Layout.preferredHeight: childrenRect.height
Layout.preferredWidth: childrenRect.width
}
ErrorText {
id: errorText
visible: mainItem.enableErrorText
text: mainItem.errorMessage
Layout.preferredWidth: implicitWidth
}
}

View file

@ -0,0 +1,114 @@
import QtQuick 2.15
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
ColumnLayout {
id: mainItem
property string title
property string validateButtonText
property string placeHolderText: qsTr("Rechercher des contacts")
property color titleColor: DefaultStyle.main2_700
property ConferenceInfoGui conferenceInfoGui
signal returnRequested()
Layout.preferredWidth: 362 * DefaultStyle.dp
RowLayout {
Layout.preferredWidth: 362 * DefaultStyle.dp
Button {
background: Item{}
icon.source: AppIcons.leftArrow
contentImageColor: DefaultStyle.main1_500_main
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
onClicked: mainItem.returnRequested()
}
Text {
text: mainItem.title
color: mainItem.titleColor
maximumLineCount: 1
font {
pixelSize: 18 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
Layout.fillWidth: true
}
Button {
Layout.preferredWidth: 70 * DefaultStyle.dp
topPadding: 6 * DefaultStyle.dp
bottomPadding: 6 * DefaultStyle.dp
// leftPadding: 12 * DefaultStyle.dp
// rightPadding: 12 * DefaultStyle.dp
text: mainItem.validateButtonText
textSize: 13 * DefaultStyle.dp
onClicked: {
mainItem.conferenceInfoGui.core.resetParticipants(contactList.selectedContacts)
mainItem.returnRequested()
}
}
}
ListView {
id: participantList
Layout.fillWidth: true
// Layout.fillHeight: true
Layout.preferredHeight: contentHeight
Layout.maximumHeight: mainItem.height / 3
width: mainItem.width
model: contactList.selectedContacts
clip: true
delegate: Item {
height: 56 * DefaultStyle.dp
width: participantList.width
RowLayout {
anchors.fill: parent
Avatar {
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
address: modelData
}
Text {
property var nameObj: UtilsCpp.getDisplayName(modelData)
text: nameObj ? nameObj.value : ""
font.pixelSize: 14 * DefaultStyle.dp
font.capitalization: Font.Capitalize
}
Item {
Layout.fillWidth: true
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
background: Item{}
icon.source: AppIcons.closeX
contentImageColor: DefaultStyle.main1_500_main
onClicked: contactList.selectedContacts.splice(index, 1)
}
}
}
}
SearchBar {
id: searchbar
Layout.fillWidth: true
placeholderText: mainItem.placeHolderText
}
Text {
text: qsTr("Contacts")
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
ContactsList {
id: contactList
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: contentHeight
multiSelectionEnabled: true
contactMenuVisible: false
confInfoGui: mainItem.conferenceInfoGui
searchBarText: searchbar.text
onContactAddedToSelection: participantList.positionViewAtEnd()
}
}

View file

@ -0,0 +1,118 @@
import QtQuick 2.12
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
import QtQml.Models 2.12
import Common 1.0
import Common.Styles 1.0
// =============================================================================
ColumnLayout{
id: mainLayout
property alias delegateModel: grid.model
property alias cellHeight: grid.cellHeight
property alias cellWidth: grid.cellWidth
function appendItem(item){
mainLayout.delegateModel.model.append(item)
}
function add(item){
if( !grid.isLayoutWillChanged())
appendItem(item)
else
bufferModels.append(item)
}
function remove(index){
if(mainLayout.delegateModel.model.count > index)
mainLayout.delegateModel.model.remove( index, 1)
}
function get(index){
return mainLayout.delegateModel.model.get(index)
}
function tryToAdd(item){
if( !grid.isLayoutWillChanged()) {
appendItem(item)
return true
}else
return false
}
function clear(){
if(mainLayout.delegateModel.model.clear) {
mainLayout.delegateModel.model.clear()
bufferModels.clear()
}
}
property int transitionCount : 0
property var bufferModels : ListModel{}
onWidthChanged: grid.updateLayout()
onHeightChanged: grid.updateLayout()
GridView{
id: grid
property int margin: 10
property int itemCount: model.count ? model.count :( model.length ? model.length : 0)
property int columns: 1
property int rows: 1
function getBestLayout(itemCount){
var availableW = mainLayout.width - grid.margin
var availableH = mainLayout.height - grid.margin
var bestSize = 0
var bestC = 1, bestR = 1
for(var R = 1 ; R <= itemCount ; ++R){
for(var C = itemCount ; C >= 1 ; --C){
if( R * C >= itemCount){// This is a good layout candidate
var estimatedSize = Math.min(availableW / C, availableH / R)
if(estimatedSize > bestSize // Size is better
|| (estimatedSize == bestSize && Math.abs(bestR-bestC) > Math.abs(R - C) )){// Stickers are more homogenized
bestSize = estimatedSize
bestC = C
bestR = R
}
}
}
}
return [bestR, bestC]
}
function updateLayout(){
var bestLayout = getBestLayout(itemCount)
if( rows != bestLayout[0])
rows = bestLayout[0]
if( columns != bestLayout[1])
columns = bestLayout[1]
}
function updateCells(){
cellWidth = Math.min(computedWidth, computedHeight)
cellHeight = Math.min(computedWidth, computedHeight)
}
onItemCountChanged: updateLayout()
property int computedWidth: (mainLayout.width - grid.margin ) / columns
property int computedHeight: (mainLayout.height - grid.margin ) / rows
onComputedHeightChanged: Qt.callLater(updateCells)
onComputedWidthChanged: Qt.callLater(updateCells)
cellWidth: Math.min(computedWidth, computedHeight)
cellHeight: Math.min(computedWidth, computedHeight)
function isLayoutWillChanged(){
var bestLayout = getBestLayout(itemCount+1)
return rows !== bestLayout[0] || columns !== bestLayout[1]
}
Layout.preferredWidth: cellWidth * columns
Layout.preferredHeight: cellHeight * rows
Layout.alignment: Qt.AlignCenter
interactive: false
model: DelegateModel{}
onCountChanged: grid.updateLayout()
}
}

View file

@ -0,0 +1,26 @@
import QtQuick 2.15
import QtQuick.Layouts
import Linphone
/*
Layout with line separator used in several views
*/
ColumnLayout {
spacing: 15 * DefaultStyle.dp
property alias content: contentItem.data
implicitHeight: contentItem.implicitHeight + 1 * DefaultStyle.dp + spacing
Item {
id: contentItem
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
Layout.preferredWidth: childrenRect.width
// Layout.leftMargin: 8 * DefaultStyle.dp
}
Rectangle {
color: DefaultStyle.main2_200
Layout.fillWidth: true
Layout.preferredHeight: 1 * DefaultStyle.dp
width: parent.width
}
}

View file

@ -17,7 +17,7 @@ LoginLayout {
visible: mainItem.showBackButton
Layout.preferredHeight: 27 * DefaultStyle.dp
Layout.preferredWidth: 27 * DefaultStyle.dp
icon.source: AppIcons.returnArrow
icon.source: AppIcons.leftArrow
background: Rectangle {
color: "transparent"
}

View file

@ -13,7 +13,7 @@ LoginLayout {
Button {
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
icon.source: AppIcons.returnArrow
icon.source: AppIcons.leftArrow
background: Rectangle {
color: "transparent"
}

View file

@ -68,16 +68,19 @@ LoginLayout {
Layout.topMargin: 20 * DefaultStyle.dp
spacing: 15 * DefaultStyle.dp
RowLayout {
TextInput {
FormItemLayout {
label: qsTr("Username")
mandatory: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
ComboBox {
label: " "
Layout.alignment: Qt.AlignBottom
enabled: false
model: [{text:"@sip.linphone.org"}]
Layout.preferredWidth: 210 * DefaultStyle.dp
Layout.preferredHeight: 49 * DefaultStyle.dp
}
}
PhoneNumberInput {
@ -85,15 +88,17 @@ LoginLayout {
label: qsTr("Phone number")
mandatory: true
placeholderText: "Phone number"
textInputWidth: 346 * DefaultStyle.dp
Layout.preferredWidth: 346 * DefaultStyle.dp
}
RowLayout {
ColumnLayout {
TextInput {
FormItemLayout {
label: qsTr("Password")
mandatory: true
hidden: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
hidden: true
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
Text {
text: qsTr("The password must contain 6 characters minimum")
@ -104,11 +109,13 @@ LoginLayout {
}
}
ColumnLayout {
TextInput {
FormItemLayout {
label: qsTr("Confirm password")
mandatory: true
hidden: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
hidden: true
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
Text {
text: qsTr("The password must contain 6 characters minimum")
@ -162,34 +169,40 @@ LoginLayout {
Layout.fillHeight: true
spacing: 15 * DefaultStyle.dp
RowLayout {
TextInput {
FormItemLayout {
label: qsTr("Username")
mandatory: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
ComboBox {
// if we don't set a label this item is offset
// due to the invisibility of the upper label
label: " "
enabled: false
model: [{text:"@sip.linphone.org"}]
Layout.preferredWidth: 210 * DefaultStyle.dp
Layout.alignment: Qt.AlignBottom
}
}
TextInput {
id: emailInput
FormItemLayout {
label: qsTr("Email")
mandatory: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
id: emailInput
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
RowLayout {
ColumnLayout {
TextInput {
id: pwdInput
FormItemLayout {
label: qsTr("Password")
mandatory: true
hidden: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
id: pwdInput
hidden: true
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
Text {
text: qsTr("The password must contain 6 characters minimum")
@ -200,12 +213,14 @@ LoginLayout {
}
}
ColumnLayout {
TextInput {
id: confirmPwdInput
FormItemLayout {
label: qsTr("Confirm password")
mandatory: true
hidden: true
textInputWidth: 346 * DefaultStyle.dp
contentItem: TextField {
id: confirmPwdInput
hidden: true
Layout.preferredWidth: 346 * DefaultStyle.dp
}
}
Text {
text: qsTr("The password must contain 6 characters minimum")

View file

@ -14,7 +14,7 @@ LoginLayout {
Button {
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
icon.source: AppIcons.returnArrow
icon.source: AppIcons.leftArrow
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
background: Item {
@ -133,34 +133,45 @@ LoginLayout {
id: secondItem
ColumnLayout {
spacing: 10 * DefaultStyle.dp
TextInput {
id: username
FormItemLayout {
label: qsTr("Username")
mandatory: true
textInputWidth: 360 * DefaultStyle.dp
contentItem: TextField {
id: username
Layout.preferredWidth: 360 * DefaultStyle.dp
}
}
TextInput {
id: password
FormItemLayout {
label: qsTr("Password")
mandatory: true
hidden: true
textInputWidth: 360 * DefaultStyle.dp
contentItem: TextField {
id: password
hidden: true
Layout.preferredWidth: 360 * DefaultStyle.dp
}
}
TextInput {
id: domain
FormItemLayout {
label: qsTr("Domain")
mandatory: true
textInputWidth: 360 * DefaultStyle.dp
contentItem: TextField {
id: domain
Layout.preferredWidth: 360 * DefaultStyle.dp
}
}
TextInput {
id: displayName
FormItemLayout {
label: qsTr("Display Name")
textInputWidth: 360 * DefaultStyle.dp
contentItem: TextField {
id: displayName
Layout.preferredWidth: 360 * DefaultStyle.dp
}
}
ComboBox {
FormItemLayout {
label: qsTr("Transport")
model:[ "TCP", "UDP", "TLS", "DTLS"]
Layout.preferredWidth: 360 * DefaultStyle.dp
contentItem: ComboBox {
height: 49 * DefaultStyle.dp
width: 360 * DefaultStyle.dp
model:[ "TCP", "UDP", "TLS", "DTLS"]
}
}
ErrorText {

View file

@ -17,6 +17,7 @@ Item {
property alias leftPanelContent: leftPanel.children
property alias rightPanelStackView: rightPanelStackView
property alias contactEditionComp: contactEditionComp
property alias rightPanel: rightPanel
property bool showDefaultItem: true
signal noItemButtonPressed()
signal contactEditionClosed()
@ -231,6 +232,7 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
// We need this component here as it is used in multiple subPages (Call and Contact pages)
Component {
id: contactEditionComp
ContactEdition {

View file

@ -317,7 +317,7 @@ AbstractMainPage {
}
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.source: AppIcons.returnArrow
icon.source: AppIcons.leftArrow
onClicked: {
console.debug("[CallPage]User: return to call history")
listStackView.pop()

View file

@ -0,0 +1,461 @@
import QtQuick 2.15
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
AbstractMainPage {
id: mainItem
noItemButtonText: qsTr("Créer une réunion")
emptyListText: qsTr("Aucune réunion")
newItemIconSource: AppIcons.plusCircle
// rightPanel.color: DefaultStyle.grey_0
// disable left panel contact list interaction while a contact is being edited
property bool leftPanelEnabled: true
property ConferenceInfoGui selectedConference
property int meetingListCount
onSelectedConferenceChanged: {
if (selectedConference) {
if (!rightPanelStackView.currentItem || rightPanelStackView.currentItem.objectName != "meetingDetail") rightPanelStackView.replace(meetingDetail, Control.StackView.Immediate)
} else {
if (rightPanelStackView.currentItem && rightPanelStackView.currentItem.objectName === "meetingDetail") rightPanelStackView.clear()
}
}
Connections {
target: leftPanelStackView
onCurrentItemChanged: {
mainItem.showDefaultItem = leftPanelStackView.currentItem.objectName == "listLayout" && mainItem.meetingListCount === 0
}
}
onMeetingListCountChanged: showDefaultItem = leftPanelStackView.currentItem.objectName == "listLayout" && meetingListCount === 0
function createConference(name, address) {
var confInfoGui = Qt.createQmlObject('import Linphone
ConferenceInfoGui{
}', mainItem)
leftPanelStackView.push(createConference, {"conferenceInfoGui": confInfoGui})
}
leftPanelContent: ColumnLayout {
id: leftPanel
Layout.fillWidth: true
Layout.fillHeight: true
property int sideMargin: 25 * DefaultStyle.dp
ColumnLayout {
Layout.topMargin: 30 * DefaultStyle.dp
Layout.leftMargin: leftPanel.sideMargin
Layout.rightMargin: leftPanel.sideMargin
enabled: mainItem.leftPanelEnabled
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Control.ScrollBar {
id: meetingsScrollbar
active: true
interactive: true
policy: Control.ScrollBar.AsNeeded
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
}
Control.StackView {
id: leftPanelStackView
initialItem: listLayout
anchors.fill: parent
}
Component {
id: listLayout
ColumnLayout {
spacing: 19 * DefaultStyle.dp
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: leftPanel.sideMargin
Layout.rightMargin: leftPanel.sideMargin
Text {
text: qsTr("Réunions")
color: DefaultStyle.main2_700
font.pixelSize: 29 * DefaultStyle.dp
font.weight: 800 * DefaultStyle.dp
}
Item {
Layout.fillWidth: true
}
Button {
background: Item {
}
icon.source: AppIcons.plusCircle
Layout.preferredWidth: 30 * DefaultStyle.dp
Layout.preferredHeight: 30 * DefaultStyle.dp
width: 30 * DefaultStyle.dp
height: 30 * DefaultStyle.dp
onClicked: {
mainItem.createConference()
}
}
}
SearchBar {
id: searchBar
Layout.rightMargin: leftPanel.sideMargin
Layout.fillWidth: true
placeholderText: qsTr("Rechercher une réunion")
}
Control.ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
rightPadding: leftPanel.sideMargin
contentWidth: width - leftPanel.sideMargin
contentHeight: content.height
clip: true
Control.ScrollBar.vertical: meetingsScrollbar
ColumnLayout {
id: content
width: parent.width
anchors.topMargin: 5 * DefaultStyle.dp
anchors.fill: parent
spacing: 15 * DefaultStyle.dp
Text {
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
text: mainItem.emptyListText
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
visible: mainItem.showDefaultItem
}
MeetingList {
id: conferenceList
visible: count != 0
hoverEnabled: mainItem.leftPanelEnabled
Layout.preferredWidth: parent.width
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: 20 * DefaultStyle.dp
searchBarText: searchBar.text
onSelectedConferenceChanged: {
mainItem.selectedConference = selectedConference
}
onCountChanged: {
mainItem.meetingListCount = count
}
}
}
}
}
}
Component {
id: createConference
NewMeeting {
onReturnRequested: leftPanelStackView.pop()
onAddParticipantsRequested: {
onClicked: leftPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui})
}
}
}
Component {
id: addParticipants
AddParticipantsLayout {
title: qsTr("Ajouter des participants")
validateButtonText: qsTr("Ajouter")
titleColor: DefaultStyle.main1_500_main
onReturnRequested: {
leftPanelStackView.pop()
}
}
}
}
}
}
Component {
id: meetingDetail
RowLayout {
ColumnLayout {
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: 393 * DefaultStyle.dp
Layout.fillWidth: false
Layout.fillHeight: true
Layout.leftMargin: 39 * DefaultStyle.dp
Layout.topMargin: 39 * DefaultStyle.dp
spacing: 25 * DefaultStyle.dp
Section {
content: RowLayout {
spacing: 8 * DefaultStyle.dp
Image {
source: AppIcons.usersThree
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
text: mainItem.selectedConference.core.subject
font {
pixelSize: 20 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
Item {
Layout.fillWidth: true
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.source: AppIcons.pencil
contentImageColor: DefaultStyle.main1_500_main
background: Item{}
onClicked: mainItem.rightPanelStackView.replace()
}
PopupButton {
id: deletePopup
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
contentImageColor: DefaultStyle.main1_500_main
popup.contentItem: RowLayout {
Button {
background: Item{}
contentItem: RowLayout {
EffectImage {
imageSource: AppIcons.trashCan
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
fillMode: Image.PreserveAspectFit
colorizationColor: DefaultStyle.danger_500main
}
Text {
text: qsTr("Delete this meeting")
color: DefaultStyle.danger_500main
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
}
onClicked: {
if (UtilsCpp.isMe(mainItem.selectedConference.core.organizerAddress))
mainItem.selectedConference.core.lDeleteConferenceInfo()
else
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Vous pouvez supprimer une conférence seulement si vous en êtes l'organisateur"), false)
// mainItem.contactDeletionRequested(mainItem.selectedConference)
deletePopup.close()
}
}
}
}
}
}
Section {
content: ColumnLayout {
spacing: 15 * DefaultStyle.dp
width: parent.width
RowLayout {
spacing: 8 * DefaultStyle.dp
Layout.fillWidth: true
Image {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
source: AppIcons.videoCamera
}
Button {
Layout.fillWidth: true
text: mainItem.selectedConference.core.uri
textSize: 14 * DefaultStyle.dp
textWeight: 400 * DefaultStyle.dp
underline: true
inversedColors: true
color: DefaultStyle.main2_600
background: Item{}
onClicked: {
console.log("TODO: join conf", text)
}
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
background: Item{}
icon.source: AppIcons.shareNetwork
onClicked: UtilsCpp.copyToClipboard(confUri.text)
}
}
RowLayout {
spacing: 8 * DefaultStyle.dp
Image {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
source: AppIcons.clock
}
Text {
text: UtilsCpp.toDateString(mainItem.selectedConference.core.dateTimeUtc)
+ " | " + UtilsCpp.toDateHourString(mainItem.selectedConference.core.dateTimeUtc)
+ " - "
+ UtilsCpp.toDateHourString(mainItem.selectedConference.core.endDateTime)
font {
pixelSize: 14 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
}
RowLayout {
spacing: 8 * DefaultStyle.dp
Image {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
source: AppIcons.globe
}
Text {
text: qsTr("Time zone: ") + mainItem.selectedConference.core.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName
font {
pixelSize: 14 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
}
}
}
Section {
visible: mainItem.selectedConference.core.description.length != 0
content: RowLayout {
spacing: 8 * DefaultStyle.dp
EffectImage {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
imageSource: AppIcons.note
colorizationColor: DefaultStyle.main2_600
}
Text {
text: mainItem.selectedConference.core.description
Layout.fillWidth: true
font {
pixelSize: 14 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
}
}
Section {
content: RowLayout {
spacing: 8 * DefaultStyle.dp
EffectImage {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
imageSource: AppIcons.userRectangle
colorizationColor: DefaultStyle.main2_600
}
Avatar {
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
address: mainItem.selectedConference.core.organizerAddress
}
Text {
text: mainItem.selectedConference.core.organizerName
font {
pixelSize: 14 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
}
}
Section {
content: RowLayout {
Layout.preferredHeight: participantList.height
width: 393 * DefaultStyle.dp
spacing: 8 * DefaultStyle.dp
Image {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.topMargin: 20 * DefaultStyle.dp
source: AppIcons.usersTwo
}
ListView {
id: participantList
Layout.preferredHeight: Math.min(184 * DefaultStyle.dp, contentHeight)
Layout.fillWidth: true
model: mainItem.selectedConference.core.participants
clip: true
delegate: RowLayout {
height: 56 * DefaultStyle.dp
width: participantList.width
Avatar {
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
address: modelData.address
}
Text {
text: modelData.displayName
Layout.fillWidth: true
font {
pixelSize: 14 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
Text {
text: qsTr("Organizer")
visible: mainItem.selectedConference.core.organizerAddress === modelData.address
color: DefaultStyle.main2_400
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
}
}
}
Button {
Layout.fillWidth: true
text: qsTr("Rejoindre la réunion")
topPadding: 11 * DefaultStyle.dp
bottomPadding: 11 * DefaultStyle.dp
onClicked: console.log("TODO: join conf", mainItem.selectedConference.core.subject)
}
}
}
}
Component {
id: meetingEdition
Section {
content: RowLayout {
spacing: 8 * DefaultStyle.dp
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.source: AppIcons.leftArrow
contentImageColor: DefaultStyle.main1_500_main
background: Item{}
onClicked: mainItem.rightPanelStackView.pop()
}
Image {
source: AppIcons.usersThree
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
text: mainItem.selectedConference.core.subject
font {
pixelSize: 20 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
Item {
Layout.fillWidth: true
}
Button {
text: qsTr("Save")
onClicked: {
console.log("TODO : save meeting infos")
mainItem.rightPanelStackView.pop(meetingDetail, Control.StackView.Immediate)
}
}
}
}
}
}

View file

@ -128,10 +128,10 @@ Window{
}
}
}
TextInput {
TextField {
id: usernameToCall
label: "Username to call"
textInputWidth: 250
Layout.preferredWidth: 250 * DefaultStyle.dp
}
Button{
text: 'Call'

View file

@ -16,12 +16,12 @@ Window{
FriendGui{
id: contact
}
TextInput{
TextField{
placeholderText: 'Name'
initialText: contact.core.givenName
onTextChanged: contact.core.givenName = text
}
TextInput{
TextField{
placeholderText: 'Address'
initialText: contact.core.address
onTextChanged: contact.core.address = text
@ -63,7 +63,7 @@ Window{
Text{
text: modelData.core.address
}
TextInput{
TextField{
initialText: modelData.core.address
onTextChanged: if(modelData.core.address != text){
modelData.core.address = text

View file

@ -8,9 +8,10 @@ QtObject {
property string eyeHide: "image://internal/eye.svg"
property string eyeShow: "image://internal/eye-slash.svg"
property string downArrow: "image://internal/caret-down.svg"
property string returnArrow: "image://internal/caret-left.svg"
property string leftArrow: "image://internal/caret-left.svg"
property string rightArrow: "image://internal/caret-right.svg"
property string upArrow: "image://internal/caret-up.svg"
property string reloadArrow: "image://internal/arrow-clockwise.svg"
property string info: "image://internal/info.svg"
property string loginImage: "image://internal/login_image.svg"
property string belledonne: "image://internal/belledonne.svg"
@ -62,6 +63,7 @@ QtObject {
property string pause: "image://internal/pause.svg"
property string play: "image://internal/play.svg"
property string smiley: "image://internal/smiley.svg"
property string smileySad: "image://internal/smiley-sad.svg"
property string trashCan: "image://internal/trash-simple.svg"
property string copy: "image://internal/copy.svg"
property string empty: "image://internal/empty.svg"
@ -75,5 +77,11 @@ QtObject {
property string bellSlash: "image://internal/bell-simple-slash.svg"
property string question: "image://internal/question.svg"
property string settings: "image://internal/settings.svg"
property string clock: "image://internal/clock.svg"
property string note: "image://internal/note.svg"
property string userRectangle: "image://internal/user-rectangle.svg"
property string usersTwo: "image://internal/users.svg"
property string globe: "image://internal/globe-hemisphere-west.svg"
property string slide: "image://internal/slideshow.svg"
}

Some files were not shown because too many files have changed in this diff Show more