diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index 05bc5706e..604b75509 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -36,6 +36,8 @@ #include "core/account/AccountProxy.hpp" #include "core/call/CallCore.hpp" #include "core/call/CallGui.hpp" +#include "core/call/CallList.hpp" +#include "core/call/CallProxy.hpp" #include "core/camera/CameraGui.hpp" #include "core/friend/FriendCore.hpp" #include "core/friend/FriendGui.hpp" @@ -149,6 +151,8 @@ void App::initCppInterfaces() { qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "AccountCore", QLatin1String("Uncreatable")); qmlRegisterType(Constants::MainQmlUri, 1, 0, "CallGui"); qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable")); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "CallProxy"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "CallGui"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "FriendGui"); qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "FriendCore", QLatin1String("Uncreatable")); qmlRegisterType(Constants::MainQmlUri, 1, 0, "MagicSearchProxy"); diff --git a/Linphone/core/CMakeLists.txt b/Linphone/core/CMakeLists.txt index 5778f1717..524bde53e 100644 --- a/Linphone/core/CMakeLists.txt +++ b/Linphone/core/CMakeLists.txt @@ -6,6 +6,8 @@ list(APPEND _LINPHONEAPP_SOURCES core/App.cpp core/call/CallCore.cpp core/call/CallGui.cpp + core/call/CallList.cpp + core/call/CallProxy.cpp core/camera/CameraGui.cpp core/camera/CameraDummy.cpp core/friend/FriendCore.cpp diff --git a/Linphone/core/call/CallCore.cpp b/Linphone/core/call/CallCore.cpp index dabf89991..ef243b2a9 100644 --- a/Linphone/core/call/CallCore.cpp +++ b/Linphone/core/call/CallCore.cpp @@ -145,6 +145,10 @@ void CallCore::setSelf(QSharedPointer me) { }); } +QString CallCore::getPeerAddress() const { + return mPeerAddress; +} + LinphoneEnums::CallStatus CallCore::getStatus() const { return mStatus; } diff --git a/Linphone/core/call/CallCore.hpp b/Linphone/core/call/CallCore.hpp index dfc32713e..5475e6433 100644 --- a/Linphone/core/call/CallCore.hpp +++ b/Linphone/core/call/CallCore.hpp @@ -40,7 +40,7 @@ class CallCore : public QObject, public AbstractObject { Q_PROPERTY(bool microphoneMuted READ getMicrophoneMuted WRITE lSetMicrophoneMuted NOTIFY microphoneMutedChanged) Q_PROPERTY(bool cameraEnabled READ getCameraEnabled WRITE lSetCameraEnabled NOTIFY cameraEnabledChanged) Q_PROPERTY(bool paused READ getPaused WRITE lSetPaused NOTIFY pausedChanged) - Q_PROPERTY(QString peerAddress MEMBER mPeerAddress CONSTANT) + Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT) Q_PROPERTY(bool peerSecured READ getPeerSecured WRITE setPeerSecured NOTIFY peerSecuredChanged) Q_PROPERTY( bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged) @@ -53,6 +53,8 @@ public: ~CallCore(); void setSelf(QSharedPointer me); + QString getPeerAddress() const; + LinphoneEnums::CallStatus getStatus() const; void setStatus(LinphoneEnums::CallStatus status); diff --git a/Linphone/core/call/CallList.cpp b/Linphone/core/call/CallList.cpp new file mode 100644 index 000000000..c63225588 --- /dev/null +++ b/Linphone/core/call/CallList.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "CallList.hpp" +#include "CallCore.hpp" +#include "CallGui.hpp" +#include "core/App.hpp" +#include +#include + +// ============================================================================= + +DEFINE_ABSTRACT_OBJECT(CallList) + +QSharedPointer CallList::create() { + auto model = QSharedPointer(new CallList(), &QObject::deleteLater); + model->moveToThread(App::getInstance()->thread()); + model->setSelf(model); + return model; +} + +QSharedPointer CallList::createCallCore(const std::shared_ptr &call) { + auto callCore = CallCore::create(call); + connect(callCore.get(), &CallCore::stateChanged, this, &CallList::onStateChanged); + return callCore; +} + +CallList::CallList(QObject *parent) : ListProxy(parent) { + mustBeInMainThread(getClassName()); +} + +CallList::~CallList() { + mustBeInMainThread("~" + getClassName()); + mModelConnection = nullptr; +} + +void CallList::setSelf(QSharedPointer me) { + mModelConnection = QSharedPointer>( + new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); + + mModelConnection->makeConnectToCore(&CallList::lUpdate, [this]() { + mModelConnection->invokeToModel([this]() { + // Avoid copy to lambdas + QList> *calls = new QList>(); + mustBeInLinphoneThread(getClassName()); + auto linphoneCalls = CoreModel::getInstance()->getCore()->getCalls(); + auto currentCall = CoreModel::getInstance()->getCore()->getCurrentCall(); + QSharedPointer currentCallCore; + for (auto it : linphoneCalls) { + auto model = createCallCore(it); + if (it == currentCall) currentCallCore = model; + calls->push_back(model); + } + mModelConnection->invokeToCore([this, calls, currentCallCore]() { + mustBeInMainThread(getClassName()); + resetData(); + add(*calls); + setHaveCall(calls->size() > 0); + setCurrentCall(currentCallCore); + delete calls; + }); + }); + }); + + mModelConnection->makeConnectToModel(&CoreModel::firstCallStarted, + [this]() { mModelConnection->invokeToCore([this]() { setHaveCall(true); }); }); + mModelConnection->makeConnectToModel(&CoreModel::lastCallEnded, [this]() { + mModelConnection->invokeToCore([this]() { + setHaveCall(false); + setCurrentCall(nullptr); + }); + }); + mModelConnection->makeConnectToModel(&CoreModel::callCreated, [this](const std::shared_ptr &call) { + auto model = createCallCore(call); + mModelConnection->invokeToCore([this, model]() { + // We set the current here and not on firstCallStarted event because we don't want to add unicity check + // while keeping the same model between list and current call. + if (mList.size() == 0) setCurrentCall(model); + add(model); + }); + }); + lUpdate(); +} + +QSharedPointer CallList::getCurrentCallCore() const { + return mCurrentCall; +} + +CallGui *CallList::getCurrentCall() const { + auto call = getCurrentCallCore(); + if (call) return new CallGui(call); + else return nullptr; +} + +void CallList::setCurrentCall(QSharedPointer call) { + if (mCurrentCall != call) { + mCurrentCall = call; + emit currentCallChanged(); + } +} + +bool CallList::getHaveCall() const { + return mHaveCall; +} + +void CallList::setHaveCall(bool haveCall) { + if (mHaveCall != haveCall) { + mHaveCall = haveCall; + emit haveCallChanged(); + } +} + +QSharedPointer CallList::getNextCall() const { + QSharedPointer call; + auto currentCall = getCurrentCallCore(); + for (auto it = mList.rbegin(); !call && it != mList.rend(); ++it) { + if (*it != currentCall) { + call = it->objectCast(); + } + } + + return call; +} + +void CallList::onStateChanged() { + auto call = dynamic_cast(sender()); + switch (call->getState()) { + case LinphoneEnums::CallState::StreamsRunning: + case LinphoneEnums::CallState::Resuming: { + auto sharedCall = get(call); + setCurrentCall(sharedCall.objectCast()); + break; + } + case LinphoneEnums::CallState::Released: { + auto sharedCall = get(call); + auto currentCall = getCurrentCallCore(); + // Update current call + if (sharedCall == currentCall) { + // Unpause the next call. The current call will change on resume. + // Assumption: All calls that are not the current are paused. + auto nextCall = getNextCall(); + if (nextCall) nextCall->lSetPaused(false); + } + sharedCall->disconnect(this); + remove(sharedCall); + break; + } + default: { + } + } +} + +QVariant CallList::data(const QModelIndex &index, int role) const { + int row = index.row(); + if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); + if (role == Qt::DisplayRole) return QVariant::fromValue(new CallGui(mList[row].objectCast())); + return QVariant(); +} diff --git a/Linphone/core/call/CallList.hpp b/Linphone/core/call/CallList.hpp new file mode 100644 index 000000000..1589c77d1 --- /dev/null +++ b/Linphone/core/call/CallList.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CALL_LIST_H_ +#define CALL_LIST_H_ + +#include "../proxy/ListProxy.hpp" +#include "tool/AbstractObject.hpp" +#include "tool/thread/SafeConnection.hpp" +#include + +class CallGui; +class CallCore; +class CoreModel; +// ============================================================================= + +class CallList : public ListProxy, public AbstractObject { + Q_OBJECT +public: + static QSharedPointer create(); + // Create a CallCore and make connections to List. + QSharedPointer createCallCore(const std::shared_ptr &call); + CallList(QObject *parent = Q_NULLPTR); + ~CallList(); + + void setSelf(QSharedPointer me); + + CallGui *getCurrentCall() const; // Used for Ui + QSharedPointer getCurrentCallCore() const; + void setCurrentCall(QSharedPointer call); + + bool getHaveCall() const; + void setHaveCall(bool haveCall); + + // Get the next call after the current one. Used to switch the current call. + // At the moment, it select the last call in the list. + QSharedPointer getNextCall() const; + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; +signals: + void lUpdate(); + void haveCallChanged(); + void currentCallChanged(); + +private: + // Check the state from CallCore: sender() must be a CallCore. + void onStateChanged(); + + bool mHaveCall = false; + QSharedPointer mCurrentCall; + QSharedPointer> mModelConnection; + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/call/CallProxy.cpp b/Linphone/core/call/CallProxy.cpp new file mode 100644 index 000000000..81b66ba2a --- /dev/null +++ b/Linphone/core/call/CallProxy.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "CallProxy.hpp" +#include "CallGui.hpp" +#include "CallList.hpp" + +DEFINE_ABSTRACT_OBJECT(CallProxy) + +CallProxy::CallProxy(QObject *parent) : SortFilterProxy(parent) { + mList = CallList::create(); + connect(mList.get(), &CallList::currentCallChanged, this, &CallProxy::resetCurrentCall); + connect(mList.get(), &CallList::haveCallChanged, this, &CallProxy::haveCallChanged); + setSourceModel(mList.get()); + sort(0); +} + +CallProxy::~CallProxy() { + setSourceModel(nullptr); +} + +QString CallProxy::getFilterText() const { + return mFilterText; +} + +void CallProxy::setFilterText(const QString &filter) { + if (mFilterText != filter) { + mFilterText = filter; + invalidate(); + emit filterTextChanged(); + } +} + +CallGui *CallProxy::getCurrentCall() { + if (!mCurrentCall) mCurrentCall = dynamic_cast(sourceModel())->getCurrentCall(); + return mCurrentCall; +} + +void CallProxy::setCurrentCall(CallGui *call) { + dynamic_cast(sourceModel())->setCurrentCall(call->mCore); +} + +// Reset the default account to let UI build its new object if needed. +void CallProxy::resetCurrentCall() { + mCurrentCall = nullptr; + emit this->currentCallChanged(); // Warn the UI +} + +bool CallProxy::getHaveCall() const { + return dynamic_cast(sourceModel())->getHaveCall(); +} + +bool CallProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + bool show = (mFilterText.isEmpty() || mFilterText == "*"); + if (!show) { + QRegularExpression search(QRegularExpression::escape(mFilterText), + QRegularExpression::CaseInsensitiveOption | + QRegularExpression::UseUnicodePropertiesOption); + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + auto model = sourceModel()->data(index); + auto call = model.value(); + show = call->getCore()->getPeerAddress().contains(search); + } + + return show; +} + +bool CallProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { + auto l = sourceModel()->data(left); + auto r = sourceModel()->data(right); + + return l.value()->getCore()->getPeerAddress() < r.value()->getCore()->getPeerAddress(); +} diff --git a/Linphone/core/call/CallProxy.hpp b/Linphone/core/call/CallProxy.hpp new file mode 100644 index 000000000..7bd30262d --- /dev/null +++ b/Linphone/core/call/CallProxy.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CALL_PROXY_H_ +#define CALL_PROXY_H_ + +#include "../proxy/SortFilterProxy.hpp" +#include "core/call/CallGui.hpp" +#include "core/call/CallList.hpp" +#include "tool/AbstractObject.hpp" + +// ============================================================================= + +class CallProxy : public SortFilterProxy, public AbstractObject { + Q_OBJECT + + Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged) + Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged) + Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged) + +public: + CallProxy(QObject *parent = Q_NULLPTR); + ~CallProxy(); + + QString getFilterText() const; + void setFilterText(const QString &filter); + // Get a new object from List or give the stored one. + CallGui *getCurrentCall(); + // TODO for manual setting. Changing the currentCall is automatically done by call->onStateChanged() on + // StreamRunning and Resuming + void setCurrentCall(CallGui *call); + void resetCurrentCall(); // Reset the default account to let UI build its new object if needed. + + bool getHaveCall() const; + +signals: + void filterTextChanged(); + void currentCallChanged(); + void haveCallChanged(); + +protected: + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + + QString mFilterText; + CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List + QSharedPointer mList; + + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/model/call/CallModel.cpp b/Linphone/model/call/CallModel.cpp index 4c9e48e12..79294d7c7 100644 --- a/Linphone/model/call/CallModel.cpp +++ b/Linphone/model/call/CallModel.cpp @@ -68,6 +68,7 @@ void CallModel::terminate() { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mMonitor->terminate(); } + void CallModel::setPaused(bool paused) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); if (paused) { diff --git a/Linphone/model/core/CoreModel.cpp b/Linphone/model/core/CoreModel.cpp index f5d514c05..883392331 100644 --- a/Linphone/model/core/CoreModel.cpp +++ b/Linphone/model/core/CoreModel.cpp @@ -201,7 +201,7 @@ void CoreModel::onCallStatsUpdated(const std::shared_ptr &core, emit callStatsUpdated(core, call, stats); } void CoreModel::onCallCreated(const std::shared_ptr &lc, const std::shared_ptr &call) { - emit callCreated(lc, call); + emit callCreated(call); } void CoreModel::onChatRoomRead(const std::shared_ptr &core, const std::shared_ptr &chatRoom) { @@ -235,6 +235,9 @@ void CoreModel::onEcCalibrationResult(const std::shared_ptr &cor int delayMs) { emit ecCalibrationResult(core, status, delayMs); } +void CoreModel::onFirstCallStarted(const std::shared_ptr &core) { + emit firstCallStarted(); +} void CoreModel::onGlobalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message) { @@ -244,6 +247,11 @@ void CoreModel::onIsComposingReceived(const std::shared_ptr &cor const std::shared_ptr &room) { emit isComposingReceived(core, room); } + +void CoreModel::onLastCallEnded(const std::shared_ptr &core) { + emit lastCallEnded(); +} + void CoreModel::onLogCollectionUploadStateChanged(const std::shared_ptr &core, linphone::Core::LogCollectionUploadState state, const std::string &info) { diff --git a/Linphone/model/core/CoreModel.hpp b/Linphone/model/core/CoreModel.hpp index 8c145cd40..77f08e81a 100644 --- a/Linphone/model/core/CoreModel.hpp +++ b/Linphone/model/core/CoreModel.hpp @@ -119,11 +119,13 @@ private: virtual void onEcCalibrationResult(const std::shared_ptr &core, linphone::EcCalibratorStatus status, int delayMs) override; + virtual void onFirstCallStarted(const std::shared_ptr &core) override; virtual void onGlobalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message) override; virtual void onIsComposingReceived(const std::shared_ptr &core, const std::shared_ptr &room) override; + virtual void onLastCallEnded(const std::shared_ptr &core) override; virtual void onLogCollectionUploadStateChanged(const std::shared_ptr &core, linphone::Core::LogCollectionUploadState state, const std::string &info) override; @@ -183,7 +185,7 @@ signals: void callStatsUpdated(const std::shared_ptr &core, const std::shared_ptr &call, const std::shared_ptr &stats); - void callCreated(const std::shared_ptr &lc, const std::shared_ptr &call); + void callCreated(const std::shared_ptr &call); void chatRoomRead(const std::shared_ptr &core, const std::shared_ptr &chatRoom); void chatRoomStateChanged(const std::shared_ptr &core, const std::shared_ptr &chatRoom, @@ -198,11 +200,13 @@ signals: void dtmfReceived(const std::shared_ptr &lc, const std::shared_ptr &call, int dtmf); void ecCalibrationResult(const std::shared_ptr &core, linphone::EcCalibratorStatus status, int delayMs); + void firstCallStarted(); void globalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message); void isComposingReceived(const std::shared_ptr &core, const std::shared_ptr &room); + void lastCallEnded(); void logCollectionUploadStateChanged(const std::shared_ptr &core, linphone::Core::LogCollectionUploadState state, const std::string &info); diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index ff80b9f68..ef9447acb 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -97,7 +97,9 @@ VariantObject *Utils::createCall(const QString &sipAddress, return data; } - +void Utils::openCallsWindow(CallGui *call) { + if (call) App::getInstance()->getCallsWindow(QVariant::fromValue(call))->show(); +} void Utils::closeCallsWindow() { App::getInstance()->closeCallsWindow(); } @@ -179,4 +181,4 @@ QString Utils::formatElapsedTime(int seconds) { } return (h == 0 ? "" : hours + ":") + min + ":" + sec; -} \ No newline at end of file +} diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index 3887097ab..89322c5cc 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -42,6 +42,7 @@ class QQuickWindow; class VariantObject; +class CallGui; class Utils : public QObject { Q_OBJECT @@ -51,9 +52,11 @@ public: Q_INVOKABLE static VariantObject *getDisplayName(const QString &address); Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32 + Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress, const QString &prepareTransfertAddress = "", const QHash &headers = {}); + Q_INVOKABLE static void openCallsWindow(CallGui *call); Q_INVOKABLE static void closeCallsWindow(); Q_INVOKABLE static VariantObject *haveAccount(); Q_INVOKABLE static QString createAvatar(const QUrl &fileUrl); // Return the avatar path diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index 1b4880ad5..494ccac37 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -51,6 +51,14 @@ Window { autoCloseWindow.restart() } } + + CallProxy{ + id: callList + onCurrentCallChanged: { + console.log("Current call changed:"+currentCall) + if(currentCall) mainWindow.call = currentCall + } + } component BottomButton : Button { required property string enabledIcon diff --git a/Linphone/view/Item/Notification/NotificationReceivedCall.qml b/Linphone/view/Item/Notification/NotificationReceivedCall.qml index 6134616a4..efbc7b2cf 100644 --- a/Linphone/view/Item/Notification/NotificationReceivedCall.qml +++ b/Linphone/view/Item/Notification/NotificationReceivedCall.qml @@ -1,7 +1,7 @@ import QtQuick 2.7 import QtQuick.Layouts 1.3 import Linphone - +import UtilsCpp // ============================================================================= Notification { @@ -36,10 +36,7 @@ Notification { Layout.rightMargin: 20 onClicked: { notification.call.core.lAccept(true) - var windowComp = Qt.createComponent("OngoingCallPage.qml") - var callWindow = windowComp.createObject(null, {callVarObject: callVarObject}) - callWindow.modality = Qt.ApplicationModal - callWindow.show() + UtilsCpp.openCallsWindow(notification.call) } } Item{ diff --git a/Linphone/view/Item/RectangleTest.qml b/Linphone/view/Item/RectangleTest.qml index 74badd244..80945a7b7 100644 --- a/Linphone/view/Item/RectangleTest.qml +++ b/Linphone/view/Item/RectangleTest.qml @@ -7,7 +7,6 @@ Rectangle { +Math.floor(Math.random()*255).toString(16) } - anchors.fill: parent color: genRandomColor() //"blue" opacity: 0.2 border.color: genRandomColor() //"red" diff --git a/Linphone/view/Prototype/CallPrototype.qml b/Linphone/view/Prototype/CallPrototype.qml index fd9ce1563..bef277406 100644 --- a/Linphone/view/Prototype/CallPrototype.qml +++ b/Linphone/view/Prototype/CallPrototype.qml @@ -30,126 +30,162 @@ Window{ target: call && call.core || null onLastErrorMessageChanged: if(mainItem.call) errorMessageText.text=mainItem.call.core.lastErrorMessage } - ColumnLayout{ + RowLayout{ anchors.fill: parent - RowLayout { - id: accountLayout - Layout.fillWidth: true - property AccountProxy accounts: AccountProxy{id: accountProxy} - property var haveAccountVar: UtilsCpp.haveAccount() - property var haveAccount: haveAccountVar ? haveAccountVar.value : false - onHaveAccountChanged: { - console.log("HaveAccount: " +haveAccount) - logStack.replace(haveAccount ? accountListComponent : loginComponent) - } - Control.StackView{ - id: logStack - Layout.preferredHeight: 250 - Layout.preferredWidth: 250 - //initialItem: loginComponent - } - Component{ - id: accountListComponent - ListView{ - id: accountList - Layout.fillHeight: true - model: AccountProxy{} - delegate:Rectangle{ - color: "#11111111" - height: 20 - width: accountList.width - Text{ - - text: modelData.core.identityAddress - } + Rectangle{ + Layout.fillHeight: true + Layout.preferredWidth: 200 + color: 'gray' + opacity: 0.2 + ListView{ + id: callList + anchors.fill: parent + model: CallProxy{ + id: callsModel + onCountChanged: console.log("count:"+count) + } + delegate: RectangleTest{ + height: 40 + width: callList.width + Text{ + id: addressText + anchors.fill: parent + text: modelData.core.peerAddress + onTextChanged: console.log(addressText.text) + Component.onCompleted: console.log(addressText.text) + } + MouseArea{ + anchors.fill: parent + onClicked: { + //modelData.core.lSetPaused(false) + callsModel.currentCall = modelData } } } - Component{ - id: loginComponent - LoginForm{} + } + } + ColumnLayout{ + Layout.fillWidth: true + Layout.fillHeight: true + RowLayout { + id: accountLayout + Layout.fillWidth: true + property AccountProxy accounts: AccountProxy{id: accountProxy} + property var haveAccountVar: UtilsCpp.haveAccount() + property var haveAccount: haveAccountVar ? haveAccountVar.value : false + onHaveAccountChanged: { + console.log("HaveAccount: " +haveAccount) + logStack.replace(haveAccount ? accountListComponent : loginComponent) } - Rectangle{ - id: accountStatus - Layout.preferredWidth: 50 - Layout.preferredHeight: 50 - property int accountCount: accountProxy.count - onAccountCountChanged: console.log("AccountCount:"+accountCount) - property var defaultAccount: accountProxy.defaultAccount - onDefaultAccountChanged: console.log("DefaultAccount:"+defaultAccount) - property var state: accountProxy.count > 0 && defaultAccount? defaultAccount.core.registrationState : LoginPageCpp.registrationState - onStateChanged: console.log("State:"+state) - - color: state === LinphoneEnums.RegistrationState.Ok - ? 'green' - : state === LinphoneEnums.RegistrationState.Failed || state === LinphoneEnums.RegistrationState.None - ? 'red' - : 'orange' - MouseArea{ - anchors.fill: parent - onClicked:{ - logStack.replace(loginComponent) - gc() + Control.StackView{ + id: logStack + Layout.preferredHeight: 250 + Layout.preferredWidth: 250 + //initialItem: loginComponent + } + Component{ + id: accountListComponent + ListView{ + id: accountList + Layout.fillHeight: true + model: AccountProxy{} + delegate:Rectangle{ + color: "#11111111" + height: 20 + width: accountList.width + Text{ + + text: modelData.core.identityAddress + } + } + } + } + Component{ + id: loginComponent + LoginForm{} + } + Rectangle{ + id: accountStatus + Layout.preferredWidth: 50 + Layout.preferredHeight: 50 + property int accountCount: accountProxy.count + onAccountCountChanged: console.log("AccountCount:"+accountCount) + property var defaultAccount: accountProxy.defaultAccount + onDefaultAccountChanged: console.log("DefaultAccount:"+defaultAccount) + property var state: accountProxy.count > 0 && defaultAccount? defaultAccount.core.registrationState : LoginPageCpp.registrationState + onStateChanged: console.log("State:"+state) + + color: state === LinphoneEnums.RegistrationState.Ok + ? 'green' + : state === LinphoneEnums.RegistrationState.Failed || state === LinphoneEnums.RegistrationState.None + ? 'red' + : 'orange' + MouseArea{ + anchors.fill: parent + onClicked:{ + logStack.replace(loginComponent) + gc() + } + } + } + TextInput { + id: usernameToCall + label: "Username to call" + textInputWidth: 250 + } + Button{ + text: 'Call' + onClicked: { + var address = usernameToCall.text + "@sip.linphone.org" + console.log("Calling "+address) + mainItem.callVarObject = UtilsCpp.createCall(address) + proto.component1 = comp } } } - TextInput { - id: usernameToCall - label: "Username to call" - textInputWidth: 250 - } - Button{ - text: 'Call' - onClicked: { - var address = usernameToCall.text + "@sip.linphone.org" - console.log("Calling "+address) - mainItem.callVarObject = UtilsCpp.createCall(address) - proto.component1 = comp - } - } - } - - Rectangle{ - Layout.fillWidth: true - Layout.preferredHeight: 50 - color: call - ? call.core.state === LinphoneEnums.CallState.StreamsRunning - ? 'green' - : call.core.state === LinphoneEnums.CallState.Released - ? 'pink' - : 'orange' - : 'red' + Rectangle{ - anchors.centerIn: parent - color: 'white' - width: stateText.contentWidth - height: stateText.contentHeight - Text{ - id: stateText - text: "State:"+(mainItem.callState ? mainItem.callState : 'None') + Layout.fillWidth: true + Layout.preferredHeight: 50 + color: call + ? call.core.state === LinphoneEnums.CallState.StreamsRunning + ? 'green' + : call.core.state === LinphoneEnums.CallState.Released + ? 'pink' + : 'orange' + : 'red' + Rectangle{ + anchors.centerIn: parent + color: 'white' + width: stateText.contentWidth + height: stateText.contentHeight + Text{ + id: stateText + text: "State:"+(mainItem.callState ? mainItem.callState : 'None') + } } } + Text{ + id: errorMessageText + color: 'red' + } + ItemPrototype{ + id: proto + Layout.fillHeight: true + Layout.fillWidth: true + } + Item{ + Layout.fillHeight: true + Layout.fillWidth: true + } } - Text{ - id: errorMessageText - color: 'red' - } - ItemPrototype{ - id: proto - Layout.fillHeight: true - Layout.fillWidth: true - } - Item{ - Layout.fillHeight: true - Layout.fillWidth: true - } - } - Component{ - id: comp - Rectangle{ - width: 100 - height: width - color: 'pink' + Component{ + id: comp + Rectangle{ + width: 100 + height: width + color: 'pink' + } } } }