diff --git a/qt/01_AccountLogin/.gitignore b/qt/01_AccountLogin/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/qt/01_AccountLogin/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/qt/01_AccountLogin/CMakeLists.txt b/qt/01_AccountLogin/CMakeLists.txt new file mode 100644 index 0000000..57a6876 --- /dev/null +++ b/qt/01_AccountLogin/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.22) + +project(01_AccountLogin LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick) +find_package(LinphoneCxx REQUIRED) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC ON) + +set(SOURCES + "src/main.cpp" + "src/App.cpp" + "src/CoreHandler.cpp" + "src/CoreListener.cpp" + "src/CoreManager.cpp" +) +set(QRC_RESOURCES resources.qrc) +set(QML_SOURCES) +file(STRINGS ${QRC_RESOURCES} QRC_RESOURCES_CONTENT) +foreach(line ${QRC_RESOURCES_CONTENT}) + set(result) + string(REGEX REPLACE + "^[ \t]*<[ \t]*file[ \t]*>[ \t]*(.+\\.[a-z]+)[ \t]*<[ \t]*/[ \t]*file[ \t]*>[ \t]*$" + "\\1" + result + "${line}" + ) + string(REGEX MATCH "\\.[a-z]+$" is_ui ${result}) + if(NOT ${is_ui} STREQUAL "") + list(APPEND QML_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${result}") + endif() +endforeach() + +get_filename_component(SDK_PATH "${CMAKE_PREFIX_PATH}" REALPATH) +find_path(MSPLUGINS_PATH "plugins" PATH_SUFFIXES "lib/mediastreamer" "lib64/mediastreamer" REQUIRED) +set(MSPLUGINS_PATH "${MSPLUGINS_PATH}/plugins") + +add_executable(01_AccountLogin ${SOURCES} ${QML_SOURCES} ${QRC_RESOURCES}) + +target_compile_definitions(01_AccountLogin PRIVATE "SDK_PATH=\"${SDK_PATH}\"" "MSPLUGINS_PATH=\"${MSPLUGINS_PATH}\"") +target_include_directories(01_AccountLogin PRIVATE ${LINPHONECXX_INCLUDE_DIRS}) +target_link_libraries(01_AccountLogin PRIVATE Qt5::Core Qt5::Gui Qt5::Qml Qt5::Quick ${LINPHONECXX_LIBRARIES}) + +set_target_properties(01_AccountLogin PROPERTIES AUTORCC ON) +set_target_properties(01_AccountLogin PROPERTIES + WIN32_EXECUTABLE ON + MACOSX_BUNDLE ON +) diff --git a/qt/01_AccountLogin/README.md b/qt/01_AccountLogin/README.md new file mode 100644 index 0000000..e972bcd --- /dev/null +++ b/qt/01_AccountLogin/README.md @@ -0,0 +1,15 @@ +# Account Login tutorial + +This project will walk you through the different steps of logging in and out of a SIP account. + +If you do not yet have a SIP account, please create one here : https://www.linphone.org/freesip/home + + +## How to build + +In the following instructions, replace **** by the real path where your SDK is located, e.g. *~/projects/linphone-sdk/build-default/linphone-sdk/desktop/* + + mkdir build + cd build + cmake .. -DCMAKE_PREFIX_PATH= + cmake --build . diff --git a/qt/01_AccountLogin/resources.qrc b/qt/01_AccountLogin/resources.qrc new file mode 100644 index 0000000..e42b046 --- /dev/null +++ b/qt/01_AccountLogin/resources.qrc @@ -0,0 +1,6 @@ + + + ui/MainPage.qml + ui/RegistrationPage.qml + + diff --git a/qt/01_AccountLogin/src/App.cpp b/qt/01_AccountLogin/src/App.cpp new file mode 100644 index 0000000..77fc765 --- /dev/null +++ b/qt/01_AccountLogin/src/App.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include "App.hpp" +#include "CoreManager.hpp" + +using namespace std; +using namespace linphone; + +App::App(int &argc, char *argv[]) : QGuiApplication(argc, argv) +{ + setOrganizationName("Belledonne Communications"); + setOrganizationDomain("belledonne-communications.com"); + setApplicationName(QFileInfo(applicationFilePath()).baseName()); +} + +App::~App() +{ +} + +void App::init() +{ + registerTypes(); + + mEngine = new QQmlApplicationEngine(); + mEngine->load(QUrl("qrc:/ui/MainPage.qml")); + if (mEngine->rootObjects().isEmpty()) + qFatal("Unable to open main window."); + + // Initialize the CoreManager singleton and add it to the Qml context. + CoreManager::init(this); + auto coreManager = CoreManager::getInstance(); + QQmlContext *ctx = mEngine->rootContext(); + ctx->setContextProperty("coreManager", coreManager); +} + +void App::stop() +{ + CoreManager::uninit(); +} + +void App::registerTypes() +{ + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType>(); +} diff --git a/qt/01_AccountLogin/src/App.hpp b/qt/01_AccountLogin/src/App.hpp new file mode 100644 index 0000000..ce507e1 --- /dev/null +++ b/qt/01_AccountLogin/src/App.hpp @@ -0,0 +1,25 @@ +#include +#include + +#include + +class App : public QGuiApplication +{ + Q_OBJECT + +public: + App(int &argc, char *argv[]); + ~App(); + + void init(); + void stop(); + +private: + void registerTypes(); + + QQmlApplicationEngine *mEngine = nullptr; +}; + +Q_DECLARE_METATYPE(std::string); +Q_DECLARE_METATYPE(linphone::RegistrationState); +Q_DECLARE_METATYPE(std::shared_ptr); diff --git a/qt/01_AccountLogin/src/CoreHandler.cpp b/qt/01_AccountLogin/src/CoreHandler.cpp new file mode 100644 index 0000000..f3fd09c --- /dev/null +++ b/qt/01_AccountLogin/src/CoreHandler.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "CoreHandler.hpp" +#include "CoreListener.hpp" +#include "CoreManager.hpp" + +CoreHandler::CoreHandler() +{ + mCoreListener = std::make_shared(); + connectTo(mCoreListener.get()); +} + +void CoreHandler::setListener(std::shared_ptr core) +{ + core->addListener(mCoreListener); +} + +void CoreHandler::removeListener(std::shared_ptr core) +{ + core->removeListener(mCoreListener); +} + +void CoreHandler::onAccountRegistrationStateChanged(const std::shared_ptr &, const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message) +{ + emit registrationStateChanged(account, state, message); +} + +void CoreHandler::onGlobalStateChanged(const std::shared_ptr &, linphone::GlobalState state, const std::string &message) +{ + switch (state) + { + case linphone::GlobalState::On: + qInfo() << "Core is running " << QString::fromStdString(message); + break; + case linphone::GlobalState::Off: + qInfo() << "Core is stopped " << QString::fromStdString(message); + emit coreStopped(); + break; + case linphone::GlobalState::Startup: + qInfo() << "Core is starting" << QString::fromStdString(message); + emit coreStarting(); + break; + default: + break; + } +} + +void CoreHandler::connectTo(CoreListener *listener) +{ + connect(listener, &CoreListener::accountRegistrationStateChanged, this, &CoreHandler::onAccountRegistrationStateChanged); + connect(listener, &CoreListener::globalStateChanged, this, &CoreHandler::onGlobalStateChanged); +} \ No newline at end of file diff --git a/qt/01_AccountLogin/src/CoreHandler.hpp b/qt/01_AccountLogin/src/CoreHandler.hpp new file mode 100644 index 0000000..0181aa5 --- /dev/null +++ b/qt/01_AccountLogin/src/CoreHandler.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * 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 . + */ + +#pragma once + +#include +#include + +class CoreListener; + +class CoreHandler : public QObject +{ + Q_OBJECT + +public: + CoreHandler(); + + void setListener(std::shared_ptr core); + void removeListener(std::shared_ptr core); + +signals: + void coreStarting(); + void coreStopped(); + void registrationStateChanged(const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message); + +public slots: + void onAccountRegistrationStateChanged(const std::shared_ptr &core, const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message); + void onGlobalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message); + +private: + void connectTo(CoreListener *listener); + std::shared_ptr mCoreListener; +}; \ No newline at end of file diff --git a/qt/01_AccountLogin/src/CoreListener.cpp b/qt/01_AccountLogin/src/CoreListener.cpp new file mode 100644 index 0000000..5aa6fe1 --- /dev/null +++ b/qt/01_AccountLogin/src/CoreListener.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "CoreListener.hpp" + +CoreListener::CoreListener(QObject *parent) : QObject(parent) +{ +} + +void CoreListener::onAccountRegistrationStateChanged(const std::shared_ptr &core, const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message) +{ + emit accountRegistrationStateChanged(core, account, state, message); +} + +void CoreListener::onGlobalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message) +{ + emit globalStateChanged(core, gstate, message); +} diff --git a/qt/01_AccountLogin/src/CoreListener.hpp b/qt/01_AccountLogin/src/CoreListener.hpp new file mode 100644 index 0000000..4ca1efa --- /dev/null +++ b/qt/01_AccountLogin/src/CoreListener.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * 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 . + */ + +#pragma once + +#include +#include + +class CoreListener : public QObject, public linphone::CoreListener +{ + Q_OBJECT + +public: + CoreListener(QObject *parent = nullptr); + virtual ~CoreListener() = default; + + virtual void onAccountRegistrationStateChanged(const std::shared_ptr &core, const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message) override; + virtual void onGlobalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message) override; + +signals: + void accountRegistrationStateChanged(const std::shared_ptr &core, const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message); + void globalStateChanged(const std::shared_ptr &core, linphone::GlobalState gstate, const std::string &message); +}; \ No newline at end of file diff --git a/qt/01_AccountLogin/src/CoreManager.cpp b/qt/01_AccountLogin/src/CoreManager.cpp new file mode 100644 index 0000000..df3abd2 --- /dev/null +++ b/qt/01_AccountLogin/src/CoreManager.cpp @@ -0,0 +1,235 @@ +#include + +#include "CoreHandler.hpp" +#include "CoreManager.hpp" + +using namespace std; +using namespace linphone; + +CoreManager *CoreManager::mInstance = nullptr; + +CoreManager::CoreManager(QObject *parent) : QObject(parent) +{ + mHandler = QSharedPointer::create(); + CoreHandler *coreHandler = mHandler.get(); + QObject::connect(coreHandler, &CoreHandler::coreStarting, this, &CoreManager::startIterate, Qt::QueuedConnection); + QObject::connect(coreHandler, &CoreHandler::coreStopped, this, &CoreManager::stopIterate, Qt::QueuedConnection); + QObject::connect(coreHandler, &CoreHandler::registrationStateChanged, this, &CoreManager::onRegistrationStateChanged, Qt::QueuedConnection); + + // Delay the creation of the core so that the CoreManager instance is + // already set. + QTimer::singleShot(10, [this]() + { createLinphoneCore(); }); +} + +CoreManager::~CoreManager() +{ + mHandler->removeListener(mCore); + mHandler = nullptr; + mCore = nullptr; +} + +void CoreManager::init(QObject *parent) +{ + if (mInstance) + return; + mInstance = new CoreManager(parent); +} + +void CoreManager::uninit() +{ + if (mInstance) + { + mInstance->stopIterate(); + auto core = mInstance->mCore; + delete mInstance; + mInstance = nullptr; + core->stop(); + } +} + +CoreManager *CoreManager::getInstance() +{ + return mInstance; +} + +void CoreManager::startIterate() +{ + // Start a timer to call the core iterate every 20 ms. + mIterateTimer = new QTimer(this); + mIterateTimer->setInterval(20); + QObject::connect(mIterateTimer, &QTimer::timeout, this, &CoreManager::iterate); + qInfo() << QStringLiteral("Start iterate"); + mIterateTimer->start(); +} + +void CoreManager::stopIterate() +{ + qInfo() << QStringLiteral("Stop iterate"); + mIterateTimer->stop(); + mIterateTimer->deleteLater(); // Allow the timer to continue its stuff + mIterateTimer = nullptr; +} + +void CoreManager::login(QString identity, QString password, QString transport) +{ + if (mLoginButtonEnabled) + { + setProperty("loginButtonEnabled", false); + + // To configure a SIP account, we need an Account object and an AuthInfo object + // The first one is how to connect to the proxy server, the second one stores the credentials + + // Here we are creating an AuthInfo object from the identity Address and password provided by the user. + shared_ptr
address = Factory::get()->createAddress(identity.toStdString()); + + // The AuthInfo can be created from the Factory as it's only a data class + // userID is set to null as it's the same as the username in our case + // ha1 is set to null as we are using the clear text password. Upon first register, the hash will be computed automatically. + // The realm will be determined automatically from the first register, as well as the algorithm + shared_ptr authInfo = Factory::get()->createAuthInfo(address->getUsername(), "", password.toStdString(), "", "", address->getDomain()); + // And we add it to the Core + mCore->addAuthInfo(authInfo); + + // Then we create an AccountParams object. + // It contains the account informations needed by the core + shared_ptr accountParams = mCore->createAccountParams(); + // A SIP account is identified by an identity address that we can construct from the username and domain + accountParams->setIdentityAddress(address); + // We also need to configure where the proxy server is located + shared_ptr
serverAddr = Factory::get()->createAddress("sip:" + address->getDomain()); + // We use the Address object to easily set the transport protocol + if (transport == "tls") + { + serverAddr->setTransport(TransportType::Tls); + } + else if (transport == "tcp") + { + serverAddr->setTransport(TransportType::Tcp); + } + else + { + serverAddr->setTransport(TransportType::Udp); + } + accountParams->setServerAddress(serverAddr); + // If enableRegister is set to true, when this account will be added to the core it will + // automatically try to connect. + accountParams->enableRegister(true); + + // We can now create an Account object from the AccountParams ... + shared_ptr account = mCore->createAccount(accountParams); + // ... and add it to the core, launching the connection process. + mCore->addAccount(account); + // Also set the newly added account as default + mCore->setDefaultAccount(account); + } +} + +void CoreManager::logout() +{ + if (mLogoutButtonEnabled) + { + setProperty("logoutButtonEnabled", false); + + // Setting enableRegister to false on a connected Account object will + // launch the logout action. + shared_ptr account = mCore->getDefaultAccount(); + if (account) + { + // BUT BE CAREFUL : the Params of an account are read-only + // You MUST Clone it : + shared_ptr accountParams = account->getParams()->clone(); + // Then you can modify the clone : + accountParams->enableRegister(false); + // And finally setting the new Params value triggers the changes, here the logout. + account->setParams(accountParams); + } + } +} + +void CoreManager::onRegistrationStateChanged(const shared_ptr &account, RegistrationState state, const string &message) +{ + setProperty("registerText", QString::fromStdString("Your registration state is : " + message)); + switch (state) + { + // If the Account was logged out, we clear the Core. + case RegistrationState::Cleared: + case RegistrationState::None: + mCore->clearAllAuthInfo(); + mCore->clearAccounts(); + logoutGuiChanges(); + break; + case RegistrationState::Ok: + loginGuiChanges(); + break; + case RegistrationState::Progress: + loginInProgressGuiChanges(); + break; + case RegistrationState::Failed: + loginFailedGuiChanges(); + break; + default: + break; + } +} + +void CoreManager::logoutGuiChanges() +{ + setProperty("loginButtonEnabled", true); + setProperty("logoutButtonEnabled", false); + setProperty("loginText", "You are logged out"); +} + +void CoreManager::loginFailedGuiChanges() +{ + setProperty("loginButtonEnabled", true); + setProperty("logoutButtonEnabled", false); + setProperty("loginText", "Login failed, try again"); +} + +void CoreManager::loginGuiChanges() +{ + setProperty("loginButtonEnabled", false); + setProperty("logoutButtonEnabled", true); + setProperty("loginText", QString::fromStdString("You are logged in, with identity " + mCore->getIdentity() + ".")); +} + +void CoreManager::loginInProgressGuiChanges() +{ + setProperty("loginButtonEnabled", false); + setProperty("logoutButtonEnabled", false); + setProperty("loginText", QString::fromStdString("Login in progress, with identity " + mCore->getIdentity() + ".")); +} + +void CoreManager::createLinphoneCore() +{ + // Setting linphone log level to message. + auto loggingService = LoggingService::get(); + loggingService->setLogLevel(LogLevel::Message); + + // Configure paths. + string assetsPath = string(SDK_PATH) + "/share"; + Factory::get()->setTopResourcesDir(assetsPath); + Factory::get()->setDataResourcesDir(assetsPath); + Factory::get()->setSoundResourcesDir(assetsPath + "/sounds/linphone"); + Factory::get()->setRingResourcesDir(Factory::get()->getSoundResourcesDir() + "/rings"); + Factory::get()->setImageResourcesDir(assetsPath + "/images"); + Factory::get()->setMspluginsDir(MSPLUGINS_PATH); + + // Create a core from the factory. + mCore = Factory::get()->createCore("", "", nullptr); + + mCore->setRootCa(assetsPath + "/linphone/rootca.pem"); + + // Listen for core events. + mHandler->setListener(mCore); + + // Start the core. + mCore->start(); +} + +void CoreManager::iterate() +{ + if (mCore) + mCore->iterate(); +} diff --git a/qt/01_AccountLogin/src/CoreManager.hpp b/qt/01_AccountLogin/src/CoreManager.hpp new file mode 100644 index 0000000..f767abc --- /dev/null +++ b/qt/01_AccountLogin/src/CoreManager.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +#include + +class CoreHandler; + +class CoreManager : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString loginText MEMBER mLoginText NOTIFY loginTextChanged) + Q_PROPERTY(QString registerText MEMBER mRegisterText NOTIFY registerTextChanged) + Q_PROPERTY(bool loginButtonEnabled MEMBER mLoginButtonEnabled NOTIFY loginButtonEnabledChanged) + Q_PROPERTY(bool logoutButtonEnabled MEMBER mLogoutButtonEnabled NOTIFY logoutButtonEnabledChanged) + +public: + static void init(QObject *parent); + static void uninit(); + static CoreManager *getInstance(); + +signals: + void loginTextChanged(QString); + void registerTextChanged(QString); + void loginButtonEnabledChanged(bool); + void logoutButtonEnabledChanged(bool); + +public slots: + void startIterate(); + void stopIterate(); + void login(QString identity, QString password, QString transport); + void logout(); + void onRegistrationStateChanged(const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message); + +private: + CoreManager(QObject *parent); + ~CoreManager(); + + void logoutGuiChanges(); + void loginFailedGuiChanges(); + void loginGuiChanges(); + void loginInProgressGuiChanges(); + + void createLinphoneCore(); + void iterate(); + + std::shared_ptr mCore = nullptr; + QSharedPointer mHandler; + QTimer *mIterateTimer = nullptr; + + QString mLoginText; + QString mRegisterText; + bool mLoginButtonEnabled = true; + bool mLogoutButtonEnabled = false; + + static CoreManager *mInstance; +}; \ No newline at end of file diff --git a/qt/01_AccountLogin/src/main.cpp b/qt/01_AccountLogin/src/main.cpp new file mode 100644 index 0000000..521f7f7 --- /dev/null +++ b/qt/01_AccountLogin/src/main.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "App.hpp" + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + App app(argc, argv); + app.init(); + app.exec(); + app.stop(); +} diff --git a/qt/01_AccountLogin/ui/MainPage.qml b/qt/01_AccountLogin/ui/MainPage.qml new file mode 100644 index 0000000..06f662e --- /dev/null +++ b/qt/01_AccountLogin/ui/MainPage.qml @@ -0,0 +1,19 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +ApplicationWindow { + id: window + visible: true + + title: "Account Login" + width: 640 + height: 480 + + // Main content + Loader { + id: contentLoader + anchors.fill: parent + source: 'qrc:/ui/RegistrationPage.qml' + } +} diff --git a/qt/01_AccountLogin/ui/RegistrationPage.qml b/qt/01_AccountLogin/ui/RegistrationPage.qml new file mode 100644 index 0000000..d677187 --- /dev/null +++ b/qt/01_AccountLogin/ui/RegistrationPage.qml @@ -0,0 +1,95 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +ColumnLayout { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.fillHeight: true + + GridLayout { + Layout.fillWidth: true + Layout.margins: 20 + columnSpacing: 20 + columns: 2 + + Text { + text: "Identity:" + } + TextField { + id: identityTextField + Layout.fillWidth: true + text: "sip:" + } + + Text { + text: "Password:" + } + TextField { + id: passwordTextField + echoMode: TextInput.Password + Layout.fillWidth: true + placeholderText: "my password" + } + + Text { + text: "Transport:" + } + RowLayout { + Layout.fillWidth: true + RadioButton { + id: tlsButton + text: "TLS" + checked: true + } + RadioButton { + id: tcpButton + text: "TCP" + } + RadioButton { + id: udpButton + text: "UDP" + } + } + } + + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + spacing: 20 + + Button { + id: loginButton + text: "Login" + enabled: coreManager.loginButtonEnabled && identityTextField.text.length != 0 && passwordTextField.text.length != 0 + onClicked: { + var transport = "tls" + if (tcpButton.checked) { transport = "tcp" } + else if (udpButton.checked) { transport = "udp" } + coreManager.login(identityTextField.text, passwordTextField.text, transport) + } + } + Button { + id: logoutButton + text: "Logout" + enabled: coreManager.logoutButtonEnabled + onClicked: { + coreManager.logout() + } + } + } + + ColumnLayout { + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + Text { + id: loginText + text: coreManager.loginText + } + Text { + id: registrationText + text: coreManager.registerText + } + } +}