diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index 566bb5ad7..18274667a 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -143,9 +143,6 @@ void App::init() { coreModel->start(); auto settings = Settings::create(); QMetaObject::invokeMethod(App::getInstance()->thread(), [this, settings]() mutable { - mSettings = settings; - settings.reset(); - // QML mEngine = new QQmlApplicationEngine(this); // Provide `+custom` folders for custom components and `5.9` for old components. @@ -164,6 +161,8 @@ void App::init() { // Enable notifications. mNotifier = new Notifier(mEngine); + mSettings = settings; + settings.reset(); const QUrl url(u"qrc:/Linphone/view/App/Main.qml"_qs); QObject::connect( @@ -261,15 +260,15 @@ void App::initCppInterfaces() { //------------------------------------------------------------ void App::clean() { + if (mSettings) mSettings.reset(); // Wait 500ms to let time for log te be stored. // mNotifier destroyed in mEngine deletion as it is its parent delete mEngine; mEngine = nullptr; - if (mSettings) { - mSettings = nullptr; - } - mLinphoneThread->wait(250); - qApp->processEvents(QEventLoop::AllEvents, 250); + // if (mSettings) { + // mSettings.reset(); + // } + qApp->processEvents(QEventLoop::AllEvents, 500); mLinphoneThread->exit(); mLinphoneThread->wait(); delete mLinphoneThread; diff --git a/Linphone/core/call-history/CallHistoryCore.cpp b/Linphone/core/call-history/CallHistoryCore.cpp index 612716a4a..3ae3e9d95 100644 --- a/Linphone/core/call-history/CallHistoryCore.cpp +++ b/Linphone/core/call-history/CallHistoryCore.cpp @@ -20,6 +20,7 @@ #include "CallHistoryCore.hpp" #include "core/App.hpp" +#include "core/conference/ConferenceInfoCore.hpp" #include "model/call-history/CallHistoryModel.hpp" #include "model/object/VariantObject.hpp" #include "model/tool/ToolModel.hpp" @@ -54,7 +55,7 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr &callL mIsConference = callLog->wasConference(); if (mIsConference) { auto confinfo = callLog->getConferenceInfo(); - confinfo->getSubject(); + mConferenceInfo = ConferenceInfoCore::create(confinfo); mRemoteAddress = Utils::coreStringToAppString(confinfo->getUri()->asStringUriOnly()); mDisplayName = Utils::coreStringToAppString(confinfo->getSubject()); } else { @@ -73,6 +74,10 @@ void CallHistoryCore::setSelf(QSharedPointer me) { new SafeConnection(me, mCallHistoryModel), &QObject::deleteLater); } +ConferenceInfoGui *CallHistoryCore::getConferenceInfoGui() const { + return mConferenceInfo ? new ConferenceInfoGui(mConferenceInfo) : nullptr; +} + QString CallHistoryCore::getDuration() const { return mDuration; } diff --git a/Linphone/core/call-history/CallHistoryCore.hpp b/Linphone/core/call-history/CallHistoryCore.hpp index 8f24ded80..7e4024dd7 100644 --- a/Linphone/core/call-history/CallHistoryCore.hpp +++ b/Linphone/core/call-history/CallHistoryCore.hpp @@ -21,6 +21,7 @@ #ifndef CALL_HISTORY_CORE_H_ #define CALL_HISTORY_CORE_H_ +#include "core/conference/ConferenceInfoGui.hpp" #include "tool/LinphoneEnums.hpp" #include "tool/thread/SafeConnection.hpp" #include @@ -37,6 +38,7 @@ class CallHistoryCore : public QObject, public AbstractObject { Q_PROPERTY(QString remoteAddress MEMBER mRemoteAddress CONSTANT) Q_PROPERTY(bool isOutgoing MEMBER mIsOutgoing CONSTANT) Q_PROPERTY(bool isConference MEMBER mIsConference CONSTANT) + Q_PROPERTY(ConferenceInfoGui *conferenceInfo READ getConferenceInfoGui CONSTANT) Q_PROPERTY(QDateTime date MEMBER mDate CONSTANT) Q_PROPERTY(LinphoneEnums::CallStatus status MEMBER mStatus CONSTANT) Q_PROPERTY(QString duration READ getDuration WRITE setDuration NOTIFY durationChanged) @@ -47,6 +49,7 @@ public: ~CallHistoryCore(); void setSelf(QSharedPointer me); + ConferenceInfoGui *getConferenceInfoGui() const; QString getDuration() const; void setDuration(const QString &duration); @@ -57,7 +60,7 @@ public: QString mDisplayName; QDateTime mDate; bool mIsOutgoing; - bool mIsConference; + bool mIsConference = false; LinphoneEnums::CallStatus mStatus; signals: @@ -65,7 +68,7 @@ signals: private: QString mDuration; - + QSharedPointer mConferenceInfo = nullptr; std::shared_ptr mCallHistoryModel; QSharedPointer> mHistoryModelConnection; diff --git a/Linphone/core/call/CallCore.cpp b/Linphone/core/call/CallCore.cpp index 68594b758..47826d526 100644 --- a/Linphone/core/call/CallCore.cpp +++ b/Linphone/core/call/CallCore.cpp @@ -88,14 +88,16 @@ CallCore::CallCore(const std::shared_ptr &call) : QObject(nullpt mSpeakerVolumeGain = mCallModel->getSpeakerVolumeGain(); // TODO : change this with settings value when settings done if (mSpeakerVolumeGain < 0) { - call->setSpeakerVolumeGain(0.5); - mSpeakerVolumeGain = 0.5; + auto vol = CoreModel::getInstance()->getCore()->getPlaybackGainDb(); + call->setSpeakerVolumeGain(vol); + mSpeakerVolumeGain = vol; } mMicrophoneVolumeGain = call->getMicrophoneVolumeGain(); // TODO : change this with settings value when settings done if (mMicrophoneVolumeGain < 0) { - call->setMicrophoneVolumeGain(0.5); - mMicrophoneVolumeGain = 0.5; + auto vol = CoreModel::getInstance()->getCore()->getMicGainDb(); + call->setMicrophoneVolumeGain(vol); + mMicrophoneVolumeGain = vol; } mMicrophoneVolume = call->getRecordVolume(); mRecordable = mState == LinphoneEnums::CallState::StreamsRunning; @@ -163,6 +165,12 @@ void CallCore::setSelf(QSharedPointer me) { mCallModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) { mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); }); }); + mCallModelConnection->makeConnectToModel(&CallModel::speakerVolumeGainChanged, [this](float volume) { + mCallModelConnection->invokeToCore([this, volume]() { setSpeakerVolumeGain(volume); }); + }); + mCallModelConnection->makeConnectToModel(&CallModel::microphoneVolumeGainChanged, [this](float volume) { + mCallModelConnection->invokeToCore([this, volume]() { setMicrophoneVolumeGain(volume); }); + }); mCallModelConnection->makeConnectToModel(&CallModel::microphoneVolumeChanged, [this](float volume) { mCallModelConnection->invokeToCore([this, volume]() { setMicrophoneVolume(volume); }); }); @@ -175,12 +183,26 @@ void CallCore::setSelf(QSharedPointer me) { 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->makeConnectToModel( + &CallModel::stateChanged, [this](linphone::Call::State state, const std::string &message) { + double speakerVolume = mSpeakerVolumeGain; + double micVolume = mMicrophoneVolumeGain; + if (state == linphone::Call::State::StreamsRunning) { + speakerVolume = mCallModel->getSpeakerVolumeGain(); + if (speakerVolume < 0) { + speakerVolume = CoreModel::getInstance()->getCore()->getPlaybackGainDb(); + } + micVolume = mCallModel->getMicrophoneVolumeGain(); + if (micVolume < 0) { + micVolume = CoreModel::getInstance()->getCore()->getMicGainDb(); + } + } + mCallModelConnection->invokeToCore([this, state, speakerVolume, micVolume]() { + setSpeakerVolumeGain(speakerVolume); + setMicrophoneVolumeGain(micVolume); + setRecordable(state == linphone::Call::State::StreamsRunning); + }); + }); mCallModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) { mCallModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); }); }); @@ -319,7 +341,10 @@ 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); + if (state == LinphoneEnums::CallState::Error) { + lDebug() << "[CallCore] Error message : " << message; + setLastErrorMessage(message); + } emit stateChanged(mState); } } diff --git a/Linphone/core/conference/ConferenceCore.cpp b/Linphone/core/conference/ConferenceCore.cpp index ed8588c53..4373c82f5 100644 --- a/Linphone/core/conference/ConferenceCore.cpp +++ b/Linphone/core/conference/ConferenceCore.cpp @@ -58,18 +58,26 @@ void ConferenceCore::setSelf(QSharedPointer me) { auto device = ParticipantDeviceCore::create(participantDevice); mConferenceModelConnection->invokeToCore([this, device]() { setActiveSpeaker(device); }); }); - mConferenceModelConnection->makeConnectToModel( - &ConferenceModel::participantDeviceAdded, - [this](const std::shared_ptr &participantDevice) { - int count = mConferenceModel->getParticipantDeviceCount(); - mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); - }); - mConferenceModelConnection->makeConnectToModel( - &ConferenceModel::participantDeviceRemoved, - [this](const std::shared_ptr &participantDevice) { - int count = mConferenceModel->getParticipantDeviceCount(); - mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); - }); + mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceAdded, [this]() { + int count = mConferenceModel->getParticipantDeviceCount(); + mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); + }); + mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceRemoved, [this]() { + int count = mConferenceModel->getParticipantDeviceCount(); + mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); + }); + mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantAdded, [this]() { + int count = mConferenceModel->getParticipantDeviceCount(); + mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); + }); + mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantRemoved, [this]() { + int count = mConferenceModel->getParticipantDeviceCount(); + mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); + }); + mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceStateChanged, [this]() { + int count = mConferenceModel->getParticipantDeviceCount(); + mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); }); + }); } bool ConferenceCore::updateLocalParticipant() { // true if changed @@ -94,6 +102,9 @@ void ConferenceCore::setParticipantDeviceCount(int count) { } } +/** + * /!\ mParticipantDeviceCount retrieves all devices but mine + **/ int ConferenceCore::getParticipantDeviceCount() const { return mParticipantDeviceCount; } diff --git a/Linphone/core/conference/ConferenceCore.hpp b/Linphone/core/conference/ConferenceCore.hpp index 1684f3421..34dca0e29 100644 --- a/Linphone/core/conference/ConferenceCore.hpp +++ b/Linphone/core/conference/ConferenceCore.hpp @@ -41,6 +41,7 @@ public: // Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT) // Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged) Q_PROPERTY(bool isReady MEMBER mIsReady WRITE setIsReady NOTIFY isReadyChanged) + Q_PROPERTY(QString subject MEMBER mSubject CONSTANT) Q_PROPERTY(int participantDeviceCount READ getParticipantDeviceCount NOTIFY participantDeviceCountChanged) Q_PROPERTY(ParticipantDeviceGui *activeSpeaker READ getActiveSpeakerGui NOTIFY activeSpeakerChanged) Q_PROPERTY(ParticipantGui *me READ getMeGui) diff --git a/Linphone/core/conference/ConferenceInfoCore.hpp b/Linphone/core/conference/ConferenceInfoCore.hpp index 2212a3d2f..9a9121b68 100644 --- a/Linphone/core/conference/ConferenceInfoCore.hpp +++ b/Linphone/core/conference/ConferenceInfoCore.hpp @@ -44,6 +44,7 @@ public: 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(QString startEndDateString READ getStartEndDateString NOTIFY dateTimeChanged) Q_PROPERTY(int duration READ getDuration WRITE setDuration NOTIFY durationChanged) Q_PROPERTY( QString organizerAddress READ getOrganizerAddress WRITE setOrganizerAddress NOTIFY organizerAddressChanged) diff --git a/Linphone/core/conference/ConferenceInfoProxy.cpp b/Linphone/core/conference/ConferenceInfoProxy.cpp index 3353b6e92..cbad20a4b 100644 --- a/Linphone/core/conference/ConferenceInfoProxy.cpp +++ b/Linphone/core/conference/ConferenceInfoProxy.cpp @@ -83,7 +83,7 @@ bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sou return res; } else return mFilterType == -1; } else { - return !mList->haveCurrentDate(); + return !mList->haveCurrentDate() && + mList->getCount() > 1; // if mlist count == 1 there is only the dummy row which we don't display alone } - return false; } \ No newline at end of file diff --git a/Linphone/data/image/arrows-merge.svg b/Linphone/data/image/arrows-merge.svg new file mode 100644 index 000000000..de0f25b86 --- /dev/null +++ b/Linphone/data/image/arrows-merge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/chat-teardrop-slash.svg b/Linphone/data/image/chat-teardrop-slash.svg new file mode 100644 index 000000000..9a0498463 --- /dev/null +++ b/Linphone/data/image/chat-teardrop-slash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/lock-simple.svg b/Linphone/data/image/lock-simple.svg new file mode 100644 index 000000000..0fc6a8a6e --- /dev/null +++ b/Linphone/data/image/lock-simple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/monitor-arrow-up.svg b/Linphone/data/image/monitor-arrow-up.svg new file mode 100644 index 000000000..913ab4917 --- /dev/null +++ b/Linphone/data/image/monitor-arrow-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/model/call/CallModel.cpp b/Linphone/model/call/CallModel.cpp index 7b65ea93f..93b34bd8b 100644 --- a/Linphone/model/call/CallModel.cpp +++ b/Linphone/model/call/CallModel.cpp @@ -204,7 +204,6 @@ void CallModel::setSpeakerVolumeGain(float gain) { float CallModel::getSpeakerVolumeGain() const { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto gain = mMonitor->getSpeakerVolumeGain(); - if (gain < 0) gain = CoreModel::getInstance()->getCore()->getPlaybackGainDb(); return gain; } diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index cecc4f069..4c194763a 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -99,6 +99,7 @@ void Utils::createCall(const QString &sipAddress, QVariantMap options, const QString &prepareTransfertAddress, const QHash &headers) { + lDebug() << "[Utils] create call with uri :" << sipAddress; App::postModelAsync([sipAddress, options, prepareTransfertAddress, headers]() { QString errorMessage; bool success = ToolModel::createCall(sipAddress, options, prepareTransfertAddress, headers, @@ -352,8 +353,16 @@ int Utils::getRandomIndex(int size) { return QRandomGenerator::global()->bounded(size); } -void Utils::copyToClipboard(const QString &text) { - QApplication::clipboard()->setText(text); +bool Utils::copyToClipboard(const QString &text) { + QClipboard *clipboard = QApplication::clipboard(); + clipboard->clear(); + clipboard->setText(text); + + QString clipboardText = clipboard->text(); + if (clipboardText.isEmpty()) { + lDebug() << "[Utils] Clipboard is empty!"; + } + return !clipboardText.isEmpty(); } QString Utils::getApplicationProduct() { diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index b35b01e48..8455d4510 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -69,7 +69,7 @@ public: const QString &description, bool isSuccess = true, QQuickWindow *window = nullptr); - Q_INVOKABLE static QQuickWindow *getCallsWindow(CallGui *callGui); + Q_INVOKABLE static QQuickWindow *getCallsWindow(CallGui *callGui = nullptr); Q_INVOKABLE static void closeCallsWindow(); Q_INVOKABLE static VariantObject *haveAccount(); Q_INVOKABLE static void smartShowWindow(QQuickWindow *window); @@ -80,7 +80,7 @@ public: Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date); 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); + Q_INVOKABLE static bool copyToClipboard(const QString &text); 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); diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index 249541574..4540cb8a9 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -15,66 +15,25 @@ AppWindow { // modality: Qt.WindowModal property CallGui call - property ConferenceInfoGui conferenceInfo property ConferenceGui conference: call && call.core.conference || null property int conferenceLayout: call && call.core.conferenceVideoLayout || 0 property bool callTerminatedByUser: false - + property var callState: call && call.core.state + property var transferState: call && call.core.transferState + onCallChanged: { // if conference, the main item is only // displayed when state is connected - if (call && middleItemStackView.currentItem != inCallItem - && (!conferenceInfo || conference) ) + if (call && middleItemStackView.currentItem != inCallItem && conference) middleItemStackView.replace(inCallItem) } - function joinConference(options) { - if (!conferenceInfo || conferenceInfo.core.uri.length === 0) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence n'a pas pu démarrer en raison d'une erreur d'uri."), mainWindow) - else { - UtilsCpp.createCall(conferenceInfo.core.uri, options) - } - } - - function shareInvitation() { - UtilsCpp.copyToClipboard(conference.core.uri) - showInformationPopup(qsTr("Copié"), qsTr("Le lien de la réunion a été copié dans le presse-papier"), true) - } - - function changeLayout(layoutIndex) { - if (layoutIndex == 0) { - console.log("Set Grid layout") - call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.Grid) - } else if (layoutIndex == 1) { - console.log("Set AS layout") - call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.ActiveSpeaker) - } else { - console.log("Set audio-only layout") - call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.AudioOnly) - } - } - - Connections { - enabled: !!call - target: call && call.core - onRemoteVideoEnabledChanged: console.log("remote video enabled", call.core.remoteVideoEnabled) - onSecurityUpdated: { - if (call.core.isSecured) { - zrtpValidation.close() - } - else if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) { - zrtpValidation.open() - // mainWindow.attachVirtualWindow(Utils.buildLinphoneDialogUri('ZrtpTokenAuthenticationDialog'), {call:callModel}) - } - } - } - - property var callState: call && call.core.state onCallStateChanged: { if (callState === LinphoneEnums.CallState.Connected) { - if (conferenceInfo && middleItemStackView.currentItem != inCallItem) { + if (middleItemStackView.currentItem != inCallItem) { middleItemStackView.replace(inCallItem) bottomButtonsLayout.visible = true } @@ -86,7 +45,6 @@ AppWindow { callEnded(call) } } - property var transferState: call && call.core.transferState onTransferStateChanged: { console.log("Transfer state:", transferState) if (transferState === LinphoneEnums.CallState.Error) { @@ -106,12 +64,17 @@ AppWindow { } } - Timer { - id: autoCloseWindow - interval: 2000 - onTriggered: { - UtilsCpp.closeCallsWindow() - } + function changeLayout(layoutIndex) { + if (layoutIndex == 0) { + console.log("Set Grid layout") + call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.Grid) + } else if (layoutIndex == 1) { + console.log("Set AS layout") + call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.ActiveSpeaker) + } else { + console.log("Set audio-only layout") + call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.AudioOnly) + } } function endCall(callToFinish) { @@ -119,7 +82,7 @@ AppWindow { } function callEnded(call){ if (!callsModel.haveCall) { - if (call.core.conference) UtilsCpp.closeCallsWindow() + if (call && call.core.conference) UtilsCpp.closeCallsWindow() else { bottomButtonsLayout.setButtonsEnabled(false) autoCloseWindow.restart() @@ -129,6 +92,50 @@ AppWindow { } } + signal setUpConferenceRequested(ConferenceInfoGui conferenceInfo) + function setupConference(conferenceInfo) { + middleItemStackView.replace(waitingRoom) + setUpConferenceRequested(conferenceInfo) + } + + function joinConference(uri, options) { + if (uri.length === 0) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence n'a pas pu démarrer en raison d'une erreur d'uri."), mainWindow) + else { + UtilsCpp.createCall(uri, options) + } + } + function cancelJoinConference() { + if (!callsModel.haveCall) { + UtilsCpp.closeCallsWindow() + } else { + mainWindow.call = callsModel.currentCall + } + middleItemStackView.replace(inCallItem) + } + + Connections { + enabled: !!call + target: call && call.core + onRemoteVideoEnabledChanged: console.log("remote video enabled", call.core.remoteVideoEnabled) + onSecurityUpdated: { + if (call.core.isSecured) { + zrtpValidation.close() + } + else if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) { + zrtpValidation.open() + // mainWindow.attachVirtualWindow(Utils.buildLinphoneDialogUri('ZrtpTokenAuthenticationDialog'), {call:callModel}) + } + } + } + + Timer { + id: autoCloseWindow + interval: 2000 + onTriggered: { + UtilsCpp.closeCallsWindow() + } + } + Dialog { id: terminateAllCallsDialog onAccepted: call.core.lTerminateAllCalls() @@ -250,128 +257,144 @@ AppWindow { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter spacing: 10 * DefaultStyle.dp - EffectImage { - id: callStatusIcon - Layout.preferredWidth: 30 * DefaultStyle.dp - Layout.preferredHeight: 30 * DefaultStyle.dp - // TODO : change with broadcast or meeting icon when available - imageSource: !mainWindow.call - ? AppIcons.meeting - : (mainWindow.callState === LinphoneEnums.CallState.End - || mainWindow.callState === LinphoneEnums.CallState.Released) - ? AppIcons.endCall - : (mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) - ? AppIcons.pause - : mainWindow.conferenceInfo - ? AppIcons.usersThree - : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing - ? AppIcons.arrowUpRight - : AppIcons.arrowDownLeft - colorizationColor: !mainWindow.call || mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote || mainWindow.callState === LinphoneEnums.CallState.End - || mainWindow.callState === LinphoneEnums.CallState.Released || mainWindow.conferenceInfo - ? DefaultStyle.danger_500main - : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing - ? DefaultStyle.info_500_main - : DefaultStyle.success_500main - } - Text { - id: callStatusText - text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) - ? qsTr("End of the call") - : (mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) - ? qsTr("Appel mis en pause") - : mainWindow.conferenceInfo - ? mainWindow.conferenceInfo.core.subject - : mainWindow.call - ? EnumsToStringCpp.dirToString(mainWindow.call.core.dir) + qsTr(" call") - : "" - color: DefaultStyle.grey_0 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp + ColumnLayout { + RowLayout { + spacing: 10 * DefaultStyle.dp + EffectImage { + id: callStatusIcon + Layout.preferredWidth: 30 * DefaultStyle.dp + Layout.preferredHeight: 30 * DefaultStyle.dp + // TODO : change with broadcast or meeting icon when available + imageSource: !mainWindow.call + ? AppIcons.meeting + : (mainWindow.callState === LinphoneEnums.CallState.End + || mainWindow.callState === LinphoneEnums.CallState.Released) + ? AppIcons.endCall + : (mainWindow.callState === LinphoneEnums.CallState.Paused + || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) + ? AppIcons.pause + : mainWindow.conference + ? AppIcons.usersThree + : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing + ? AppIcons.arrowUpRight + : AppIcons.arrowDownLeft + colorizationColor: !mainWindow.call || mainWindow.callState === LinphoneEnums.CallState.Paused + || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote || mainWindow.callState === LinphoneEnums.CallState.End + || mainWindow.callState === LinphoneEnums.CallState.Released || mainWindow.conference + ? DefaultStyle.danger_500main + : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing + ? DefaultStyle.info_500_main + : DefaultStyle.success_500main + } + Text { + id: callStatusText + text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) + ? qsTr("End of the call") + : (mainWindow.callState === LinphoneEnums.CallState.Paused + || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) + ? (mainWindow.conference ? qsTr('Réunion mise ') : qsTr('Appel mis')) + qsTr(" en pause") + : mainWindow.conference + ? mainWindow.conference.core.subject + : mainWindow.call + ? EnumsToStringCpp.dirToString(mainWindow.call.core.dir) + qsTr(" call") + : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 22 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + Rectangle { + visible: mainWindow.call && (mainWindow.callState === LinphoneEnums.CallState.Connected + || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) + Layout.preferredHeight: parent.height + Layout.preferredWidth: 2 * DefaultStyle.dp + color: DefaultStyle.grey_0 + } + Text { + text: mainWindow.call ? UtilsCpp.formatElapsedTime(mainWindow.call.core.duration) : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 22 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + visible: mainWindow.callState === LinphoneEnums.CallState.Connected + || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning + } + Text { + Layout.leftMargin: 14 * DefaultStyle.dp + id: conferenceDate + text: mainWindow.conferenceInfo ? mainWindow.conferenceInfo.core.getStartEndDateString() : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + capitalization: Font.Capitalize + } + } } - } - Rectangle { - visible: mainWindow.call && (mainWindow.callState === LinphoneEnums.CallState.Connected - || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) - Layout.preferredHeight: parent.height - Layout.preferredWidth: 2 * DefaultStyle.dp - } - Text { - text: mainWindow.call ? UtilsCpp.formatElapsedTime(mainWindow.call.core.duration) : "" - color: DefaultStyle.grey_0 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - visible: mainWindow.callState === LinphoneEnums.CallState.Connected - || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - } - Text { - text: mainWindow.conferenceInfo ? mainWindow.conferenceInfo.core.getStartEndDateString() : "" - color: DefaultStyle.grey_0 - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp + RowLayout { + spacing: 5 * DefaultStyle.dp + visible: mainWindow.call && mainWindow.call.core.isSecured + EffectImage { + Layout.preferredWidth: 15 * DefaultStyle.dp + Layout.preferredHeight: 15 * DefaultStyle.dp + colorizationColor: DefaultStyle.info_500_main + imageSource: AppIcons.lockSimple + } + Text { + text: qsTr("Appel chiffré de bout en bout") + color: DefaultStyle.info_500_main + font { + pixelSize: 12 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + Item { + Layout.fillWidth: true + } } } Item { Layout.fillWidth: true } - RowLayout { - visible: mainWindow.call && (mainWindow.call.core.recording || mainWindow.call.core.remoteRecording) - spacing: 0 - Text { - color: DefaultStyle.danger_500main - font.pixelSize: 14 * DefaultStyle.dp - text: mainWindow.call - ? mainWindow.call.core.recording - ? qsTr("Vous enregistrez l'appel") - : qsTr("Votre correspondant enregistre l'appel") - : "" - } + Item { + //TODO : network quality display + } + } + + Control.Control { + visible: mainWindow.call && (mainWindow.call.core.recording || mainWindow.call.core.remoteRecording) + width: 563 * DefaultStyle.dp + height: 45 * DefaultStyle.dp + anchors.centerIn: parent + leftPadding: 15 * DefaultStyle.dp + rightPadding: 14 * DefaultStyle.dp + background: Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_500 + radius: 10 * DefaultStyle.dp + } + contentItem: RowLayout { EffectImage { imageSource: AppIcons.recordFill colorizationColor: DefaultStyle.danger_500main Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp } - } - } - - Control.Control { - visible: mainWindow.call && mainWindow.call.core.isSecured - anchors.centerIn: parent - topPadding: 8 * DefaultStyle.dp - bottomPadding: 8 * DefaultStyle.dp - leftPadding: 10 * DefaultStyle.dp - rightPadding: 10 * DefaultStyle.dp - width: 269 * DefaultStyle.dp - background: Rectangle { - anchors.fill: parent - border.color: DefaultStyle.info_500_main - radius: 15 * DefaultStyle.dp - } - contentItem: RowLayout { - spacing: 0 - Image { - source: AppIcons.trusted - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - sourceSize.width: 24 * DefaultStyle.dp - sourceSize.height: 24 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - } Text { - text: "This call is completely secured" - color: DefaultStyle.info_500_main - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } + color: DefaultStyle.danger_500main + font.pixelSize: 14 * DefaultStyle.dp + text: mainWindow.call + ? mainWindow.call.core.recording + ? mainWindow.conference ? qsTr("Vous enregistrez la réunion") : qsTr("Vous enregistrez l'appel") + : mainWindow.conference ? qsTr("Un participant enregistre la réunion") : qsTr("Votre correspondant enregistre l'appel") + : "" + } + Button { + visible: mainWindow.call.core.recording + text: qsTr("Arrêter l'enregistrement") + onPressed: mainWindow.call.core.lStopRecording() } } } @@ -379,10 +402,11 @@ AppWindow { RowLayout { Layout.fillWidth: true Layout.fillHeight: true - spacing: 0 + spacing: 23 * DefaultStyle.dp + Layout.rightMargin: 20 * DefaultStyle.dp Control.StackView { id: middleItemStackView - initialItem: mainWindow.call ? inCallItem : waitingRoom + initialItem: inCallItem Layout.fillWidth: true Layout.fillHeight: true @@ -392,7 +416,6 @@ AppWindow { Layout.fillHeight: true Layout.preferredWidth: 393 * DefaultStyle.dp Layout.topMargin: 10 * DefaultStyle.dp - Layout.rightMargin: 20 * DefaultStyle.dp // !! Design model is inconsistent property int currentIndex: 0 visible: false function replace(id) { @@ -405,13 +428,19 @@ AppWindow { } Component { id: contactsListPanel - CallContactsLists { + Item { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Transfert d'appel") - groupCallVisible: false - searchBarColor: DefaultStyle.grey_0 - searchBarBorderColor: DefaultStyle.grey_200 - onCallButtonPressed: (address) => { - mainWindow.call.core.lTransferCall(address) + CallContactsLists { + anchors.fill: parent + anchors.topMargin: 21 * DefaultStyle.dp + anchors.leftMargin: 16 * DefaultStyle.dp + anchors.rightMargin: 16 * DefaultStyle.dp + groupCallVisible: false + searchBarColor: DefaultStyle.grey_0 + searchBarBorderColor: DefaultStyle.grey_200 + onCallButtonPressed: (address) => { + mainWindow.call.core.lTransferCall(address) + } } } } @@ -437,16 +466,21 @@ AppWindow { numericPadButton.visible: false } Item { - Layout.fillWidth: true + Layout.preferredWidth: parent.width Layout.preferredHeight: numPad.height Layout.topMargin: 10 * DefaultStyle.dp NumericPad { id: numPad width: parent.width - visible: parent.visible closeButtonVisible: false + roundedBottom: true + visible: parent.visible + leftPadding: 40 * DefaultStyle.dp + rightPadding: 40 * DefaultStyle.dp + topPadding: 41 * DefaultStyle.dp + bottomPadding: 18 * DefaultStyle.dp onLaunchCall: { - UtilsCpp.createCall(dialerTextInput.text + "@sip.linphone.org") + UtilsCpp.createCall(dialerTextInput.text) } } } @@ -454,62 +488,69 @@ AppWindow { } Component { id: changeLayoutPanel - ColumnLayout { + Item { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Modifier la disposition") - spacing: 12 * DefaultStyle.dp - Text { - Layout.fillWidth: true - text: qsTr("La disposition choisie sera enregistrée pour vos prochaines réunions") - font.pixelSize: 14 * DefaultStyle.dp - color: DefaultStyle.main2_500main - } - RoundedBackgroundControl { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - Repeater { - model: [ - {text: qsTr("Mosaïque"), imgUrl: AppIcons.squaresFour}, - {text: qsTr("Intervenant actif"), imgUrl: AppIcons.pip}, - {text: qsTr("Audio seulement"), imgUrl: AppIcons.waveform} - ] - RadioButton { - id: radiobutton - checkOnClick: false - color: DefaultStyle.main1_500_main - indicatorSize: 20 * DefaultStyle.dp - leftPadding: indicator.width + spacing - spacing: 8 * DefaultStyle.dp - checkable: false // Qt Documentation is wrong: It is true by default. We don't want to change the checked state if the layout change is not effective. - checked: index == 0 - ? mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.Grid - : index == 1 - ? mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.ActiveSpeaker - : mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.AudioOnly - onClicked: mainWindow.changeLayout(index) + ColumnLayout { + anchors.fill: parent + anchors.topMargin: 16 * DefaultStyle.dp + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + spacing: 12 * DefaultStyle.dp + Text { + Layout.fillWidth: true + text: qsTr("La disposition choisie sera enregistrée pour vos prochaines réunions") + font.pixelSize: 14 * DefaultStyle.dp + color: DefaultStyle.main2_500main + } + RoundedBackgroundControl { + Layout.fillWidth: true + contentItem: ColumnLayout { + spacing: 0 + Repeater { + model: [ + {text: qsTr("Mosaïque"), imgUrl: AppIcons.squaresFour}, + {text: qsTr("Intervenant actif"), imgUrl: AppIcons.pip}, + {text: qsTr("Audio seulement"), imgUrl: AppIcons.waveform} + ] + RadioButton { + id: radiobutton + checkOnClick: false + color: DefaultStyle.main1_500_main + indicatorSize: 20 * DefaultStyle.dp + leftPadding: indicator.width + spacing + spacing: 8 * DefaultStyle.dp + checkable: false // Qt Documentation is wrong: It is true by default. We don't want to change the checked state if the layout change is not effective. + checked: index == 0 + ? mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.Grid + : index == 1 + ? mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.ActiveSpeaker + : mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.AudioOnly + onClicked: mainWindow.changeLayout(index) - contentItem: RowLayout { - spacing: 5 * DefaultStyle.dp - EffectImage { - id: radioButtonImg - Layout.preferredWidth: 32 * DefaultStyle.dp - Layout.preferredHeight: 32 * DefaultStyle.dp - imageSource: modelData.imgUrl - colorizationColor: DefaultStyle.main2_500main - } - Text { - text: modelData.text - color: DefaultStyle.main2_500main - verticalAlignment: Text.AlignVCenter - font.pixelSize: 14 * DefaultStyle.dp - Layout.fillWidth: true + contentItem: RowLayout { + spacing: 5 * DefaultStyle.dp + EffectImage { + id: radioButtonImg + Layout.preferredWidth: 32 * DefaultStyle.dp + Layout.preferredHeight: 32 * DefaultStyle.dp + imageSource: modelData.imgUrl + colorizationColor: DefaultStyle.main2_500main + } + Text { + text: modelData.text + color: DefaultStyle.main2_500main + verticalAlignment: Text.AlignVCenter + font.pixelSize: 14 * DefaultStyle.dp + Layout.fillWidth: true + } } } } } } + Item {Layout.fillHeight: true} } - Item {Layout.fillHeight: true} } } Component { @@ -521,10 +562,15 @@ AppWindow { Layout.fillWidth: true Layout.maximumHeight: rightPanel.height visible: callList.contentHeight > 0 - leftPadding: 17 * DefaultStyle.dp - rightPadding: 17 * DefaultStyle.dp - topPadding: 16 * DefaultStyle.dp + leftPadding: 16 * DefaultStyle.dp + rightPadding: 16 * DefaultStyle.dp + topPadding: 15 * DefaultStyle.dp bottomPadding: 16 * DefaultStyle.dp + + Layout.topMargin: 15 * DefaultStyle.dp + Layout.bottomMargin: 16 * DefaultStyle.dp + Layout.leftMargin: 16 * DefaultStyle.dp + Layout.rightMargin: 16 * DefaultStyle.dp contentItem: ListView { id: callList @@ -565,9 +611,11 @@ AppWindow { Text { id: callStateText Layout.rightMargin: 2 * DefaultStyle.dp - text: modelData.core.state === LinphoneEnums.CallState.Paused + property string type: modelData.core.isConference ? qsTr('Réunion') : qsTr('Appel') + text: modelData.core.state === LinphoneEnums.CallState.Paused || modelData.core.state === LinphoneEnums.CallState.PausedByRemote - ? qsTr("Appel en pause") : qsTr("Appel en cours") + ? type + qsTr(" en pause") + : type + qsTr(" en cours") } PopupButton { id: listCallOptionsButton @@ -579,7 +627,7 @@ AppWindow { Button { background: Item {} contentItem: RowLayout { - spacing: 0 + spacing: 5 * DefaultStyle.dp Image { source: modelData.core.state === LinphoneEnums.CallState.Paused || modelData.core.state === LinphoneEnums.CallState.PausedByRemote @@ -595,11 +643,6 @@ AppWindow { || modelData.core.state === LinphoneEnums.CallState.PausedByRemote ? qsTr("Reprendre l'appel") : qsTr("Mettre en pause") color: DefaultStyle.main2_500main - Layout.preferredWidth: metrics.width - } - TextMetrics { - id: metrics - text: qsTr("Reprendre l'appel") } Item { Layout.fillWidth: true @@ -610,7 +653,7 @@ AppWindow { Button { background: Item {} contentItem: RowLayout { - spacing: 0 + spacing: 5 * DefaultStyle.dp EffectImage { imageSource: AppIcons.endCall colorizationColor: DefaultStyle.danger_500main @@ -640,103 +683,120 @@ AppWindow { } Component { id: settingsPanel - InCallSettingsPanel { + Item { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Paramètres") - call: mainWindow.call + InCallSettingsPanel { + anchors.fill: parent + call: mainWindow.call + anchors.topMargin: 16 * DefaultStyle.dp + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + } } } Component { id: screencastPanel - ScreencastPanel { - call: mainWindow.call + Item { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Partage de votre écran") + ScreencastPanel { + anchors.topMargin: 16 * DefaultStyle.dp + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + call: mainWindow.call + } } } Component { id: participantListPanel - Control.StackView { - id: participantsStack - initialItem: participantListComp - // Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count) - onCurrentItemChanged: rightPanel.headerStack.currentIndex = currentItem.Control.StackView.index - property list selectedParticipants - signal participantAdded() + Item { + Control.StackView { + id: participantsStack + anchors.fill: parent + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + initialItem: participantListComp + onCurrentItemChanged: rightPanel.headerStack.currentIndex = currentItem.Control.StackView.index + property list selectedParticipants + signal participantAdded() - Connections { - target: rightPanel - onReturnRequested: participantsStack.pop() - } + Connections { + target: rightPanel + onReturnRequested: participantsStack.pop() + } - Component { - id: participantListComp - ParticipantListView { - id: participantList - Component { - id: headerbutton - PopupButton { - popup.contentItem: Button { - background: Item{} - contentItem: RowLayout { - spacing: 0 - EffectImage { - colorizationColor: DefaultStyle.main2_600 - imageSource: AppIcons.shareNetwork - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp + Component { + id: participantListComp + ParticipantListView { + id: participantList + Component { + id: headerbutton + PopupButton { + popup.contentItem: Button { + background: Item{} + contentItem: RowLayout { + spacing: 0 + EffectImage { + colorizationColor: DefaultStyle.main2_600 + imageSource: AppIcons.shareNetwork + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + } + Text { + text: qsTr("Partager le lien de la réunion") + font.pixelSize: 14 * DefaultStyle.dp + } } - Text { - text: qsTr("Partager le lien de la réunion") - font.pixelSize: 14 * DefaultStyle.dp + onClicked: { + UtilsCpp.copyToClipboard(mainWindow.conference.core.uri) + showInformationPopup(qsTr("Copié"), qsTr("Le lien de la réunion a été copié dans le presse-papier"), true) } } - onClicked: { - mainItem.shareInvitation() - } } } - } - Control.StackView.onActivated: { - rightPanel.customHeaderButtons = headerbutton.createObject(rightPanel) - } - call: mainWindow.call - onAddParticipantRequested: participantsStack.push(addParticipantComp) - onCountChanged: if (participantsStack.Control.StackView.status === Control.StackView.Active && participantsStack.currentItem == participantList) { - rightPanel.headerTitleText = qsTr("Participants (%1)").arg(count) - } - Connections { - target: participantsStack - onCurrentItemChanged: { - if (participantsStack.currentItem == participantList) rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count) + Control.StackView.onActivated: { + rightPanel.customHeaderButtons = headerbutton.createObject(rightPanel) } - } - Connections { - target: rightPanel - onValidateRequested: { - participantList.model.addAddresses(participantsStack.selectedParticipants) - participantsStack.pop() - participantsStack.participantAdded() + call: mainWindow.call + onAddParticipantRequested: participantsStack.push(addParticipantComp) + onCountChanged: if (participantsStack.Control.StackView.status === Control.StackView.Active && participantsStack.currentItem == participantListComp) { + rightPanel.headerTitleText = qsTr("Participants (%1)").arg(count) + } + Connections { + target: participantsStack + onCurrentItemChanged: { + if (participantsStack.currentItem == participantList) rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count) + } + } + Connections { + target: rightPanel + onValidateRequested: { + participantList.model.addAddresses(participantsStack.selectedParticipants) + participantsStack.pop() + participantsStack.participantAdded() + } } } } - } - Component { - id: addParticipantComp - AddParticipantsLayout { - id: addParticipantLayout - searchBarColor: DefaultStyle.grey_0 - searchBarBorderColor: DefaultStyle.grey_200 - onSelectedParticipantsCountChanged: { - if (participantsStack.Control.StackView.status === Control.StackView.Active && Control.StackView.visible) { - rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné").arg(selectedParticipants.length).arg(selectedParticipants.length > 1 ? "s" : "") + Component { + id: addParticipantComp + AddParticipantsLayout { + id: addParticipantLayout + searchBarColor: DefaultStyle.grey_0 + searchBarBorderColor: DefaultStyle.grey_200 + onSelectedParticipantsCountChanged: { + rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(selectedParticipantsCount).arg(selectedParticipantsCount > 1 ? "s" : "") + participantsStack.selectedParticipants = selectedParticipants } - participantsStack.selectedParticipants = selectedParticipants - } - Connections { - target: participantsStack - onCurrentItemChanged: { - if (participantsStack.currentItem == addParticipantLayout) { - rightPanel.headerTitleText = qsTr("Ajouter des participants") - rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(addParticipantLayout.selectedParticipants.length).arg(addParticipantLayout.selectedParticipants.length > 1 ? "s" : "") + Connections { + target: participantsStack + onCurrentItemChanged: { + if (participantsStack.currentItem == addParticipantLayout) { + rightPanel.headerTitleText = qsTr("Ajouter des participants") + rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(addParticipantLayout.selectedParticipants.length).arg(addParticipantLayout.selectedParticipants.length > 1 ? "s" : "") + } } } } @@ -750,7 +810,6 @@ AppWindow { WaitingRoom { id: waitingRoomIn Layout.alignment: Qt.AlignCenter - conferenceInfo: mainWindow.conferenceInfo onSettingsButtonCheckedChanged: { if (settingsButtonChecked) { rightPanel.visible = true @@ -759,16 +818,46 @@ AppWindow { rightPanel.visible = false } } + Binding { + target: callStatusIcon + when: middleItemStackView.currentItem === waitingRoomIn + property: "imageSource" + value: AppIcons.usersThree + restoreMode: Binding.RestoreBindingOrValue + } + Binding { + target: callStatusText + when: middleItemStackView.currentItem === waitingRoomIn + property: "text" + value: waitingRoomIn.conferenceInfo.core.subject + restoreMode: Binding.RestoreBindingOrValue + } + Binding { + target: conferenceDate + when: middleItemStackView.currentItem === waitingRoomIn + property: "text" + value: waitingRoomIn.conferenceInfo.core.startEndDateString + } Connections { target: rightPanel onVisibleChanged: if (!visible) waitingRoomIn.settingsButtonChecked = false } - onJoinConfRequested: mainWindow.joinConference({'microEnabled':microEnabled, 'localVideoEnabled':localVideoEnabled}) + Connections { + target:mainWindow + onSetUpConferenceRequested: (conferenceInfo) => { + waitingRoomIn.conferenceInfo = conferenceInfo + } + } + onJoinConfRequested: (uri) => { + mainWindow.joinConference(uri, {'microEnabled':microEnabled, 'localVideoEnabled':localVideoEnabled}) + } + onCancelJoiningRequested: mainWindow.cancelJoinConference() } } Component { id: inCallItem Item { + property string objectName: "inCallItem" CallLayout{ anchors.fill: parent anchors.leftMargin: 20 * DefaultStyle.dp @@ -776,7 +865,6 @@ AppWindow { anchors.topMargin: 10 * DefaultStyle.dp call: mainWindow.call callTerminatedByUser: mainWindow.callTerminatedByUser - onShareInvitationRequested: mainWindow.shareInvitation() } } } @@ -784,7 +872,7 @@ AppWindow { id: bottomButtonsLayout Layout.alignment: Qt.AlignHCenter spacing: 58 * DefaultStyle.dp - visible: mainWindow.call && !mainWindow.conferenceInfo + visible: middleItemStackView.currentItem.objectName == "inCallItem" function refreshLayout() { if (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) { @@ -1058,6 +1146,7 @@ AppWindow { icon.source: AppIcons.recordFill icon.width: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp + checked: mainWindow.call && mainWindow.call.core.recording contentImageColor: down ? DefaultStyle.main1_500_main :mainWindow.call && mainWindow.call.core.recording @@ -1070,7 +1159,7 @@ AppWindow { ? DefaultStyle.danger_500main : DefaultStyle.main2_500main Layout.fillWidth: true - onCheckedChanged: { + onToggled: { if (mainWindow.call) if (mainWindow.call.core.recording) mainWindow.call.core.lStopRecording() else mainWindow.call.core.lStartRecording() diff --git a/Linphone/view/Item/Button.qml b/Linphone/view/Item/Button.qml index 4b26cbb2a..29d75040a 100644 --- a/Linphone/view/Item/Button.qml +++ b/Linphone/view/Item/Button.qml @@ -41,8 +41,8 @@ Control.Button { ? inversedColors ? mainItem.pressed ? DefaultStyle.grey_100 - : DefaultStyle.grey_0 - : mainItem.pressed + : mainItem.borderColor + : mainItem.pressed ? mainItem.pressedColor : mainItem.color : mainItem.disabledColor diff --git a/Linphone/view/Item/Call/CallContactsLists.qml b/Linphone/view/Item/Call/CallContactsLists.qml index 36306c494..4c2bd5521 100644 --- a/Linphone/view/Item/Call/CallContactsLists.qml +++ b/Linphone/view/Item/Call/CallContactsLists.qml @@ -125,7 +125,6 @@ Item { Layout.alignment: Qt.AlignTop Layout.fillWidth: true Layout.maximumWidth: mainItem.width - Layout.rightMargin: 39 * DefaultStyle.dp color: mainItem.searchBarColor borderColor: mainItem.searchBarBorderColor placeholderText: qsTr("Rechercher un contact") diff --git a/Linphone/view/Item/Call/InCallSettingsPanel.qml b/Linphone/view/Item/Call/InCallSettingsPanel.qml index 02c2f814b..e16588b17 100644 --- a/Linphone/view/Item/Call/InCallSettingsPanel.qml +++ b/Linphone/view/Item/Call/InCallSettingsPanel.qml @@ -42,6 +42,7 @@ ColumnLayout { } Text { text: qsTr("Haut-parleurs") + font.pixelSize: 14 * DefaultStyle.dp Layout.fillWidth: true } } @@ -80,6 +81,7 @@ ColumnLayout { } Text { text: qsTr("Microphone") + font.pixelSize: 14 * DefaultStyle.dp Layout.fillWidth: true } } @@ -153,6 +155,7 @@ ColumnLayout { } Text { text: qsTr("Caméra") + font.pixelSize: 14 * DefaultStyle.dp Layout.fillWidth: true } } diff --git a/Linphone/view/Item/Call/OngoingCallRightPanel.qml b/Linphone/view/Item/Call/OngoingCallRightPanel.qml index efd3e5aa3..9ee9a14d7 100644 --- a/Linphone/view/Item/Call/OngoingCallRightPanel.qml +++ b/Linphone/view/Item/Call/OngoingCallRightPanel.qml @@ -18,9 +18,7 @@ Control.Page { signal validateRequested() topPadding: 16 * DefaultStyle.dp - bottomPadding: 16 * DefaultStyle.dp - leftPadding: 17 * DefaultStyle.dp - rightPadding: 17 * DefaultStyle.dp + // bottomPadding: 16 * DefaultStyle.dp background: Rectangle { width: mainItem.width @@ -135,7 +133,5 @@ Control.Page { } contentItem: Control.StackView { id: contentStackView - // width: parent.width - // height: parent.height } } diff --git a/Linphone/view/Item/Call/WaitingRoom.qml b/Linphone/view/Item/Call/WaitingRoom.qml index fbba735c1..8a1048a58 100644 --- a/Linphone/view/Item/Call/WaitingRoom.qml +++ b/Linphone/view/Item/Call/WaitingRoom.qml @@ -11,7 +11,8 @@ RowLayout { property bool microEnabled: true property bool settingsButtonChecked: settingsButton.checked property ConferenceInfoGui conferenceInfo - signal joinConfRequested() + signal joinConfRequested(string uri) + signal cancelJoiningRequested() RowLayout { Layout.fillWidth: false Layout.fillHeight: false @@ -114,17 +115,31 @@ RowLayout { } } } - Button { - Layout.preferredWidth: 292 * DefaultStyle.dp - leftPadding: 20 * DefaultStyle.dp - rightPadding: 20 * DefaultStyle.dp - topPadding: 11 * DefaultStyle.dp - bottomPadding: 11 * DefaultStyle.dp - text: qsTr("Join") - onClicked: { - settingsButton.checked = false - stackLayout.currentIndex = 1 - mainItem.joinConfRequested() + ColumnLayout { + spacing: 5 * DefaultStyle.dp + Button { + Layout.preferredWidth: 292 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + text: qsTr("Join") + onClicked: { + settingsButton.checked = false + stackLayout.currentIndex = 1 + mainItem.joinConfRequested(mainItem.conferenceInfo.core.uri) + } + } + Button { + Layout.preferredWidth: 292 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + inversedColors: true + text: qsTr("Cancel") + onClicked: { + mainItem.cancelJoiningRequested() + } } } } diff --git a/Linphone/view/Item/NumericPad.qml b/Linphone/view/Item/NumericPad.qml index 09cf982e9..391e3c5c2 100644 --- a/Linphone/view/Item/NumericPad.qml +++ b/Linphone/view/Item/NumericPad.qml @@ -10,34 +10,37 @@ Control.Popup { signal launchCall() signal wipe() property bool closeButtonVisible: true + property bool roundedBottom: false closePolicy: Control.Popup.CloseOnEscape leftPadding: 72 * DefaultStyle.dp rightPadding: 72 * DefaultStyle.dp topPadding: 41 * DefaultStyle.dp bottomPadding: 18 * DefaultStyle.dp - // topPadding: closeButton.height + 4 * DefaultStyle.dp background: Item { anchors.fill: parent Rectangle { id: numPadBackground - anchors.fill: parent + width: parent.width + height: parent.height color: DefaultStyle.grey_100 radius: 20 * DefaultStyle.dp } MultiEffect { id: effect - anchors.fill: parent + anchors.fill: numPadBackground source: numPadBackground shadowEnabled: true shadowColor: DefaultStyle.grey_1000 shadowOpacity: 0.1 shadowBlur: 1 + z: -1 } Rectangle { width: parent.width height: parent.height / 2 anchors.bottom: parent.bottom color: DefaultStyle.grey_100 + visible: !mainItem.roundedBottom } Button { id: closeButton diff --git a/Linphone/view/Layout/Call/ActiveSpeakerLayout.qml b/Linphone/view/Layout/Call/ActiveSpeakerLayout.qml index 6e5ee04c9..ce848b3a9 100644 --- a/Linphone/view/Layout/Call/ActiveSpeakerLayout.qml +++ b/Linphone/view/Layout/Call/ActiveSpeakerLayout.qml @@ -13,36 +13,116 @@ Item{ id: mainItem property alias call: allDevices.currentCall property ConferenceGui conference: call && call.core.conference || null + property int participantDeviceCount: allDevices.count + onParticipantDeviceCountChanged: { + setUpMainItem() + } property var callState: call && call.core.state || undefined + onCallStateChanged: if (callState === LinphoneEnums.CallState.End || callState === LinphoneEnums.CallState.Released) preview.visible = false property string localAddress: call && call.conference ? call.conference.core.me.core.sipAddress : call.core.localAddress || "" - onLocalAddressChanged: console.log("======== local addr changed", localAddress) + // currently speaking address (for hiding in list view) + property string activeSpeakerAddress + property ParticipantDeviceProxy participantDevices : ParticipantDeviceProxy { id: allDevices qmlName: "AS" onCountChanged: console.log("Device count changed : " +count) Component.onCompleted: console.log("Loaded : " +allDevices) } - onCallStateChanged: if (callState === LinphoneEnums.CallState.End || callState === LinphoneEnums.CallState.Released) preview.visible = false + + Component.onCompleted: setUpMainItem() + onVisibleChanged: if (visible) setUpMainItem() + + function setUpMainItem() { + if (mainItem.conference && mainItem.participantDeviceCount <= 1) { + mainStackView.replace(waitingForOthersComponent) + } else { + mainStackView.replace(activeSpeakerComp) + } + } + RowLayout{ anchors.fill: parent anchors.rightMargin: 10 * DefaultStyle.dp spacing: 16 * DefaultStyle.dp - Sticker { - id: activeSpeakerSticker - previewEnabled: false + Control.StackView { + id: mainStackView + // initialItem: waitingForOthersComponent Layout.fillWidth: true Layout.fillHeight: true - call: mainItem.call - participantDevice: mainItem.conference && mainItem.conference.core.activeSpeaker - property var address: participantDevice && participantDevice.core.address - videoEnabled: (participantDevice && participantDevice.core.videoEnabled) || (!participantDevice && call && call.core.remoteVideoEnabled) - qmlName: 'AS' - displayPresence: false + } + Component { + id: waitingForOthersComponent + Rectangle { + color: DefaultStyle.grey_600 + radius: 15 * DefaultStyle.dp + ColumnLayout { + anchors.centerIn: parent + spacing: 22 * DefaultStyle.dp + width: waitText.implicitWidth + Text { + id: waitText + text: qsTr("Waiting for other participants...") + Layout.preferredHeight: 67 * DefaultStyle.dp + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + color: DefaultStyle.grey_0 + font { + pixelSize: 30 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + } + Item { + Layout.fillWidth: true + Button { + color: "transparent" + borderColor: DefaultStyle.main2_400 + pressedColor: DefaultStyle.main2_500main + icon.source: AppIcons.shareNetwork + contentImageColor: DefaultStyle.main2_400 + text: qsTr("Share invitation") + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + anchors.centerIn: parent + textColor: DefaultStyle.main2_400 + onClicked: { + if (mainItem.conference) { + UtilsCpp.copyToClipboard(mainItem.call.core.peerAddress) + showInformationPopup(qsTr("Copié"), qsTr("Le lien de la réunion a été copié dans le presse-papier"), true) + } + } + } + } + } + } + } + Component { + id: activeSpeakerComp + Sticker { + id: activeSpeakerSticker + previewEnabled: false + call: mainItem.call + width: parent.width + height: parent.height + participantDevice: mainItem.conference && mainItem.conference.core.activeSpeaker + property var address: participantDevice && participantDevice.core.address + videoEnabled: (participantDevice && participantDevice.core.videoEnabled) || (!participantDevice && call && call.core.remoteVideoEnabled) + qmlName: 'AS' + displayPresence: false + Binding { + target: mainItem + property: "activeSpeakerAddress" + value: activeSpeakerSticker.address + when: true + } + } } ListView{ Layout.fillHeight: true @@ -56,7 +136,7 @@ Item{ clip: true delegate: Item{ // Spacing workaround visible: $modelData && mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released - && $modelData.core.address != activeSpeakerSticker.address || false + && $modelData.core.address != activeSpeakerAddress || false height: visible ? (180 + 15) * DefaultStyle.dp : 0 width: 300 * DefaultStyle.dp Sticker { diff --git a/Linphone/view/Layout/Call/CallLayout.qml b/Linphone/view/Layout/Call/CallLayout.qml index cf579f728..9e360d260 100644 --- a/Linphone/view/Layout/Call/CallLayout.qml +++ b/Linphone/view/Layout/Call/CallLayout.qml @@ -16,7 +16,10 @@ Item { property bool callTerminatedByUser: false readonly property var callState: call && call.core.state || undefined property int conferenceLayout: call && call.core.conferenceVideoLayout || 0 - property int participantDeviceCount: conference ? conference.core.participantDeviceCount : -1 + // property int participantDeviceCount: conference ? conference.core.participantDeviceCount : -1 + // onParticipantDeviceCountChanged: { + // setConferenceLayout() + // } Component.onCompleted: setConferenceLayout() onConferenceLayoutChanged: { console.log("CallLayout change : " +conferenceLayout) @@ -25,16 +28,14 @@ Item { onCallStateChanged: { if( callState === LinphoneEnums.CallState.Error) { centerLayout.currentIndex = 1 - } else if( callState === LinphoneEnums.CallState.End) { - callTerminatedText.visible = true - } + } + // else if( callState === LinphoneEnums.CallState.End) { + // callTerminatedText.visible = true + // } } + // onCallChanged: callTerminatedText.visible = false - signal shareInvitationRequested() function setConferenceLayout() { - if (mainItem.participantDeviceCount < 2 ) { - return - } callLayout.sourceComponent = undefined // unload old view before opening the new view to avoid conflicts in Video UI. callLayout.sourceComponent = mainItem.conferenceLayout == LinphoneEnums.ConferenceLayout.ActiveSpeaker ? activeSpeakerComponent @@ -47,7 +48,7 @@ Item { anchors.top: parent.top anchors.topMargin: 25 * DefaultStyle.dp z: 1 - visible: false + visible: callState === LinphoneEnums.CallState.End text: mainItem.conference ? qsTr("Vous avez quitté la conférence") : mainItem.callTerminatedByUser @@ -68,7 +69,7 @@ Item { id: callLayout Layout.Layout.fillWidth: true Layout.Layout.fillHeight: true - sourceComponent: mainItem.conference && mainItem.participantDeviceCount < 2 + sourceComponent: mainItem.participantDeviceCount === 0 ? waitingForOthersComponent : activeSpeakerComponent } @@ -101,50 +102,6 @@ Item { call: mainItem.call } } - Component { - id: waitingForOthersComponent - Rectangle { - color: DefaultStyle.grey_600 - radius: 15 * DefaultStyle.dp - Layout.Layout.fillWidth: true - Layout.Layout.fillHeight: true - Layout.ColumnLayout { - id: waitingForOthersLayout - anchors.centerIn: parent - spacing: 22 * DefaultStyle.dp - Text { - text: qsTr("Waiting for other participants...") - Layout.Layout.preferredHeight: 67 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - horizontalAlignment: Text.AlignHCenter - color: DefaultStyle.grey_0 - font { - pixelSize: 30 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp - } - } - Button { - color: "transparent" - borderColor: DefaultStyle.main2_400 - pressedColor: DefaultStyle.main2_500main - icon.source: AppIcons.shareNetwork - contentImageColor: DefaultStyle.main2_400 - text: qsTr("Share invitation") - topPadding: 11 * DefaultStyle.dp - bottomPadding: 11 * DefaultStyle.dp - leftPadding: 20 * DefaultStyle.dp - rightPadding: 20 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - textColor: DefaultStyle.main2_400 - onClicked: { - if (mainItem.conference) { - mainItem.shareInvitationRequested() - } - } - } - } - } - } } // TODO : waitingForParticipant // ColumnLayout { diff --git a/Linphone/view/Layout/Call/GridLayout.qml b/Linphone/view/Layout/Call/GridLayout.qml index 6d43f02cc..72c4a5be4 100644 --- a/Linphone/view/Layout/Call/GridLayout.qml +++ b/Linphone/view/Layout/Call/GridLayout.qml @@ -23,10 +23,10 @@ Mosaic { Component.onCompleted: console.log("Loaded : " +allDevices + " = " +allDevices.count) } property AccountProxy accounts: AccountProxy{id: accountProxy} - model: grid.call.core.isConference ? participantDevices: [0,1] + model: grid.call && grid.call.core.isConference ? participantDevices: [0,1] delegate: Item{ id: avatarCell - property ParticipantDeviceGui currentDevice: index >= 0 && grid.call.core.isConference ? $modelData : null + property ParticipantDeviceGui currentDevice: index >= 0 && grid.call && grid.call.core.isConference ? $modelData : null 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) } @@ -39,7 +39,7 @@ Mosaic { visible: mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released anchors.fill: parent qmlName: 'G_'+index - call: !grid.call.core.isConference ? grid.call : null + call: grid.call && !grid.call.core.isConference ? grid.call : null account: index == 0 ? accountProxy.findAccountByAddress(mainItem.localAddress) : null displayAll: false bigBottomAddress: true diff --git a/Linphone/view/Layout/Contact/ContactLayout.qml b/Linphone/view/Layout/Contact/ContactLayout.qml index 9014e4ef5..aa091ad37 100644 --- a/Linphone/view/Layout/Contact/ContactLayout.qml +++ b/Linphone/view/Layout/Contact/ContactLayout.qml @@ -10,6 +10,8 @@ ColumnLayout { spacing: 30 * DefaultStyle.dp property FriendGui contact + property ConferenceInfoGui conferenceInfo + property bool isConference: conferenceInfo != undefined && conferenceInfo != null property string contactAddress: contact && contact.core.defaultAddress || "" property string contactName: contact && contact.core.displayName || "" @@ -31,6 +33,7 @@ ColumnLayout { bottomPadding: 16 * DefaultStyle.dp leftPadding: 16 * DefaultStyle.dp rightPadding: 16 * DefaultStyle.dp + contentImageColor: DefaultStyle.main2_600 background: Rectangle { anchors.fill: parent radius: 40 * DefaultStyle.dp @@ -58,7 +61,9 @@ ColumnLayout { width: 100 * DefaultStyle.dp height: 100 * DefaultStyle.dp contact: mainItem.contact || null - address: mainItem.contactAddress || mainItem.contactName + address: mainItem.conferenceInfo + ? mainItem.conferenceInfo.core.subject + : mainItem.contactAddress || mainItem.contactName } Item { id: rightButton @@ -118,7 +123,23 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter Layout.preferredWidth: mainItem.implicitWidth Layout.preferredHeight: childrenRect.height + Button { + visible: mainItem.isConference + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Rejoindre la réunion") + color: DefaultStyle.main2_200 + pressedColor: DefaultStyle.main2_400 + textColor: DefaultStyle.main2_600 + onClicked: { + if (mainItem.conferenceInfo) { + var callsWindow = UtilsCpp.getCallsWindow() + callsWindow.setupConference(mainItem.conferenceInfo) + callsWindow.show() + } + } + } LabelButton { + visible: !mainItem.isConference anchors.left: parent.left width: 56 * DefaultStyle.dp height: 56 * DefaultStyle.dp @@ -131,6 +152,7 @@ ColumnLayout { } } LabelButton { + visible: !mainItem.isConference anchors.horizontalCenter: parent.horizontalCenter width: 56 * DefaultStyle.dp height: 56 * DefaultStyle.dp @@ -141,7 +163,7 @@ ColumnLayout { button.onClicked: console.debug("[CallPage.qml] TODO : open conversation") } LabelButton { - id: videoCall + visible: !mainItem.isConference anchors.right: parent.right width: 56 * DefaultStyle.dp height: 56 * DefaultStyle.dp diff --git a/Linphone/view/Page/Main/CallPage.qml b/Linphone/view/Page/Main/CallPage.qml index 351390551..8c42c06d0 100644 --- a/Linphone/view/Page/Main/CallPage.qml +++ b/Linphone/view/Page/Main/CallPage.qml @@ -49,10 +49,6 @@ AbstractMainPage { listStackView.push(newCallItem) } - function createCall(addr) { - UtilsCpp.createCall(addr) - } - Dialog { id: deleteHistoryPopup width: 278 * DefaultStyle.dp @@ -316,9 +312,13 @@ AbstractMainPage { icon.height: 24 * DefaultStyle.dp onClicked: { if (modelData.core.isConference) { - + var callsWindow = UtilsCpp.getCallsWindow() + callsWindow.setupConference(modelData.core.conferenceInfo) + callsWindow.show() + } + else { + UtilsCpp.createCall(modelData.core.remoteAddress) } - else UtilsCpp.createCall(modelData.core.remoteAddress) } } } @@ -515,7 +515,8 @@ AbstractMainPage { id: contactDetail visible: mainItem.selectedRowHistoryGui != undefined property var contactObj: UtilsCpp.findFriendByAddress(contactAddress) - contact: contactObj && contactObj.value || null + contact: contactObj && contactObj.value || null + conferenceInfo: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.conferenceInfo contactAddress: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress || "" contactName: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.displayName : "" anchors.top: rightPanelStackView.top @@ -546,7 +547,11 @@ AbstractMainPage { text: qsTr("Copier l'adresse SIP") iconSource: AppIcons.copy } - onClicked: UtilsCpp.copyToClipboard(mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress) + onClicked: { + var success = UtilsCpp.copyToClipboard(mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress) + if (success) UtilsCpp.showInformationPopup(qsTr("Copié"), qsTr("L'adresse a été copiée dans le presse-papier"), true) + else UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Erreur lors de la copie de l'adresse"), false) + } } Button { background: Item {} @@ -626,7 +631,7 @@ AbstractMainPage { || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted - ? AppIcons.arrowElbow + ? AppIcons.arrowElbow : modelData.core.isOutgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft diff --git a/Linphone/view/Page/Main/ContactPage.qml b/Linphone/view/Page/Main/ContactPage.qml index 9c6b2086f..1798c0f54 100644 --- a/Linphone/view/Page/Main/ContactPage.qml +++ b/Linphone/view/Page/Main/ContactPage.qml @@ -271,15 +271,13 @@ AbstractMainPage { visible: mainItem.selectedContact != undefined Layout.fillWidth: true Layout.fillHeight: true - Control.StackView.onActivated: - mainItem.leftPanelEnabled = true + Control.StackView.onActivated: mainItem.leftPanelEnabled = true Control.StackView.onDeactivated: mainItem.leftPanelEnabled = false ContactLayout { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.topMargin: 45 * DefaultStyle.dp - Layout.leftMargin: 74 * DefaultStyle.dp contact: mainItem.selectedContact Layout.preferredWidth: 360 * DefaultStyle.dp buttonContent: Button { @@ -296,8 +294,9 @@ AbstractMainPage { Layout.preferredWidth: 360 * DefaultStyle.dp spacing: 32 * DefaultStyle.dp ColumnLayout { - spacing: 15 * DefaultStyle.dp + spacing: 9 * DefaultStyle.dp Text { + Layout.leftMargin: 10 * DefaultStyle.dp text: qsTr("Informations") font { pixelSize: 16 * DefaultStyle.dp @@ -309,27 +308,32 @@ AbstractMainPage { Layout.preferredHeight: Math.min(226 * DefaultStyle.dp, addrList.contentHeight + topPadding + bottomPadding) height: Math.min(226 * DefaultStyle.dp, addrList.contentHeight) Layout.fillWidth: true + topPadding: 12 * DefaultStyle.dp + bottomPadding: 12 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp contentItem: ListView { id: addrList width: 360 * DefaultStyle.dp height: contentHeight clip: true + spacing: 9 * DefaultStyle.dp model: VariantList { model: mainItem.selectedContact ? mainItem.selectedContact.core.allAddresses : [] } delegate: Item { width: addrList.width - height: 70 * DefaultStyle.dp + height: 46 * DefaultStyle.dp ColumnLayout { anchors.fill: parent - anchors.topMargin: 5 * DefaultStyle.dp + // anchors.topMargin: 5 * DefaultStyle.dp RowLayout { Layout.fillWidth: true // Layout.fillHeight: true // Layout.alignment: Qt.AlignVCenter - Layout.topMargin: 10 * DefaultStyle.dp - Layout.bottomMargin: 10 * DefaultStyle.dp + // Layout.topMargin: 10 * DefaultStyle.dp + // Layout.bottomMargin: 10 * DefaultStyle.dp ColumnLayout { Layout.fillWidth: true Text { @@ -384,6 +388,10 @@ AbstractMainPage { RoundedBackgroundControl { visible: companyText.text.length != 0 || jobText.text.length != 0 Layout.fillWidth: true + topPadding: 12 * DefaultStyle.dp + bottomPadding: 12 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp // Layout.fillHeight: true contentItem: ColumnLayout { @@ -462,11 +470,13 @@ AbstractMainPage { } ColumnLayout { spacing: 10 * DefaultStyle.dp + Layout.rightMargin: 90 * DefaultStyle.dp ColumnLayout { visible: false RowLayout { Text { text: qsTr("Confiance") + Layout.leftMargin: 10 * DefaultStyle.dp font { pixelSize: 16 * DefaultStyle.dp weight: 800 * DefaultStyle.dp @@ -482,7 +492,10 @@ AbstractMainPage { } } ColumnLayout { + spacing: 9 * DefaultStyle.dp Text { + Layout.preferredHeight: 22 * DefaultStyle.dp + Layout.leftMargin: 10 * DefaultStyle.dp text: qsTr("Other actions") font { pixelSize: 16 * DefaultStyle.dp diff --git a/Linphone/view/Page/Main/MeetingPage.qml b/Linphone/view/Page/Main/MeetingPage.qml index 18d01785a..c8cd78902 100644 --- a/Linphone/view/Page/Main/MeetingPage.qml +++ b/Linphone/view/Page/Main/MeetingPage.qml @@ -19,6 +19,7 @@ AbstractMainPage { signal returnRequested() signal addParticipantsValidated(list selectedParticipants) Component.onCompleted: rightPanelStackView.push(overridenRightPanel, Control.StackView.Immediate) + showDefaultItem: false//leftPanelStackView.currentItem.objectName === "listLayout" onSelectedConferenceChanged: { overridenRightPanelStackView.clear() @@ -27,15 +28,7 @@ AbstractMainPage { } } - Connections { - target: leftPanelStackView - onCurrentItemChanged: { - mainItem.showDefaultItem = leftPanelStackView.currentItem == listLayout && mainItem.meetingListCount === 0 - } - } - onMeetingListCountChanged: showDefaultItem = leftPanelStackView.currentItem == listLayout && meetingListCount === 0 - - function setUpConference(confInfoGui = null) { + function editConference(confInfoGui = null) { var isCreation = !confInfoGui if (isCreation) { confInfoGui = Qt.createQmlObject('import Linphone @@ -126,13 +119,24 @@ AbstractMainPage { Component { id: listLayout ColumnLayout { + id: listLayoutIn spacing: 0 + property string objectName: "listLayout" Control.StackView.onDeactivated: { mainItem.selectedConference = null + // mainItem.showDefaultItem.visible = false // mainItem.righPanelStackView.clear() } Control.StackView.onActivated: { mainItem.selectedConference = conferenceList.selectedConference + // mainItem.showDefaultItem = conferenceList.count == 0 + } + Binding { + target: mainItem + when: leftPanelStackView.currentItem.objectName === "listLayout" + property: "showDefaultItem" + value: conferenceList.count === 0 + restoreMode: Binding.RestoreBindingOrValue } RowLayout { enabled: mainItem.leftPanelEnabled @@ -155,7 +159,7 @@ AbstractMainPage { icon.width: 28 * DefaultStyle.dp icon.height: 28 * DefaultStyle.dp onClicked: { - mainItem.setUpConference() + mainItem.editConference() } } } @@ -169,6 +173,7 @@ AbstractMainPage { } Text { + Layout.topMargin: 38 * DefaultStyle.dp Layout.fillHeight: true Layout.alignment: Qt.AlignHCenter text: mainItem.emptyListText @@ -193,12 +198,6 @@ AbstractMainPage { onSelectedConferenceChanged: { mainItem.selectedConference = selectedConference } - onCountChanged: { - mainItem.meetingListCount = count - } - Connections { - target: mainItem - } Control.ScrollBar.vertical: ScrollBar { id: meetingsScrollbar anchors.right: parent.right @@ -494,7 +493,7 @@ AbstractMainPage { icon.source: AppIcons.pencil contentImageColor: DefaultStyle.main1_500_main background: Item{} - onClicked: mainItem.setUpConference(mainItem.selectedConference) + onClicked: mainItem.editConference(mainItem.selectedConference) } PopupButton { id: deletePopup @@ -718,7 +717,9 @@ AbstractMainPage { bottomPadding: 11 * DefaultStyle.dp onClicked: { console.log(mainItem.selectedConference.core.uri) - UtilsCpp.setupConference(mainItem.selectedConference) + var callsWindow = UtilsCpp.getCallsWindow() + callsWindow.setupConference(mainItem.selectedConference) + callsWindow.show() } } Item { Layout.fillHeight: true} diff --git a/Linphone/view/Style/AppIcons.qml b/Linphone/view/Style/AppIcons.qml index e3c6a519e..35deb2bd7 100644 --- a/Linphone/view/Style/AppIcons.qml +++ b/Linphone/view/Style/AppIcons.qml @@ -5,6 +5,7 @@ QtObject { property string welcomeLinphoneLogo: "image://internal/linphone.svg" property string welcomeLock: "image://internal/secured.svg" property string lock: "image://internal/lock.svg" + property string lockSimple: "image://internal/lock-simple.svg" property string welcomeOpenSource: "image://internal/open_source.svg" property string eyeHide: "image://internal/eye.svg" property string eyeShow: "image://internal/eye-slash.svg"