From 2770076a44b8a244d89a412c509935a3b9c3fcf3 Mon Sep 17 00:00:00 2001 From: Gaelle Braud Date: Tue, 19 Mar 2024 12:38:59 +0100 Subject: [PATCH] Delete/cancel conference, Conference Info, icons, meeting list, waiting room, settings panel, video device --- Linphone/core/App.cpp | 11 +- Linphone/core/App.hpp | 1 + Linphone/core/conference/ConferenceCore.cpp | 2 +- .../core/conference/ConferenceInfoCore.cpp | 36 +- .../core/conference/ConferenceInfoCore.hpp | 5 +- .../core/conference/ConferenceInfoGui.cpp | 6 +- .../core/conference/ConferenceInfoList.cpp | 1 + .../core/conference/ConferenceInfoProxy.cpp | 1 + .../core/conference/ConferenceInfoProxy.hpp | 1 + Linphone/core/setting/SettingsCore.cpp | 21 + Linphone/core/setting/SettingsCore.hpp | 5 + Linphone/data/image/address-book-fill.svg | 1 + Linphone/data/image/address-book-selected.svg | 17 - Linphone/data/image/arrow-down-left.svg | 3 + Linphone/data/image/arrow-elbow-left.svg | 3 + Linphone/data/image/arrow-up-right.svg | 3 + Linphone/data/image/busy-indicator.svg | 3 + .../data/image/chat-teardrop-text-fill.svg | 1 + .../image/chat-teardrop-text-selected.svg | 17 - Linphone/data/image/incoming_call.svg | 3 - Linphone/data/image/incoming_call_missed.svg | 3 - Linphone/data/image/outgoing_call.svg | 3 - Linphone/data/image/outgoing_call_missed.svg | 3 - Linphone/data/image/phone-fill.svg | 1 + Linphone/data/image/phone-selected.svg | 17 - Linphone/data/image/reunion.svg | 4 + Linphone/data/image/users-three-fill.svg | 1 + Linphone/data/image/users-three-selected.svg | 17 - .../model/conference/ConferenceInfoModel.cpp | 9 + .../model/conference/ConferenceInfoModel.hpp | 3 + Linphone/model/setting/SettingsModel.cpp | 2 +- Linphone/model/setting/SettingsModel.hpp | 2 +- Linphone/tool/Utils.cpp | 49 +- Linphone/tool/Utils.hpp | 10 +- Linphone/view/App/CallsWindow.qml | 681 ++++++++---------- Linphone/view/App/Layout/MainLayout.qml | 136 ++-- Linphone/view/CMakeLists.txt | 3 + Linphone/view/Item/BusyIndicator.qml | 25 +- Linphone/view/Item/Button.qml | 2 +- .../view/Item/Call/InCallSettingsPanel.qml | 169 +++++ .../view/Item/Call/OngoingCallRightPanel.qml | 11 +- Linphone/view/Item/Call/WaitingRoom.qml | 149 ++++ Linphone/view/Item/CheckableButton.qml | 31 + Linphone/view/Item/Dialog.qml | 2 + Linphone/view/Item/Form/LoginForm.qml | 4 +- Linphone/view/Item/Meeting/MeetingList.qml | 5 + Linphone/view/Item/Meeting/MeetingSetUp.qml | 10 +- .../Item/ZrtpTokenAuthenticationDialog.qml | 6 +- Linphone/view/Page/Main/CallPage.qml | 91 ++- Linphone/view/Page/Main/ContactPage.qml | 2 +- Linphone/view/Page/Main/MeetingPage.qml | 209 ++++-- Linphone/view/Style/AppIcons.qml | 20 +- 52 files changed, 1139 insertions(+), 682 deletions(-) create mode 100644 Linphone/data/image/address-book-fill.svg delete mode 100644 Linphone/data/image/address-book-selected.svg create mode 100644 Linphone/data/image/arrow-down-left.svg create mode 100644 Linphone/data/image/arrow-elbow-left.svg create mode 100644 Linphone/data/image/arrow-up-right.svg create mode 100644 Linphone/data/image/busy-indicator.svg create mode 100644 Linphone/data/image/chat-teardrop-text-fill.svg delete mode 100644 Linphone/data/image/chat-teardrop-text-selected.svg delete mode 100644 Linphone/data/image/incoming_call.svg delete mode 100644 Linphone/data/image/incoming_call_missed.svg delete mode 100644 Linphone/data/image/outgoing_call.svg delete mode 100644 Linphone/data/image/outgoing_call_missed.svg create mode 100644 Linphone/data/image/phone-fill.svg delete mode 100644 Linphone/data/image/phone-selected.svg create mode 100644 Linphone/data/image/reunion.svg create mode 100644 Linphone/data/image/users-three-fill.svg delete mode 100644 Linphone/data/image/users-three-selected.svg create mode 100644 Linphone/view/Item/Call/InCallSettingsPanel.qml create mode 100644 Linphone/view/Item/Call/WaitingRoom.qml create mode 100644 Linphone/view/Item/CheckableButton.qml diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index 676e0023d..0c0edce81 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -287,7 +287,10 @@ QQuickWindow *App::getCallsWindow(QVariant callGui) { } qInfo() << log().arg("Subwindow status: `%1`.").arg(component.status()); - QObject *object = component.createWithInitialProperties({{"call", callGui}}); + QObject *object = nullptr; + // if (!callGui.isNull() && callGui.isValid()) object = component.createWithInitialProperties({{"call", + // callGui}}); + object = component.create(); Q_ASSERT(object); if (!object) { qCritical() << log().arg("Calls window could not be created."); @@ -306,10 +309,14 @@ QQuickWindow *App::getCallsWindow(QVariant callGui) { // window->setParent(mMainWindow); mCallsWindow = window; } - mCallsWindow->setProperty("call", callGui); + if (!callGui.isNull() && callGui.isValid()) mCallsWindow->setProperty("call", callGui); return mCallsWindow; } +void App::setCallsWindowProperty(const char *id, QVariant property) { + if (mCallsWindow) mCallsWindow->setProperty(id, property); +} + void App::closeCallsWindow() { if (mCallsWindow) { mCallsWindow->close(); diff --git a/Linphone/core/App.hpp b/Linphone/core/App.hpp index 8e7af8a0c..13675a5d4 100644 --- a/Linphone/core/App.hpp +++ b/Linphone/core/App.hpp @@ -93,6 +93,7 @@ public: void onLoggerInitialized(); QQuickWindow *getCallsWindow(QVariant callGui); + void setCallsWindowProperty(const char *id, QVariant property); void closeCallsWindow(); QQuickWindow *getMainWindow(); diff --git a/Linphone/core/conference/ConferenceCore.cpp b/Linphone/core/conference/ConferenceCore.cpp index 1f37332ed..a2505c56a 100644 --- a/Linphone/core/conference/ConferenceCore.cpp +++ b/Linphone/core/conference/ConferenceCore.cpp @@ -39,7 +39,7 @@ ConferenceCore::ConferenceCore(const std::shared_ptr &conf } ConferenceCore::~ConferenceCore() { mustBeInMainThread("~" + getClassName()); - emit mConferenceModel->removeListener(); + if (mConferenceModel) emit mConferenceModel->removeListener(); } void ConferenceCore::setSelf(QSharedPointer me) { diff --git a/Linphone/core/conference/ConferenceInfoCore.cpp b/Linphone/core/conference/ConferenceInfoCore.cpp index 92f2d3ec1..462011a52 100644 --- a/Linphone/core/conference/ConferenceInfoCore.cpp +++ b/Linphone/core/conference/ConferenceInfoCore.cpp @@ -101,6 +101,7 @@ ConferenceInfoCore::ConferenceInfoCore(std::shared_ptr }); } + connect(this, &ConferenceInfoCore::dateTimeChanged, [this] { setDuration(mDateTime.secsTo(mEndDateTime) / 60.0); }); connect(this, &ConferenceInfoCore::endDateTimeChanged, [this] { setDuration(mDateTime.secsTo(mEndDateTime) / 60.0); }); connect(this, &ConferenceInfoCore::durationChanged, [this] { setEndDateTime(mDateTime.addSecs(mDuration * 60)); }); @@ -168,15 +169,27 @@ void ConferenceInfoCore::setSelf(QSharedPointer me) { setIsEnded(computeIsEnded()); }); }); - mConfInfoModelConnection->makeConnectToCore(&ConferenceInfoCore::lDeleteConferenceInfo, - [this]() { mConferenceInfoModel->deleteConferenceInfo(); }); + mConfInfoModelConnection->makeConnectToCore(&ConferenceInfoCore::lCancelConferenceInfo, [this]() { + mConfInfoModelConnection->invokeToModel([this] { + if (Utils::isMe(mOrganizerAddress)) { + mConferenceInfoModel->cancelConference(); + } + }); + }); + mConfInfoModelConnection->makeConnectToCore(&ConferenceInfoCore::lDeleteConferenceInfo, [this]() { + mConfInfoModelConnection->invokeToModel([this] { mConferenceInfoModel->deleteConferenceInfo(); }); + }); mConfInfoModelConnection->makeConnectToModel(&ConferenceInfoModel::conferenceInfoDeleted, &ConferenceInfoCore::removed); mConfInfoModelConnection->makeConnectToModel( &ConferenceInfoModel::schedulerStateChanged, [this](linphone::ConferenceScheduler::State state) { - mConfInfoModelConnection->invokeToCore( - [this, state = LinphoneEnums::fromLinphone(state)] { setConferenceSchedulerState(state); }); + auto confInfoState = mConferenceInfoModel->getState(); + mConfInfoModelConnection->invokeToCore([this, state = LinphoneEnums::fromLinphone(state), + infoState = LinphoneEnums::fromLinphone(confInfoState)] { + setConferenceSchedulerState(state); + setConferenceInfoState(infoState); + }); }); mConfInfoModelConnection->makeConnectToModel( &ConferenceInfoModel::invitationsSent, @@ -190,7 +203,14 @@ void ConferenceInfoCore::setSelf(QSharedPointer me) { } } -//------------------------------------------------------------------------------------------------ +QString ConferenceInfoCore::getStartEndDateString() { + if (Utils::datesAreEqual(mDateTime.date(), mEndDateTime.date())) { + return QLocale().toString(mDateTime, "ddd d MMM - hh") + "h - " + QLocale().toString(mEndDateTime, "hh") + "h"; + } else { + return QLocale().toString(mDateTime, "ddd d MMM - hh") + "h - " + + QLocale().toString(mEndDateTime, "ddd d MMM - hh") + "h"; + } +} // Note conferenceInfo->getDateTime uses UTC QDateTime ConferenceInfoCore::getDateTimeUtc() const { @@ -492,6 +512,7 @@ void ConferenceInfoCore::save() { mustBeInLinphoneThread(getClassName() + "::save()"); thisCopy->writeIntoModel(mConferenceInfoModel); thisCopy->deleteLater(); + mConferenceInfoModel->updateConferenceInfo(); }); } else { mCoreModelConnection->invokeToModel([this, thisCopy]() { @@ -545,11 +566,6 @@ void ConferenceInfoCore::undo() { } } -void ConferenceInfoCore::cancelConference() { - if (!mConferenceInfoModel) return; - mConferenceInfoModel->cancelConference(); -} - //------------------------------------------------------------------------------------------------- // void ConferenceInfoCore::createConference(const int &securityLevel) { diff --git a/Linphone/core/conference/ConferenceInfoCore.hpp b/Linphone/core/conference/ConferenceInfoCore.hpp index bc28b59e1..7e6fa0731 100644 --- a/Linphone/core/conference/ConferenceInfoCore.hpp +++ b/Linphone/core/conference/ConferenceInfoCore.hpp @@ -96,6 +96,7 @@ public: LinphoneEnums::ConferenceInfoState getConferenceInfoState() const; LinphoneEnums::ConferenceSchedulerState getConferenceSchedulerState() const; // LinphoneEnums::ConferenceSchedulerState getConferenceSchedulerState() const; + QString toStartEndDateString(); void setDateTime(const QDateTime &date); void setEndDateTime(const QDateTime &date); @@ -118,12 +119,12 @@ public: void resetParticipants(QVariantList participants); Q_INVOKABLE void resetParticipants(const QStringList &adresses); Q_INVOKABLE int getParticipantIndex(const QString &address); + Q_INVOKABLE QString getStartEndDateString(); void writeFromModel(const std::shared_ptr &model); void writeIntoModel(std::shared_ptr model); Q_INVOKABLE void save(); - Q_INVOKABLE void cancelConference(); Q_INVOKABLE void undo(); // Tools @@ -158,7 +159,7 @@ signals: void removed(); // void lCreateConference(const int &securityLevel); - // void lCancelConference(); + void lCancelConferenceInfo(); void lDeleteConferenceInfo(); // Remove completly this conference info from DB private: diff --git a/Linphone/core/conference/ConferenceInfoGui.cpp b/Linphone/core/conference/ConferenceInfoGui.cpp index 60c3cf9d3..bb9db2330 100644 --- a/Linphone/core/conference/ConferenceInfoGui.cpp +++ b/Linphone/core/conference/ConferenceInfoGui.cpp @@ -25,13 +25,13 @@ DEFINE_ABSTRACT_OBJECT(ConferenceInfoGui) ConferenceInfoGui::ConferenceInfoGui() { - qDebug() << "[ConferenceInfoGui] new" << this; + // qDebug() << "[ConferenceInfoGui] new" << this; mCore = ConferenceInfoCore::create(nullptr); App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); if (isInLinphoneThread()) moveToThread(App::getInstance()->thread()); } ConferenceInfoGui::ConferenceInfoGui(QSharedPointer core) { - qDebug() << "[ConferenceInfoGui] new" << this; + // qDebug() << "[ConferenceInfoGui] new" << this; App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); mCore = core; if (isInLinphoneThread()) moveToThread(App::getInstance()->thread()); @@ -39,7 +39,7 @@ ConferenceInfoGui::ConferenceInfoGui(QSharedPointer core) { ConferenceInfoGui::~ConferenceInfoGui() { mustBeInMainThread("~" + getClassName()); - qDebug() << "[ConferenceInfoGui] delete" << this; + // qDebug() << "[ConferenceInfoGui] delete" << this; } ConferenceInfoCore *ConferenceInfoGui::getCore() const { diff --git a/Linphone/core/conference/ConferenceInfoList.cpp b/Linphone/core/conference/ConferenceInfoList.cpp index 4ec3a16ae..0292b99c0 100644 --- a/Linphone/core/conference/ConferenceInfoList.cpp +++ b/Linphone/core/conference/ConferenceInfoList.cpp @@ -88,6 +88,7 @@ void ConferenceInfoList::setSelf(QSharedPointer me) { // qWarning() << "No ConferenceInfo have beend found for " << conferenceInfo->getUri()->asString().c_str(); // }); + mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, &ConferenceInfoList::lUpdate); mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceInfoReceived, &ConferenceInfoList::lUpdate); mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceStateChanged, [this] { qDebug() << "list: conf state changed"; diff --git a/Linphone/core/conference/ConferenceInfoProxy.cpp b/Linphone/core/conference/ConferenceInfoProxy.cpp index 24fb6a229..9b5cd0244 100644 --- a/Linphone/core/conference/ConferenceInfoProxy.cpp +++ b/Linphone/core/conference/ConferenceInfoProxy.cpp @@ -29,6 +29,7 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(pare mList = ConferenceInfoList::create(); setSourceModel(mList.get()); connect(this, &ConferenceInfoProxy::searchTextChanged, [this] { invalidate(); }); + connect(this, &ConferenceInfoProxy::lUpdate, mList.get(), &ConferenceInfoList::lUpdate); } ConferenceInfoProxy::~ConferenceInfoProxy() { diff --git a/Linphone/core/conference/ConferenceInfoProxy.hpp b/Linphone/core/conference/ConferenceInfoProxy.hpp index 0ff5b94c2..79df3b025 100644 --- a/Linphone/core/conference/ConferenceInfoProxy.hpp +++ b/Linphone/core/conference/ConferenceInfoProxy.hpp @@ -44,6 +44,7 @@ protected: signals: void searchTextChanged(); + void lUpdate(); private: QString mSearchText; diff --git a/Linphone/core/setting/SettingsCore.cpp b/Linphone/core/setting/SettingsCore.cpp index 27fb6598a..f1032e362 100644 --- a/Linphone/core/setting/SettingsCore.cpp +++ b/Linphone/core/setting/SettingsCore.cpp @@ -71,6 +71,10 @@ void Settings::setSelf(QSharedPointer me) { mSettingsModelConnection->invokeToModel( [this, id]() { mSettingsModel->setVideoDevice(Utils::appStringToCoreString(id)); }); }); + mSettingsModelConnection->makeConnectToModel(&SettingsModel::videoDeviceChanged, [this](const std::string &id) { + mSettingsModelConnection->invokeToModel( + [this, id = Utils::coreStringToAppString(id)]() { setCurrentVideoDevice(id); }); + }); } QString Settings::getConfigPath(const QCommandLineParser &parser) { @@ -97,6 +101,23 @@ QStringList Settings::getVideoDevicesList() const { return mVideoDevices; } +void Settings::setCurrentVideoDevice(const QString &id) { + if (mCurrentVideoDeviceId != id) { + mCurrentVideoDeviceId = id; + emit videoDeviceChanged(); + } +} + +int Settings::getCurrentVideoDeviceIndex() { + auto found = std::find_if(mVideoDevices.begin(), mVideoDevices.end(), + [this](const QString &device) { return mCurrentVideoDeviceId == device; }); + if (found != mVideoDevices.end()) { + auto index = std::distance(mVideoDevices.begin(), found); + return index; + } + return -1; +} + bool Settings::getFirstLaunch() const { auto val = mAppSettings.value("firstLaunch", 1).toInt(); return val; diff --git a/Linphone/core/setting/SettingsCore.hpp b/Linphone/core/setting/SettingsCore.hpp index 9bfaacf6a..6a5a38963 100644 --- a/Linphone/core/setting/SettingsCore.hpp +++ b/Linphone/core/setting/SettingsCore.hpp @@ -34,6 +34,7 @@ class Settings : public QObject, public AbstractObject { Q_PROPERTY(QStringList inputAudioDevicesList READ getInputAudioDevicesList NOTIFY inputAudioDeviceChanged) Q_PROPERTY(QStringList outputAudioDevicesList READ getOutputAudioDevicesList NOTIFY outputAudioDeviceChanged) Q_PROPERTY(QStringList videoDevicesList READ getVideoDevicesList NOTIFY videoDeviceChanged) + Q_PROPERTY(int currentVideoDeviceIndex READ getCurrentVideoDeviceIndex NOTIFY videoDeviceChanged) public: static QSharedPointer create(); Settings(QObject *parent = Q_NULLPTR); @@ -49,6 +50,9 @@ public: QStringList getVideoDevicesList() const; + void setCurrentVideoDevice(const QString &id); + int getCurrentVideoDeviceIndex(); + Q_INVOKABLE void setFirstLaunch(bool first); Q_INVOKABLE bool getFirstLaunch() const; @@ -64,6 +68,7 @@ signals: private: std::shared_ptr mSettingsModel; QStringList mInputAudioDevices; + QString mCurrentVideoDeviceId; QStringList mOutputAudioDevices; QStringList mVideoDevices; QSettings mAppSettings; diff --git a/Linphone/data/image/address-book-fill.svg b/Linphone/data/image/address-book-fill.svg new file mode 100644 index 000000000..1d0283024 --- /dev/null +++ b/Linphone/data/image/address-book-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/address-book-selected.svg b/Linphone/data/image/address-book-selected.svg deleted file mode 100644 index 0d781cc2e..000000000 --- a/Linphone/data/image/address-book-selected.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/Linphone/data/image/arrow-down-left.svg b/Linphone/data/image/arrow-down-left.svg new file mode 100644 index 000000000..fd06d027c --- /dev/null +++ b/Linphone/data/image/arrow-down-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/Linphone/data/image/arrow-elbow-left.svg b/Linphone/data/image/arrow-elbow-left.svg new file mode 100644 index 000000000..a17c241e1 --- /dev/null +++ b/Linphone/data/image/arrow-elbow-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/Linphone/data/image/arrow-up-right.svg b/Linphone/data/image/arrow-up-right.svg new file mode 100644 index 000000000..dff9370d5 --- /dev/null +++ b/Linphone/data/image/arrow-up-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/Linphone/data/image/busy-indicator.svg b/Linphone/data/image/busy-indicator.svg new file mode 100644 index 000000000..ec685503e --- /dev/null +++ b/Linphone/data/image/busy-indicator.svg @@ -0,0 +1,3 @@ + + + diff --git a/Linphone/data/image/chat-teardrop-text-fill.svg b/Linphone/data/image/chat-teardrop-text-fill.svg new file mode 100644 index 000000000..7b9f1701a --- /dev/null +++ b/Linphone/data/image/chat-teardrop-text-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/chat-teardrop-text-selected.svg b/Linphone/data/image/chat-teardrop-text-selected.svg deleted file mode 100644 index 335f55979..000000000 --- a/Linphone/data/image/chat-teardrop-text-selected.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/Linphone/data/image/incoming_call.svg b/Linphone/data/image/incoming_call.svg deleted file mode 100644 index 5dab38385..000000000 --- a/Linphone/data/image/incoming_call.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Linphone/data/image/incoming_call_missed.svg b/Linphone/data/image/incoming_call_missed.svg deleted file mode 100644 index 4faa85b70..000000000 --- a/Linphone/data/image/incoming_call_missed.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Linphone/data/image/outgoing_call.svg b/Linphone/data/image/outgoing_call.svg deleted file mode 100644 index 21bb7c7da..000000000 --- a/Linphone/data/image/outgoing_call.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Linphone/data/image/outgoing_call_missed.svg b/Linphone/data/image/outgoing_call_missed.svg deleted file mode 100644 index a5433e0d3..000000000 --- a/Linphone/data/image/outgoing_call_missed.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Linphone/data/image/phone-fill.svg b/Linphone/data/image/phone-fill.svg new file mode 100644 index 000000000..051617755 --- /dev/null +++ b/Linphone/data/image/phone-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/phone-selected.svg b/Linphone/data/image/phone-selected.svg deleted file mode 100644 index 1865bbd77..000000000 --- a/Linphone/data/image/phone-selected.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/Linphone/data/image/reunion.svg b/Linphone/data/image/reunion.svg new file mode 100644 index 000000000..a6a2ce698 --- /dev/null +++ b/Linphone/data/image/reunion.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Linphone/data/image/users-three-fill.svg b/Linphone/data/image/users-three-fill.svg new file mode 100644 index 000000000..ed26cb757 --- /dev/null +++ b/Linphone/data/image/users-three-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/users-three-selected.svg b/Linphone/data/image/users-three-selected.svg deleted file mode 100644 index 481fb3fa9..000000000 --- a/Linphone/data/image/users-three-selected.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/Linphone/model/conference/ConferenceInfoModel.cpp b/Linphone/model/conference/ConferenceInfoModel.cpp index 3fd52dbe3..4f56edf18 100644 --- a/Linphone/model/conference/ConferenceInfoModel.cpp +++ b/Linphone/model/conference/ConferenceInfoModel.cpp @@ -81,6 +81,10 @@ QString ConferenceInfoModel::getSubject() const { return Utils::coreStringToAppString(mConferenceInfo->getSubject()); } +linphone::ConferenceInfo::State ConferenceInfoModel::getState() const { + return mConferenceInfo->getState(); +} + QString ConferenceInfoModel::getOrganizerName() const { auto organizer = mConferenceInfo->getOrganizer(); auto name = Utils::coreStringToAppString(organizer->getDisplayName()); @@ -142,4 +146,9 @@ void ConferenceInfoModel::deleteConferenceInfo() { void ConferenceInfoModel::cancelConference() { if (!mConferenceSchedulerModel) return; mConferenceSchedulerModel->cancelConference(mConferenceInfo); + emit conferenceInfoCanceled(); +} + +void ConferenceInfoModel::updateConferenceInfo() { + mConferenceSchedulerModel->setInfo(mConferenceInfo); } \ No newline at end of file diff --git a/Linphone/model/conference/ConferenceInfoModel.hpp b/Linphone/model/conference/ConferenceInfoModel.hpp index 9fd2de891..766f47086 100644 --- a/Linphone/model/conference/ConferenceInfoModel.hpp +++ b/Linphone/model/conference/ConferenceInfoModel.hpp @@ -42,6 +42,7 @@ public: int getDuration() const; QDateTime getEndTime() const; QString getSubject() const; + linphone::ConferenceInfo::State getState() const; QString getOrganizerName() const; QString getOrganizerAddress() const; QString getDescription() const; @@ -55,6 +56,7 @@ public: void setParticipantInfos(const std::list> &participantInfos); void deleteConferenceInfo(); void cancelConference(); + void updateConferenceInfo(); signals: void dateTimeChanged(const QDateTime &date); @@ -64,6 +66,7 @@ signals: void descriptionChanged(const QString &description); void participantsChanged(); void conferenceInfoDeleted(); + void conferenceInfoCanceled(); void schedulerStateChanged(linphone::ConferenceScheduler::State state); void infoStateChanged(linphone::ConferenceInfo::State state); void invitationsSent(const std::list> &failedInvitations); diff --git a/Linphone/model/setting/SettingsModel.cpp b/Linphone/model/setting/SettingsModel.cpp index d24dad3a5..0f25bb049 100644 --- a/Linphone/model/setting/SettingsModel.cpp +++ b/Linphone/model/setting/SettingsModel.cpp @@ -57,6 +57,6 @@ void SettingsModel::setVideoDevice(const std::string &id) { auto core = CoreModel::getInstance()->getCore(); if (core->getVideoDevice() != id) { CoreModel::getInstance()->getCore()->setVideoDevice(id); - emit videoDeviceChanged(); + emit videoDeviceChanged(id); } } \ No newline at end of file diff --git a/Linphone/model/setting/SettingsModel.hpp b/Linphone/model/setting/SettingsModel.hpp index c1ba906d7..37e350957 100644 --- a/Linphone/model/setting/SettingsModel.hpp +++ b/Linphone/model/setting/SettingsModel.hpp @@ -49,7 +49,7 @@ public: std::shared_ptr mConfig; signals: - void videoDeviceChanged(); + void videoDeviceChanged(const std::string &id); private: DECLARE_ABSTRACT_OBJECT diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index 6701a1329..62a52b017 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -22,6 +22,8 @@ #include "core/App.hpp" #include "core/call/CallGui.hpp" +#include "core/conference/ConferenceInfoCore.hpp" +#include "core/conference/ConferenceInfoGui.hpp" #include "core/path/Paths.hpp" #include "model/object/VariantObject.hpp" #include "model/tool/ToolModel.hpp" @@ -120,10 +122,26 @@ VariantObject *Utils::createCall(const QString &sipAddress, return data; } +void Utils::setupConference(ConferenceInfoGui *confGui) { + if (!confGui) return; + auto window = App::getInstance()->getCallsWindow(QVariant()); + window->setProperty("conferenceInfo", QVariant::fromValue(confGui)); + window->show(); +} + void Utils::openCallsWindow(CallGui *call) { if (call) App::getInstance()->getCallsWindow(QVariant::fromValue(call))->show(); } +void Utils::setCallsWindowCall(CallGui *call) { + if (call) App::getInstance()->setCallsWindowProperty("call", QVariant::fromValue(call)); +} + +void Utils::setCallsWindowProperty(const QString &id, const QVariant &property) { + const char *idChar = id.toLocal8Bit().data(); + App::getInstance()->setCallsWindowProperty(idChar, property); +} + QQuickWindow *Utils::getCallsWindow(CallGui *callGui) { auto app = App::getInstance(); auto window = app->getCallsWindow(QVariant::fromValue(callGui)); @@ -141,9 +159,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), +void Utils::showInformationPopup(const QString &title, + const QString &description, + bool isSuccess, + QQuickWindow *window) { + if (!window) window = App::getInstance()->getMainWindow(); + QMetaObject::invokeMethod(window, "showInformationPopup", Q_ARG(QVariant, title), Q_ARG(QVariant, description), Q_ARG(QVariant, isSuccess)); } @@ -1173,16 +1194,20 @@ int Utils::getYear(const QDate &date) { } 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; + bool isMe = false; + App::postModelSync([&isMe, 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; + // } + isMe = false; + } else { + auto accountAddr = CoreModel::getInstance()->getCore()->getDefaultAccount()->getContactAddress(); + isMe = linAddr && accountAddr ? accountAddr->weakEqual(linAddr) : false; } - return false; - } else { - auto accountAddr = CoreModel::getInstance()->getCore()->getDefaultAccount()->getContactAddress(); - return linAddr && accountAddr ? accountAddr->weakEqual(linAddr) : false; - } + }); + return isMe; } // QDateTime dateTime(QDateTime::fromString(date, "yyyy-MM-dd hh:mm:ss")); diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index 588729df8..b76b5e705 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -44,6 +44,7 @@ class CallGui; class QQuickWindow; class VariantObject; class CallGui; +class ConferenceInfoGui; class Utils : public QObject { Q_OBJECT @@ -61,9 +62,14 @@ public: const QString &prepareTransfertAddress = "", const QHash &headers = {}); Q_INVOKABLE static void openCallsWindow(CallGui *call); + Q_INVOKABLE static void setupConference(ConferenceInfoGui *confGui); + Q_INVOKABLE static void setCallsWindowCall(CallGui *call); + Q_INVOKABLE static void setCallsWindowProperty(const QString &id, const QVariant &property); Q_INVOKABLE static QQuickWindow *getMainWindow(); - Q_INVOKABLE static void - showInformationPopup(const QString &title, const QString &description, bool isSuccess = true); + Q_INVOKABLE static void showInformationPopup(const QString &title, + const QString &description, + bool isSuccess = true, + QQuickWindow *window = nullptr); Q_INVOKABLE static QQuickWindow *getCallsWindow(CallGui *callGui); Q_INVOKABLE static void closeCallsWindow(); Q_INVOKABLE static VariantObject *haveAccount(); diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index 38e4497d3..2a3101530 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -15,11 +15,30 @@ Window { // modality: Qt.WindowModal property CallGui call + property ConferenceInfoGui conferenceInfo + onConferenceInfoChanged: console.log("CONFERENCE INFO", conferenceInfo) + property ConferenceGui conference: call && call.core.conference || null property bool callTerminatedByUser: false + + onCallChanged: { + console.log("CALL", call) + // if conference, the main item is only + // displayed when state is connected + if (call && !conferenceInfo) middleItemStackView.replace(inCallItem) + } + Component.onCompleted: if (call && !conferenceInfo) middleItemStackView.replace(inCallItem) + + function joinConference(withVideo) { + 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.")) + else { + var callObj = UtilsCpp.createCall(conferenceInfo.core.uri, withVideo) + } + } Connections { - target: call.core + enabled: call != undefined && call != null + target: call && call.core onRemoteVideoEnabledChanged: console.log("remote video enabled", call.core.remoteVideoEnabled) onSecurityUpdated: { if (call.core.isSecured) { @@ -32,16 +51,11 @@ Window { } } - onCallChanged: { - waitingTime.seconds = 0 - waitingTimer.restart() - console.log("call changed", call, waitingTime.seconds) - } - - property var callState: call.core.state + property var callState: call && call.core.state onCallStateChanged: { console.log("State:", callState) if (callState === LinphoneEnums.CallState.Connected) { + if (conferenceInfo) middleItemStackView.replace(inCallItem) if(!call.core.isSecured && call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) { zrtpValidation.open() } @@ -50,23 +64,24 @@ Window { callEnded(call) } } - property var transferState: call.core.transferState + property var transferState: call && call.core.transferState onTransferStateChanged: { console.log("Transfer state:", transferState) - if (call.core.transferState === LinphoneEnums.CallState.Error) { + if (transferState === LinphoneEnums.CallState.Error) { transferErrorPopup.visible = true } - else if (call.core.transferState === LinphoneEnums.CallState.Connected){ + else if (transferState === LinphoneEnums.CallState.Connected){ var mainWin = UtilsCpp.getMainWindow() UtilsCpp.smartShowWindow(mainWin) mainWin.transferCallSucceed() } } onClosing: (close) => { - close.accepted = false - if (callsModel.haveCall) + if (callsModel.haveCall) { + close.accepted = false terminateAllCallsDialog.open() + } } Timer { @@ -144,9 +159,9 @@ Window { } Popup { id: waitingPopup - visible: mainWindow.call.core.transferState === LinphoneEnums.CallState.OutgoingInit - || mainWindow.call.core.transferState === LinphoneEnums.CallState.OutgoingProgress - || mainWindow.call.core.transferState === LinphoneEnums.CallState.OutgoingRinging || false + visible: mainWindow.transferState === LinphoneEnums.CallState.OutgoingInit + || mainWindow.transferState === LinphoneEnums.CallState.OutgoingProgress + || mainWindow.transferState === LinphoneEnums.CallState.OutgoingRinging || false modal: true closePolicy: Control.Popup.NoAutoClose anchors.centerIn: parent @@ -211,31 +226,43 @@ Window { spacing: 10 * DefaultStyle.dp EffectImage { id: callStatusIcon - width: 15 * DefaultStyle.dp - height: 15 * DefaultStyle.dp - imageSource:(mainWindow.call.core.state === LinphoneEnums.CallState.End - || mainWindow.call.core.state === LinphoneEnums.CallState.Released) - ? AppIcons.endCall - : (mainWindow.call.core.state === LinphoneEnums.CallState.Paused - || mainWindow.call.core.state === LinphoneEnums.CallState.PausedByRemote) - ? AppIcons.pause - : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing - ? AppIcons.outgoingCall - : AppIcons.incomingCall - colorizationColor: mainWindow.call.core.state === LinphoneEnums.CallState.Paused - || mainWindow.call.core.state === LinphoneEnums.CallState.PausedByRemote || mainWindow.call.core.state === LinphoneEnums.CallState.End - || mainWindow.call.core.state === LinphoneEnums.CallState.Released ? DefaultStyle.danger_500main : undefined + 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.call.core.state === LinphoneEnums.CallState.End || mainWindow.call.core.state === LinphoneEnums.CallState.Released) + text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) ? qsTr("End of the call") - : (mainWindow.call.core.state === LinphoneEnums.CallState.Paused - || mainWindow.call.core.state === LinphoneEnums.CallState.PausedByRemote) + : (mainWindow.callState === LinphoneEnums.CallState.Paused + || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) ? qsTr("Appel mis en pause") - : mainWindow.conference - ? mainWindow.conference.core.subject - : EnumsToStringCpp.dirToString(mainWindow.call.core.dir) + qsTr(" call") + : 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 @@ -243,30 +270,42 @@ Window { } } Rectangle { - visible: mainWindow.call.core.state === LinphoneEnums.CallState.Connected - || mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning + visible: mainWindow.call && (mainWindow.callState === LinphoneEnums.CallState.Connected + || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) Layout.preferredHeight: parent.height Layout.preferredWidth: 2 * DefaultStyle.dp } Text { - text: UtilsCpp.formatElapsedTime(mainWindow.call.core.duration) + text: mainWindow.call ? UtilsCpp.formatElapsedTime(mainWindow.call.core.duration) : "" color: DefaultStyle.grey_0 font { pixelSize: 22 * DefaultStyle.dp weight: 800 * DefaultStyle.dp } - visible: mainWindow.call.core.state === LinphoneEnums.CallState.Connected - || mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning + 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 + } } Item { Layout.fillWidth: true } RowLayout { - visible: mainWindow.call.core.recording || mainWindow.call.core.remoteRecording + visible: mainWindow.call && (mainWindow.call.core.recording || mainWindow.call.core.remoteRecording) Text { color: DefaultStyle.danger_500main font.pixelSize: 14 * DefaultStyle.dp - text: mainWindow.call.core.recording ? qsTr("Vous enregistrez l'appel") : qsTr("Votre correspondant enregistre l'appel") + text: mainWindow.call + ? mainWindow.call.core.recording + ? qsTr("Vous enregistrez l'appel") + : qsTr("Votre correspondant enregistre l'appel") + : "" } EffectImage { imageSource: AppIcons.recordFill @@ -278,13 +317,13 @@ Window { } 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 - visible: mainWindow.call && mainWindow.call.core.isSecured background: Rectangle { anchors.fill: parent border.color: DefaultStyle.info_500_main @@ -311,162 +350,14 @@ Window { } } RowLayout { - Control.Control { + Layout.fillWidth: true + Layout.fillHeight: true + Control.StackView { + id: middleItemStackView + initialItem: waitingRoom Layout.fillWidth: true - Layout.preferredWidth: 1059 * DefaultStyle.dp Layout.fillHeight: true - Layout.leftMargin: 10 * DefaultStyle.dp - Layout.rightMargin: 10 * DefaultStyle.dp - Layout.alignment: Qt.AlignCenter - background: Rectangle { - anchors.fill: parent - color: DefaultStyle.grey_600 - radius: 15 * DefaultStyle.dp - } - contentItem: Item { - id: centerItem - anchors.fill: parent - Text { - id: callTerminatedText - Connections { - target: mainWindow - onCallStateChanged: { - if (mainWindow.call.core.state === LinphoneEnums.CallState.End) { - callTerminatedText.visible = true - } - } - } - visible: false - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 25 * DefaultStyle.dp - text: mainWindow.callTerminatedByUser ? qsTr("Vous avez terminé l'appel") : qsTr("Votre correspondant a terminé l'appel") - color: DefaultStyle.grey_0 - z: 1 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp - } - } - StackLayout { - id: centerLayout - currentIndex: 0 - anchors.fill: parent - Connections { - target: mainWindow - onCallStateChanged: { - if (mainWindow.call.core.state === LinphoneEnums.CallState.Error) { - centerLayout.currentIndex = 1 - } - } - } - Sticker { - call: mainWindow.call - Layout.fillWidth: true - Layout.fillHeight: true - // visible: mainWindow.call.core.state != LinphoneEnums.CallState.End - - Timer { - id: waitingTimer - interval: 1000 - repeat: true - onTriggered: waitingTime.seconds += 1 - } - ColumnLayout { - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 30 * DefaultStyle.dp - visible: mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingInit - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingProgress - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingRinging - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingEarlyMedia - || mainWindow.call.core.state == LinphoneEnums.CallState.IncomingReceived - BusyIndicator { - indicatorColor: DefaultStyle.main2_100 - Layout.alignment: Qt.AlignHCenter - } - Text { - id: waitingTime - property int seconds - text: UtilsCpp.formatElapsedTime(seconds) - color: DefaultStyle.grey_0 - Layout.alignment: Qt.AlignHCenter - horizontalAlignment: Text.AlignHCenter - font { - pixelSize: 30 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp - } - Component.onCompleted: { - waitingTimer.restart() - } - } - } - } - ColumnLayout { - id: userNotFoundLayout - Layout.preferredWidth: parent.width - Layout.preferredHeight: parent.height - Layout.alignment: Qt.AlignCenter - Text { - text: qsTr(mainWindow.call.core.lastErrorMessage) - Layout.alignment: Qt.AlignCenter - color: DefaultStyle.grey_0 - font.pixelSize: 40 * DefaultStyle.dp - } - } - } - Sticker { - id: preview - visible: mainWindow.call.core.state != LinphoneEnums.CallState.End - && mainWindow.call.core.state != LinphoneEnums.CallState.Released - height: 180 * DefaultStyle.dp - width: 300 * DefaultStyle.dp - anchors.right: centerItem.right - anchors.bottom: centerItem.bottom - anchors.rightMargin: 10 * DefaultStyle.dp - anchors.bottomMargin: 10 * DefaultStyle.dp - AccountProxy{ - id: accounts - } - account: accounts.defaultAccount - enablePersonalCamera: mainWindow.call.core.cameraEnabled - - MovableMouseArea { - id: previewMouseArea - anchors.fill: parent - // visible: mainItem.participantCount <= 2 - movableArea: centerItem - margin: 10 * DefaultStyle.dp - function resetPosition(){ - preview.anchors.right = centerItem.right - preview.anchors.bottom = centerItem.bottom - preview.anchors.rightMargin = previewMouseArea.margin - preview.anchors.bottomMargin = previewMouseArea.margin - } - onVisibleChanged: if(!visible){ - resetPosition() - } - drag.target: preview - onDraggingChanged: if(dragging) { - preview.anchors.right = undefined - preview.anchors.bottom = undefined - } - onRequestResetPosition: resetPosition() - } - } - property int previousWidth - Component.onCompleted: { - previousWidth = width - } - onWidthChanged: { - if (width < previousWidth) { - previewMouseArea.updatePosition(0, 0) - } else { - previewMouseArea.updatePosition(width - previousWidth, 0) - } - previousWidth = width - } - } + Layout.margins: 20 * DefaultStyle.dp } OngoingCallRightPanel { id: rightPanel @@ -497,6 +388,7 @@ Window { Component { id: contactsListPanel CallContactsLists { + Control.StackView.onActivated: rightPanelTitle.text = qsTr("Transfert d'appel") sideMargin: 10 * DefaultStyle.dp topMargin: 15 * DefaultStyle.dp groupCallVisible: false @@ -505,7 +397,6 @@ Window { onCallButtonPressed: (address) => { mainWindow.call.core.lTransferCall(address) } - Control.StackView.onActivated: rightPanelTitle.text = qsTr("Transfert d'appel") } } Component { @@ -548,12 +439,11 @@ Window { Component { id: callsListPanel ColumnLayout { + Control.StackView.onActivated: rightPanelTitle.text = qsTr("Liste d'appel") RoundedBackgroundControl { - Control.StackView.onActivated: rightPanelTitle.text = qsTr("Liste d'appel") Layout.fillWidth: true // height: Math.min(callList.height + topPadding + bottomPadding, rightPanelStack.height) - onHeightChanged: console.log("calls list height changed", height) - height: Math.min(callList.height + topPadding + bottomPadding, rightPanelStack.height) + Layout.preferredHeight: Math.min(callList.height + topPadding + bottomPadding, rightPanelStack.height) topPadding: 15 * DefaultStyle.dp bottomPadding: 15 * DefaultStyle.dp @@ -680,152 +570,206 @@ Window { } Component { id: settingsPanel - ColumnLayout { - RoundedBackgroundControl { - Layout.alignment: Qt.AlignHCenter - Control.StackView.onActivated: { - rightPanelTitle.text = qsTr("Paramètres") + InCallSettingsPanel { + Control.StackView.onActivated: rightPanelTitle.text = qsTr("Paramètres") + call: mainWindow.call + } + } + } + } + } + Component { + id: waitingRoom + WaitingRoom { + id: waitingRoomIn + Layout.alignment: Qt.AlignCenter + conferenceInfo: mainWindow.conferenceInfo + onSettingsButtonCheckedChanged: { + if (settingsButtonChecked) { + rightPanel.visible = true + rightPanel.replace(settingsPanel) + } else { + rightPanel.visible = false + } + } + Connections { + target: rightPanel + onVisibleChanged: if (!visible) waitingRoomIn.settingsButtonChecked = false + } + Connections { + target: mainWindow + onCallChanged: if (mainWindow.conferenceInfo && mainWindow.call) { + mainWindow.call.core.lSetCameraEnabled(waitingRoomIn.cameraEnabled) + mainWindow.call.core.lSetMicrophoneMuted(!waitingRoomIn.microEnabled) + } + } + onJoinConfRequested: mainWindow.joinConference(cameraEnabled) + } + } + Component { + id: inCallItem + Control.Control { + Layout.fillWidth: true + implicitWidth: 1059 * DefaultStyle.dp + // implicitHeight: parent.height + Layout.fillHeight: true + Layout.leftMargin: 10 * DefaultStyle.dp + Layout.rightMargin: 10 * DefaultStyle.dp + Layout.alignment: Qt.AlignCenter + background: Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_600 + radius: 15 * DefaultStyle.dp + } + contentItem: Item { + id: centerItem + anchors.fill: parent + Text { + id: callTerminatedText + Connections { + target: mainWindow + onCallStateChanged: { + if (mainWindow.callState === LinphoneEnums.CallState.End) { + callTerminatedText.visible = true } - backgroundColor: DefaultStyle.main2_0 - height: contentItem.implicitHeight + topPadding + bottomPadding - Layout.fillWidth: true - topPadding: 25 * DefaultStyle.dp - bottomPadding: 25 * DefaultStyle.dp - leftPadding: 25 * DefaultStyle.dp - rightPadding: 25 * DefaultStyle.dp - contentItem: ColumnLayout { - spacing: 10 * DefaultStyle.dp - - RowLayout { - Layout.fillWidth: true - EffectImage { - imageSource: AppIcons.speaker - colorizationColor: DefaultStyle.main1_500_main - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - imageWidth: 24 * DefaultStyle.dp - imageHeight: 24 * DefaultStyle.dp - } - Text { - text: qsTr("Haut-parleurs") - Layout.fillWidth: true - } - } - ComboBox { - Layout.fillWidth: true - Layout.preferredWidth: parent.width - model: SettingsCpp.outputAudioDevicesList - onCurrentTextChanged: { - mainWindow.call.core.lSetOutputAudioDevice(currentText) - } - } - Slider { - id: speakerVolume - Layout.fillWidth: true - from: 0.0 - to: 1.0 - value: mainWindow.call && mainWindow.call.core.speakerVolumeGain - onMoved: { - mainWindow.call.core.lSetSpeakerVolumeGain(value) - } - } - RowLayout { - Layout.fillWidth: true - EffectImage { - imageSource: AppIcons.microphone - colorizationColor: DefaultStyle.main1_500_main - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - imageWidth: 24 * DefaultStyle.dp - imageHeight: 24 * DefaultStyle.dp - } - Text { - text: qsTr("Microphone") - Layout.fillWidth: true - } - } - ComboBox { - Layout.fillWidth: true - Layout.preferredWidth: parent.width - model: SettingsCpp.inputAudioDevicesList - onCurrentTextChanged: { - mainWindow.call.core.lSetInputAudioDevice(currentText) - } - } - Slider { - id: microVolume - Layout.fillWidth: true - from: 0.0 - to: 1.0 - value: mainWindow.call && mainWindow.call.core.microphoneVolumeGain - onMoved: { - mainWindow.call.core.lSetMicrophoneVolumeGain(value) - } - } - Timer { - interval: 50 - repeat: true - running: mainWindow.call || false - onTriggered: audioTestSlider.value = (mainWindow.call && mainWindow.call.core.microVolume) - } - Slider { - id: audioTestSlider - Layout.fillWidth: true - enabled: false - Layout.preferredHeight: 10 * DefaultStyle.dp - - background: Rectangle { - x: audioTestSlider.leftPadding - y: audioTestSlider.topPadding + audioTestSlider.availableHeight / 2 - height / 2 - implicitWidth: 200 * DefaultStyle.dp - implicitHeight: 10 * DefaultStyle.dp - width: audioTestSlider.availableWidth - height: implicitHeight - radius: 2 * DefaultStyle.dp - color: "#D9D9D9" - - Rectangle { - width: audioTestSlider.visualPosition * parent.width - height: parent.height - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { position: 0.0; color: "#6FF88D" } - GradientStop { position: 1.0; color: "#00D916" } - } - radius: 2 * DefaultStyle.dp - } - } - handle: Item {visible: false} - } - RowLayout { - Layout.fillWidth: true - EffectImage { - imageSource: AppIcons.videoCamera - colorizationColor: DefaultStyle.main1_500_main - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - imageWidth: 24 * DefaultStyle.dp - imageHeight: 24 * DefaultStyle.dp - } - Text { - text: qsTr("Caméra") - Layout.fillWidth: true - } - } - ComboBox { - Layout.fillWidth: true - Layout.preferredWidth: parent.width - model: SettingsCpp.videoDevicesList - onCurrentTextChanged: { - SettingsCpp.lSetVideoDevice(currentText) - } - } - } - } - Item { - Layout.fillHeight: true } } + visible: false + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 25 * DefaultStyle.dp + text: mainWindow.callTerminatedByUser ? qsTr("Vous avez terminé l'appel") : qsTr("Votre correspondant a terminé l'appel") + color: DefaultStyle.grey_0 + z: 1 + font { + pixelSize: 22 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + } + StackLayout { + id: centerLayout + currentIndex: 0 + anchors.fill: parent + Connections { + target: mainWindow + onCallStateChanged: { + if (mainWindow.callState === LinphoneEnums.CallState.Error) { + centerLayout.currentIndex = 1 + } + } + } + Sticker { + call: mainWindow.call + Layout.fillWidth: true + Layout.fillHeight: true + // visible: mainWindow.callState != LinphoneEnums.CallState.End + Connections { + target: mainWindow + onCallChanged: { + waitingTime.seconds = 0 + waitingTimer.restart() + console.log("call changed", call, waitingTime.seconds) + } + } + Timer { + id: waitingTimer + interval: 1000 + repeat: true + onTriggered: waitingTime.seconds += 1 + } + ColumnLayout { + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 30 * DefaultStyle.dp + visible: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit + || mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress + || mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging + || mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia + || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived + BusyIndicator { + indicatorColor: DefaultStyle.main2_100 + Layout.alignment: Qt.AlignHCenter + } + Text { + id: waitingTime + property int seconds + text: UtilsCpp.formatElapsedTime(seconds) + color: DefaultStyle.grey_0 + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + font { + pixelSize: 30 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + Component.onCompleted: { + waitingTimer.restart() + } + } + } + } + ColumnLayout { + id: errorLayout + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + Layout.alignment: Qt.AlignCenter + Text { + text: qsTr(mainWindow.call.core.lastErrorMessage) + Layout.alignment: Qt.AlignCenter + color: DefaultStyle.grey_0 + font.pixelSize: 40 * DefaultStyle.dp + } + } + } + Sticker { + id: preview + visible: mainWindow.callState != LinphoneEnums.CallState.End + && mainWindow.callState != LinphoneEnums.CallState.Released + height: 180 * DefaultStyle.dp + width: 300 * DefaultStyle.dp + anchors.right: centerItem.right + anchors.bottom: centerItem.bottom + anchors.rightMargin: 10 * DefaultStyle.dp + anchors.bottomMargin: 10 * DefaultStyle.dp + AccountProxy{ + id: accounts + } + account: accounts.defaultAccount + enablePersonalCamera: mainWindow.call.core.cameraEnabled + + MovableMouseArea { + id: previewMouseArea + anchors.fill: parent + // visible: mainWindow.participantCount <= 2 + movableArea: centerItem + margin: 10 * DefaultStyle.dp + function resetPosition(){ + preview.anchors.right = centerItem.right + preview.anchors.bottom = centerItem.bottom + preview.anchors.rightMargin = previewMouseArea.margin + preview.anchors.bottomMargin = previewMouseArea.margin + } + onVisibleChanged: if(!visible){ + resetPosition() + } + drag.target: preview + onDraggingChanged: if(dragging) { + preview.anchors.right = undefined + preview.anchors.bottom = undefined + } + onRequestResetPosition: resetPosition() + } + } + property int previousWidth + Component.onCompleted: { + previousWidth = width + } + onWidthChanged: { + if (width < previousWidth) { + previewMouseArea.updatePosition(0, 0) + } else { + previewMouseArea.updatePosition(width - previousWidth, 0) + } + previousWidth = width } } } @@ -837,9 +781,10 @@ Window { Layout.alignment: Qt.AlignHCenter layoutDirection: Qt.LeftToRight columnSpacing: 20 * DefaultStyle.dp + visible: mainWindow.conferenceUri ? mainWindow.conferenceJoined : mainWindow.call function refreshLayout() { - if (mainWindow.call.core.state === LinphoneEnums.CallState.Connected || mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning) { + if (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) { bottomButtonsLayout.layoutDirection = Qt.RightToLeft connectedCallButtons.visible = true videoCameraButton.enabled = true @@ -867,11 +812,11 @@ Window { Layout.row: 0 enabledIcon: AppIcons.endCall checkable: false - Layout.column: mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingInit - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingProgress - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingRinging - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingEarlyMedia - || mainWindow.call.core.state == LinphoneEnums.CallState.IncomingReceived + Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit + || mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress + || mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging + || mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia + || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived ? 0 : bottomButtonsLayout.columns - 1 Layout.preferredWidth: 75 * DefaultStyle.dp Layout.preferredHeight: 55 * DefaultStyle.dp @@ -905,9 +850,9 @@ Window { : DefaultStyle.grey_500 : DefaultStyle.grey_600 } - enabled: mainWindow.call.core.state != LinphoneEnums.CallState.PausedByRemote + enabled: mainWindow.callState != LinphoneEnums.CallState.PausedByRemote enabledIcon: enabled && checked ? AppIcons.play : AppIcons.pause - checked: mainWindow.call.core.paused + checked: mainWindow.call && mainWindow.call.core.paused onClicked: { mainWindow.call.core.lSetPaused(!callsModel.currentCall.core.paused) } @@ -945,17 +890,17 @@ Window { } RowLayout { Layout.row: 0 - Layout.column: mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingInit - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingProgress - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingRinging - || mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingEarlyMedia - || mainWindow.call.core.state == LinphoneEnums.CallState.IncomingReceived + Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit + || mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress + || mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging + || mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia + || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived ? bottomButtonsLayout.columns - 1 : 0 BottomButton { id: videoCameraButton enabledIcon: AppIcons.videoCamera disabledIcon: AppIcons.videoCameraSlash - checked: !mainWindow.call.core.cameraEnabled + checked: mainWindow.call && !mainWindow.call.core.cameraEnabled Layout.preferredWidth: 55 * DefaultStyle.dp Layout.preferredHeight: 55 * DefaultStyle.dp onClicked: mainWindow.call.core.lSetCameraEnabled(!mainWindow.call.core.cameraEnabled) @@ -963,7 +908,7 @@ Window { BottomButton { enabledIcon: AppIcons.microphone disabledIcon: AppIcons.microphoneSlash - checked: mainWindow.call.core.microphoneMuted + checked: mainWindow.call && mainWindow.call.core.microphoneMuted Layout.preferredWidth: 55 * DefaultStyle.dp Layout.preferredHeight: 55 * DefaultStyle.dp onClicked: mainWindow.call.core.lSetMicrophoneMuted(!mainWindow.call.core.microphoneMuted) @@ -1037,7 +982,7 @@ Window { Button { id: recordButton Layout.fillWidth: true - enabled: mainWindow.call.core.recordable + enabled: mainWindow.call && mainWindow.call.core.recordable checkable: true background: Item {} contentItem: RowLayout { @@ -1046,16 +991,16 @@ Window { Layout.preferredHeight: 24 * DefaultStyle.dp fillMode: Image.PreserveAspectFit imageSource: AppIcons.recordFill - colorizationColor: mainWindow.call.core.recording ? DefaultStyle.danger_500main : undefined + colorizationColor: mainWindow.call && mainWindow.call.core.recording ? DefaultStyle.danger_500main : undefined } Text { - color: mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_600 - text: mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel") + color: mainWindow.call && mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_600 + text: mainWindow.call && mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel") } } onClicked: { - mainWindow.call.core.recording ? mainWindow.call.core.lStopRecording() : mainWindow.call.core.lStartRecording() + mainWindow.call && mainWindow.call.core.recording ? mainWindow.call.core.lStopRecording() : mainWindow.call.core.lStartRecording() } } Control.Button { @@ -1069,11 +1014,11 @@ Window { Layout.preferredHeight: 24 * DefaultStyle.dp fillMode: Image.PreserveAspectFit imageSource: AppIcons.recordFill - colorizationColor: mainWindow.call.core.recording ? DefaultStyle.danger_500main : undefined + colorizationColor: mainWindow.call && mainWindow.call.core.recording ? DefaultStyle.danger_500main : undefined } Text { - color: mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_600 - text: mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel") + color: mainWindow.call && mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_600 + text: mainWindow.call && mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel") } } diff --git a/Linphone/view/App/Layout/MainLayout.qml b/Linphone/view/App/Layout/MainLayout.qml index 9805aaed3..b825ead09 100644 --- a/Linphone/view/App/Layout/MainLayout.qml +++ b/Linphone/view/App/Layout/MainLayout.qml @@ -127,6 +127,7 @@ Item { id: topRow Layout.leftMargin: 25 * DefaultStyle.dp Layout.rightMargin: 41 * DefaultStyle.dp + spacing: 25 * DefaultStyle.dp SearchBar { id: magicSearchBar Layout.fillWidth: true @@ -263,74 +264,77 @@ Item { } } } - PopupButton { - id: avatarButton - AccountProxy{ - id: accountProxy - //property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false - } - background.visible: false - Layout.preferredWidth: 54 * DefaultStyle.dp - Layout.preferredHeight: width - contentItem: Avatar { - id: avatar - height: avatarButton.height - width: avatarButton.width - account: accountProxy.defaultAccount - } - popup.x: width - popup.width - popup.padding: 0 - popup.contentItem: ColumnLayout { - Accounts { - id: accounts - onAddAccountRequest: mainItem.addAccountRequest() + RowLayout { + spacing: 10 * DefaultStyle.dp + PopupButton { + id: avatarButton + AccountProxy{ + id: accountProxy + //property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false + } + background.visible: false + Layout.preferredWidth: 54 * DefaultStyle.dp + Layout.preferredHeight: width + contentItem: Avatar { + id: avatar + height: avatarButton.height + width: avatarButton.width + account: accountProxy.defaultAccount + } + popup.x: width - popup.width + popup.padding: 0 + popup.contentItem: ColumnLayout { + Accounts { + id: accounts + onAddAccountRequest: mainItem.addAccountRequest() + } } } - } - PopupButton { - id: settingsButton - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - popup.x: width - popup.width - popup.width: 271 * DefaultStyle.dp - popup.contentItem: ColumnLayout { - spacing: 20 * DefaultStyle.dp - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - iconSize: 32 * DefaultStyle.dp - text: qsTr("Mon compte") - iconSource: AppIcons.manageProfile - onClicked: console.log("TODO : manage profile") - } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - iconSize: 32 * DefaultStyle.dp - text: qsTr("Paramètres") - iconSource: AppIcons.settings - } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - iconSize: 32 * DefaultStyle.dp - text: qsTr("Enregistrements") - iconSource: AppIcons.micro - } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - iconSize: 32 * DefaultStyle.dp - text: qsTr("Aide") - iconSource: AppIcons.question - } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 * DefaultStyle.dp - color: DefaultStyle.main2_400 - } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - iconSize: 32 * DefaultStyle.dp - text: qsTr("Ajouter un compte") - iconSource: AppIcons.plusCircle - onClicked: mainItem.addAccountRequest() + PopupButton { + id: settingsButton + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + popup.x: width - popup.width + popup.width: 271 * DefaultStyle.dp + popup.contentItem: ColumnLayout { + spacing: 20 * DefaultStyle.dp + IconLabelButton { + Layout.preferredHeight: 32 * DefaultStyle.dp + iconSize: 32 * DefaultStyle.dp + text: qsTr("Mon compte") + iconSource: AppIcons.manageProfile + onClicked: console.log("TODO : manage profile") + } + IconLabelButton { + Layout.preferredHeight: 32 * DefaultStyle.dp + iconSize: 32 * DefaultStyle.dp + text: qsTr("Paramètres") + iconSource: AppIcons.settings + } + IconLabelButton { + Layout.preferredHeight: 32 * DefaultStyle.dp + iconSize: 32 * DefaultStyle.dp + text: qsTr("Enregistrements") + iconSource: AppIcons.micro + } + IconLabelButton { + Layout.preferredHeight: 32 * DefaultStyle.dp + iconSize: 32 * DefaultStyle.dp + text: qsTr("Aide") + iconSource: AppIcons.question + } + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_400 + } + IconLabelButton { + Layout.preferredHeight: 32 * DefaultStyle.dp + iconSize: 32 * DefaultStyle.dp + text: qsTr("Ajouter un compte") + iconSource: AppIcons.plusCircle + onClicked: mainItem.addAccountRequest() + } } } } diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index 897660e84..e09b67165 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -16,7 +16,9 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/Account/Accounts.qml view/Item/Call/CallContactsLists.qml + view/Item/Call/InCallSettingsPanel.qml view/Item/Call/OngoingCallRightPanel.qml + view/Item/Call/WaitingRoom.qml view/Item/Notification/Notification.qml view/Item/Notification/NotificationReceivedCall.qml @@ -38,6 +40,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/Calendar.qml view/Item/CalendarComboBox.qml view/Item/Carousel.qml + view/Item/CheckableButton.qml view/Item/CheckBox.qml view/Item/ComboBox.qml view/Item/DesktopPopup.qml diff --git a/Linphone/view/Item/BusyIndicator.qml b/Linphone/view/Item/BusyIndicator.qml index 16b1e6965..2812abc93 100644 --- a/Linphone/view/Item/BusyIndicator.qml +++ b/Linphone/view/Item/BusyIndicator.qml @@ -1,5 +1,5 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 as Control +import QtQuick +import QtQuick.Controls as Control import QtQuick.Effects import Linphone @@ -13,11 +13,20 @@ Item { id: busyIndicator running: mainItem.visible anchors.centerIn: mainItem - } - MultiEffect { - source: busyIndicator - anchors.fill: busyIndicator - colorizationColor: mainItem.indicatorColor - colorization: 1.0 + contentItem: EffectImage { + id: busyImage + imageWidth: mainItem.width + imageHeight: mainItem.height + imageSource: AppIcons.busyIndicator + colorizationColor: mainItem.indicatorColor + RotationAnimator { + target: busyImage + running: busyIndicator.running + from: 0 + to: 360 + loops: Animation.Infinite + duration: 10000 + } + } } } \ No newline at end of file diff --git a/Linphone/view/Item/Button.qml b/Linphone/view/Item/Button.qml index ab08874a5..e4cfeb63f 100644 --- a/Linphone/view/Item/Button.qml +++ b/Linphone/view/Item/Button.qml @@ -44,7 +44,7 @@ Control.Button { ? mainItem.pressedColor : mainItem.color radius: 48 * DefaultStyle.dp - border.color: inversedColors ? mainItem.color : DefaultStyle.grey_0 + border.color: inversedColors ? mainItem.color : "transparent" MouseArea { anchors.fill: parent diff --git a/Linphone/view/Item/Call/InCallSettingsPanel.qml b/Linphone/view/Item/Call/InCallSettingsPanel.qml new file mode 100644 index 000000000..1b6c6998a --- /dev/null +++ b/Linphone/view/Item/Call/InCallSettingsPanel.qml @@ -0,0 +1,169 @@ +import QtQuick +import QtQuick.Controls as Control +import QtQuick.Layouts +import Linphone +import SettingsCpp 1.0 + +ColumnLayout { + id: mainItem + property CallGui call + onCallChanged: { + if (call) { + console.log("============================== volume ", speakerVolume.value, microVolume.value) + call.core.lSetOutputAudioDevice(outputAudioDeviceCBox.currentText) + call.core.lSetSpeakerVolumeGain(speakerVolume.value) + call.core.lSetInputAudioDevice(inputAudioDeviceCBox.currentText) + call.core.lSetMicrophoneVolumeGain(microVolume.value) + } + } + RoundedBackgroundControl { + Layout.alignment: Qt.AlignHCenter + Control.StackView.onActivated: { + rightPanelTitle.text = qsTr("Paramètres") + } + backgroundColor: DefaultStyle.main2_0 + height: contentItem.implicitHeight + topPadding + bottomPadding + Layout.fillWidth: true + topPadding: 25 * DefaultStyle.dp + bottomPadding: 25 * DefaultStyle.dp + leftPadding: 25 * DefaultStyle.dp + rightPadding: 25 * DefaultStyle.dp + contentItem: ColumnLayout { + spacing: 10 * DefaultStyle.dp + + RowLayout { + Layout.fillWidth: true + EffectImage { + imageSource: AppIcons.speaker + colorizationColor: DefaultStyle.main1_500_main + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + imageWidth: 24 * DefaultStyle.dp + imageHeight: 24 * DefaultStyle.dp + } + Text { + text: qsTr("Haut-parleurs") + Layout.fillWidth: true + } + } + ComboBox { + id: outputAudioDeviceCBox + Layout.fillWidth: true + Layout.preferredWidth: parent.width + Layout.preferredHeight: 49 * DefaultStyle.dp + model: SettingsCpp.outputAudioDevicesList + onCurrentTextChanged: { + if (mainItem.call) mainItem.call.core.lSetOutputAudioDevice(currentText) + } + } + Slider { + id: speakerVolume + Layout.fillWidth: true + from: 0.0 + to: 1.0 + value: mainItem.call ? mainItem.call.core.speakerVolumeGain : 0.5 + onMoved: { + if (mainItem.call) mainItem.call.core.lSetSpeakerVolumeGain(value) + } + } + RowLayout { + Layout.fillWidth: true + EffectImage { + imageSource: AppIcons.microphone + colorizationColor: DefaultStyle.main1_500_main + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + imageWidth: 24 * DefaultStyle.dp + imageHeight: 24 * DefaultStyle.dp + } + Text { + text: qsTr("Microphone") + Layout.fillWidth: true + } + } + ComboBox { + id: inputAudioDeviceCBox + Layout.fillWidth: true + Layout.preferredWidth: parent.width + Layout.preferredHeight: 49 * DefaultStyle.dp + model: SettingsCpp.inputAudioDevicesList + onCurrentTextChanged: { + if (mainItem.call) mainItem.call.core.lSetInputAudioDevice(currentText) + } + } + Slider { + id: microVolume + Layout.fillWidth: true + from: 0.0 + to: 1.0 + value: mainItem.call ? mainItem.call.core.microphoneVolumeGain : 0.5 + onMoved: { + if (mainItem.call) mainItem.call.core.lSetMicrophoneVolumeGain(value) + } + } + Timer { + interval: 50 + repeat: true + running: mainItem.call || false + onTriggered: audioTestSlider.value = (mainItem.call && mainItem.call.core.microVolume) + } + Slider { + id: audioTestSlider + Layout.fillWidth: true + enabled: false + Layout.preferredHeight: 10 * DefaultStyle.dp + + background: Rectangle { + x: audioTestSlider.leftPadding + y: audioTestSlider.topPadding + audioTestSlider.availableHeight / 2 - height / 2 + implicitWidth: 200 * DefaultStyle.dp + implicitHeight: 10 * DefaultStyle.dp + width: audioTestSlider.availableWidth + height: implicitHeight + radius: 2 * DefaultStyle.dp + color: "#D9D9D9" + + Rectangle { + width: audioTestSlider.visualPosition * parent.width + height: parent.height + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { position: 0.0; color: "#6FF88D" } + GradientStop { position: 1.0; color: "#00D916" } + } + radius: 2 * DefaultStyle.dp + } + } + handle: Item {visible: false} + } + RowLayout { + Layout.fillWidth: true + EffectImage { + imageSource: AppIcons.videoCamera + colorizationColor: DefaultStyle.main1_500_main + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + imageWidth: 24 * DefaultStyle.dp + imageHeight: 24 * DefaultStyle.dp + } + Text { + text: qsTr("Caméra") + Layout.fillWidth: true + } + } + ComboBox { + Layout.fillWidth: true + Layout.preferredWidth: parent.width + Layout.preferredHeight: 49 * DefaultStyle.dp + model: SettingsCpp.videoDevicesList + currentIndex: SettingsCpp.currentVideoDeviceIndex + onCurrentTextChanged: { + SettingsCpp.lSetVideoDevice(currentText) + } + } + } + } + Item { + Layout.fillHeight: true + } +} \ No newline at end of file diff --git a/Linphone/view/Item/Call/OngoingCallRightPanel.qml b/Linphone/view/Item/Call/OngoingCallRightPanel.qml index 19ae99b98..ec45f514c 100644 --- a/Linphone/view/Item/Call/OngoingCallRightPanel.qml +++ b/Linphone/view/Item/Call/OngoingCallRightPanel.qml @@ -17,6 +17,9 @@ Control.Page { header: Control.Control { id: pageHeader width: mainItem.width + height: 56 * DefaultStyle.dp + leftPadding: 10 * DefaultStyle.dp + rightPadding: 10 * DefaultStyle.dp background: Rectangle { id: headerBackground width: pageHeader.width @@ -30,19 +33,13 @@ Control.Page { } } contentItem: RowLayout { - width: pageHeader.width - height: pageHeader.height - anchors.leftMargin: 10 * DefaultStyle.dp - anchors.left: pageHeader.left Item { id: header - } - Item { Layout.fillWidth: true + Layout.fillHeight: true } Button { id: closeButton - Layout.alignment: Qt.AlignRight background: Item { visible: false } diff --git a/Linphone/view/Item/Call/WaitingRoom.qml b/Linphone/view/Item/Call/WaitingRoom.qml new file mode 100644 index 000000000..d0082a59a --- /dev/null +++ b/Linphone/view/Item/Call/WaitingRoom.qml @@ -0,0 +1,149 @@ +import QtQuick 2.15 +import QtQuick.Layouts +import QtQuick.Effects +import QtQuick.Controls as Control +import Linphone +import UtilsCpp 1.0 + +RowLayout { + id: mainItem + property bool cameraEnabled: true + property bool microEnabled: true + property bool settingsButtonChecked: settingsButton.checked + property ConferenceInfoGui conferenceInfo + signal joinConfRequested() + RowLayout { + Layout.fillWidth: false + Layout.fillHeight: false + spacing: 100 * DefaultStyle.dp + Layout.alignment: Qt.AlignCenter + ColumnLayout { + spacing: 31 * DefaultStyle.dp + // Layout.leftMargin: 97 * DefaultStyle.dp + Sticker { + id: preview + Layout.preferredHeight: 330 * DefaultStyle.dp + Layout.preferredWidth: 558 * DefaultStyle.dp + AccountProxy{ + id: accounts + } + account: accounts.defaultAccount + enablePersonalCamera: mainItem.cameraEnabled + } + RowLayout { + Layout.alignment: Qt.AlignHCenter + CheckableButton { + id: videoButton + iconUrl: AppIcons.videoCamera + checkedIconUrl: AppIcons.videoCameraSlash + color: DefaultStyle.grey_500 + contentImageColor: DefaultStyle.main2_0 + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + onCheckedChanged: mainItem.cameraEnabled = !mainItem.cameraEnabled + } + CheckableButton { + id: microButton + iconUrl: AppIcons.microphone + checkedIconUrl: AppIcons.microphoneSlash + color: DefaultStyle.grey_500 + contentImageColor: DefaultStyle.main2_0 + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + onCheckedChanged: mainItem.microEnabled = !mainItem.microEnabled + } + CheckableButton { + id: settingsButton + visible: stackLayout.currentIndex === 0 + icon.source: AppIcons.more + color: DefaultStyle.grey_500 + checkedColor: DefaultStyle.main2_100 + contentImageColor: checked ? DefaultStyle.grey_500 : DefaultStyle.grey_0 + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + } + CheckableButton { + id: speakerButton + visible: stackLayout.currentIndex === 1 + iconUrl: AppIcons.speaker + checkedIconUrl: AppIcons.speakerSlash + color: DefaultStyle.grey_500 + contentImageColor: checked ? DefaultStyle.grey_500 : DefaultStyle.grey_0 + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + } + } + } + StackLayout { + id: stackLayout + currentIndex: 0 + ColumnLayout { + spacing: 93 * DefaultStyle.dp + ColumnLayout { + spacing: 5 * DefaultStyle.dp + Text { + Layout.fillWidth: true + text: qsTr("Participer à :\n") + color: DefaultStyle.grey_0 + font { + pixelSize: 30 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + } + Text { + Layout.fillWidth: true + text: mainItem.conferenceInfo && mainItem.conferenceInfo.core.subject + color: DefaultStyle.grey_0 + font { + pixelSize: 30 * DefaultStyle.dp + weight: 300 * 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() + } + } + } + ColumnLayout { + spacing: 37 * DefaultStyle.dp + ColumnLayout { + spacing: 13 * DefaultStyle.dp + Text { + Layout.fillWidth: true + text: qsTr("Connexion à la réunion") + color: DefaultStyle.grey_0 + font { + pixelSize: 30 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + } + Text { + Layout.fillWidth: true + text: qsTr("Vous allez rejoindre la réunion dans quelques instants...") + color: DefaultStyle.grey_0 + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + BusyIndicator { + indicatorColor: DefaultStyle.main1_500_main + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: 48 * DefaultStyle.dp + Layout.preferredHeight: 48 * DefaultStyle.dp + } + } + } + } +} \ No newline at end of file diff --git a/Linphone/view/Item/CheckableButton.qml b/Linphone/view/Item/CheckableButton.qml new file mode 100644 index 000000000..151f6b5a6 --- /dev/null +++ b/Linphone/view/Item/CheckableButton.qml @@ -0,0 +1,31 @@ +import QtQuick 2.15 +import QtQuick.Layouts +import QtQuick.Effects +import QtQuick.Controls as Control +import Linphone + +Button { + id: mainItem + property string iconUrl + property string checkedIconUrl + property color color: DefaultStyle.grey_500 + property color checkedColor: DefaultStyle.main2_400 + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + checkable: true + background: Rectangle { + anchors.fill: parent + color: mainItem.enabled + ? mainItem.pressed || mainItem.checked + ? mainItem.checkedColor + : mainItem.color + : DefaultStyle.grey_600 + radius: mainItem.width * 1.29 + } + icon.source: checkedIconUrl && mainItem.checked ? checkedIconUrl : iconUrl + icon.width: width * 0.58 + icon.height: width * 0.58 + contentImageColor: enabled ? DefaultStyle.grey_0 : DefaultStyle.grey_500 +} \ No newline at end of file diff --git a/Linphone/view/Item/Dialog.qml b/Linphone/view/Item/Dialog.qml index 48f2048b5..43d92d618 100644 --- a/Linphone/view/Item/Dialog.qml +++ b/Linphone/view/Item/Dialog.qml @@ -53,6 +53,7 @@ Popup { contentItem: ColumnLayout { spacing: 20 * DefaultStyle.dp + ColumnLayout { id: contentLayout Layout.fillWidth: true @@ -64,6 +65,7 @@ Popup { visible: text.length != 0 width: parent.width Layout.preferredWidth: 278 * DefaultStyle.dp + Layout.alignment: Qt.AlignCenter text: mainItem.text font { pixelSize: 14 * DefaultStyle.dp diff --git a/Linphone/view/Item/Form/LoginForm.qml b/Linphone/view/Item/Form/LoginForm.qml index b4289175f..29c4ec1e4 100644 --- a/Linphone/view/Item/Form/LoginForm.qml +++ b/Linphone/view/Item/Form/LoginForm.qml @@ -91,8 +91,8 @@ ColumnLayout { color: DefaultStyle.grey_0 } BusyIndicator { - width: parent.height - height: parent.height + implicitWidth: parent.height + implicitHeight: parent.height Layout.alignment: Qt.AlignCenter indicatorColor: DefaultStyle.grey_0 } diff --git a/Linphone/view/Item/Meeting/MeetingList.qml b/Linphone/view/Item/Meeting/MeetingList.qml index bf785f5d1..583d510de 100644 --- a/Linphone/view/Item/Meeting/MeetingList.qml +++ b/Linphone/view/Item/Meeting/MeetingList.qml @@ -25,9 +25,14 @@ ListView { onCountChanged: selectedConference = model.getAt(currentIndex) || null onCurrentIndexChanged: selectedConference = model.getAt(currentIndex) || null + function forceUpdate() { + confInfoProxy.lUpdate() + } + signal conferenceSelected(var contact) model: ConferenceInfoProxy { + id: confInfoProxy searchText: searchBarText.length === 0 ? "" : searchBarText } diff --git a/Linphone/view/Item/Meeting/MeetingSetUp.qml b/Linphone/view/Item/Meeting/MeetingSetUp.qml index ca5499a3d..63e917226 100644 --- a/Linphone/view/Item/Meeting/MeetingSetUp.qml +++ b/Linphone/view/Item/Meeting/MeetingSetUp.qml @@ -12,13 +12,15 @@ ColumnLayout { property ConferenceInfoGui conferenceInfoGui signal addParticipantsRequested() signal returnRequested() - signal creationSucceed() + signal saveSucceed(bool isCreation) Connections { target: mainItem.conferenceInfoGui.core onSchedulerStateChanged: { - if (isCreation && mainItem.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Ready) mainItem.creationSucceed() console.log("scheduler state changed", mainItem.conferenceInfoGui.core.schedulerState) + if (mainItem.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Ready) { + mainItem.saveSucceed(isCreation) + } } } @@ -181,6 +183,7 @@ ColumnLayout { CalendarComboBox { id: startDate background.visible: mainItem.isCreation + indicator.visible: mainItem.isCreation contentText.font.weight: (isCreation ? 700 : 400) * DefaultStyle.dp Layout.preferredWidth: 200 * DefaultStyle.dp Layout.preferredHeight: 30 * DefaultStyle.dp @@ -197,6 +200,7 @@ ColumnLayout { TimeComboBox { id: startHour visible: allDaySwitch.position === 0 + indicator.visible: mainItem.isCreation // Layout.fillWidth: true Layout.preferredWidth: 94 * DefaultStyle.dp Layout.preferredHeight: 30 * DefaultStyle.dp @@ -218,6 +222,7 @@ ColumnLayout { CalendarComboBox { id: endDate background.visible: mainItem.isCreation + indicator.visible: mainItem.isCreation // Layout.fillWidth: true Layout.preferredWidth: 200 * DefaultStyle.dp Layout.preferredHeight: 30 * DefaultStyle.dp @@ -228,6 +233,7 @@ ColumnLayout { TimeComboBox { id: endHour visible: allDaySwitch.position === 0 + indicator.visible: mainItem.isCreation Layout.preferredWidth: 94 * DefaultStyle.dp Layout.preferredHeight: 30 * DefaultStyle.dp background.visible: mainItem.isCreation diff --git a/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml b/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml index ca19527d5..5a2d6cb16 100644 --- a/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml +++ b/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml @@ -22,7 +22,8 @@ Dialog { onCallChanged: if(!call) close() Connections { - target: call.core + enabled: call != undefined && call != null + target: call && call.core onStatusChanged: if (status === CallModel.CallStatusEnded) close() } @@ -98,7 +99,8 @@ Dialog { property var correctIndex property var modelList Connections { - target: mainItem.call.core + enabled: mainItem.call + target: mainItem.call ? mainItem.call.core : null // this connection is needed to get the remoteSas when available // due to the asynchronous connection between core and ui onRemoteSasChanged: { diff --git a/Linphone/view/Page/Main/CallPage.qml b/Linphone/view/Page/Main/CallPage.qml index 01f81c050..a9a56209f 100644 --- a/Linphone/view/Page/Main/CallPage.qml +++ b/Linphone/view/Page/Main/CallPage.qml @@ -44,6 +44,7 @@ AbstractMainPage { id: leftPanel Layout.fillWidth: true Layout.fillHeight: true + Control.StackView { id: listStackView clip: true @@ -57,6 +58,7 @@ AbstractMainPage { id: historyListItem ColumnLayout { + spacing: 30 * DefaultStyle.dp property alias listView: historyListView RowLayout { spacing: 16 * DefaultStyle.dp @@ -211,25 +213,37 @@ AbstractMainPage { } RowLayout { spacing: 3 * DefaultStyle.dp - Image { - source: modelData.core.status === LinphoneEnums.CallStatus.Declined + EffectImage { + id: statusIcon + imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted - ? modelData.core.isOutgoing - ? AppIcons.outgoingCallRejected - : AppIcons.incomingCallRejected - : modelData.core.status === LinphoneEnums.CallStatus.Missed - ? modelData.core.isOutgoing - ? AppIcons.outgoingCallMissed - : AppIcons.incomingCallMissed - : modelData.core.isOutgoing - ? AppIcons.outgoingCall - : AppIcons.incomingCall - Layout.preferredWidth: 5 * DefaultStyle.dp - Layout.preferredHeight: 5 * DefaultStyle.dp - sourceSize.width: 5 * DefaultStyle.dp - sourceSize.height: 5 * DefaultStyle.dp + ? AppIcons.arrowElbow + : modelData.core.isOutgoing + ? AppIcons.arrowUpRight + : AppIcons.arrowDownLeft + colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined + || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere + || modelData.core.status === LinphoneEnums.CallStatus.Aborted + || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted + || modelData.core.status === LinphoneEnums.CallStatus.Missed + ? DefaultStyle.danger_500main + : modelData.core.isOutgoing + ? DefaultStyle.info_500_main + : DefaultStyle.success_500main + Layout.preferredWidth: 12 * DefaultStyle.dp + Layout.preferredHeight: 12 * DefaultStyle.dp + transform: Rotation { + angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined + || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere + || modelData.core.status === LinphoneEnums.CallStatus.Aborted + || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0 + origin { + x: statusIcon.width/2 + y: statusIcon.height/2 + } + } } Text { // text: modelData.core.date @@ -309,6 +323,7 @@ AbstractMainPage { Component { id: newCallItem ColumnLayout { + spacing: 30 * DefaultStyle.dp RowLayout { Layout.leftMargin: listStackView.sideMargin Layout.rightMargin: listStackView.sideMargin @@ -465,25 +480,37 @@ AbstractMainPage { ColumnLayout { Layout.alignment: Qt.AlignVCenter RowLayout { - Image { - source: modelData.core.status === LinphoneEnums.CallStatus.Declined + EffectImage { + id: statusIcon + imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted - ? modelData.core.isOutgoing - ? AppIcons.outgoingCallRejected - : AppIcons.incomingCallRejected - : modelData.core.status === LinphoneEnums.CallStatus.Missed - ? modelData.core.isOutgoing - ? AppIcons.outgoingCallMissed - : AppIcons.incomingCallMissed - : modelData.core.isOutgoing - ? AppIcons.outgoingCall - : AppIcons.incomingCall - Layout.preferredWidth: 6.67 * DefaultStyle.dp - Layout.preferredHeight: 6.67 * DefaultStyle.dp - sourceSize.width: 6.67 * DefaultStyle.dp - sourceSize.height: 6.67 * DefaultStyle.dp + ? AppIcons.arrowElbow + : modelData.core.isOutgoing + ? AppIcons.arrowUpRight + : AppIcons.arrowDownLeft + colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined + || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere + || modelData.core.status === LinphoneEnums.CallStatus.Aborted + || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted + || modelData.core.status === LinphoneEnums.CallStatus.Missed + ? DefaultStyle.danger_500main + : modelData.core.isOutgoing + ? DefaultStyle.info_500_main + : DefaultStyle.success_500main + Layout.preferredWidth: 16 * DefaultStyle.dp + Layout.preferredHeight: 16 * DefaultStyle.dp + transform: Rotation { + angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined + || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere + || modelData.core.status === LinphoneEnums.CallStatus.Aborted + || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0 + origin { + x: statusIcon.width/2 + y: statusIcon.height/2 + } + } } Text { text: modelData.core.status === LinphoneEnums.CallStatus.Missed diff --git a/Linphone/view/Page/Main/ContactPage.qml b/Linphone/view/Page/Main/ContactPage.qml index 0795f4472..8d82267d6 100644 --- a/Linphone/view/Page/Main/ContactPage.qml +++ b/Linphone/view/Page/Main/ContactPage.qml @@ -62,6 +62,7 @@ AbstractMainPage { Layout.fillWidth: true Layout.fillHeight: true property int sideMargin: 25 * DefaultStyle.dp + spacing: 30 * DefaultStyle.dp RowLayout { Layout.fillWidth: true @@ -92,7 +93,6 @@ AbstractMainPage { } ColumnLayout { - Layout.topMargin: 30 * DefaultStyle.dp Layout.leftMargin: leftPanel.sideMargin enabled: mainItem.leftPanelEnabled SearchBar { diff --git a/Linphone/view/Page/Main/MeetingPage.qml b/Linphone/view/Page/Main/MeetingPage.qml index 04d04af94..413a1b3f9 100644 --- a/Linphone/view/Page/Main/MeetingPage.qml +++ b/Linphone/view/Page/Main/MeetingPage.qml @@ -16,6 +16,7 @@ AbstractMainPage { property bool leftPanelEnabled: true property ConferenceInfoGui selectedConference property int meetingListCount + signal newConfCreated() onSelectedConferenceChanged: { if (selectedConference) { @@ -45,6 +46,52 @@ AbstractMainPage { } } + Dialog { + id: cancelAndDeleteConfDialog + property bool cancel: false + signal cancelRequested() + // width: 278 * DefaultStyle.dp + text: cancel ? qsTr("Souhaitez-vous annuler et supprimer cette réunion ?") : qsTr("Souhaitez-vous supprimer cette réunion ?") + buttons: [ + Button { + visible: cancelAndDeleteConfDialog.cancel + text: qsTr("Annuler et supprimer") + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + onClicked: { + cancelAndDeleteConfDialog.accepted() + cancelAndDeleteConfDialog.close() + cancelAndDeleteConfDialog.cancelRequested() + } + }, + Button { + text: cancelAndDeleteConfDialog.cancel ? qsTr("Supprimer seulement") : qsTr("Supprimer") + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + onClicked: { + cancelAndDeleteConfDialog.accepted() + cancelAndDeleteConfDialog.close() + } + }, + Button { + text: qsTr("Retour") + inversedColors: true + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + onClicked: { + cancelAndDeleteConfDialog.rejected() + cancelAndDeleteConfDialog.close() + } + } + ] + } + leftPanelContent: ColumnLayout { id: leftPanel Layout.fillWidth: true @@ -52,66 +99,59 @@ AbstractMainPage { property int sideMargin: 25 * DefaultStyle.dp ColumnLayout { - Layout.topMargin: 30 * DefaultStyle.dp + // Layout.topMargin: 30 * DefaultStyle.dp Layout.leftMargin: leftPanel.sideMargin + spacing: 30 * DefaultStyle.dp + enabled: mainItem.leftPanelEnabled + + RowLayout { + visible: leftPanelStackView.currentItem.objectName == "listLayout" + Layout.fillWidth: true + 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.setUpConference() + } + } + } + Item { Layout.fillWidth: true Layout.fillHeight: true - Control.ScrollBar { - id: meetingsScrollbar - visible: leftPanelStackView.currentItem.objectName == "listLayout" - 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 - anchors.rightMargin: leftPanel.sideMargin } Component { id: listLayout ColumnLayout { property string objectName: "listLayout" 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.setUpConference() - } - } - } SearchBar { id: searchBar - Layout.rightMargin: leftPanel.sideMargin Layout.fillWidth: true + Layout.rightMargin: leftPanel.sideMargin placeholderText: qsTr("Rechercher une réunion") } @@ -126,21 +166,40 @@ AbstractMainPage { visible: mainItem.showDefaultItem } - MeetingList { - id: conferenceList - visible: count != 0 - hoverEnabled: mainItem.leftPanelEnabled - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: 20 * DefaultStyle.dp - searchBarText: searchBar.text - onSelectedConferenceChanged: { - mainItem.selectedConference = selectedConference + RowLayout { + MeetingList { + id: conferenceList + visible: count != 0 + hoverEnabled: mainItem.leftPanelEnabled + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: 20 * DefaultStyle.dp + searchBarText: searchBar.text + onSelectedConferenceChanged: { + mainItem.selectedConference = selectedConference + } + onCountChanged: { + mainItem.meetingListCount = count + } + Connections { + target: mainItem + onNewConfCreated: { + conferenceList.forceUpdate() + } + } + Control.ScrollBar.vertical: meetingsScrollbar } - onCountChanged: { - mainItem.meetingListCount = count + Control.ScrollBar { + id: meetingsScrollbar + visible: leftPanelStackView.currentItem.objectName == "listLayout" + active: true + interactive: true + policy: Control.ScrollBar.AsNeeded + Layout.fillHeight: true + // anchors.top: parent.top + // anchors.bottom: parent.bottom + // anchors.right: parent.right } - Control.ScrollBar.vertical: meetingsScrollbar } } } @@ -152,10 +211,14 @@ AbstractMainPage { id: createConf MeetingSetUp { Layout.rightMargin: leftPanel.sideMargin - onCreationSucceed: { + onSaveSucceed: { + mainItem.newConfCreated() leftPanelStackView.pop() UtilsCpp.showInformationPopup(qsTr("Nouvelle réunion"), qsTr("Réunion planifiée avec succès"), true) } + onReturnRequested: { + leftPanelStackView.pop() + } onAddParticipantsRequested: { leftPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui, "container": leftPanelStackView}) } @@ -178,6 +241,10 @@ AbstractMainPage { onReturnRequested: { mainItem.rightPanelStackView.pop() } + onSaveSucceed: { + mainItem.rightPanelStackView.pop() + UtilsCpp.showInformationPopup(qsTr("Enregistré"), qsTr("Réunion modifiée avec succès"), true) + } onAddParticipantsRequested: { mainItem.rightPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui, "container": mainItem.rightPanelStackView}) } @@ -200,8 +267,8 @@ AbstractMainPage { id: meetingDetail RowLayout { ColumnLayout { - Layout.alignment: Qt.AlignTop Layout.preferredWidth: 393 * DefaultStyle.dp + Layout.alignment: Qt.AlignTop Layout.fillWidth: false Layout.fillHeight: true Layout.leftMargin: 39 * DefaultStyle.dp @@ -216,7 +283,7 @@ AbstractMainPage { Layout.preferredHeight: 24 * DefaultStyle.dp } Text { - text: mainItem.selectedConference && mainItem.selectedConference.core.subject + text: mainItem.selectedConference ? mainItem.selectedConference.core.subject : "" font { pixelSize: 20 * DefaultStyle.dp weight: 800 * DefaultStyle.dp @@ -261,13 +328,20 @@ AbstractMainPage { } } 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) + cancelAndDeleteConfDialog.cancel = UtilsCpp.isMe(mainItem.selectedConference.core.organizerAddress) + cancelAndDeleteConfDialog.open() // mainItem.contactDeletionRequested(mainItem.selectedConference) deletePopup.close() } + Connections { + target: cancelAndDeleteConfDialog + onCancelRequested: { + mainItem.selectedConference.core.lCancelConferenceInfo() + } + onAccepted: { + mainItem.selectedConference.core.lDeleteConferenceInfo() + } + } } } } @@ -287,7 +361,7 @@ AbstractMainPage { } Button { Layout.fillWidth: true - text: mainItem.selectedConference && mainItem.selectedConference.core.uri + text: mainItem.selectedConference ? mainItem.selectedConference.core.uri : "" textSize: 14 * DefaultStyle.dp textWeight: 400 * DefaultStyle.dp underline: true @@ -334,7 +408,7 @@ AbstractMainPage { source: AppIcons.globe } Text { - text: qsTr("Time zone: ") + (mainItem.selectedConference && (mainItem.selectedConference.core.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName)) + text: qsTr("Time zone: ") + (mainItem.selectedConference ? (mainItem.selectedConference.core.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName) : "") font { pixelSize: 14 * DefaultStyle.dp capitalization: Font.Capitalize @@ -354,7 +428,7 @@ AbstractMainPage { colorizationColor: DefaultStyle.main2_600 } Text { - text: mainItem.selectedConference && mainItem.selectedConference.core.description + text: mainItem.selectedConference ? mainItem.selectedConference.core.description : "" Layout.fillWidth: true font { pixelSize: 14 * DefaultStyle.dp @@ -375,10 +449,10 @@ AbstractMainPage { Avatar { Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp - address: mainItem.selectedConference && mainItem.selectedConference.core.organizerAddress + address: mainItem.selectedConference ? mainItem.selectedConference.core.organizerAddress : "" } Text { - text: mainItem.selectedConference && mainItem.selectedConference.core.organizerName + text: mainItem.selectedConference ? mainItem.selectedConference.core.organizerName : "" font { pixelSize: 14 * DefaultStyle.dp capitalization: Font.Capitalize @@ -402,7 +476,7 @@ AbstractMainPage { id: participantList Layout.preferredHeight: Math.min(184 * DefaultStyle.dp, contentHeight) Layout.fillWidth: true - model: mainItem.selectedConference && mainItem.selectedConference.core.participants || [] + model: mainItem.selectedConference ? mainItem.selectedConference.core.participants : [] clip: true delegate: RowLayout { height: 56 * DefaultStyle.dp @@ -434,7 +508,6 @@ AbstractMainPage { } } Button { - property var callObj Layout.fillWidth: true text: qsTr("Rejoindre la réunion") topPadding: 11 * DefaultStyle.dp @@ -442,7 +515,7 @@ AbstractMainPage { onClicked: { console.log("TODO: join conf", mainItem.selectedConference.core.subject) console.log(mainItem.selectedConference.core.uri) - callObj = UtilsCpp.createCall(mainItem.selectedConference.core.uri) + UtilsCpp.setupConference(mainItem.selectedConference) } } } diff --git a/Linphone/view/Style/AppIcons.qml b/Linphone/view/Style/AppIcons.qml index f35708992..26eadae8b 100644 --- a/Linphone/view/Style/AppIcons.qml +++ b/Linphone/view/Style/AppIcons.qml @@ -24,17 +24,17 @@ QtObject { property string chiffrement: "image://internal/chiffrement.svg" property string interoperable: "image://internal/interoperable.svg" property string phone: "image://internal/phone.svg" - property string phoneSelected: "image://internal/phone-selected.svg" + property string phoneSelected: "image://internal/phone-fill.svg" property string newCall: "image://internal/phone-plus.svg" property string endCall: "image://internal/phone-disconnect.svg" property string callList: "image://internal/phone-list.svg" property string transferCall: "image://internal/phone-transfer.svg" property string adressBook: "image://internal/address-book.svg" - property string adressBookSelected: "image://internal/address-book-selected.svg" + property string adressBookSelected: "image://internal/address-book-fill.svg" property string chatTeardropText: "image://internal/chat-teardrop-text.svg" - property string chatTeardropTextSelected: "image://internal/chat-teardrop-text-selected.svg" + property string chatTeardropTextSelected: "image://internal/chat-teardrop-text-fill.svg" property string usersThree: "image://internal/users-three.svg" - property string usersThreeSelected: "image://internal/users-three-selected.svg" + property string usersThreeSelected: "image://internal/users-three-fill.svg" property string userPlus: "image://internal/user-plus.svg" property string noItemImage: "image://internal/noItemImage.svg" property string verticalDots: "image://internal/dots-three-vertical.svg" @@ -45,12 +45,9 @@ QtObject { property string magnifier: "image://internal/magnifying-glass.svg" property string backspaceFill: "image://internal/backspace-fill.svg" property string closeX: "image://internal/x.svg" - property string incomingCall: "image://internal/incoming_call.svg" - property string incomingCallMissed: "image://internal/incoming_call_missed.svg" - property string incomingCallRejected: "image://internal/incoming_call_rejected.svg" - property string outgoingCall: "image://internal/outgoing_call.svg" - property string outgoingCallMissed: "image://internal/outgoing_call_missed.svg" - property string outgoingCallRejected: "image://internal/outgoing_call_rejected.svg" + property string arrowDownLeft: "image://internal/arrow-down-left.svg" + property string arrowUpRight: "image://internal/arrow-up-right.svg" + property string arrowElbow: "image://internal/arrow-elbow-left.svg" property string microphone: "image://internal/microphone.svg" property string microphoneSlash: "image://internal/microphone-slash.svg" property string camera: "image://internal/camera.svg" @@ -83,5 +80,6 @@ QtObject { property string usersTwo: "image://internal/users.svg" property string globe: "image://internal/globe-hemisphere-west.svg" property string slide: "image://internal/slideshow.svg" - + property string busyIndicator: "image://internal/busy-indicator.svg" + property string meeting: "image://internal/reunion.svg" }