Use a webview for account creation

This commit is contained in:
Julien Wadel 2021-05-24 17:46:30 +02:00
parent a0cfe58193
commit 4b094d3261
23 changed files with 598 additions and 342 deletions

View file

@ -16,7 +16,7 @@
#job-centos7-makefile-clang:
# tags: [ "docker-centos7" ]
# image: gitlab.linphone.org:4567/bc/public/linphone-sdk/bc-dev-centos:7
# image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-centos7-fuse-qt-wget:$CENTOS_7_QT_IMAGE_VERSION
# only:
# variables:
# - $NIGHTLY_MASTER

View file

@ -1,7 +1,7 @@
job-ubuntu-rolling-ninja-clang:
tags: [ "docker-ubuntu-rolling" ]
image: gitlab.linphone.org:4567/bc/public/linphone-sdk/bc-dev-ubuntu-rolling:$UBUNTU_ROLLING_IMAGE_VERSION
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-rolling-qt-fuse-wget-gpg2:$UBUNTU_ROLLING_IMAGE_VERSION
except:
refs:
- schedules
@ -20,7 +20,7 @@ job-ubuntu-rolling-ninja-clang:
job-ubuntu-rolling-makefile-gcc:
tags: [ "docker-ubuntu-rolling" ]
image: gitlab.linphone.org:4567/bc/public/linphone-sdk/bc-dev-ubuntu-rolling:$UBUNTU_ROLLING_IMAGE_VERSION
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-rolling-qt-fuse-wget-gpg2:$UBUNTU_ROLLING_IMAGE_VERSION
only:
variables:
- $NIGHTLY_MASTER
@ -34,7 +34,7 @@ job-ubuntu-rolling-makefile-gcc:
job-ubuntu-rolling-makefile-clang:
tags: [ "docker-ubuntu-rolling" ]
image: gitlab.linphone.org:4567/bc/public/linphone-sdk/bc-dev-ubuntu-rolling:$UBUNTU_ROLLING_IMAGE_VERSION
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-rolling-qt-fuse-wget-gpg2:$UBUNTU_ROLLING_IMAGE_VERSION
only:
variables:
- $NIGHTLY_MASTER
@ -48,7 +48,7 @@ job-ubuntu-rolling-makefile-clang:
job-ubuntu-rolling-ninja-gcc:
tags: [ "docker-ubuntu-rolling" ]
image: gitlab.linphone.org:4567/bc/public/linphone-sdk/bc-dev-ubuntu-rolling:$UBUNTU_ROLLING_IMAGE_VERSION
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-rolling-qt-fuse-wget-gpg2:$UBUNTU_ROLLING_IMAGE_VERSION
only:
variables:
- $NIGHTLY_MASTER

View file

@ -22,10 +22,10 @@ variables:
# Docker image version
ARCHLINUX_IMAGE_VERSION: latestupdated
CENTOS_7_QT_IMAGE_VERSION: 20210401_python3
CENTOS_7_QT_IMAGE_VERSION: 20211012_add_qtwebview
DEBIAN_9_QT_IMAGE_VERSION: 20211027_update_qt_5.12.12
DEBIAN_10_IMAGE_VERSION: 20210217_python3
UBUNTU_ROLLING_IMAGE_VERSION: 20210217_python3
UBUNTU_ROLLING_IMAGE_VERSION: 20211012_add_qtwebview
#################################################
# Platforms to test

View file

@ -9,11 +9,11 @@ RUN scl enable devtoolset-7 bash
# Configure AppImages dependencies
RUN sudo yum install -y fuse fuse-libs wget
# Build qt5.12.5
# Build qt5.12
RUN git clone -b master --single-branch https://gitlab.linphone.org/BC/public/linphone-desktop.git && \
./linphone-desktop/tools/build_qt_rpm && \
sudo rpm -i ./linphone-desktop/rpm-linphone-qt-5.12.5/rpmbuild/RPMS/x86_64/*.rpm && \
sudo mv ./linphone-desktop/rpm-linphone-qt-5.12.5/rpmbuild/RPMS/x86_64/*.rpm / && \
sudo rpm -i ./linphone-desktop/rpm-linphone-qt-5.12/rpmbuild/RPMS/x86_64/*.rpm && \
sudo mv ./linphone-desktop/rpm-linphone-qt-5.12/rpmbuild/RPMS/x86_64/*.rpm / && \
sudo rm -rf ./linphone-desktop

View file

@ -96,7 +96,7 @@ if( WIN32)
endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)#useful for config.h
set(QT5_PACKAGES Core Gui Quick Widgets QuickControls2 Svg LinguistTools Concurrent Network Test)
set(QT5_PACKAGES Core Gui Quick Widgets QuickControls2 Svg LinguistTools Concurrent Network Test WebView)
if (UNIX AND NOT APPLE)
list(APPEND QT5_PACKAGES DBus)
endif ()

View file

@ -83,6 +83,17 @@ make install INSTALL_ROOT=%{buildroot} -j12
# Some files got ambiguous python shebangs, we fix them to avoid install errors
# Because in centos8 shebangs like #!/usr/bin/python are FORBIDDEN (see https://fedoraproject.org/wiki/Changes/Make_ambiguous_python_shebangs_error)
%build qtwebengine
cd qtwebengine
qmake
make -j12
find . \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/#!\/usr\/bin\/python/#!\/usr\/bin\/python3/g'
make install INSTALL_ROOT=%{buildroot} -j12
cd ..
%files
%defattr(-,root,root,-)
%license LICENSE.LGPL* LICENSE.FDL

View file

@ -20,6 +20,7 @@
#include "AppController.hpp"
#include <qloggingcategory.h>
#include <QtWebView>
#ifdef QT_QML_DEBUG
#include <QQmlDebuggingEnabler>
#endif
@ -29,11 +30,13 @@
int main (int argc, char *argv[]) {
AppController controller(argc, argv);
QtWebView::initialize();
#ifdef QT_QML_DEBUG
QQmlDebuggingEnabler enabler;
#endif
//QLoggingCategory::setFilterRules("*.debug=true;qml=false");
App *app = controller.getApp();
if (app->isSecondary())
{
qInfo() << QStringLiteral("Running secondary app success. Kill it now.");

View file

@ -251,7 +251,8 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
// Sip address.
{
shared_ptr<linphone::Address> address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(literal));
shared_ptr<linphone::Address> address = Utils::interpretUrl(literal);
if (!address) {
qWarning() << QStringLiteral("Unable to create sip address object from: `%1`.").arg(literal);
return false;
@ -274,17 +275,26 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
}
}
proxyConfig->setPublishExpires(data["registrationDuration"].toInt());
proxyConfig->setRoute(Utils::appStringToCoreString(data["route"].toString()));
if(data.contains("registrationDuration"))
proxyConfig->setPublishExpires(data["registrationDuration"].toInt());
if(data.contains("route"))
proxyConfig->setRoute(Utils::appStringToCoreString(data["route"].toString()));
QString conferenceURI = data["conferenceUri"].toString();
if(!conferenceURI.isEmpty())
proxyConfig->setConferenceFactoryUri(Utils::appStringToCoreString(conferenceURI));
proxyConfig->setContactParameters(Utils::appStringToCoreString(data["contactParams"].toString()));
proxyConfig->setAvpfRrInterval(uint8_t(data["avpfInterval"].toInt()));
proxyConfig->enableRegister(data["registerEnabled"].toBool());
newPublishPresence = proxyConfig->publishEnabled() != data["publishPresence"].toBool();
proxyConfig->enablePublish(data["publishPresence"].toBool());
proxyConfig->setAvpfMode(data["avpfEnabled"].toBool()
if(data.contains("contactParams"))
proxyConfig->setContactParameters(Utils::appStringToCoreString(data["contactParams"].toString()));
if(data.contains("avpfInterval"))
proxyConfig->setAvpfRrInterval(uint8_t(data["avpfInterval"].toInt()));
if(data.contains("registerEnabled"))
proxyConfig->enableRegister(data.contains("registerEnabled") ? data["registerEnabled"].toBool() : true);
if(data.contains("publishPresence")) {
newPublishPresence = proxyConfig->publishEnabled() != data["publishPresence"].toBool();
proxyConfig->enablePublish(data["publishPresence"].toBool());
}else
newPublishPresence = proxyConfig->publishEnabled();
if(data.contains("avpfEnabled"))
proxyConfig->setAvpfMode(data["avpfEnabled"].toBool()
? linphone::AVPFMode::Enabled
: linphone::AVPFMode::Default
);
@ -293,13 +303,17 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
bool createdNat = !natPolicy;
if (createdNat)
natPolicy = proxyConfig->getCore()->createNatPolicy();
natPolicy->enableIce(data["iceEnabled"].toBool());
natPolicy->enableStun(data["iceEnabled"].toBool());
const string turnUser(Utils::appStringToCoreString(data["turnUser"].toString()));
const string stunServer(Utils::appStringToCoreString(data["stunServer"].toString()));
natPolicy->enableTurn(data["turnEnabled"].toBool());
if(data.contains("iceEnabled"))
natPolicy->enableIce(data["iceEnabled"].toBool());
if(data.contains("iceEnabled"))
natPolicy->enableStun(data["iceEnabled"].toBool());
string turnUser, stunServer;
if(data.contains("turnUser"))
turnUser = Utils::appStringToCoreString(data["turnUser"].toString());
if(data.contains("stunServer"))
stunServer = Utils::appStringToCoreString(data["stunServer"].toString());
if(data.contains("turnEnabled"))
natPolicy->enableTurn(data["turnEnabled"].toBool());
natPolicy->setStunServerUsername(turnUser);
natPolicy->setStunServer(stunServer);
@ -313,7 +327,6 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
clonedAuthInfo->setUserid(turnUser);
clonedAuthInfo->setUsername(turnUser);
clonedAuthInfo->setPassword(Utils::appStringToCoreString(data["turnPassword"].toString()));
core->addAuthInfo(clonedAuthInfo);
core->removeAuthInfo(authInfo);
} else
@ -330,13 +343,26 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
return addOrUpdateProxyConfig(proxyConfig);
}
shared_ptr<linphone::ProxyConfig> AccountSettingsModel::createProxyConfig () {
bool AccountSettingsModel::addOrUpdateProxyConfig (
const QVariantMap &data
) {
shared_ptr<linphone::ProxyConfig> proxyConfig;
QString sipAddress = data["sipAddress"].toString();
shared_ptr<linphone::Address> address = CoreManager::getInstance()->getCore()->interpretUrl(sipAddress.toStdString());
for (const auto &databaseProxyConfig : CoreManager::getInstance()->getCore()->getProxyConfigList())
if (databaseProxyConfig->getIdentityAddress()->weakEqual(address)) {
proxyConfig = databaseProxyConfig;
}
if(!proxyConfig)
proxyConfig = createProxyConfig(data.contains("configFilename") ? data["configFilename"].toString() : "create-app-sip-account.rc" );
return addOrUpdateProxyConfig(proxyConfig, data);
}
shared_ptr<linphone::ProxyConfig> AccountSettingsModel::createProxyConfig (const QString& assistantFile) {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->getConfig()->loadFromXmlFile(
Paths::getAssistantConfigDirPath() + "create-app-sip-account.rc"
);
qInfo() << QStringLiteral("Set config on assistant: `%1`.").arg(assistantFile);
core->getConfig()->loadFromXmlFile(Paths::getAssistantConfigDirPath() + assistantFile.toStdString());
return core->createProxyConfig();
}

View file

@ -74,9 +74,10 @@ public:
Q_INVOKABLE void setDefaultProxyConfigFromSipAddress (const QString &sipAddress);
Q_INVOKABLE bool addOrUpdateProxyConfig (const std::shared_ptr<linphone::ProxyConfig> &proxyConfig, const QVariantMap &data);
Q_INVOKABLE bool addOrUpdateProxyConfig (const QVariantMap &data);// Create default proxy config and apply data
Q_INVOKABLE void removeProxyConfig (const std::shared_ptr<linphone::ProxyConfig> &proxyConfig);
Q_INVOKABLE std::shared_ptr<linphone::ProxyConfig> createProxyConfig ();
Q_INVOKABLE std::shared_ptr<linphone::ProxyConfig> createProxyConfig (const QString& assistantFile);
Q_INVOKABLE void addAuthInfo (
const std::shared_ptr<linphone::AuthInfo> &authInfo,

View file

@ -163,6 +163,33 @@ void SettingsModel::setAssistantSupportsPhoneNumbers (bool status) {
emit assistantSupportsPhoneNumbersChanged(status);
}
QString SettingsModel::getAssistantRegistrationUrl () const {
return Utils::coreStringToAppString(mConfig->getString(UiSection, "assistant_registration_url", Constants::DefaultAssistantRegistrationUrl));
}
void SettingsModel::setAssistantRegistrationUrl (QString url) {
mConfig->setString(UiSection, "assistant_registration_url", Utils::appStringToCoreString(url));
emit assistantRegistrationUrlChanged(url);
}
QString SettingsModel::getAssistantLoginUrl () const {
return Utils::coreStringToAppString(mConfig->getString(UiSection, "assistant_login_url", Constants::DefaultAssistantLoginUrl));
}
void SettingsModel::setAssistantLoginUrl (QString url) {
mConfig->setString(UiSection, "assistant_login_url", Utils::appStringToCoreString(url));
emit assistantLoginUrlChanged(url);
}
QString SettingsModel::getAssistantLogoutUrl () const {
return Utils::coreStringToAppString(mConfig->getString(UiSection, "assistant_logout_url", Constants::DefaultAssistantLogoutUrl));
}
void SettingsModel::setAssistantLogoutUrl (QString url) {
mConfig->setString(UiSection, "assistant_logout_url", Utils::appStringToCoreString(url));
emit assistantLogoutUrlChanged(url);
}
// =============================================================================
// Audio.
// =============================================================================

View file

@ -41,14 +41,17 @@ class SettingsModel : public QObject {
// ===========================================================================
// Assistant. ----------------------------------------------------------------
Q_PROPERTY(bool createAppSipAccountEnabled READ getCreateAppSipAccountEnabled WRITE setCreateAppSipAccountEnabled NOTIFY createAppSipAccountEnabledChanged)
Q_PROPERTY(bool fetchRemoteConfigurationEnabled READ getFetchRemoteConfigurationEnabled WRITE setFetchRemoteConfigurationEnabled NOTIFY fetchRemoteConfigurationEnabledChanged)
Q_PROPERTY(bool useAppSipAccountEnabled READ getUseAppSipAccountEnabled WRITE setUseAppSipAccountEnabled NOTIFY useAppSipAccountEnabledChanged)
Q_PROPERTY(bool useOtherSipAccountEnabled READ getUseOtherSipAccountEnabled WRITE setUseOtherSipAccountEnabled NOTIFY useOtherSipAccountEnabledChanged)
Q_PROPERTY(bool assistantSupportsPhoneNumbers READ getAssistantSupportsPhoneNumbers WRITE setAssistantSupportsPhoneNumbers NOTIFY assistantSupportsPhoneNumbersChanged)
Q_PROPERTY(QString assistantRegistrationUrl READ getAssistantRegistrationUrl WRITE setAssistantRegistrationUrl NOTIFY assistantRegistrationUrlChanged)
Q_PROPERTY(QString assistantLoginUrl READ getAssistantLoginUrl WRITE setAssistantLoginUrl NOTIFY assistantLoginUrlChanged)
Q_PROPERTY(QString assistantLogoutUrl READ getAssistantLogoutUrl WRITE setAssistantLogoutUrl NOTIFY assistantLogoutUrlChanged)
// Audio. --------------------------------------------------------------------
Q_PROPERTY(bool captureGraphRunning READ getCaptureGraphRunning NOTIFY captureGraphRunningChanged)
@ -234,7 +237,16 @@ public:
bool getAssistantSupportsPhoneNumbers () const;
void setAssistantSupportsPhoneNumbers (bool status);
QString getAssistantRegistrationUrl () const;
void setAssistantRegistrationUrl (QString url);
QString getAssistantLoginUrl () const;
void setAssistantLoginUrl (QString url);
QString getAssistantLogoutUrl () const;
void setAssistantLogoutUrl (QString url);
// Audio. --------------------------------------------------------------------
void createCaptureGraph();
@ -529,7 +541,11 @@ signals:
void useOtherSipAccountEnabledChanged (bool status);
void assistantSupportsPhoneNumbersChanged (bool status);
void assistantRegistrationUrlChanged (QString url);
void assistantLoginUrlChanged (QString url);
void assistantLogoutUrlChanged (QString url);
// Audio. --------------------------------------------------------------------
void captureGraphRunningChanged(bool running);

View file

@ -67,6 +67,9 @@ constexpr char Constants::DefaultXmlrpcUri[];
constexpr char Constants::DefaultConferenceURI[];
constexpr char Constants::DefaultLimeServerURL[];
constexpr char Constants::RemoteProvisioningURL[];
constexpr char Constants::DefaultAssistantRegistrationUrl[];
constexpr char Constants::DefaultAssistantLoginUrl[];
constexpr char Constants::DefaultAssistantLogoutUrl[];
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
constexpr char Constants::H264Description[];

View file

@ -67,6 +67,9 @@ public:
static constexpr char RemoteProvisioningURL[] = "https://subscribe.linphone.org/flexiapi/provisioning";
Q_PROPERTY(QString PasswordRecoveryUrl MEMBER PasswordRecoveryUrl CONSTANT)
static constexpr char DefaultAssistantRegistrationUrl[] = "https://subscribe.linphone.org/register";
static constexpr char DefaultAssistantLoginUrl[] = "https://subscribe.linphone.org/login";
static constexpr char DefaultAssistantLogoutUrl[] = "https://subscribe.linphone.org/logout";
// Max image size in bytes. (100Kb)
static constexpr qint64 MaxImageSize = 102400;// In Bytes.

View file

@ -46,14 +46,10 @@ Item {
StackView {
id: stack
clip:true
anchors {
fill: parent
bottomMargin: AssistantStyle.bottomMargin
leftMargin: AssistantStyle.leftMargin
rightMargin: AssistantStyle.rightMargin
topMargin: AssistantStyle.topMargin
fill: parent
}
initialItem: assistant.viewsPath + 'AssistantHome.qml'

View file

@ -8,105 +8,112 @@ import App.Styles 1.0
// =============================================================================
Item {
id: view
// ---------------------------------------------------------------------------
property alias mainActionEnabled: mainActionButton.enabled
property alias mainActionLabel: mainActionButton.text
property var mainAction
property alias description: description.text
property alias title: title.text
property bool backEnabled: true
default property alias _content: content.data
// ---------------------------------------------------------------------------
height: stack.height
width: stack.width
// ---------------------------------------------------------------------------
// Info.
// ---------------------------------------------------------------------------
Column {
anchors.centerIn: parent
spacing: AssistantAbstractViewStyle.info.spacing
width: parent.width
Text {
id: title
color: AssistantAbstractViewStyle.info.title.color
elide: Text.ElideRight
font {
pointSize: AssistantAbstractViewStyle.info.title.pointSize
bold: true
}
horizontalAlignment: Text.AlignHCenter
width: parent.width
}
Text {
id: description
color: AssistantAbstractViewStyle.info.description.color
elide: Text.ElideRight
font.pointSize: AssistantAbstractViewStyle.info.description.pointSize
horizontalAlignment: Text.AlignHCenter
width: parent.width
visible: text.length > 0
}
// -------------------------------------------------------------------------
// Content.
// -------------------------------------------------------------------------
Item {
id: content
anchors.horizontalCenter: parent.horizontalCenter
height: AssistantAbstractViewStyle.content.height
width: AssistantAbstractViewStyle.content.width
}
}
// ---------------------------------------------------------------------------
// Nav buttons.
// ---------------------------------------------------------------------------
Row {
id: buttons
anchors {
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
}
spacing: AssistantAbstractViewStyle.buttons.spacing
TextButtonA {
text: qsTr('back')
visible: view.backEnabled
onClicked: assistant.popView()
}
TextButtonB {
id: mainActionButton
visible: !!view.mainAction
onClicked: view.mainAction()
}
}
id: view
// ---------------------------------------------------------------------------
property alias mainActionEnabled: mainActionButton.enabled
property alias mainActionLabel: mainActionButton.text
property var mainAction
property alias description: description.text
property alias title: title.text
property bool backEnabled: true
property bool maximized: false // Used to stretch content to fit all the view (the title will be set to top)
default property alias _content: content.data
property alias contentItem: content
// ---------------------------------------------------------------------------
height: (maximized?stack.height:AssistantAbstractViewStyle.content.height)
width: (maximized?stack.width:AssistantAbstractViewStyle.content.width)
// ---------------------------------------------------------------------------
// Info.
// ---------------------------------------------------------------------------
Text {
id: title
anchors.top:parent.top
anchors.topMargin:(visible?AssistantAbstractViewStyle.info.spacing:0)
anchors.horizontalCenter: parent.horizontalCenter
color: AssistantAbstractViewStyle.info.title.color
elide: Text.ElideRight
font {
pointSize: AssistantAbstractViewStyle.info.title.pointSize
bold: true
}
horizontalAlignment: Text.AlignHCenter
width: parent.width
visible: text.length > 0
height:(visible?contentHeight:0)
}
Text {
id: description
anchors.top:title.bottom
anchors.topMargin:(visible?AssistantAbstractViewStyle.info.spacing:0)
anchors.horizontalCenter: parent.horizontalCenter
color: AssistantAbstractViewStyle.info.description.color
elide: Text.ElideRight
font.pointSize: AssistantAbstractViewStyle.info.description.pointSize
horizontalAlignment: Text.AlignHCenter
width: parent.width
visible: text.length > 0
height:(visible?contentHeight:0)
}
// -------------------------------------------------------------------------
// Content.
// -------------------------------------------------------------------------
Item {
id: content
anchors.top:description.bottom
anchors.topMargin:(description.visible || title.visible?AssistantAbstractViewStyle.info.spacing:0)
anchors.bottom:buttons.top
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
}
// ---------------------------------------------------------------------------
// Nav buttons.
// ---------------------------------------------------------------------------
Row {
id: buttons
anchors {
bottom: parent.bottom
bottomMargin:AssistantAbstractViewStyle.info.spacing
horizontalCenter: parent.horizontalCenter
}
spacing: AssistantAbstractViewStyle.buttons.spacing
TextButtonA {
text: qsTr('back')
visible: view.backEnabled
onClicked: assistant.popView()
anchors.verticalCenter: parent.verticalCenter
}
TextButtonB {
id: mainActionButton
visible: !!view.mainAction
onClicked: view.mainAction()
anchors.verticalCenter: parent.verticalCenter
}
}
}

View file

@ -10,7 +10,7 @@ import App.Styles 1.0
ColumnLayout {
spacing: 0
// ---------------------------------------------------------------------------
// Info.
// ---------------------------------------------------------------------------
@ -76,6 +76,9 @@ ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: AssistantHomeStyle.buttons.maxWidth
Layout.preferredHeight: AssistantHomeStyle.buttons.height
Layout.leftMargin: AssistantStyle.leftMargin
Layout.rightMargin: AssistantStyle.rightMargin
Layout.bottomMargin: AssistantStyle.bottomMargin
cellHeight: height / 2
cellWidth: width / 2
@ -93,7 +96,7 @@ ColumnLayout {
enabled: SettingsModel[$viewType.charAt(0).toLowerCase() + $viewType.slice(1) + "Enabled"]
text: $text.replace('%1', Qt.application.name.toUpperCase())
onClicked: assistant.pushView($view)
onClicked:{ assistant.pushView($view, $props) }
}
}
@ -101,43 +104,29 @@ ColumnLayout {
Component.onCompleted: {
insert(0, {
$text: qsTr('createAppSipAccount'),
$view: SettingsModel.assistantSupportsPhoneNumbers
? 'CreateAppSipAccount'
: 'CreateAppSipAccountWithEmail',
$viewType: 'CreateAppSipAccount'
$view: 'CreateAppSipAccount',
$viewType: 'CreateAppSipAccount',
$props:{defaultUrl: SettingsModel.assistantRegistrationUrl, defaultLogoutUrl:SettingsModel.assistantLogoutUrl, configFilename: 'create-app-sip-account.rc'}
})
append({
$text: qsTr('useAppSipAccount'),
$view: 'CreateAppSipAccount',
$viewType: 'UseAppSipAccount',
$props:{defaultUrl: SettingsModel.assistantLoginUrl, defaultLogoutUrl:SettingsModel.assistantLogoutUrl, configFilename: 'use-app-sip-account.rc'}
})
append({
$text: qsTr('useOtherSipAccount'),
$view: 'UseOtherSipAccount',
$viewType: 'UseOtherSipAccount'
})
append( {
$text: qsTr('fetchRemoteConfiguration'),
$view: 'FetchRemoteConfiguration',
$viewType: 'FetchRemoteConfiguration'
})
}
ListElement {
$text: qsTr('useAppSipAccount')
$view: 'UseAppSipAccount'
$viewType: 'UseAppSipAccount'
}
ListElement {
$text: qsTr('useOtherSipAccount')
$view: 'UseOtherSipAccount'
$viewType: 'UseOtherSipAccount'
}
ListElement {
$text: qsTr('fetchRemoteConfiguration')
$view: 'FetchRemoteConfiguration'
$viewType: 'FetchRemoteConfiguration'
}
}
interactive: false
Connections {
target: SettingsModel
onAssistantSupportsPhoneNumbersChanged: buttons.model.setProperty(
0,
'$view',
SettingsModel.assistantSupportsPhoneNumbers ?
'CreateAppSipAccount' :
'CreateAppSipAccountWithEmail'
)
}
}
}

View file

@ -1,40 +1,167 @@
import QtQuick 2.7
import QtWebView 1.1
import QtQuick.Controls 1.3 // Busy indicator
import Common 1.0
import Linphone 1.0 as Linphone
import App.Styles 1.0
// =============================================================================
AssistantAbstractView {
description: qsTr('createAppSipAccountDescription')
title: qsTr('createAppSipAccountTitle').replace('%1', Qt.application.name.toUpperCase())
id: view
maximized:true
height: (parent?parent.height:0)
width: (parent?parent.width:0)
property string defaultUrl
property string defaultLogoutUrl
property string configFilename
property bool printed : stack.currentItem == view
onPrintedChanged: {
webviewLoader.active = printed
}
//-------------------------------
property int status : 0 // 0:nothing, -1:error, 1:ok
property bool newPage : true
// ---------------------------------------------------------------------------
// Menu.
// ---------------------------------------------------------------------------
// Note : Use opacity and not visibility to allow smooth updating (when moving visibility to true, we could show the old page)
Component{
id: webviewComponent
WebView{
id:webview
property bool isLogingOut : true
state: 'hidden'
Component.onCompleted: {if(webview.httpUserAgent != undefined) webview.httpUserAgent = Linphone.App.getUserAgent() // only available on Qt 5.15 (QtWebView 1.15)
isLogingOut = true
webview.url = view.defaultLogoutUrl
}
function getData(){// Check if account_infos exists in the page and retrieve data to make/update an account
if(webview.loading){
view.status = 0
}else {
var js = "(typeof account_infos !== 'undefined'?account_infos:'')";
webview.runJavaScript(js, function(result) {
if( result == ''){
view.status = 0
}else{
webview.state = 'hidden'
reloadTimer.stop();
console.log("[CreateAccount] SIP : " +result.sip);
console.log("[CreateAccount] Username : " +result.username);
console.log("[CreateAccount] Registrar : " +result.registrar_address);
console.log("[CreateAccount] Domain : " +result.domain);
if (Linphone.AccountSettingsModel.addOrUpdateProxyConfig( {
sipAddress: result.sip,
serverAddress: result.registrar_address,
configFilename: view.configFilename
})) {
console.log("[CreateAccount] Account created")
view.status = 1
Linphone.AccountSettingsModel.setDefaultProxyConfigFromSipAddress("sip:"+result.sip)
} else {
console.error("[CreateAccount] Cannot create account. Check logs.")
view.status = -1
}
}
});
}
}
Timer {// Check data
id:reloadTimer
interval: 1000;
running: true; repeat: true
onTriggered: {webview.getData();}
}
onLoadingChanged: {
if (loadRequest.errorString)
console.error("[CreateAccount] error on loading page : " +loadRequest.errorString);
if(loading){
view.newPage = true;
}else if(view.newPage) {
view.newPage = false;
webview.runJavaScript("document.querySelector('nav').remove(); document.querySelector('footer').remove();");
}
webview.state = (loading || isLogingOut ? 'hidden' : 'showed')
if(!loading){
if(isLogingOut){
isLogingOut = false
webview.url = view.defaultUrl
}else{
reloadTimer.stop();
webview.getData();
if(view.status == 0)
reloadTimer.start();
}
}else
reloadTimer.stop();
}
states: [
State {
name: 'hidden'
PropertyChanges { target: webview; opacity: 0 }
},
State {
name: 'showed'
PropertyChanges { target: webview; opacity: 1 }
}
]
transitions: [
Transition {
from: '*'; to: 'showed'
SequentialAnimation{
NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 500 }
}
},
Transition {
SequentialAnimation{
NumberAnimation{ properties: "opacity"; duration: 1000 }
}
}
]
}
}
Loader{
id: webviewLoader
active: false
anchors.fill:parent
sourceComponent: webviewComponent
}
// ---------------------------------------------------------------------------
// Menu.
// ---------------------------------------------------------------------------
Rectangle{
id:statusPage
anchors.fill:parent
visible: webviewLoader.item && (webviewLoader.item.loading || webviewLoader.item.isLogingOut || webviewLoader.item.state == 'hidden')
BusyIndicator{
id:busy
anchors.centerIn : parent
running:true
width:CreateAppSipAccountStyle.busy.size
height:CreateAppSipAccountStyle.busy.size
}
Column {
anchors.centerIn: parent
spacing: CreateAppSipAccountStyle.buttons.spacing
width: CreateAppSipAccountStyle.buttons.button.width
TextButtonA {
text: qsTr('withPhoneNumber')
height: CreateAppSipAccountStyle.buttons.button.height
width: parent.width
onClicked: assistant.pushView('CreateAppSipAccountWithPhoneNumber')
}
TextButtonA {
text: qsTr('withEmailAddress')
height: CreateAppSipAccountStyle.buttons.button.height
width: parent.width
onClicked: assistant.pushView('CreateAppSipAccountWithEmail')
}
}
Icon{
visible: view.status != 0
icon: (view.status>0?"chat_read":"chat_error")
iconSize:busy.width
anchors.fill:busy
MouseArea{
anchors.fill:parent
onClicked: {
assistant.popView()
}
}
}
}
}

View file

@ -4,72 +4,79 @@ import Common 1.0
import Linphone 1.0
import Utils 1.0
import App.Styles 1.0
// =============================================================================
AssistantAbstractView {
mainAction: requestBlock.execute
mainActionEnabled: url.text.length > 0
mainActionLabel: qsTr('confirmAction')
title: qsTr('fetchRemoteConfigurationTitle')
// ---------------------------------------------------------------------------
Connections {
target: SettingsModel
Item{
AssistantAbstractView {
mainAction: requestBlock.execute
mainActionEnabled: url.text.length > 0
mainActionLabel: qsTr('confirmAction')
onRemoteProvisioningChanged: {
requestBlock.stop('')
title: qsTr('fetchRemoteConfigurationTitle')
width: AssistantAbstractViewStyle.content.width
height: AssistantAbstractViewStyle.content.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
// ---------------------------------------------------------------------------
Connections {
target: SettingsModel
window.detachVirtualWindow()
window.attachVirtualWindow(Utils.buildDialogUri('ConfirmDialog'), {
descriptionText: qsTr('remoteProvisioningUpdateDescription'),
}, function (status) {
if (status) {
App.restart()
} else {
window.setView('Home')
}
})
onRemoteProvisioningChanged: {
requestBlock.stop('')
window.detachVirtualWindow()
window.attachVirtualWindow(Utils.buildDialogUri('ConfirmDialog'), {
descriptionText: qsTr('remoteProvisioningUpdateDescription'),
}, function (status) {
if (status) {
App.restart()
} else {
window.setView('Home')
}
})
}
onRemoteProvisioningNotChanged: requestBlock.stop(qsTr('remoteProvisioningError'))
}
onRemoteProvisioningNotChanged: requestBlock.stop(qsTr('remoteProvisioningError'))
}
// ---------------------------------------------------------------------------
Column {
anchors.fill: parent
// ---------------------------------------------------------------------------
Form {
orientation: Qt.Vertical
width: parent.width
Column {
anchors.fill: parent.contentItem
anchors.topMargin: AssistantAbstractViewStyle.info.spacing
width: AssistantAbstractViewStyle.content.width
height: AssistantAbstractViewStyle.content.height
FormLine {
FormGroup {
label: qsTr('urlLabel')
TextField {
id: url
Form {
orientation: Qt.Vertical
width: parent.width
FormLine {
FormGroup {
label: qsTr('urlLabel')
TextField {
id: url
}
}
}
}
RequestBlock {
id: requestBlock
action: (function () {
SettingsModel.remoteProvisioning = url.text
})
width: parent.width
}
}
RequestBlock {
id: requestBlock
action: (function () {
SettingsModel.remoteProvisioning = url.text
})
width: parent.width
}
}
Component.onCompleted: {
if( !CoreManager.isLastRemoteProvisioningGood() )
//: 'Last remote provisioning failed' : Test to warn the user that the last fetch of remote provisioning has failed.
requestBlock.stop(qsTr('lastProvisioningFailed'))
}
}

View file

@ -11,7 +11,6 @@ import App.Styles 1.0
AssistantAbstractView {
id: view
readonly property bool usePhoneNumber: SettingsModel.assistantSupportsPhoneNumbers && !checkBox.checked
mainAction: requestBlock.execute

View file

@ -3,102 +3,112 @@ import QtQuick 2.7
import Common 1.0
import Linphone 1.0
import App.Styles 1.0
// =============================================================================
Item{
AssistantAbstractView {
mainAction: requestBlock.execute
mainActionEnabled: username.text.length &&
sipDomain.text.length &&
password.text.length
AssistantAbstractView {
mainAction: requestBlock.execute
mainActionLabel: qsTr('confirmAction')
mainActionEnabled: username.text.length &&
sipDomain.text.length &&
password.text.length
title: qsTr('useOtherSipAccountTitle')
mainActionLabel: qsTr('confirmAction')
width: AssistantAbstractViewStyle.content.width
height: AssistantAbstractViewStyle.content.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
title: qsTr('useOtherSipAccountTitle')
// ---------------------------------------------------------------------------
//anchors.centerIn: parent
//anchors.horizontalCenter:parent.horizontalCenter
Column {
anchors.fill: parent.contentItem
width: AssistantAbstractViewStyle.content.width
height: AssistantAbstractViewStyle.content.height
// ---------------------------------------------------------------------------
Form {
orientation: Qt.Vertical
width: parent.width
Column {
anchors.fill: parent
FormLine {
FormGroup {
label: qsTr('usernameLabel')
Form {
orientation: Qt.Vertical
width: parent.width
TextField {
id: username
}
}
FormLine {
FormGroup {
label: qsTr('usernameLabel')
FormGroup {
label: qsTr('displayNameLabel')
TextField {
id: username
}
}
TextField {
id: displayName
}
}
}
FormGroup {
label: qsTr('displayNameLabel')
FormLine {
FormGroup {
label: qsTr('sipDomainLabel')
TextField {
id: displayName
}
}
}
TextField {
id: sipDomain
}
}
}
FormLine {
FormGroup {
label: qsTr('sipDomainLabel')
FormLine {
FormGroup {
label: qsTr('passwordLabel')
TextField {
id: sipDomain
}
}
}
PasswordField {
id: password
}
}
}
FormLine {
FormGroup {
label: qsTr('passwordLabel')
FormLine {
FormGroup {
label: qsTr('transportLabel')
PasswordField {
id: password
}
}
}
ComboBox {
id: transport
model: [ 'UDP', 'TCP', 'TLS']
}
}
}
}
FormLine {
FormGroup {
label: qsTr('transportLabel')
RequestBlock {
id: requestBlock
width: parent.width
ComboBox {
id: transport
model: [ 'UDP', 'TCP', 'TLS']
}
}
}
}
RequestBlock {
id: requestBlock
action: (function () {
if (!assistantModel.addOtherSipAccount({
username: username.text,
displayName: displayName.text,
sipDomain: sipDomain.text,
password: password.text,
transport: transport.model[transport.currentIndex]
})) {
requestBlock.stop(qsTr('addOtherSipAccountError'))
} else {
requestBlock.stop('')
window.setView('Home')
}
})
width: parent.width
}
}
AssistantModel {
id: assistantModel
configFilename: 'use-other-sip-account.rc'
}
action: (function () {
if (!assistantModel.addOtherSipAccount({
username: username.text,
displayName: displayName.text,
sipDomain: sipDomain.text,
password: password.text,
transport: transport.model[transport.currentIndex]
})) {
requestBlock.stop(qsTr('addOtherSipAccountError'))
} else {
requestBlock.stop('')
window.setView('Home')
}
})
}
}
AssistantModel {
id: assistantModel
configFilename: 'use-other-sip-account.rc'
}
}
}

View file

@ -58,7 +58,7 @@ TabContainer {
}
}
}
// -------------------------------------------------------------------------
// Proxy accounts.
// -------------------------------------------------------------------------
@ -131,10 +131,35 @@ TabContainer {
Form {
title: qsTr('assistantTitle')
visible: SettingsModel.developerSettingsEnabled
width: parent.width
FormLine {
FormGroup {
label: 'Registration URL'
TextField {
text: SettingsModel.assistantRegistrationUrl
onEditingFinished: SettingsModel.assistantRegistrationUrl = text
}
}
}
FormLine {
FormGroup {
label: 'Login URL'
TextField {
text: SettingsModel.assistantLoginUrl
onEditingFinished: SettingsModel.assistantLoginUrl = text
}
}
}
FormLine {
visible: SettingsModel.developerSettingsEnabled
FormGroup {
label: qsTr('createAppSipAccountEnabledLabel')
@ -157,6 +182,7 @@ TabContainer {
}
FormLine {
visible: SettingsModel.developerSettingsEnabled
FormGroup {
label: qsTr('useOtherSipAccountEnabledLabel')
@ -179,6 +205,7 @@ TabContainer {
}
FormLine {
visible: SettingsModel.developerSettingsEnabled
FormGroup {
label: qsTr('assistantSupportsPhoneNumbersLabel')

View file

@ -13,7 +13,7 @@ QtObject {
}
property QtObject content: QtObject {
property int height: 375
property int height: 375+60//+button bar
property int width: 400
}

View file

@ -12,4 +12,8 @@ QtObject {
property int width: 258
}
}
property QtObject busy: QtObject {
property int size: 40
}
}