mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
start audio call, features : pause call + blind transfer
(call window in c++)
This commit is contained in:
parent
a1d72e6382
commit
4ea1b96246
50 changed files with 1597 additions and 229 deletions
|
|
@ -26,8 +26,10 @@
|
|||
#include <QFileSelector>
|
||||
#include <QGuiApplication>
|
||||
#include <QLibraryInfo>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlFileSelector>
|
||||
#include <QQuickWindow>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/account/AccountCore.hpp"
|
||||
|
|
@ -45,11 +47,14 @@
|
|||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/EnumsToString.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/providers/AvatarProvider.hpp"
|
||||
#include "tool/providers/ImageProvider.hpp"
|
||||
#include "tool/thread/Thread.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(App)
|
||||
|
||||
App::App(int &argc, char *argv[])
|
||||
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
|
||||
mLinphoneThread = new Thread(this);
|
||||
|
|
@ -83,7 +88,7 @@ void App::init() {
|
|||
if (mParser->isSet("qt-logs-only")) QtLogger::enableQtOnly(true);
|
||||
|
||||
if (!mLinphoneThread->isRunning()) {
|
||||
qDebug() << "[App] Starting Thread";
|
||||
qDebug() << log().arg("Starting Thread");
|
||||
mLinphoneThread->start();
|
||||
}
|
||||
setQuitOnLastWindowClosed(true); // TODO: use settings to set it
|
||||
|
|
@ -96,7 +101,7 @@ void App::init() {
|
|||
if (version.majorVersion() == 5 && version.minorVersion() == 9) selectors.push_back("5.9");
|
||||
auto selector = new QQmlFileSelector(mEngine, mEngine);
|
||||
selector->setExtraSelectors(selectors);
|
||||
qInfo() << QStringLiteral("[App] Activated selectors:") << selector->selector()->allSelectors();
|
||||
qInfo() << log().arg("Activated selectors:") << selector->selector()->allSelectors();
|
||||
|
||||
mEngine->addImportPath(":/");
|
||||
mEngine->rootContext()->setContextProperty("applicationDirPath", QGuiApplication::applicationDirPath());
|
||||
|
|
@ -110,9 +115,9 @@ void App::init() {
|
|||
const QUrl url(u"qrc:/Linphone/view/App/Main.qml"_qs);
|
||||
QObject::connect(
|
||||
mEngine, &QQmlApplicationEngine::objectCreated, this,
|
||||
[url](QObject *obj, const QUrl &objUrl) {
|
||||
[this, url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl) {
|
||||
qCritical() << "[App] Main.qml couldn't be load. The app will exit";
|
||||
qCritical() << log().arg("Main.qml couldn't be load. The app will exit");
|
||||
exit(-1);
|
||||
}
|
||||
},
|
||||
|
|
@ -129,6 +134,9 @@ void App::initCppInterfaces() {
|
|||
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Constants(engine); });
|
||||
qmlRegisterSingletonType<Utils>("UtilsCpp", 1, 0, "UtilsCpp",
|
||||
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Utils(engine); });
|
||||
qmlRegisterSingletonType<EnumsToString>(
|
||||
"EnumsToStringCpp", 1, 0, "EnumsToStringCpp",
|
||||
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new EnumsToString(engine); });
|
||||
|
||||
qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
|
||||
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
|
||||
|
|
@ -189,9 +197,70 @@ bool App::notify(QObject *receiver, QEvent *event) {
|
|||
try {
|
||||
done = QApplication::notify(receiver, event);
|
||||
} catch (const std::exception &ex) {
|
||||
qCritical() << "[App] Exception has been catch in notify";
|
||||
qCritical() << log().arg("Exception has been catch in notify");
|
||||
} catch (...) {
|
||||
qCritical() << "[App] Generic exeption has been catch in notify";
|
||||
qCritical() << log().arg("Generic exeption has been catch in notify");
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
QQuickWindow *App::getCallsWindow(QVariant callGui) {
|
||||
mustBeInMainThread(getClassName());
|
||||
if (!mCallsWindow) {
|
||||
const QUrl callUrl("qrc:/Linphone/view/App/CallsWindow.qml");
|
||||
|
||||
qInfo() << log().arg("Creating subwindow: `%1`.").arg(callUrl.toString());
|
||||
|
||||
QQmlComponent component(mEngine, callUrl);
|
||||
if (component.isError()) {
|
||||
qWarning() << component.errors();
|
||||
abort();
|
||||
}
|
||||
qInfo() << log().arg("Subwindow status: `%1`.").arg(component.status());
|
||||
|
||||
QObject *object = component.createWithInitialProperties({{"call", callGui}});
|
||||
Q_ASSERT(object);
|
||||
if (!object) {
|
||||
qCritical() << log().arg("Calls window could not be created.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
|
||||
object->setParent(mEngine);
|
||||
|
||||
auto window = qobject_cast<QQuickWindow *>(object);
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
qCritical() << log().arg("Calls window could not be created.");
|
||||
return nullptr;
|
||||
}
|
||||
mCallsWindow = window;
|
||||
}
|
||||
|
||||
postModelAsync([this]() {
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto callsNb = core->getCallsNb();
|
||||
postCoreAsync([this, callsNb] { mCallsWindow->setProperty("callsCount", callsNb); });
|
||||
});
|
||||
mCallsWindow->setProperty("call", callGui);
|
||||
return mCallsWindow;
|
||||
}
|
||||
|
||||
void App::closeCallsWindow() {
|
||||
if (mCallsWindow) {
|
||||
mCallsWindow->close();
|
||||
mCallsWindow->deleteLater();
|
||||
mCallsWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void App::smartShowWindow(QQuickWindow *window) {
|
||||
if (!window) return;
|
||||
window->setVisible(true);
|
||||
// Force show, maybe redundant with setVisible
|
||||
if (window->visibility() == QWindow::Maximized) // Avoid to change visibility mode
|
||||
window->showMaximized();
|
||||
else window->show();
|
||||
window->raise(); // Raise ensure to get focus on Mac
|
||||
window->requestActivate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,14 @@
|
|||
|
||||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
class CallGui;
|
||||
class Thread;
|
||||
class Notifier;
|
||||
class QQuickWindow;
|
||||
|
||||
class App : public SingleApplication {
|
||||
class App : public SingleApplication, public AbstractObject {
|
||||
public:
|
||||
App(int &argc, char *argv[]);
|
||||
static App *getInstance();
|
||||
|
|
@ -53,6 +56,20 @@ public:
|
|||
QMetaObject::invokeMethod(App::getInstance(), callable);
|
||||
}
|
||||
template <typename Func, typename... Args>
|
||||
static auto postCoreSync(Func &&callable, Args &&...args) {
|
||||
if (QThread::currentThread() == CoreModel::getInstance()->thread()) {
|
||||
bool end = false;
|
||||
postCoreAsync([&end, callable, args...]() mutable {
|
||||
QMetaObject::invokeMethod(App::getInstance(), callable, args..., Qt::DirectConnection);
|
||||
end = true;
|
||||
});
|
||||
while (!end)
|
||||
qApp->processEvents();
|
||||
} else {
|
||||
QMetaObject::invokeMethod(App::getInstance(), callable, Qt::DirectConnection);
|
||||
}
|
||||
}
|
||||
template <typename Func, typename... Args>
|
||||
static auto postModelSync(Func &&callable, Args &&...args) {
|
||||
if (QThread::currentThread() != CoreModel::getInstance()->thread()) {
|
||||
bool end = false;
|
||||
|
|
@ -73,8 +90,13 @@ public:
|
|||
|
||||
void onLoggerInitialized();
|
||||
|
||||
QQuickWindow *getCallsWindow(QVariant callGui);
|
||||
void closeCallsWindow();
|
||||
|
||||
Q_INVOKABLE static void smartShowWindow(QQuickWindow *window);
|
||||
|
||||
QQmlApplicationEngine *mEngine = nullptr;
|
||||
bool notify(QObject *receiver, QEvent *event);
|
||||
bool notify(QObject *receiver, QEvent *event) override;
|
||||
|
||||
enum class StatusCode { gRestartCode = 1000, gDeleteDataCode = 1001 };
|
||||
|
||||
|
|
@ -84,4 +106,9 @@ private:
|
|||
QCommandLineParser *mParser = nullptr;
|
||||
Thread *mLinphoneThread = nullptr;
|
||||
Notifier *mNotifier = nullptr;
|
||||
QQuickWindow *mCallsWindow = nullptr;
|
||||
// TODO : changer ce count lorsqu'on aura liste d'appels
|
||||
int callsCount = 0;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "CallCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
|
|
@ -38,15 +39,25 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
// Should be call from model Thread
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mDir = LinphoneEnums::fromLinphone(call->getDir());
|
||||
mCallModel = Utils::makeQObject_ptr<CallModel>(call);
|
||||
mCallModel->setSelf(mCallModel);
|
||||
mDuration = call->getDuration();
|
||||
mMicrophoneMuted = call->getMicrophoneMuted();
|
||||
mCallModel = Utils::makeQObject_ptr<CallModel>(call);
|
||||
connect(mCallModel.get(), &CallModel::stateChanged, this, &CallCore::onStateChanged);
|
||||
connect(this, &CallCore::lAccept, mCallModel.get(), &CallModel::accept);
|
||||
connect(this, &CallCore::lDecline, mCallModel.get(), &CallModel::decline);
|
||||
connect(this, &CallCore::lTerminate, mCallModel.get(), &CallModel::terminate);
|
||||
mCallModel->setSelf(mCallModel);
|
||||
// mSpeakerMuted = call->getSpeakerMuted();
|
||||
mCameraEnabled = call->cameraEnabled();
|
||||
mDuration = call->getDuration();
|
||||
mState = LinphoneEnums::fromLinphone(call->getState());
|
||||
mPeerAddress = Utils::coreStringToAppString(mCallModel->getRemoteAddress()->asString());
|
||||
mStatus = LinphoneEnums::fromLinphone(call->getCallLog()->getStatus());
|
||||
mTransferState = LinphoneEnums::fromLinphone(call->getTransferState());
|
||||
auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption());
|
||||
auto tokenVerified = mCallModel->getAuthenticationTokenVerified();
|
||||
mPeerSecured = (encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
|
||||
encryption == LinphoneEnums::MediaEncryption::Srtp ||
|
||||
encryption == LinphoneEnums::MediaEncryption::Dtls;
|
||||
mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
|
||||
mState == LinphoneEnums::CallState::PausedByRemote;
|
||||
}
|
||||
|
||||
CallCore::~CallCore() {
|
||||
|
|
@ -65,9 +76,72 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::microphoneMutedChanged, [this](bool isMuted) {
|
||||
mAccountModelConnection->invokeToCore([this, isMuted]() { setMicrophoneMuted(isMuted); });
|
||||
});
|
||||
// mAccountModelConnection->makeConnect(this, &CallCore::lSetSpeakerMuted, [this](bool isMuted) {
|
||||
// mAccountModelConnection->invokeToModel([this, isMuted]() { mCallModel->setSpeakerMuted(isMuted); });
|
||||
// });
|
||||
// mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::speakerMutedChanged, [this](bool isMuted) {
|
||||
// mAccountModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); });
|
||||
// });
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lSetCameraEnabled, [this](bool enabled) {
|
||||
mAccountModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::cameraEnabledChanged, [this](bool enabled) {
|
||||
mAccountModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::durationChanged, [this](int duration) {
|
||||
mAccountModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
|
||||
});
|
||||
connect(mCallModel.get(), &CallModel::stateChanged, this,
|
||||
[this](linphone::Call::State state, const std::string &message) {
|
||||
mAccountModelConnection->invokeToCore([this, state, message]() {
|
||||
setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message));
|
||||
});
|
||||
});
|
||||
connect(mCallModel.get(), &CallModel::statusChanged, this, [this](linphone::Call::Status status) {
|
||||
mAccountModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lSetPaused, [this](bool paused) {
|
||||
mAccountModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::pausedChanged, [this](bool paused) {
|
||||
mAccountModelConnection->invokeToCore([this, paused]() { setPaused(paused); });
|
||||
});
|
||||
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lTransferCall, [this](const QString &address) {
|
||||
mAccountModelConnection->invokeToModel(
|
||||
[this, address]() { mCallModel->transferTo(ToolModel::interpretUrl(address)); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(
|
||||
mCallModel.get(), &CallModel::transferStateChanged,
|
||||
[this](const std::shared_ptr<linphone::Call> &call, linphone::Call::State state) {
|
||||
mAccountModelConnection->invokeToCore([this, state]() {
|
||||
QString message;
|
||||
if (state == linphone::Call::State::Error) {
|
||||
message = "L'appel n'a pas pu être transféré.";
|
||||
}
|
||||
setTransferState(LinphoneEnums::fromLinphone(state), message);
|
||||
});
|
||||
});
|
||||
mAccountModelConnection->makeConnect(
|
||||
mCallModel.get(), &CallModel::encryptionChanged,
|
||||
[this](const std::shared_ptr<linphone::Call> &call, bool on, const std::string &authenticationToken) {
|
||||
auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption());
|
||||
auto tokenVerified = mCallModel->getAuthenticationTokenVerified();
|
||||
mAccountModelConnection->invokeToCore([this, call, encryption, tokenVerified]() {
|
||||
setPeerSecured((encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
|
||||
encryption == LinphoneEnums::MediaEncryption::Srtp ||
|
||||
encryption == LinphoneEnums::MediaEncryption::Dtls);
|
||||
});
|
||||
});
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lAccept, [this](bool withVideo) {
|
||||
mAccountModelConnection->invokeToModel([this, withVideo]() { mCallModel->accept(withVideo); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lDecline, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { mCallModel->decline(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lTerminate, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { mCallModel->terminate(); });
|
||||
});
|
||||
}
|
||||
|
||||
LinphoneEnums::CallStatus CallCore::getStatus() const {
|
||||
|
|
@ -82,6 +156,18 @@ void CallCore::setStatus(LinphoneEnums::CallStatus status) {
|
|||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::CallDir CallCore::getDir() const {
|
||||
return mDir;
|
||||
}
|
||||
|
||||
void CallCore::setDir(LinphoneEnums::CallDir dir) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mDir != dir) {
|
||||
mDir = dir;
|
||||
emit dirChanged(mDir);
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::CallState CallCore::getState() const {
|
||||
return mState;
|
||||
}
|
||||
|
|
@ -95,10 +181,6 @@ void CallCore::setState(LinphoneEnums::CallState state, const QString &message)
|
|||
}
|
||||
}
|
||||
|
||||
void CallCore::onStateChanged(linphone::Call::State state, const std::string &message) {
|
||||
setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message));
|
||||
}
|
||||
|
||||
QString CallCore::getLastErrorMessage() const {
|
||||
return mLastErrorMessage;
|
||||
}
|
||||
|
|
@ -130,3 +212,47 @@ void CallCore::setMicrophoneMuted(bool isMuted) {
|
|||
emit microphoneMutedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallCore::getCameraEnabled() const {
|
||||
return mCameraEnabled;
|
||||
}
|
||||
|
||||
void CallCore::setCameraEnabled(bool enabled) {
|
||||
if (mCameraEnabled != enabled) {
|
||||
mCameraEnabled = enabled;
|
||||
emit cameraEnabledChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallCore::getPaused() const {
|
||||
return mPaused;
|
||||
}
|
||||
|
||||
void CallCore::setPaused(bool paused) {
|
||||
if (mPaused != paused) {
|
||||
mPaused = paused;
|
||||
emit pausedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallCore::getPeerSecured() const {
|
||||
return mPeerSecured;
|
||||
}
|
||||
void CallCore::setPeerSecured(bool secured) {
|
||||
if (mPeerSecured != secured) {
|
||||
mPeerSecured = secured;
|
||||
emit peerSecuredChanged();
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::CallState CallCore::getTransferState() const {
|
||||
return mTransferState;
|
||||
}
|
||||
|
||||
void CallCore::setTransferState(LinphoneEnums::CallState state, const QString &message) {
|
||||
if (mTransferState != state) {
|
||||
mTransferState = state;
|
||||
if (state == LinphoneEnums::CallState::Error) setLastErrorMessage(message);
|
||||
emit transferStateChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -32,11 +32,18 @@ class SafeConnection;
|
|||
class CallCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
// Q_PROPERTY(QString peerDisplayName MEMBER mPeerDisplayName)
|
||||
Q_PROPERTY(LinphoneEnums::CallStatus status READ getStatus NOTIFY statusChanged)
|
||||
Q_PROPERTY(LinphoneEnums::CallDir dir READ getDir NOTIFY dirChanged)
|
||||
Q_PROPERTY(LinphoneEnums::CallState state READ getState NOTIFY stateChanged)
|
||||
Q_PROPERTY(QString lastErrorMessage READ getLastErrorMessage NOTIFY lastErrorMessageChanged)
|
||||
Q_PROPERTY(int duration READ getDuration NOTIFY durationChanged);
|
||||
Q_PROPERTY(int duration READ getDuration NOTIFY durationChanged)
|
||||
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(bool peerSecured READ getPeerSecured WRITE setPeerSecured NOTIFY peerSecuredChanged)
|
||||
Q_PROPERTY(LinphoneEnums::CallState transferState READ getTransferState NOTIFY transferStateChanged)
|
||||
|
||||
public:
|
||||
// Should be call from model Thread. Will be automatically in App thread after initialization
|
||||
|
|
@ -48,9 +55,11 @@ public:
|
|||
LinphoneEnums::CallStatus getStatus() const;
|
||||
void setStatus(LinphoneEnums::CallStatus status);
|
||||
|
||||
LinphoneEnums::CallDir getDir() const;
|
||||
void setDir(LinphoneEnums::CallDir dir);
|
||||
|
||||
LinphoneEnums::CallState getState() const;
|
||||
void setState(LinphoneEnums::CallState state, const QString &message);
|
||||
void onStateChanged(linphone::Call::State state, const std::string &message);
|
||||
|
||||
QString getLastErrorMessage() const;
|
||||
void setLastErrorMessage(const QString &message);
|
||||
|
|
@ -61,18 +70,39 @@ public:
|
|||
bool getMicrophoneMuted() const;
|
||||
void setMicrophoneMuted(bool isMuted);
|
||||
|
||||
bool getCameraEnabled() const;
|
||||
void setCameraEnabled(bool enabled);
|
||||
|
||||
bool getPaused() const;
|
||||
void setPaused(bool paused);
|
||||
|
||||
bool getPeerSecured() const;
|
||||
void setPeerSecured(bool secured);
|
||||
|
||||
LinphoneEnums::CallState getTransferState() const;
|
||||
void setTransferState(LinphoneEnums::CallState state, const QString &message);
|
||||
|
||||
signals:
|
||||
void statusChanged(LinphoneEnums::CallStatus status);
|
||||
void stateChanged(LinphoneEnums::CallState state);
|
||||
void dirChanged(LinphoneEnums::CallDir dir);
|
||||
void lastErrorMessageChanged();
|
||||
void peerAddressChanged();
|
||||
void durationChanged(int duration);
|
||||
void microphoneMutedChanged();
|
||||
void cameraEnabledChanged();
|
||||
void pausedChanged();
|
||||
void transferStateChanged();
|
||||
void peerSecuredChanged();
|
||||
|
||||
// Linphone commands
|
||||
void lAccept(bool withVideo); // Accept an incoming call
|
||||
void lDecline(); // Decline an incoming call
|
||||
void lTerminate(); // Hangup a call
|
||||
void lSetMicrophoneMuted(bool isMuted);
|
||||
void lSetCameraEnabled(bool enabled);
|
||||
void lSetPaused(bool paused);
|
||||
void lTransferCall(const QString &dest);
|
||||
|
||||
/* TODO
|
||||
Q_INVOKABLE void acceptWithVideo();
|
||||
|
|
@ -99,9 +129,15 @@ private:
|
|||
std::shared_ptr<CallModel> mCallModel;
|
||||
LinphoneEnums::CallStatus mStatus;
|
||||
LinphoneEnums::CallState mState;
|
||||
LinphoneEnums::CallState mTransferState;
|
||||
LinphoneEnums::CallDir mDir;
|
||||
QString mLastErrorMessage;
|
||||
QString mPeerAddress;
|
||||
bool mPeerSecured;
|
||||
int mDuration = 0;
|
||||
bool mMicrophoneMuted;
|
||||
bool mCameraEnabled;
|
||||
bool mPaused = false;
|
||||
QSharedPointer<SafeConnection> mAccountModelConnection;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
|||
"data/image/phone-selected.svg"
|
||||
"data/image/phone-plus.svg"
|
||||
"data/image/phone-disconnect.svg"
|
||||
"data/image/phone-transfer.svg"
|
||||
"data/image/address-book.svg"
|
||||
"data/image/address-book-selected.svg"
|
||||
"data/image/chat-teardrop-text.svg"
|
||||
|
|
@ -39,12 +40,23 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
|||
"data/image/magnifying-glass.svg"
|
||||
"data/image/backspace-fill.svg"
|
||||
"data/image/x.svg"
|
||||
"data/image/play.svg"
|
||||
"data/image/incoming_call.svg"
|
||||
"data/image/incoming_call_missed.svg"
|
||||
"data/image/incoming_call_rejected.svg"
|
||||
"data/image/outgoing_call.svg"
|
||||
"data/image/outgoing_call_missed.svg"
|
||||
"data/image/outgoing_call_rejected.svg"
|
||||
"data/image/microphone.svg"
|
||||
"data/image/microphone-slash.svg"
|
||||
"data/image/video-camera.svg"
|
||||
"data/image/video-camera-slash.svg"
|
||||
"data/image/speaker-high.svg"
|
||||
"data/image/speaker-slash.svg"
|
||||
"data/image/trusted.svg"
|
||||
"data/image/randomAvatar.png"
|
||||
"data/image/pause.svg"
|
||||
"data/image/smiley.svg"
|
||||
|
||||
data/shaders/roundEffect.vert.qsb
|
||||
data/shaders/roundEffect.frag.qsb
|
||||
|
|
|
|||
4
Linphone/data/image/phone-transfer.svg
Normal file
4
Linphone/data/image/phone-transfer.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="32" height="33" viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27.985 23.3848C27.7621 25.0786 26.9303 26.6333 25.6449 27.7586C24.3595 28.884 22.7084 29.5029 21 29.4998C11.075 29.4998 3.00001 21.4248 3.00001 11.4998C2.99695 9.79142 3.61587 8.14034 4.74118 6.85493C5.86649 5.56952 7.42122 4.73769 9.11501 4.51481C9.54318 4.46242 9.97682 4.54986 10.3512 4.76409C10.7256 4.97833 11.0207 5.30787 11.1925 5.70356L13.8325 11.5986V11.6136C13.9639 11.9166 14.0181 12.2475 13.9904 12.5767C13.9627 12.9058 13.8539 13.223 13.6738 13.4998C13.6513 13.5336 13.6275 13.5648 13.6025 13.5961L11 16.6811C11.9363 18.5836 13.9263 20.5561 15.8538 21.4948L18.8963 18.9061C18.9261 18.8809 18.9574 18.8576 18.99 18.8361C19.2663 18.6508 19.5846 18.5378 19.9159 18.5072C20.2471 18.4766 20.5807 18.5295 20.8863 18.6611L20.9025 18.6686L26.7913 21.3073C27.1879 21.4783 27.5185 21.773 27.7337 22.1475C27.9489 22.522 28.037 22.9561 27.985 23.3848ZM26 23.1348C26 23.1348 25.9913 23.1348 25.9863 23.1348L20.1113 20.5023L17.0675 23.0923C17.038 23.1173 17.0071 23.1407 16.975 23.1623C16.6872 23.3543 16.3545 23.4684 16.0094 23.4934C15.6644 23.5183 15.3187 23.4534 15.0063 23.3048C12.665 22.1736 10.3313 19.8573 9.19876 17.5411C9.0488 17.2309 8.9815 16.8872 9.0034 16.5434C9.0253 16.1996 9.13565 15.8672 9.32376 15.5786C9.34496 15.5447 9.36879 15.5125 9.39501 15.4823L12 12.3936L9.37501 6.51856C9.37452 6.51357 9.37452 6.50855 9.37501 6.50356C8.16283 6.66168 7.04986 7.25626 6.24453 8.17595C5.43919 9.09564 4.99674 10.2774 5.00001 11.4998C5.00464 15.7419 6.69184 19.8088 9.69142 22.8084C12.691 25.808 16.758 27.4952 21 27.4998C22.2217 27.504 23.4031 27.0631 24.3233 26.2595C25.2436 25.4559 25.8396 24.3447 26 23.1336V23.1348Z" fill="white"/>
|
||||
<path d="M15.3434 8.1709C15.3434 8.0624 15.3647 7.95495 15.4062 7.8547C15.4477 7.75445 15.5085 7.66336 15.5852 7.58664C15.662 7.50991 15.7531 7.44907 15.8533 7.40757C15.9536 7.36608 16.061 7.34475 16.1695 7.34481L21.1822 7.34554L19.6723 5.83568C19.5175 5.68084 19.4305 5.47084 19.4305 5.25187C19.4305 5.0329 19.5175 4.8229 19.6723 4.66807C19.8272 4.51323 20.0372 4.42625 20.2561 4.42625C20.4751 4.42625 20.6851 4.51323 20.8399 4.66807L23.759 7.58709C23.9138 7.74193 24.0008 7.95193 24.0008 8.1709C24.0008 8.38987 23.9138 8.59987 23.759 8.7547L20.8399 11.6737C20.6851 11.8286 20.4751 11.9155 20.2561 11.9155C20.0372 11.9155 19.8272 11.8286 19.6723 11.6737C19.5175 11.5189 19.4305 11.3089 19.4305 11.0899C19.4305 10.871 19.5175 10.661 19.6723 10.5061L21.1822 8.99625L16.1695 8.99698C16.061 8.99704 15.9536 8.97572 15.8533 8.93422C15.7531 8.89273 15.662 8.83188 15.5852 8.75516C15.5085 8.67844 15.4477 8.58735 15.4062 8.4871C15.3647 8.38685 15.3434 8.2794 15.3434 8.1709Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Linphone/data/image/randomAvatar.png
Normal file
BIN
Linphone/data/image/randomAvatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
|
|
@ -23,6 +23,7 @@
|
|||
#include <QDebug>
|
||||
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(CallModel)
|
||||
|
||||
|
|
@ -41,7 +42,6 @@ CallModel::~CallModel() {
|
|||
|
||||
void CallModel::accept(bool withVideo) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto params = core->createCallParams(mMonitor);
|
||||
params->enableVideo(withVideo);
|
||||
|
|
@ -68,12 +68,53 @@ void CallModel::terminate() {
|
|||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->terminate();
|
||||
}
|
||||
void CallModel::setPaused(bool paused) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (paused) {
|
||||
auto status = mMonitor->pause();
|
||||
if (status != -1) emit pausedChanged(paused);
|
||||
} else {
|
||||
auto status = mMonitor->resume();
|
||||
if (status != -1) emit pausedChanged(paused);
|
||||
}
|
||||
}
|
||||
|
||||
void CallModel::transferTo(const std::shared_ptr<linphone::Address> &address) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (mMonitor->transferTo(address) == -1)
|
||||
qWarning() << log()
|
||||
.arg(QStringLiteral("Unable to transfer: `%1`."))
|
||||
.arg(Utils::coreStringToAppString(address->asString()));
|
||||
}
|
||||
|
||||
void CallModel::setMicrophoneMuted(bool isMuted) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->setMicrophoneMuted(isMuted);
|
||||
emit microphoneMutedChanged(isMuted);
|
||||
}
|
||||
|
||||
void CallModel::setSpeakerMuted(bool isMuted) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->setSpeakerMuted(isMuted);
|
||||
emit speakerMutedChanged(isMuted);
|
||||
}
|
||||
|
||||
void CallModel::setCameraEnabled(bool enabled) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->enableCamera(enabled);
|
||||
emit cameraEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
std::shared_ptr<const linphone::Address> CallModel::getRemoteAddress() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
return mMonitor->getRemoteAddress();
|
||||
}
|
||||
|
||||
bool CallModel::getAuthenticationTokenVerified() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
return mMonitor->getAuthenticationTokenVerified();
|
||||
}
|
||||
|
||||
void CallModel::onDtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf) {
|
||||
emit dtmfReceived(call, dtmf);
|
||||
}
|
||||
|
|
@ -108,6 +149,14 @@ void CallModel::onStateChanged(const std::shared_ptr<linphone::Call> &call,
|
|||
emit stateChanged(state, message);
|
||||
}
|
||||
|
||||
void CallModel::onStatusChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::Status status) {
|
||||
emit statusChanged(status);
|
||||
}
|
||||
|
||||
void CallModel::onDirChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::Dir dir) {
|
||||
emit dirChanged(dir);
|
||||
}
|
||||
|
||||
void CallModel::onStatsUpdated(const std::shared_ptr<linphone::Call> &call,
|
||||
const std::shared_ptr<const linphone::CallStats> &stats) {
|
||||
emit statsUpdated(call, stats);
|
||||
|
|
|
|||
|
|
@ -41,10 +41,20 @@ public:
|
|||
void terminate();
|
||||
|
||||
void setMicrophoneMuted(bool isMuted);
|
||||
void setSpeakerMuted(bool isMuted);
|
||||
void setCameraEnabled(bool enabled);
|
||||
void setPaused(bool paused);
|
||||
void transferTo(const std::shared_ptr<linphone::Address> &address);
|
||||
|
||||
std::shared_ptr<const linphone::Address> getRemoteAddress();
|
||||
bool getAuthenticationTokenVerified();
|
||||
|
||||
signals:
|
||||
void microphoneMutedChanged(bool isMuted);
|
||||
void speakerMutedChanged(bool isMuted);
|
||||
void cameraEnabledChanged(bool enabled);
|
||||
void durationChanged(int);
|
||||
void pausedChanged(bool paused);
|
||||
|
||||
private:
|
||||
QTimer mDurationTimer;
|
||||
|
|
@ -67,6 +77,8 @@ private:
|
|||
virtual void onStateChanged(const std::shared_ptr<linphone::Call> &call,
|
||||
linphone::Call::State state,
|
||||
const std::string &message) override;
|
||||
virtual void onStatusChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::Status status);
|
||||
virtual void onDirChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::Dir dir);
|
||||
virtual void onStatsUpdated(const std::shared_ptr<linphone::Call> &call,
|
||||
const std::shared_ptr<const linphone::CallStats> &stats) override;
|
||||
virtual void onTransferStateChanged(const std::shared_ptr<linphone::Call> &call,
|
||||
|
|
@ -94,6 +106,8 @@ signals:
|
|||
void infoMessageReceived(const std::shared_ptr<linphone::Call> &call,
|
||||
const std::shared_ptr<const linphone::InfoMessage> &message);
|
||||
void stateChanged(linphone::Call::State state, const std::string &message);
|
||||
void statusChanged(linphone::Call::Status status);
|
||||
void dirChanged(linphone::Call::Dir dir);
|
||||
void statsUpdated(const std::shared_ptr<linphone::Call> &call,
|
||||
const std::shared_ptr<const linphone::CallStats> &stats);
|
||||
void transferStateChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ void CoreModel::start() {
|
|||
setPathAfterStart();
|
||||
mCore->enableFriendListSubscription(true);
|
||||
mCore->enableRecordAware(true);
|
||||
mCore->getCallsNb();
|
||||
mIterateTimer->start();
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
list(APPEND _LINPHONEAPP_SOURCES
|
||||
tool/Constants.cpp
|
||||
tool/EnumsToString.cpp
|
||||
tool/Utils.cpp
|
||||
|
||||
tool/LinphoneEnums.cpp
|
||||
|
|
|
|||
28
Linphone/tool/EnumsToString.cpp
Normal file
28
Linphone/tool/EnumsToString.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 "EnumsToString.hpp"
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "model/call/CallModel.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
50
Linphone/tool/EnumsToString.hpp
Normal file
50
Linphone/tool/EnumsToString.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 ENUMSTOSTRING_H_
|
||||
#define ENUMSTOSTRING_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "LinphoneEnums.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/***
|
||||
* Class to make the link between qml and LinphoneEnums functions
|
||||
* TODO : transform LinphoneEnums into a class so we can delete this one
|
||||
*/
|
||||
|
||||
class EnumsToString : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EnumsToString(QObject *parent = nullptr) : QObject(parent) {
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString dirToString(const LinphoneEnums::CallDir &data) {
|
||||
return LinphoneEnums::toString(data);
|
||||
}
|
||||
Q_INVOKABLE QString statusToString(const LinphoneEnums::CallStatus &data) {
|
||||
return LinphoneEnums::toString(data);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ENUMSTOSTRING_H_
|
||||
|
|
@ -115,6 +115,22 @@ QString LinphoneEnums::toString(const LinphoneEnums::CallStatus &data) {
|
|||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::CallDir LinphoneEnums::fromLinphone(const linphone::Call::Dir &data) {
|
||||
return static_cast<LinphoneEnums::CallDir>(data);
|
||||
}
|
||||
|
||||
linphone::Call::Dir LinphoneEnums::toLinphone(const LinphoneEnums::CallDir &data) {
|
||||
return static_cast<linphone::Call::Dir>(data);
|
||||
}
|
||||
QString LinphoneEnums::toString(const LinphoneEnums::CallDir &data) {
|
||||
switch (data) {
|
||||
case LinphoneEnums::CallDir::Incoming:
|
||||
return "Incoming";
|
||||
case LinphoneEnums::CallDir::Outgoing:
|
||||
return "Outgoing";
|
||||
}
|
||||
}
|
||||
|
||||
linphone::Conference::Layout LinphoneEnums::toLinphone(const LinphoneEnums::ConferenceLayout &layout) {
|
||||
if (layout != LinphoneEnums::ConferenceLayout::AudioOnly) return static_cast<linphone::Conference::Layout>(layout);
|
||||
else return linphone::Conference::Layout::Grid; // Audio Only mode
|
||||
|
|
|
|||
|
|
@ -159,6 +159,13 @@ linphone::Call::Status toLinphone(const LinphoneEnums::CallStatus &data);
|
|||
LinphoneEnums::CallStatus fromLinphone(const linphone::Call::Status &data);
|
||||
QString toString(const LinphoneEnums::CallStatus &data);
|
||||
|
||||
enum class CallDir { Outgoing = int(linphone::Call::Dir::Outgoing), Incoming = int(linphone::Call::Dir::Incoming) };
|
||||
Q_ENUM_NS(CallDir)
|
||||
|
||||
linphone::Call::Dir toLinphone(const LinphoneEnums::CallDir &data);
|
||||
LinphoneEnums::CallDir fromLinphone(const linphone::Call::Dir &data);
|
||||
QString toString(const LinphoneEnums::CallDir &data);
|
||||
|
||||
enum class ConferenceLayout {
|
||||
Grid = int(linphone::Conference::Layout::Grid),
|
||||
ActiveSpeaker = int(linphone::Conference::Layout::ActiveSpeaker),
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/providers/AvatarProvider.hpp"
|
||||
#include <QImageReader>
|
||||
#include <QQuickWindow>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
@ -81,7 +82,13 @@ VariantObject *Utils::createCall(const QString &sipAddress,
|
|||
data->makeRequest([sipAddress, prepareTransfertAddress, headers]() {
|
||||
auto call = ToolModel::createCall(sipAddress, prepareTransfertAddress, headers);
|
||||
if (call) {
|
||||
return QVariant::fromValue(new CallGui(call));
|
||||
auto callGui = QVariant::fromValue(new CallGui(call));
|
||||
App::postCoreSync([callGui]() {
|
||||
auto app = App::getInstance();
|
||||
auto window = app->getCallsWindow(callGui);
|
||||
window->show();
|
||||
});
|
||||
return callGui;
|
||||
} else return QVariant();
|
||||
});
|
||||
data->requestValue();
|
||||
|
|
@ -89,6 +96,10 @@ VariantObject *Utils::createCall(const QString &sipAddress,
|
|||
return data;
|
||||
}
|
||||
|
||||
void Utils::closeCallsWindow() {
|
||||
App::getInstance()->closeCallsWindow();
|
||||
}
|
||||
|
||||
VariantObject *Utils::haveAccount() {
|
||||
VariantObject *result = new VariantObject();
|
||||
|
||||
|
|
@ -134,3 +145,36 @@ QString Utils::createAvatar(const QUrl &fileUrl) {
|
|||
}
|
||||
return fileUri;
|
||||
}
|
||||
|
||||
QString Utils::formatElapsedTime(int seconds) {
|
||||
// s, m, h, d, W, M, Y
|
||||
// 1, 60, 3600, 86400, 604800, 2592000, 31104000
|
||||
auto y = floor(seconds / 31104000);
|
||||
if (y > 0) return QString::number(y) + " years";
|
||||
auto M = floor(seconds / 2592000);
|
||||
if (M > 0) return QString::number(M) + " months";
|
||||
auto w = floor(seconds / 604800);
|
||||
if (w > 0) return QString::number(w) + " week";
|
||||
auto d = floor(seconds / 86400);
|
||||
if (d > 0) return QString::number(d) + " days";
|
||||
|
||||
auto h = floor(seconds / 3600);
|
||||
auto m = floor((seconds - h * 3600) / 60);
|
||||
auto s = seconds - h * 3600 - m * 60;
|
||||
|
||||
QString hours, min, sec;
|
||||
|
||||
if (h < 10 && h > 0) {
|
||||
hours = "0" + QString::number(h);
|
||||
}
|
||||
|
||||
if (m < 10) {
|
||||
min = "0" + QString::number(m);
|
||||
}
|
||||
|
||||
if (s < 10) {
|
||||
sec = "0" + QString::number(s);
|
||||
}
|
||||
|
||||
return (h == 0 ? "" : hours + ":") + min + ":" + sec;
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#endif // if defined(__GNUC__) && __GNUC__ >= 7
|
||||
#endif // ifndef UTILS_NO_BREAK
|
||||
|
||||
class QQuickWindow;
|
||||
class VariantObject;
|
||||
|
||||
class Utils : public QObject {
|
||||
|
|
@ -53,8 +54,10 @@ public:
|
|||
Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress,
|
||||
const QString &prepareTransfertAddress = "",
|
||||
const QHash<QString, QString> &headers = {});
|
||||
Q_INVOKABLE static void closeCallsWindow();
|
||||
Q_INVOKABLE static VariantObject *haveAccount();
|
||||
Q_INVOKABLE static QString createAvatar(const QUrl &fileUrl); // Return the avatar path
|
||||
Q_INVOKABLE static QString formatElapsedTime(int seconds); // Return the elapsed time formated
|
||||
|
||||
static inline QString coreStringToAppString(const std::string &str) {
|
||||
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ ImageAsyncImageResponse::ImageAsyncImageResponse(const QString &id, const QSize
|
|||
QString path = ":/data/image/";
|
||||
QStringList filters;
|
||||
filters << "*.svg";
|
||||
filters << "*.png";
|
||||
QDir imageDir(path);
|
||||
if (!imageDir.exists()) {
|
||||
qDebug() << QStringLiteral("[ImageProvider] Dir doesn't exist: `%1`.").arg(path);
|
||||
|
|
|
|||
531
Linphone/view/App/CallsWindow.qml
Normal file
531
Linphone/view/App/CallsWindow.qml
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
import EnumsToStringCpp 1.0
|
||||
import UtilsCpp 1.0
|
||||
|
||||
Window {
|
||||
id: mainWindow
|
||||
width: 1512 * DefaultStyle.dp
|
||||
height: 982 * DefaultStyle.dp
|
||||
|
||||
property CallGui call
|
||||
|
||||
property bool isInContactList: false
|
||||
|
||||
property int callsCount: 0
|
||||
onCallsCountChanged: console.log("calls count", callsCount)
|
||||
|
||||
property var peerName: UtilsCpp.getDisplayName(call.core.peerAddress)
|
||||
property string peerNameText: peerName ? peerName.value : ""
|
||||
|
||||
// TODO : remove this, for debug only
|
||||
property var callState: call && call.core.state
|
||||
onCallStateChanged: {
|
||||
console.log("State:", callState)
|
||||
if (callState === LinphoneEnums.CallState.Error || callState === LinphoneEnums.CallState.End) {
|
||||
endCall()
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
endCall()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: autoCloseWindow
|
||||
interval: 2000
|
||||
onTriggered: {
|
||||
UtilsCpp.closeCallsWindow()
|
||||
}
|
||||
}
|
||||
|
||||
function endCall() {
|
||||
console.log("remaining calls before ending", mainWindow.callsCount)
|
||||
callStatusText.text = qsTr("End of the call")
|
||||
if (call) call.core.lTerminate()
|
||||
if (callsCount === 1) {
|
||||
bottomButtonsLayout.setButtonsEnabled(false)
|
||||
autoCloseWindow.restart()
|
||||
}
|
||||
}
|
||||
|
||||
component BottomButton : Button {
|
||||
required property string enabledIcon
|
||||
property string disabledIcon
|
||||
id: bottomButton
|
||||
enabled: call != undefined
|
||||
padding: 18 * DefaultStyle.dp
|
||||
checkable: true
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: bottomButton.enabled
|
||||
? bottomButton.checked
|
||||
? disabledIcon
|
||||
? DefaultStyle.grey_0
|
||||
: DefaultStyle.main2_400
|
||||
: bottomButton.pressed
|
||||
? DefaultStyle.main2_400
|
||||
: DefaultStyle.grey_500
|
||||
: DefaultStyle.grey_600
|
||||
radius: 71 * DefaultStyle.dp
|
||||
}
|
||||
contentItem: EffectImage {
|
||||
image.source: disabledIcon && bottomButton.checked ? disabledIcon : enabledIcon
|
||||
anchors.fill: parent
|
||||
image.width: 32 * DefaultStyle.dp
|
||||
image.height: 32 * DefaultStyle.dp
|
||||
colorizationColor: disabledIcon && bottomButton.checked ? DefaultStyle.main2_0 : DefaultStyle.grey_0
|
||||
}
|
||||
}
|
||||
Control.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
|
||||
modal: true
|
||||
closePolicy: Control.Popup.NoAutoClose
|
||||
anchors.centerIn: parent
|
||||
padding: 20
|
||||
background: Item {
|
||||
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.height + 2
|
||||
color: DefaultStyle.main1_500_main
|
||||
radius: 15
|
||||
}
|
||||
Rectangle {
|
||||
id: mainBackground
|
||||
anchors.fill: parent
|
||||
radius: 15
|
||||
}
|
||||
}
|
||||
contentItem: ColumnLayout {
|
||||
BusyIndicator{
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Transfert en cours, veuillez patienter")
|
||||
}
|
||||
}
|
||||
}
|
||||
Control.Popup {
|
||||
id: transferErrorPopup
|
||||
visible: mainWindow.call.core.transferState === LinphoneEnums.CallState.Error
|
||||
modal: true
|
||||
closePolicy: Control.Popup.NoAutoClose
|
||||
x : parent.x + parent.width - width
|
||||
y : parent.y + parent.height - height
|
||||
padding: 20
|
||||
background: Item {
|
||||
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.height + 2
|
||||
color: DefaultStyle.danger_500
|
||||
}
|
||||
Rectangle {
|
||||
id: transferErrorBackground
|
||||
anchors.fill: parent
|
||||
radius: 15
|
||||
}
|
||||
MultiEffect {
|
||||
anchors.fill: transferErrorBackground
|
||||
shadowEnabled: true
|
||||
shadowColor: DefaultStyle.grey_900
|
||||
shadowBlur: 10
|
||||
// shadowOpacity: 0.1
|
||||
}
|
||||
}
|
||||
contentItem: ColumnLayout {
|
||||
Text {
|
||||
text: qsTr("Erreur de transfert")
|
||||
}
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Le transfert d'appel a échoué.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.ongoingCallWindowColor
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 5
|
||||
anchors.bottomMargin: 5
|
||||
Item {
|
||||
Layout.margins: 10
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 25
|
||||
RowLayout {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 10
|
||||
EffectImage {
|
||||
id: callStatusIcon
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
image.width: 15
|
||||
image.height: 15
|
||||
image.sourceSize.width: 15
|
||||
image.sourceSize.height: 15
|
||||
image.source: (mainWindow.call.core.state === LinphoneEnums.CallState.Paused
|
||||
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)
|
||||
? AppIcons.pause
|
||||
: (mainWindow.callState === LinphoneEnums.CallState.End
|
||||
|| mainWindow.callState === LinphoneEnums.CallState.Released)
|
||||
? AppIcons.endCall
|
||||
: mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing
|
||||
? AppIcons.outgoingCall
|
||||
: AppIcons.incomingCall
|
||||
colorizationColor: mainWindow.callState === LinphoneEnums.CallState.Paused
|
||||
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote || mainWindow.callState === LinphoneEnums.CallState.End
|
||||
|| mainWindow.callState === LinphoneEnums.CallState.Released ? DefaultStyle.danger_500 : undefined
|
||||
}
|
||||
Text {
|
||||
id: callStatusText
|
||||
text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released)
|
||||
? qsTr("End of the call")
|
||||
: (mainWindow.callState === LinphoneEnums.CallState.Paused || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)
|
||||
? qsTr("Appel mis en pause")
|
||||
: EnumsToStringCpp.dirToString(mainWindow.call.core.dir) + qsTr(" call")
|
||||
color: DefaultStyle.grey_0
|
||||
font.bold: true
|
||||
}
|
||||
Rectangle {
|
||||
visible: mainWindow.callState === LinphoneEnums.CallState.Connected
|
||||
|| mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
|
||||
Layout.preferredHeight: parent.height
|
||||
Layout.preferredWidth: 2
|
||||
}
|
||||
Text {
|
||||
text: UtilsCpp.formatElapsedTime(mainWindow.call.core.duration)
|
||||
color: DefaultStyle.grey_0
|
||||
visible: mainWindow.callState === LinphoneEnums.CallState.Connected
|
||||
|| mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
|
||||
}
|
||||
}
|
||||
|
||||
Control.Control {
|
||||
anchors.centerIn: parent
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
visible: mainWindow.call.core.peerSecured
|
||||
onVisibleChanged: console.log("peer secured", mainWindow.call.core.peerSecured)
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
border.color: DefaultStyle.info_500_main
|
||||
radius: 15
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
source: AppIcons.trusted
|
||||
Layout.preferredWidth: 15
|
||||
Layout.preferredHeight: 15
|
||||
sourceSize.width: 15
|
||||
sourceSize.height: 15
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: "This call is completely secured"
|
||||
color: DefaultStyle.info_500_main
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Control.Control {
|
||||
id: centerItem
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1059 * DefaultStyle.dp
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 10
|
||||
Layout.rightMargin: 10
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.ongoingCallBackgroundColor
|
||||
radius: 15
|
||||
}
|
||||
contentItem: Item {
|
||||
anchors.fill: parent
|
||||
StackLayout {
|
||||
id: centerLayout
|
||||
anchors.fill: parent
|
||||
Connections {
|
||||
target: mainWindow
|
||||
onCallStateChanged: {
|
||||
if (mainWindow.callState === LinphoneEnums.CallState.Error) {
|
||||
centerLayout.currentIndex = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: audioCallItem
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: parent.height
|
||||
Timer {
|
||||
id: secondsTimer
|
||||
interval: 1000
|
||||
repeat: true
|
||||
onTriggered: waitingTime.seconds += 1
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
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.pointSize: DefaultStyle.ongoingCallElapsedTimeSize
|
||||
Component.onCompleted: {
|
||||
secondsTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
// Avatar {
|
||||
// Layout.alignment: Qt.AlignCenter
|
||||
// visible: mainWindow.isInContactList
|
||||
// image.source: AppIcons.avatar
|
||||
// size: 100
|
||||
// }
|
||||
// DefaultAvatar {
|
||||
// id: defaultAvatar
|
||||
// Layout.alignment: Qt.AlignCenter
|
||||
// visible: !mainWindow.isInContactList
|
||||
// initials:{
|
||||
// var usernameList = mainWindow.peerNameText.split(' ')
|
||||
// for (var i = 0; i < usernameList.length; ++i) {
|
||||
// initials += usernameList[i][0]
|
||||
// }
|
||||
// }
|
||||
// Connections {
|
||||
// target: mainWindow
|
||||
// onPeerNameChanged: {
|
||||
// defaultAvatar.initials = ""
|
||||
// var usernameList = mainWindow.peerName.value.split(' ')
|
||||
// for (var i = 0; i < usernameList.length; ++i) {
|
||||
// defaultAvatar.initials += usernameList[i][0]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// width: 100
|
||||
// height: 100
|
||||
// }
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: 15
|
||||
visible: mainWindow.peerNameText.length > 0
|
||||
text: mainWindow.peerNameText
|
||||
color: DefaultStyle.grey_0
|
||||
font {
|
||||
pointSize: DefaultStyle.ongoingCallNameSize
|
||||
capitalization: Font.Capitalize
|
||||
}
|
||||
}
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: mainWindow.call.core.peerAddress
|
||||
color: DefaultStyle.grey_0
|
||||
font.pointSize: DefaultStyle.ongoingCallAddressSize
|
||||
}
|
||||
}
|
||||
}
|
||||
Image {
|
||||
id: videoCallItem
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: parent.height
|
||||
}
|
||||
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.pointSize: DefaultStyle.ongoingCallNameSize
|
||||
}
|
||||
}
|
||||
}
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.leftMargin: 10
|
||||
anchors.bottomMargin: 10
|
||||
text: mainWindow.peerNameText
|
||||
color: DefaultStyle.grey_0
|
||||
font.pointSize: DefaultStyle.ongoingCallAddressSize
|
||||
}
|
||||
}
|
||||
}
|
||||
OngoingCallRightPanel {
|
||||
id: rightPanel
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 393 * DefaultStyle.dp
|
||||
property int currentIndex: 0
|
||||
Layout.rightMargin: 10
|
||||
visible: false
|
||||
headerContent: StackLayout {
|
||||
currentIndex: rightPanel.currentIndex
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Text {
|
||||
color: DefaultStyle.mainPageTitleColor
|
||||
text: qsTr("Transfert d'appel")
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
contentItem: StackLayout {
|
||||
currentIndex: rightPanel.currentIndex
|
||||
ContactsList {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
sideMargin: 10
|
||||
topMargin: 15
|
||||
groupCallVisible: false
|
||||
searchBarColor: DefaultStyle.grey_0
|
||||
searchBarBorderColor: DefaultStyle.callRightPanelSearchBarBorderColor
|
||||
onCallButtonPressed: (address) => {
|
||||
mainWindow.call.core.lTransferCall(address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GridLayout {
|
||||
id: bottomButtonsLayout
|
||||
rows: 1
|
||||
columns: 3
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
layoutDirection: Qt.LeftToRight
|
||||
columnSpacing: 20
|
||||
Connections {
|
||||
target: mainWindow
|
||||
onCallStateChanged: if (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) {
|
||||
bottomButtonsLayout.layoutDirection = Qt.RightToLeft
|
||||
connectedCallButtons.visible = true
|
||||
}
|
||||
}
|
||||
function setButtonsEnabled(enabled) {
|
||||
for(var i=0; i < children.length; ++i) {
|
||||
children[i].enabled = false
|
||||
}
|
||||
}
|
||||
BottomButton {
|
||||
Layout.row: 0
|
||||
enabledIcon: AppIcons.endCall
|
||||
checkable: false
|
||||
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
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.danger_500
|
||||
radius: 71 * DefaultStyle.dp
|
||||
}
|
||||
onClicked: mainWindow.endCall()
|
||||
}
|
||||
RowLayout {
|
||||
id: connectedCallButtons
|
||||
visible: false
|
||||
Layout.row: 0
|
||||
Layout.column: 1
|
||||
BottomButton {
|
||||
Layout.preferredWidth: 55 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 71 * DefaultStyle.dp
|
||||
color: parent.enabled
|
||||
? parent.checked
|
||||
? DefaultStyle.success_500main
|
||||
: parent.pressed
|
||||
? DefaultStyle.main2_400
|
||||
: DefaultStyle.grey_500
|
||||
: DefaultStyle.grey_600
|
||||
}
|
||||
enabled: mainWindow.callState != LinphoneEnums.CallState.PausedByRemote
|
||||
enabledIcon: enabled && checked ? AppIcons.play : AppIcons.pause
|
||||
checked: mainWindow.call && (mainWindow.call.callState === LinphoneEnums.CallState.Paused
|
||||
|| mainWindow.call.callState === LinphoneEnums.CallState.PausedByRemote) || false
|
||||
onClicked: mainWindow.call.core.lSetPaused(!mainWindow.call.core.paused)
|
||||
}
|
||||
BottomButton {
|
||||
id: transferCallButton
|
||||
enabledIcon: AppIcons.transferCall
|
||||
Layout.preferredWidth: 55 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
onClicked: {
|
||||
rightPanel.visible = !rightPanel.visible
|
||||
rightPanel.currentIndex = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.row: 0
|
||||
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 {
|
||||
enabled: false
|
||||
enabledIcon: AppIcons.videoCamera
|
||||
disabledIcon: AppIcons.videoCameraSlash
|
||||
checked: !mainWindow.call.core.cameraEnabled
|
||||
Layout.preferredWidth: 55 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
onClicked: mainWindow.call.core.lSetCameraEnabled(!mainWindow.call.core.cameraEnabled)
|
||||
|
||||
}
|
||||
BottomButton {
|
||||
id: micButton
|
||||
enabledIcon: AppIcons.microphone
|
||||
disabledIcon: AppIcons.microphoneSlash
|
||||
checked: mainWindow.call.core.microphoneMuted
|
||||
Layout.preferredWidth: 55 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
onClicked: mainWindow.call.core.lSetMicrophoneMuted(!mainWindow.call.core.microphoneMuted)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import Linphone
|
|||
Window {
|
||||
id: mainWindow
|
||||
width: 1512 * DefaultStyle.dp
|
||||
height: 930 * DefaultStyle.dp
|
||||
height: 982 * DefaultStyle.dp
|
||||
visible: true
|
||||
title: qsTr("Linphone")
|
||||
property bool firstConnection: true
|
||||
|
|
|
|||
|
|
@ -1,11 +1,21 @@
|
|||
|
||||
list(APPEND _LINPHONEAPP_QML_FILES
|
||||
view/App/Main.qml
|
||||
view/App/CallsWindow.qml
|
||||
view/App/Layout/LoginLayout.qml
|
||||
view/App/Layout/MainLayout.qml
|
||||
|
||||
view/Item/Account/Accounts.qml
|
||||
|
||||
view/Item/Call/ContactsList.qml
|
||||
view/Item/Call/OngoingCallRightPanel.qml
|
||||
|
||||
view/Item/Notification/Notification.qml
|
||||
view/Item/Notification/NotificationReceivedCall.qml
|
||||
|
||||
view/Item/Prototype/CanvasCircle.qml
|
||||
|
||||
view/Item/BusyIndicator.qml
|
||||
view/Item/Button.qml
|
||||
view/Item/Carousel.qml
|
||||
view/Item/CheckBox.qml
|
||||
|
|
@ -17,10 +27,6 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
|
||||
view/Item/DesktopPopup.qml
|
||||
view/Item/DigitInput.qml
|
||||
|
||||
view/Item/Notification/Notification.qml
|
||||
view/Item/Notification/NotificationReceivedCall.qml
|
||||
|
||||
view/Item/EffectImage.qml
|
||||
view/Item/NumericPad.qml
|
||||
view/Item/PhoneNumberComboBox.qml
|
||||
|
|
@ -48,7 +54,6 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
|
||||
view/Page/Main/AbstractMainPage.qml
|
||||
view/Page/Main/CallPage.qml
|
||||
# view/Page/Main/OngoingCallPage.qml
|
||||
|
||||
# Prototypes
|
||||
view/Prototype/PhoneNumberPrototype.qml
|
||||
|
|
|
|||
22
Linphone/view/Item/BusyIndicator.qml
Normal file
22
Linphone/view/Item/BusyIndicator.qml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2 as Control
|
||||
import QtQuick.Effects
|
||||
|
||||
import Linphone
|
||||
|
||||
Item {
|
||||
id: mainItem
|
||||
property color indicatorColor: DefaultStyle.main1_500_main
|
||||
width: busyIndicator.width
|
||||
height: busyIndicator.height
|
||||
Control.BusyIndicator {
|
||||
id: busyIndicator
|
||||
running: mainItem.visible
|
||||
}
|
||||
MultiEffect {
|
||||
source: busyIndicator
|
||||
anchors.fill: busyIndicator
|
||||
colorizationColor: mainItem.indicatorColor
|
||||
colorization: 1.0
|
||||
}
|
||||
}
|
||||
|
|
@ -19,12 +19,12 @@ Control.Button {
|
|||
color: inversedColors
|
||||
? mainItem.pressed
|
||||
? DefaultStyle.buttonPressedInversedBackground
|
||||
: DefaultStyle.buttonInversedBackground
|
||||
: DefaultStyle.grey_0
|
||||
: mainItem.pressed
|
||||
? DefaultStyle.buttonPressedBackground
|
||||
: DefaultStyle.buttonBackground
|
||||
: DefaultStyle.main1_500_main
|
||||
radius: 24
|
||||
border.color: inversedColors ? DefaultStyle.buttonBackground : DefaultStyle.buttonInversedBackground
|
||||
border.color: inversedColors ? DefaultStyle.main1_500_main : DefaultStyle.grey_0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
|
@ -42,17 +42,12 @@ Control.Button {
|
|||
}
|
||||
}
|
||||
|
||||
leftPadding: 13
|
||||
rightPadding: 13
|
||||
topPadding: 10
|
||||
bottomPadding: 10
|
||||
|
||||
contentItem: Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
wrapMode: Text.WordWrap
|
||||
text: mainItem.text
|
||||
color: inversedColors ? DefaultStyle.buttonInversedTextColor : DefaultStyle.buttonTextColor
|
||||
color: inversedColors ? DefaultStyle.main1_500_main : DefaultStyle.grey_0
|
||||
font {
|
||||
bold: mainItem.boldText
|
||||
pointSize: mainItem.textSize
|
||||
|
|
|
|||
168
Linphone/view/Item/Call/ContactsList.qml
Normal file
168
Linphone/view/Item/Call/ContactsList.qml
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.2 as Control
|
||||
import QtQuick.Effects
|
||||
|
||||
import Linphone
|
||||
|
||||
Item {
|
||||
id: mainItem
|
||||
property int sideMargin: 25
|
||||
property int topMargin: 5
|
||||
property bool groupCallVisible
|
||||
property color searchBarColor: DefaultStyle.contactListSearchBarColor
|
||||
property color searchBarBorderColor: "transparent"
|
||||
signal callButtonPressed(string address)
|
||||
clip: true
|
||||
Control.Control {
|
||||
id: listLayout
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: mainItem.sideMargin
|
||||
anchors.rightMargin: mainItem.sideMargin
|
||||
anchors.topMargin: mainItem.topMargin
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
}
|
||||
contentItem: ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
SearchBar {
|
||||
id: searchBar
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: mainItem.width
|
||||
color: mainItem.searchBarColor
|
||||
borderColor: mainItem.searchBarBorderColor
|
||||
placeholderText: qsTr("Rechercher un contact")
|
||||
numericPad: numPad
|
||||
}
|
||||
Button {
|
||||
visible: mainItem.groupCallVisible
|
||||
Layout.fillWidth: true
|
||||
leftPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
bottomPadding: 0
|
||||
background: Rectangle {
|
||||
color: DefaultStyle.groupCallButtonColor
|
||||
anchors.fill: parent
|
||||
radius: 50
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
source: AppIcons.groupCall
|
||||
Layout.preferredWidth: 35
|
||||
sourceSize.width: 35
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: "Appel de groupe"
|
||||
font.bold: true
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Image {
|
||||
source: AppIcons.rightArrow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: searchBar.text.length > 0 // && contactList.count === 0 (pas trouvé dans la liste)
|
||||
Layout.maximumWidth: parent.width
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: searchBar.text
|
||||
maximumLineCount: 1
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Control.Button {
|
||||
implicitWidth: 30
|
||||
implicitHeight: 30
|
||||
background: Item {
|
||||
visible: false
|
||||
}
|
||||
contentItem: Image {
|
||||
source: AppIcons.phone
|
||||
width: 20
|
||||
sourceSize.width: 20
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
onClicked: {
|
||||
mainItem.callButtonPressed(searchBar.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
ListView {
|
||||
id: contactList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
// call history
|
||||
model: 30
|
||||
delegate: Item {
|
||||
required property int index
|
||||
width:contactList.width
|
||||
height: 30
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
Image {
|
||||
source: AppIcons.info
|
||||
}
|
||||
ColumnLayout {
|
||||
Text {
|
||||
text: "John Doe"
|
||||
}
|
||||
// RowLayout {
|
||||
// Image {
|
||||
// source: AppIcons.incomingCall
|
||||
// }
|
||||
// Text {
|
||||
// text: "info sur l'appel"
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.1
|
||||
radius: 15
|
||||
color: DefaultStyle.comboBoxHoverColor
|
||||
visible: parent.containsMouse
|
||||
}
|
||||
onClicked: contactList.currentIndex = parent.index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: numPad.height
|
||||
NumericPad {
|
||||
id: numPad
|
||||
// anchors.centerIn: parent
|
||||
width: parent.width
|
||||
onLaunchCall: {
|
||||
var callVarObject = UtilsCpp.createCall(searchBar.text + "@sip.linphone.org")
|
||||
// TODO : auto completion instead of sip linphone
|
||||
var windowComp = Qt.createComponent("OngoingCallPage.qml")
|
||||
var callWindow = windowComp.createObject({callVarObject: callVarObject})
|
||||
callWindow.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Linphone/view/Item/Call/OngoingCallRightPanel.qml
Normal file
61
Linphone/view/Item/Call/OngoingCallRightPanel.qml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
|
||||
Control.Page {
|
||||
id: mainItem
|
||||
property alias headerContent: header.children
|
||||
|
||||
background: Rectangle {
|
||||
width: mainItem.width
|
||||
height: mainItem.height
|
||||
color: DefaultStyle.callRightPanelBackgroundColor
|
||||
radius: 15
|
||||
}
|
||||
|
||||
header: Control.Control {
|
||||
id: pageHeader
|
||||
width: mainItem.width
|
||||
background: Rectangle {
|
||||
id: headerBackground
|
||||
width: pageHeader.width
|
||||
height: pageHeader.height
|
||||
color: DefaultStyle.grey_0
|
||||
radius: 15
|
||||
Rectangle {
|
||||
y: pageHeader.height/2
|
||||
height: pageHeader.height/2
|
||||
width: pageHeader.width
|
||||
|
||||
}
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
width: pageHeader.width
|
||||
height: pageHeader.height
|
||||
anchors.leftMargin: 10
|
||||
anchors.left: pageHeader.left
|
||||
Item {
|
||||
id: header
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Button {
|
||||
id: closeButton
|
||||
Layout.alignment: Qt.AlignRight
|
||||
background: Item {
|
||||
visible: false
|
||||
}
|
||||
contentItem: Image {
|
||||
anchors.centerIn: closeButton
|
||||
source: AppIcons.closeX
|
||||
width: 10
|
||||
sourceSize.width: 10
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
onClicked: mainItem.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ ColumnLayout {
|
|||
signal buttonClicked(int index)
|
||||
|
||||
background: Rectangle {
|
||||
color: stackLayout.currentIndex == slideIndex ? DefaultStyle.buttonBackground : DefaultStyle.carouselLightGrayColor
|
||||
color: stackLayout.currentIndex == slideIndex ? DefaultStyle.main1_500_main : DefaultStyle.carouselLightGrayColor
|
||||
radius: 15
|
||||
width: stackLayout.currentIndex == slideIndex ? 11 : 8
|
||||
height: 8
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ Control.CheckBox {
|
|||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
radius: 3
|
||||
border.color: DefaultStyle.checkboxBorderColor
|
||||
border.color: DefaultStyle.main1_500_main
|
||||
border.width: DefaultStyle.checkboxBorderWidth
|
||||
// color: mainItem.checked ? DefaultStyle.checkboxBorderColor : "transparent"
|
||||
// color: mainItem.checked ? DefaultStyle.main1_500_main : "transparent"
|
||||
|
||||
Text {
|
||||
visible: mainItem.checked
|
||||
text: "\u2714"
|
||||
font.pointSize: 18
|
||||
color: DefaultStyle.checkboxBorderColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ ColumnLayout {
|
|||
visible: label.length > 0
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: mainItem.label
|
||||
color: combobox.activeFocus ? DefaultStyle.formItemFocusBorderColor : DefaultStyle.formItemLabelColor
|
||||
color: combobox.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.formItemLabelColor
|
||||
font {
|
||||
pointSize: DefaultStyle.formItemLabelSize
|
||||
bold: true
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Linphone
|
|||
Control.TextField {
|
||||
id: mainItem
|
||||
property int inputSize: 60
|
||||
color: activeFocus ? DefaultStyle.digitInputFocusedColor : DefaultStyle.digitInputColor
|
||||
color: activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.digitInputColor
|
||||
rightPadding: inputSize / 4
|
||||
leftPadding: inputSize / 4
|
||||
validator: IntValidator{bottom: 0; top: 9}
|
||||
|
|
@ -20,7 +20,7 @@ Control.TextField {
|
|||
|
||||
background: Rectangle {
|
||||
// id: background
|
||||
border.color: mainItem.activeFocus ? DefaultStyle.digitInputFocusedColor : DefaultStyle.digitInputColor
|
||||
border.color: mainItem.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.digitInputColor
|
||||
radius: mainItem.inputSize / 8
|
||||
}
|
||||
// cursorDelegate: Rectangle {
|
||||
|
|
@ -34,6 +34,6 @@ Control.TextField {
|
|||
// // anchors.left: parent.left
|
||||
// // anchors.bottomMargin: inputSize/8
|
||||
// // transform: [/*Translate {x: mainItem.cursorRectangle.height},*/ Rotation {angle: -90}]
|
||||
// color:DefaultStyle.digitInputFocusedColor
|
||||
// color:DefaultStyle.main1_500_main
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,19 +17,20 @@ Item {
|
|||
|
||||
Image {
|
||||
id: image
|
||||
visible: !effect2.enabled
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
//sourceSize.width: parent.width
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.centerIn: parent
|
||||
visible: !effect2.enabled
|
||||
}
|
||||
MultiEffect {
|
||||
id: effect
|
||||
visible: !effect2.enabled
|
||||
anchors.fill: image
|
||||
source: image
|
||||
maskSource: image
|
||||
visible: !effect2.enabled
|
||||
brightness: effect2.enabled ? 1.0 : 0.0
|
||||
}
|
||||
MultiEffect {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ ColumnLayout {
|
|||
text: "Forgotten password?"
|
||||
font{
|
||||
underline: true
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
}
|
||||
onClicked: console.debug("[LoginForm]User: forgotten password button clicked")
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ 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()
|
||||
}
|
||||
}
|
||||
Item{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ Control.Popup {
|
|||
clip: true
|
||||
id: mainItem
|
||||
signal buttonPressed(string text)
|
||||
signal launchCall()
|
||||
signal wipe()
|
||||
closePolicy: Control.Popup.CloseOnEscape
|
||||
leftPadding: closeButton.width
|
||||
|
|
@ -61,7 +62,7 @@ Control.Popup {
|
|||
implicitHeight: 40
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: numPadButton.down ? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.numericPadButtonColor
|
||||
color: numPadButton.down ? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.grey_0
|
||||
radius: 20
|
||||
}
|
||||
contentItem: Text {
|
||||
|
|
@ -91,7 +92,7 @@ Control.Popup {
|
|||
implicitHeight: 40
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: digitButton.down ? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.numericPadButtonColor
|
||||
color: digitButton.down ? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.grey_0
|
||||
radius: 20
|
||||
}
|
||||
contentItem: Item {
|
||||
|
|
@ -131,7 +132,7 @@ Control.Popup {
|
|||
bottomPadding: 15
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.numericPadLaunchCallButtonColor
|
||||
color: DefaultStyle.launchCallButtonColor
|
||||
radius: 15
|
||||
}
|
||||
contentItem: EffectImage {
|
||||
|
|
@ -142,8 +143,9 @@ Control.Popup {
|
|||
width: 20
|
||||
height: 20
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
effect.brightness: 1.0
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
}
|
||||
onClicked: mainItem.launchCall()
|
||||
}
|
||||
Button {
|
||||
leftPadding: 5
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ ColumnLayout {
|
|||
visible: mainItem.label.length > 0
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: mainItem.label
|
||||
color: combobox.activeFocus ? DefaultStyle.formItemFocusBorderColor : DefaultStyle.formItemLabelColor
|
||||
color: combobox.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.formItemLabelColor
|
||||
font {
|
||||
pointSize: DefaultStyle.formItemLabelSize
|
||||
bold: true
|
||||
|
|
@ -39,7 +39,7 @@ ColumnLayout {
|
|||
? (mainItem.errorMessage.length > 0
|
||||
? DefaultStyle.errorMessageColor
|
||||
: textField.activeFocus
|
||||
? DefaultStyle.formItemFocusBorderColor
|
||||
? DefaultStyle.main1_500_main
|
||||
: DefaultStyle.formItemBorderColor)
|
||||
: "transparent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ ColumnLayout {
|
|||
visible: label.length > 0
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: mainItem.label + (mainItem.mandatory ? "*" : "")
|
||||
color: (combobox.hasActiveFocus || textField.hasActiveFocus) ? DefaultStyle.formItemFocusBorderColor : DefaultStyle.formItemLabelColor
|
||||
color: (combobox.hasActiveFocus || textField.hasActiveFocus) ? DefaultStyle.main1_500_main : DefaultStyle.formItemLabelColor
|
||||
font {
|
||||
pointSize: DefaultStyle.formItemLabelSize
|
||||
bold: true
|
||||
|
|
@ -34,7 +34,7 @@ ColumnLayout {
|
|||
border.color: mainItem.errorMessage.length > 0
|
||||
? DefaultStyle.errorMessageColor
|
||||
: (textField.hasActiveFocus || combobox.hasActiveFocus)
|
||||
? DefaultStyle.formItemFocusBorderColor
|
||||
? DefaultStyle.main1_500_main
|
||||
: DefaultStyle.formItemBorderColor
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
|
@ -69,7 +69,7 @@ ColumnLayout {
|
|||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
font {
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
family: DefaultStyle.defaultFont
|
||||
bold: true
|
||||
}
|
||||
|
|
|
|||
61
Linphone/view/Item/Prototype/CanvasCircle.qml
Normal file
61
Linphone/view/Item/Prototype/CanvasCircle.qml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 150
|
||||
property color borderColor
|
||||
property color innerColor
|
||||
width: size
|
||||
height: size
|
||||
|
||||
onBorderColorChanged: c.requestPaint()
|
||||
|
||||
function requestPaint(animated) {
|
||||
c.animated = animated
|
||||
if (animated) animationTimer.restart()
|
||||
else {
|
||||
animationTimer.stop()
|
||||
c.requestPaint()
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: c
|
||||
property bool animated: false
|
||||
property int offset: 0
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
onOffsetChanged: requestPaint()
|
||||
Timer {
|
||||
id: animationTimer
|
||||
interval: 200
|
||||
repeat: true
|
||||
onTriggered: c.offset = (c.offset + 1)%360
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
ctx.reset()
|
||||
ctx.setLineDash([3, 2]);
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
ctx.lineDashOffset = offset;
|
||||
|
||||
var x = root.width / 2;
|
||||
var y = root.height / 2;
|
||||
|
||||
var radius = root.size / 2
|
||||
var startAngle = (Math.PI / 180) * 270;
|
||||
var fullAngle = (Math.PI / 180) * (270 + 360);
|
||||
|
||||
ctx.strokeStyle = root.borderColor;
|
||||
ctx.fillStyle = root.innerColor;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius - 1, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
if (animated) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ Control.RadioButton {
|
|||
|
||||
background: Rectangle {
|
||||
color: DefaultStyle.formItemBackgroundColor
|
||||
border.color: mainItem.checked ? DefaultStyle.radioButtonCheckedColor : "transparent"
|
||||
border.color: mainItem.checked ? DefaultStyle.info_500_main : "transparent"
|
||||
radius: 20
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ Control.RadioButton {
|
|||
implicitWidth: 16
|
||||
implicitHeight: 16
|
||||
radius: implicitWidth/2
|
||||
border.color: mainItem.checked ? DefaultStyle.radioButtonCheckedColor : DefaultStyle.radioButtonUncheckedColor
|
||||
border.color: mainItem.checked ? DefaultStyle.info_500_main : DefaultStyle.main1_500_main
|
||||
|
||||
Rectangle {
|
||||
width: parent.width/2
|
||||
|
|
@ -42,14 +42,14 @@ Control.RadioButton {
|
|||
x: parent.width/4
|
||||
y: parent.width/4
|
||||
radius: width/2
|
||||
color: DefaultStyle.radioButtonCheckedColor
|
||||
color: DefaultStyle.info_500_main
|
||||
visible: mainItem.checked
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: mainItem.title
|
||||
font.bold: true
|
||||
color: DefaultStyle.radioButtonTitleColor
|
||||
color: DefaultStyle.grey_900
|
||||
font.pointSize: DefaultStyle.radioButtonTitleSize
|
||||
}
|
||||
Control.Button {
|
||||
|
|
@ -83,7 +83,7 @@ Control.RadioButton {
|
|||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.preferredWidth: 220
|
||||
Layout.preferredHeight: 100
|
||||
font.pointSize: DefaultStyle.defaultTextSize
|
||||
font.pointSize: DefaultStyle.descriptionTextSize
|
||||
text: mainItem.contentText
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
import QtQuick 2.7
|
||||
|
||||
Rectangle {
|
||||
function genRandomColor(){
|
||||
return '#'+ Math.floor(Math.random()*255).toString(16)
|
||||
+Math.floor(Math.random()*255).toString(16)
|
||||
+Math.floor(Math.random()*255).toString(16)
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
color: "blue"
|
||||
color: genRandomColor() //"blue"
|
||||
opacity: 0.2
|
||||
border.color: "green"
|
||||
border.color: genRandomColor() //"red"
|
||||
border.width: 2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@ Rectangle {
|
|||
id: mainItem
|
||||
property string placeholderText: ""
|
||||
property int textInputWidth: 350
|
||||
property var validator: RegularExpressionValidator{}
|
||||
property color borderColor: "transparent"
|
||||
property string text: textField.text
|
||||
property var validator: RegularExpressionValidator{}
|
||||
property var numericPad
|
||||
property alias numericPadButton: dialerButton
|
||||
readonly property bool hasActiveFocus: textField.activeFocus
|
||||
property var numericPad
|
||||
signal numericPadButtonPressed(bool checked)
|
||||
|
||||
onVisibleChanged: if (!visible && numericPad) numericPad.close()
|
||||
|
|
@ -32,7 +33,7 @@ Rectangle {
|
|||
implicitHeight: 30
|
||||
radius: 20
|
||||
color: DefaultStyle.formItemBackgroundColor
|
||||
border.color: textField.activeFocus ? DefaultStyle.searchBarFocusBorderColor : "transparent"
|
||||
border.color: textField.activeFocus ? DefaultStyle.searchBarFocusBorderColor : mainItem.borderColor
|
||||
Image {
|
||||
id: magnifier
|
||||
anchors.left: parent.left
|
||||
|
|
@ -43,9 +44,10 @@ Rectangle {
|
|||
Control.TextField {
|
||||
id: textField
|
||||
anchors.left: magnifier.right
|
||||
anchors.right: dialerButton.visible ? dialerButton.left : parent.right
|
||||
anchors.right: clearTextButton.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
placeholderText: mainItem.placeholderText
|
||||
width: mainItem.width - dialerButton.width
|
||||
echoMode: (mainItem.hidden && !dialerButton.checked) ? TextInput.Password : TextInput.Normal
|
||||
font.family: DefaultStyle.defaultFont
|
||||
font.pointSize: DefaultStyle.defaultFontPointSize
|
||||
|
|
@ -57,13 +59,13 @@ Rectangle {
|
|||
}
|
||||
cursorDelegate: Rectangle {
|
||||
visible: textField.activeFocus
|
||||
color: DefaultStyle.formItemFocusBorderColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
width: 2
|
||||
}
|
||||
}
|
||||
Control.Button {
|
||||
id: dialerButton
|
||||
visible: numericPad != undefined
|
||||
visible: numericPad != undefined && textField.text.length === 0
|
||||
checkable: true
|
||||
checked: false
|
||||
background: Rectangle {
|
||||
|
|
@ -82,4 +84,24 @@ Rectangle {
|
|||
else mainItem.numericPad.close()
|
||||
}
|
||||
}
|
||||
Control.Button {
|
||||
id: clearTextButton
|
||||
visible: textField.text.length > 0
|
||||
checkable: true
|
||||
checked: false
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
contentItem: Image {
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: AppIcons.closeX
|
||||
}
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
onCheckedChanged: {
|
||||
textField.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Control.TabBar {
|
|||
|
||||
// Quick.Rectangle {
|
||||
// height: 4
|
||||
// color: DefaultStyle.orangeColor
|
||||
// color: DefaultStyle.main1_500_main
|
||||
// anchors.bottom: parent.bottom
|
||||
// // anchors.left: mainItem.currentItem.left
|
||||
// // anchors.right: mainItem.currentItem.right
|
||||
|
|
@ -59,7 +59,7 @@ Control.TabBar {
|
|||
Quick.Rectangle {
|
||||
visible: mainItem.currentIndex === index
|
||||
height: 4
|
||||
color: DefaultStyle.orangeColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ ColumnLayout {
|
|||
visible: mainItem.label.length > 0
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: mainItem.label + (mainItem.mandatory ? "*" : "")
|
||||
color: textField.activeFocus ? DefaultStyle.formItemFocusBorderColor : DefaultStyle.formItemLabelColor
|
||||
color: textField.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.formItemLabelColor
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 1
|
||||
|
|
@ -58,7 +58,7 @@ ColumnLayout {
|
|||
? (mainItem.errorMessage.length > 0
|
||||
? DefaultStyle.errorMessageColor
|
||||
: textField.activeFocus
|
||||
? DefaultStyle.formItemFocusBorderColor
|
||||
? DefaultStyle.main1_500_main
|
||||
: DefaultStyle.formItemBorderColor)
|
||||
: "transparent"
|
||||
Control.TextField {
|
||||
|
|
@ -78,7 +78,7 @@ ColumnLayout {
|
|||
}
|
||||
cursorDelegate: Rectangle {
|
||||
visible: textField.activeFocus
|
||||
color: DefaultStyle.formItemFocusBorderColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
width: 2
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ ColumnLayout {
|
|||
wrapMode: Text.Wrap
|
||||
// maximumLineCount: 1
|
||||
font {
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
family: DefaultStyle.defaultFont
|
||||
bold: true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,18 +33,18 @@ Control.TabBar {
|
|||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.verticalTabBarColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
radius: 25
|
||||
}
|
||||
Rectangle {
|
||||
color: DefaultStyle.verticalTabBarColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: parent.width/2
|
||||
height: parent.height/2
|
||||
}
|
||||
Rectangle {
|
||||
color: DefaultStyle.verticalTabBarColor
|
||||
color: DefaultStyle.main1_500_main
|
||||
x: parent.x + parent.width/2
|
||||
y: parent.y + parent.height/2
|
||||
width: parent.width/2
|
||||
|
|
@ -69,9 +69,8 @@ Control.TabBar {
|
|||
Layout.preferredWidth: buttonSize
|
||||
Layout.preferredHeight: buttonSize
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
image.sourceSize.width: buttonSize
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
effect.brightness: 1.0
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
}
|
||||
Text {
|
||||
id: buttonText
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ LoginLayout {
|
|||
Text {
|
||||
Layout.rightMargin: 15
|
||||
text: "No account yet ?"
|
||||
font.pointSize: DefaultStyle.defaultTextSize
|
||||
font.pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ LoginLayout {
|
|||
Layout.rightMargin: 15
|
||||
text: "Didn't receive the code ?"
|
||||
color: DefaultStyle.questionTextColor
|
||||
font.pointSize: DefaultStyle.defaultTextSize
|
||||
font.pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ LoginLayout {
|
|||
Layout.rightMargin: 15
|
||||
color: DefaultStyle.questionTextColor
|
||||
text: "Already have an account ?"
|
||||
font.pointSize: DefaultStyle.defaultTextSize
|
||||
font.pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
Button {
|
||||
// Layout.alignment: Qt.AlignRight
|
||||
|
|
@ -87,7 +87,7 @@ LoginLayout {
|
|||
Text {
|
||||
text: "The password must contain 6 characters minimum"
|
||||
font {
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ LoginLayout {
|
|||
Text {
|
||||
text: "The password must contain 6 characters minimum"
|
||||
font {
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -176,7 +176,7 @@ LoginLayout {
|
|||
Text {
|
||||
text: "The password must contain 6 characters minimum"
|
||||
font {
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -191,7 +191,7 @@ LoginLayout {
|
|||
Text {
|
||||
text: "The password must contain 6 characters minimum"
|
||||
font {
|
||||
pointSize: DefaultStyle.defaultTextSize
|
||||
pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ LoginLayout {
|
|||
Text {
|
||||
Layout.rightMargin: 15
|
||||
text: "No account yet ?"
|
||||
font.pointSize: DefaultStyle.defaultTextSize
|
||||
font.pointSize: DefaultStyle.indicatorMessageTextSize
|
||||
}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
|
@ -75,7 +75,7 @@ LoginLayout {
|
|||
width: rootStackView.width
|
||||
wrapMode: Text.WordWrap
|
||||
color: DefaultStyle.darkGrayColor
|
||||
font.pointSize: DefaultStyle.defaultTextSize
|
||||
font.pointSize: DefaultStyle.descriptionTextSize
|
||||
text: "<p>Some features require a Linphone account, such as group messaging, video conferences...</p>
|
||||
<p>These features are hidden when you register with a third party SIP account.</p>
|
||||
<p>To enable it in a commercial projet, please contact us. </p>"
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ Item {
|
|||
property string newItemIconSource
|
||||
property string emptyListText
|
||||
property alias leftPanelContent: leftPanel.children
|
||||
property Component rightPanelContent
|
||||
property var rightPanelContent: rightPanelItem.children
|
||||
property bool showDefaultItem: true
|
||||
onShowDefaultItemChanged: stackView.replace(showDefaultItem ? defaultItem : rightPanel)
|
||||
// onShowDefaultItemChanged: stackView.replace(showDefaultItem ? defaultItem : rightPanelItem)
|
||||
signal noItemButtonPressed()
|
||||
|
||||
Control.SplitView {
|
||||
|
|
@ -37,64 +37,74 @@ Item {
|
|||
id: rightPanel
|
||||
clip: true
|
||||
color: DefaultStyle.mainPageRightPanelBackgroundColor
|
||||
Control.StackView {
|
||||
id: stackView
|
||||
initialItem: defaultItem
|
||||
StackLayout {
|
||||
currentIndex: mainItem.showDefaultItem ? 0 : 1
|
||||
anchors.fill: parent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
Component {
|
||||
id: defaultItem
|
||||
ColumnLayout {
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
ColumnLayout {
|
||||
id: defaultItem
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
visible: mainItem.showDefaultItem
|
||||
// anchors.centerIn: parent
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 25
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
source: AppIcons.noItemImage
|
||||
Layout.preferredWidth: 250
|
||||
Layout.preferredHeight: 250
|
||||
fillMode: Image.PreserveAspectFit
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: mainItem.emptyListText
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.bold: true
|
||||
}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
contentItem: RowLayout {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
EffectImage {
|
||||
effect.brightness: 1
|
||||
image.source: mainItem.newItemIconSource
|
||||
image.width: 20
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: mainItem.noItemButtonText
|
||||
wrapMode: Text.WordWrap
|
||||
color: DefaultStyle.buttonTextColor
|
||||
font {
|
||||
bold: true
|
||||
pointSize: DefaultStyle.buttonTextSize
|
||||
family: DefaultStyle.defaultFont
|
||||
ColumnLayout {
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
source: AppIcons.noItemImage
|
||||
Layout.preferredWidth: 250
|
||||
Layout.preferredHeight: 250
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: mainItem.emptyListText
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.bold: true
|
||||
}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
contentItem: RowLayout {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
EffectImage {
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
image.source: mainItem.newItemIconSource
|
||||
image.width: 20
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: mainItem.noItemButtonText
|
||||
wrapMode: Text.WordWrap
|
||||
color: DefaultStyle.grey_0
|
||||
font {
|
||||
bold: true
|
||||
pointSize: DefaultStyle.buttonTextSize
|
||||
family: DefaultStyle.defaultFont
|
||||
}
|
||||
}
|
||||
}
|
||||
onPressed: mainItem.noItemButtonPressed()
|
||||
}
|
||||
onPressed: mainItem.noItemButtonPressed()
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
}
|
||||
Item {
|
||||
id: rightPanelItem
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import QtQuick 2.15
|
|||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
import UtilsCpp 1.0
|
||||
|
||||
AbstractMainPage {
|
||||
id: mainItem
|
||||
|
|
@ -16,10 +17,12 @@ AbstractMainPage {
|
|||
Layout.fillHeight: true
|
||||
Control.StackView {
|
||||
id: listStackView
|
||||
clip: true
|
||||
initialItem: listItem
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 25
|
||||
anchors.rightMargin: 25
|
||||
property int sideMargin: 25
|
||||
// anchors.leftMargin: 25
|
||||
// anchors.rightMargin: 25
|
||||
}
|
||||
Component {
|
||||
id: listItem
|
||||
|
|
@ -27,6 +30,8 @@ AbstractMainPage {
|
|||
ColumnLayout {
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: listStackView.sideMargin
|
||||
Layout.rightMargin: listStackView.sideMargin
|
||||
Text {
|
||||
text: qsTr("Appels")
|
||||
color: DefaultStyle.mainPageTitleColor
|
||||
|
|
@ -65,6 +70,8 @@ AbstractMainPage {
|
|||
id: listLayout
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: listStackView.sideMargin
|
||||
Layout.rightMargin: listStackView.sideMargin
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
|
|
@ -148,6 +155,11 @@ AbstractMainPage {
|
|||
|
||||
onCountChanged: mainItem.showDefaultItem = listView.count === 0
|
||||
|
||||
Connections {
|
||||
target: mainItem
|
||||
onShowDefaultItemChanged: mainItem.showDefaultItem = mainItem.showDefaultItem && listView.count === 0
|
||||
}
|
||||
|
||||
Control.ScrollIndicator.vertical: Control.ScrollIndicator { }
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +170,13 @@ AbstractMainPage {
|
|||
Component {
|
||||
id: newCallItem
|
||||
ColumnLayout {
|
||||
Control.StackView.onActivating: {
|
||||
mainItem.showDefaultItem = false
|
||||
}
|
||||
Control.StackView.onDeactivating: mainItem.showDefaultItem = true
|
||||
RowLayout {
|
||||
Layout.leftMargin: listStackView.sideMargin
|
||||
Layout.rightMargin: listStackView.sideMargin
|
||||
Control.Button {
|
||||
background: Item {
|
||||
}
|
||||
|
|
@ -180,74 +198,26 @@ AbstractMainPage {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Control.Control {
|
||||
id: listLayout
|
||||
ContactsList {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
SearchBar {
|
||||
id: searchBar
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Rechercher un appel")
|
||||
numericPad: numPad
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
leftPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
bottomPadding: 0
|
||||
background: Rectangle {
|
||||
color: DefaultStyle.groupCallButtonColor
|
||||
anchors.fill: parent
|
||||
radius: 50
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
source: AppIcons.groupCall
|
||||
Layout.preferredWidth: 35
|
||||
sourceSize.width: 35
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: "Appel de groupe"
|
||||
font.bold: true
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Image {
|
||||
source: AppIcons.rightArrow
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
ListView {
|
||||
Layout.fillHeight: true
|
||||
// call history
|
||||
}
|
||||
}
|
||||
Layout.maximumWidth: parent.width
|
||||
groupCallVisible: true
|
||||
searchBarColor: DefaultStyle.contactListSearchBarColor
|
||||
|
||||
onCallButtonPressed: (address) => {
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if (!address.endsWith(addressEnd)) address += addressEnd
|
||||
var callVarObject = UtilsCpp.createCall(address)
|
||||
// var windowComp = Qt.createComponent("CallsWindow.qml")
|
||||
// var call = callVarObject.value
|
||||
// var callWindow = windowComp.createObject(null, {callVarObject: callVarObject})
|
||||
// callWindow.modality = Qt.ApplicationModal
|
||||
// callWindow.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: numPad.height
|
||||
NumericPad {
|
||||
id: numPad
|
||||
// anchors.centerIn: parent
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rightPanelContent: ColumnLayout {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ QtObject {
|
|||
property string phoneSelected: "image://internal/phone-selected.svg"
|
||||
property string newCall: "image://internal/phone-plus.svg"
|
||||
property string endCall: "image://internal/phone-disconnect.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 chatTeardropText: "image://internal/chat-teardrop-text.svg"
|
||||
|
|
@ -44,5 +45,15 @@ QtObject {
|
|||
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 microphone: "image://internal/microphone.svg"
|
||||
property string microphoneSlash: "image://internal/microphone-slash.svg"
|
||||
property string videoCamera: "image://internal/video-camera.svg"
|
||||
property string videoCameraSlash: "image://internal/video-camera-slash.svg"
|
||||
property string speaker: "image://internal/speaker-high.svg"
|
||||
property string speakerSlash: "image://internal/speaker-slash.svg"
|
||||
property string trusted: "image://internal/trusted.svg"
|
||||
property string avatar: "image://internal/randomAvatar.png"
|
||||
property string pause: "image://internal/pause.svg"
|
||||
property string play: "image://internal/play.svg"
|
||||
property string smiley: "image://internal/smiley.svg"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,34 @@ pragma Singleton
|
|||
import QtQuick 2.15
|
||||
|
||||
QtObject {
|
||||
property color main1_500_main: "#FE5E00"
|
||||
|
||||
property color main2_0: "#FAFEFF"
|
||||
property color main2_100: "#EEF6F8"
|
||||
property color main2_200: "#DFECF2"
|
||||
property color main2_300: "#C0D1D9"
|
||||
property color main2_400: "#9AABB5"
|
||||
property color main2_500main: "#6C7A87"
|
||||
property color main2_700: "#364860"
|
||||
|
||||
property color warning_600: "#DBB820"
|
||||
|
||||
property color grey_0: "#FFFFFF"
|
||||
property color grey_500: "#4E4E4E"
|
||||
property color grey_600: "#2E3030"
|
||||
property color grey_900: "#070707"
|
||||
|
||||
property color danger_500: "#DD5F5F"
|
||||
|
||||
property color info_500_main: "#4AA8FF"
|
||||
|
||||
property color success_500main: "#4FAE80"
|
||||
|
||||
property string emojiFont: "Noto Color Emoji"
|
||||
property color orangeColor: "#FE5E00"
|
||||
property color buttonBackground: "#FE5E00"
|
||||
property color buttonPressedBackground: "#c74b02"
|
||||
property color buttonInversedBackground: "white"
|
||||
property color buttonPressedInversedBackground: "#fff1e8"
|
||||
property color buttonTextColor: "white"
|
||||
property color radioButtonCheckedColor: "#4AA8FF"
|
||||
property color radioButtonUncheckedColor: "#FE5E00"
|
||||
property color radioButtonTitleColor: "#070707"
|
||||
property int radioButtonTextSize: 8
|
||||
property int radioButtonTitleSize: 9
|
||||
property color buttonInversedTextColor: "#FE5E00"
|
||||
property color checkboxBorderColor: "#FE5E00"
|
||||
property double checkboxBorderWidth: 2
|
||||
property int buttonTextSize: 10
|
||||
property color carouselLightGrayColor: "#DFECF2"
|
||||
|
|
@ -26,10 +39,8 @@ QtObject {
|
|||
property color formItemDisableBackgroundColor: "#EDEDED"
|
||||
property color formItemBackgroundColor: "#F9F9F9"
|
||||
property color formItemBorderColor: "#EDEDED"
|
||||
property color formItemFocusBorderColor: "#FE5E00"
|
||||
|
||||
property int tabButtonTextSize: 11
|
||||
property color verticalTabBarColor: "#FE5E00"
|
||||
property color verticalTabBarTextColor: "white"
|
||||
property int verticalTabButtonTextSize: 6
|
||||
|
||||
|
|
@ -43,7 +54,6 @@ QtObject {
|
|||
|
||||
property color tooltipBackgroundColor: "#DFECF2"
|
||||
|
||||
property color digitInputFocusedColor: "#FE5E00"
|
||||
property color digitInputColor: "#6C7A87"
|
||||
|
||||
property color darkBlueColor: "#22334D"
|
||||
|
|
@ -53,7 +63,8 @@ QtObject {
|
|||
|
||||
property color defaultTextColor: "#4E6074"
|
||||
property color disableTextColor: "#9AABB5"
|
||||
property int defaultTextSize: 7
|
||||
property int descriptionTextSize: 7
|
||||
property int indicatorMessageTextSize: 7
|
||||
property string defaultFont: "Noto Sans"
|
||||
property int defaultFontPointSize: 10
|
||||
property int title1FontPointSize: 50
|
||||
|
|
@ -65,29 +76,30 @@ QtObject {
|
|||
property int mainPageTitleSize: 15
|
||||
|
||||
property color searchBarFocusBorderColor: "#6C7A87"
|
||||
property color contactListSearchBarColor: "#F9F9F9"
|
||||
property color callRightPanelSearchBarBorderColor: "#EDEDED"
|
||||
|
||||
property color numericPadBackgroundColor: "#F9F9F9"
|
||||
property color numericPadShadowColor: Qt.rgba(0.0, 0.0, 0.0, 0.1)
|
||||
property color numericPadButtonColor: "#FFFFFF"
|
||||
property int numericPadButtonTextSize: 15
|
||||
property int numericPadButtonSubtextSize: 6
|
||||
property color numericPadPressedButtonColor: "#EEF7F8"
|
||||
property color numericPadLaunchCallButtonColor: "#4FAE80"
|
||||
|
||||
property color groupCallButtonColor: "#EEF7F8"
|
||||
property color launchCallButtonColor: "#4FAE80"
|
||||
property color callCheckedButtonColor: "#9AABB5"
|
||||
|
||||
property color splitViewHandleColor: "#F9F9F9"
|
||||
property color splitViewHoveredHandleColor: "#EDEDED"
|
||||
|
||||
property color danger_500main: "#DD5F5F"
|
||||
property color grey_0: "#FFFFFF"
|
||||
property color success_500main: "#4FAE80"
|
||||
property color warning_600: "#DBB820"
|
||||
property color main2_200: "#DFECF2"
|
||||
property color main2_300: "#C0D1D9"
|
||||
property color main2_400: "#9AABB5"
|
||||
property color main2_700: "#364860"
|
||||
property color main2_500main: "#6C7A87"
|
||||
|
||||
property color ongoingCallWindowColor: "#000000"
|
||||
property color ongoingCallBackgroundColor: "#2E3030"
|
||||
property int ongoingCallElapsedTimeSize: 15
|
||||
property int ongoingCallNameSize: 10
|
||||
property int ongoingCallAddressSize: 6
|
||||
property color callRightPanelBackgroundColor: "#F9F9F9"
|
||||
|
||||
property color defaultAvatarBackgroundColor: "#DFECF2"
|
||||
|
||||
property double dp: 1.0//0.66
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue