Feature : Call list.

- Add CallProxy for GUI to manage call list;
- Add a function on Core to retrieve remote address (TODO: change the name)
- Connect first/last call events.
- Fix wrong parameter in call notification.
This commit is contained in:
Julien Wadel 2023-12-07 15:33:25 +01:00
parent 1cf6a076d4
commit 577aee8c98
17 changed files with 595 additions and 119 deletions

View file

@ -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<AccountCore>(Constants::MainQmlUri, 1, 0, "AccountCore", QLatin1String("Uncreatable"));
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
qmlRegisterUncreatableType<CallCore>(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable"));
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy");
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
qmlRegisterType<FriendGui>(Constants::MainQmlUri, 1, 0, "FriendGui");
qmlRegisterUncreatableType<FriendCore>(Constants::MainQmlUri, 1, 0, "FriendCore", QLatin1String("Uncreatable"));
qmlRegisterType<MagicSearchProxy>(Constants::MainQmlUri, 1, 0, "MagicSearchProxy");

View file

@ -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

View file

@ -145,6 +145,10 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
});
}
QString CallCore::getPeerAddress() const {
return mPeerAddress;
}
LinphoneEnums::CallStatus CallCore::getStatus() const {
return mStatus;
}

View file

@ -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<CallCore> me);
QString getPeerAddress() const;
LinphoneEnums::CallStatus getStatus() const;
void setStatus(LinphoneEnums::CallStatus status);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "CallList.hpp"
#include "CallCore.hpp"
#include "CallGui.hpp"
#include "core/App.hpp"
#include <QSharedPointer>
#include <linphone++/linphone.hh>
// =============================================================================
DEFINE_ABSTRACT_OBJECT(CallList)
QSharedPointer<CallList> CallList::create() {
auto model = QSharedPointer<CallList>(new CallList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
model->setSelf(model);
return model;
}
QSharedPointer<CallCore> CallList::createCallCore(const std::shared_ptr<linphone::Call> &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<CallList> me) {
mModelConnection = QSharedPointer<SafeConnection<CallList, CoreModel>>(
new SafeConnection<CallList, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
mModelConnection->makeConnectToCore(&CallList::lUpdate, [this]() {
mModelConnection->invokeToModel([this]() {
// Avoid copy to lambdas
QList<QSharedPointer<CallCore>> *calls = new QList<QSharedPointer<CallCore>>();
mustBeInLinphoneThread(getClassName());
auto linphoneCalls = CoreModel::getInstance()->getCore()->getCalls();
auto currentCall = CoreModel::getInstance()->getCore()->getCurrentCall();
QSharedPointer<CallCore> 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<linphone::Call> &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<CallCore> 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<CallCore> 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<CallCore> CallList::getNextCall() const {
QSharedPointer<CallCore> call;
auto currentCall = getCurrentCallCore();
for (auto it = mList.rbegin(); !call && it != mList.rend(); ++it) {
if (*it != currentCall) {
call = it->objectCast<CallCore>();
}
}
return call;
}
void CallList::onStateChanged() {
auto call = dynamic_cast<CallCore *>(sender());
switch (call->getState()) {
case LinphoneEnums::CallState::StreamsRunning:
case LinphoneEnums::CallState::Resuming: {
auto sharedCall = get(call);
setCurrentCall(sharedCall.objectCast<CallCore>());
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<CallCore>()));
return QVariant();
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef CALL_LIST_H_
#define CALL_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QLocale>
class CallGui;
class CallCore;
class CoreModel;
// =============================================================================
class CallList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<CallList> create();
// Create a CallCore and make connections to List.
QSharedPointer<CallCore> createCallCore(const std::shared_ptr<linphone::Call> &call);
CallList(QObject *parent = Q_NULLPTR);
~CallList();
void setSelf(QSharedPointer<CallList> me);
CallGui *getCurrentCall() const; // Used for Ui
QSharedPointer<CallCore> getCurrentCallCore() const;
void setCurrentCall(QSharedPointer<CallCore> 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<CallCore> 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<CallCore> mCurrentCall;
QSharedPointer<SafeConnection<CallList, CoreModel>> mModelConnection;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<CallList *>(sourceModel())->getCurrentCall();
return mCurrentCall;
}
void CallProxy::setCurrentCall(CallGui *call) {
dynamic_cast<CallList *>(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<CallList *>(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<CallGui *>();
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<CallGui *>()->getCore()->getPeerAddress() < r.value<CallGui *>()->getCore()->getPeerAddress();
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<CallList> mList;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -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) {

View file

@ -201,7 +201,7 @@ void CoreModel::onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core,
emit callStatsUpdated(core, call, stats);
}
void CoreModel::onCallCreated(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call) {
emit callCreated(lc, call);
emit callCreated(call);
}
void CoreModel::onChatRoomRead(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
@ -235,6 +235,9 @@ void CoreModel::onEcCalibrationResult(const std::shared_ptr<linphone::Core> &cor
int delayMs) {
emit ecCalibrationResult(core, status, delayMs);
}
void CoreModel::onFirstCallStarted(const std::shared_ptr<linphone::Core> &core) {
emit firstCallStarted();
}
void CoreModel::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message) {
@ -244,6 +247,11 @@ void CoreModel::onIsComposingReceived(const std::shared_ptr<linphone::Core> &cor
const std::shared_ptr<linphone::ChatRoom> &room) {
emit isComposingReceived(core, room);
}
void CoreModel::onLastCallEnded(const std::shared_ptr<linphone::Core> &core) {
emit lastCallEnded();
}
void CoreModel::onLogCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info) {

View file

@ -119,11 +119,13 @@ private:
virtual void onEcCalibrationResult(const std::shared_ptr<linphone::Core> &core,
linphone::EcCalibratorStatus status,
int delayMs) override;
virtual void onFirstCallStarted(const std::shared_ptr<linphone::Core> &core) override;
virtual void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message) override;
virtual void onIsComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room) override;
virtual void onLastCallEnded(const std::shared_ptr<linphone::Core> &core) override;
virtual void onLogCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info) override;
@ -183,7 +185,7 @@ signals:
void callStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats);
void callCreated(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call);
void callCreated(const std::shared_ptr<linphone::Call> &call);
void chatRoomRead(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::ChatRoom> &chatRoom);
void chatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
@ -198,11 +200,13 @@ signals:
void dtmfReceived(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call, int dtmf);
void
ecCalibrationResult(const std::shared_ptr<linphone::Core> &core, linphone::EcCalibratorStatus status, int delayMs);
void firstCallStarted();
void globalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message);
void isComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room);
void lastCallEnded();
void logCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info);

View file

@ -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;
}
}

View file

@ -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<QString, QString> &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

View file

@ -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

View file

@ -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{

View file

@ -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"

View file

@ -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'
}
}
}
}