diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index e63c03bc..adae50d0 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -81,6 +81,7 @@ void App::init() { // Core. Manage the logger so it must be instantiate at first. auto coreModel = CoreModel::create("", mLinphoneThread); connect(mLinphoneThread, &QThread::started, coreModel.get(), &CoreModel::start); + mFirstLaunch = mSettings.value("firstLaunch", 1).toInt(); // Console Commands createCommandParser(); mParser->parse(this->arguments()); @@ -264,6 +265,17 @@ void App::closeCallsWindow() { } } +void App::setFirstLaunch(bool first) { + if (mFirstLaunch != first) { + mFirstLaunch = first; + mSettings.setValue("firstLaunch", first); + } +} + +bool App::getFirstLaunch() const { + return mFirstLaunch; +} + QQuickWindow *App::getMainWindow() { return mMainWindow; -} \ No newline at end of file +} diff --git a/Linphone/core/App.hpp b/Linphone/core/App.hpp index 1f7b6226..04f73a0a 100644 --- a/Linphone/core/App.hpp +++ b/Linphone/core/App.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "core/singleapplication/singleapplication.h" @@ -93,6 +94,9 @@ public: QQuickWindow *getCallsWindow(QVariant callGui); void closeCallsWindow(); + bool getFirstLaunch() const; + void setFirstLaunch(bool first); + QQuickWindow *getMainWindow(); QQmlApplicationEngine *mEngine = nullptr; @@ -108,6 +112,8 @@ private: Notifier *mNotifier = nullptr; QQuickWindow *mMainWindow = nullptr; QQuickWindow *mCallsWindow = nullptr; + QSettings mSettings; + bool mFirstLaunch = true; // TODO : changer ce count lorsqu'on aura liste d'appels int callsCount = 0; diff --git a/Linphone/core/login/LoginPage.cpp b/Linphone/core/login/LoginPage.cpp index a3ef4438..e9eaa7fa 100644 --- a/Linphone/core/login/LoginPage.cpp +++ b/Linphone/core/login/LoginPage.cpp @@ -49,28 +49,48 @@ void LoginPage::setRegistrationState(linphone::RegistrationState status) { } } +QString LoginPage::getErrorMessage() const { + return mErrorMessage; +} + +void LoginPage::setErrorMessage(const QString &error) { + // force signal emission to display the error even if it doesn't change + mErrorMessage = error; + emit errorMessageChanged(); +} + void LoginPage::login(const QString &username, const QString &password) { App::postModelAsync([=]() { + QString *error = new QString(tr("Le couple identifiant mot de passe ne correspont pas")); // Create on Model thread. AccountManager *accountManager = new AccountManager(); connect(accountManager, &AccountManager::registrationStateChanged, this, - [accountManager, this](linphone::RegistrationState state) mutable { + [accountManager, this, error](linphone::RegistrationState state) mutable { // View thread setRegistrationState(state); switch (state) { - case linphone::RegistrationState::Ok: - case linphone::RegistrationState::Cleared: case linphone::RegistrationState::Failed: { + emit accountManager->errorMessageChanged(*error); accountManager->deleteLater(); break; } + case linphone::RegistrationState::Ok: { + emit accountManager->errorMessageChanged(""); + break; + } + case linphone::RegistrationState::Cleared: case linphone::RegistrationState::None: case linphone::RegistrationState::Progress: case linphone::RegistrationState::Refreshing: break; } }); - if (!accountManager->login(username, password)) { + connect(accountManager, &AccountManager::errorMessageChanged, this, + [this](QString errorMessage) { setErrorMessage(errorMessage); }); + + connect(accountManager, &AccountManager::destroyed, [error]() { delete error; }); + + if (!accountManager->login(username, password, error)) { emit accountManager->registrationStateChanged(linphone::RegistrationState::Failed); } }); diff --git a/Linphone/core/login/LoginPage.hpp b/Linphone/core/login/LoginPage.hpp index edda6c8c..0eb118dd 100644 --- a/Linphone/core/login/LoginPage.hpp +++ b/Linphone/core/login/LoginPage.hpp @@ -33,17 +33,23 @@ public: ~LoginPage(); Q_PROPERTY(linphone::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged) + Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged) Q_INVOKABLE void login(const QString &username, const QString &password); linphone::RegistrationState getRegistrationState() const; void setRegistrationState(linphone::RegistrationState status); + QString getErrorMessage() const; + void setErrorMessage(const QString &error); + signals: void registrationStateChanged(); + void errorMessageChanged(); private: linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None; + QString mErrorMessage; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/model/account/AccountManager.cpp b/Linphone/model/account/AccountManager.cpp index 06c5d8d4..a71bf4e8 100644 --- a/Linphone/model/account/AccountManager.cpp +++ b/Linphone/model/account/AccountManager.cpp @@ -48,7 +48,7 @@ std::shared_ptr AccountManager::createAccount(const QString & return core->createAccount(core->createAccountParams()); } -bool AccountManager::login(QString username, QString password) { +bool AccountManager::login(QString username, QString password, QString *errorMessage) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto core = CoreModel::getInstance()->getCore(); auto factory = linphone::Factory::get(); @@ -56,13 +56,23 @@ bool AccountManager::login(QString username, QString password) { auto params = account->getParams()->clone(); // Sip address. auto identity = params->getIdentityAddress()->clone(); + if (mAccountModel) return false; + auto accounts = core->getAccountList(); + for (auto account : accounts) { + if (account->getParams()->getIdentityAddress()->getUsername() == Utils::appStringToCoreString(username)) { + *errorMessage = tr("Le compte est déjà connecté"); + return false; + } + } identity->setUsername(Utils::appStringToCoreString(username)); if (params->setIdentityAddress(identity)) { qWarning() << log() .arg(QStringLiteral("Unable to set identity address: `%1`.")) .arg(Utils::coreStringToAppString(identity->asStringUriOnly())); + *errorMessage = + tr("Unable to set identity address: `%1`.").arg(Utils::coreStringToAppString(identity->asStringUriOnly())); return false; } diff --git a/Linphone/model/account/AccountManager.hpp b/Linphone/model/account/AccountManager.hpp index 4b9f02a4..3b337e59 100644 --- a/Linphone/model/account/AccountManager.hpp +++ b/Linphone/model/account/AccountManager.hpp @@ -33,7 +33,7 @@ public: AccountManager(QObject *parent = nullptr); ~AccountManager(); - bool login(QString username, QString password); + bool login(QString username, QString password, QString *errorMessage = nullptr); std::shared_ptr createAccount(const QString &assistantFile); @@ -42,6 +42,7 @@ public: const std::string &message); signals: void registrationStateChanged(linphone::RegistrationState state); + void errorMessageChanged(const QString &errorMessage); private: std::shared_ptr mAccountModel; diff --git a/Linphone/model/object/VariantObject.cpp b/Linphone/model/object/VariantObject.cpp index b12d8756..d93b0f96 100644 --- a/Linphone/model/object/VariantObject.cpp +++ b/Linphone/model/object/VariantObject.cpp @@ -37,10 +37,16 @@ VariantObject::VariantObject(QVariant defaultValue, QObject *parent) { new SafeConnection(mCoreObject, mModelObject), &QObject::deleteLater); mConnection->makeConnectToCore(&SafeObject::setValue, [this](QVariant value) { - mConnection->invokeToModel([this, value]() { mModelObject->onSetValue(value); }); + mConnection->invokeToModel([this, value]() { + // TODO : fix this properly + if (mModelObject) mModelObject->onSetValue(value); + }); }); mConnection->makeConnectToModel(&SafeObject::setValue, [this](QVariant value) { - mConnection->invokeToCore([this, value]() { mCoreObject->onSetValue(value); }); + mConnection->invokeToCore([this, value]() { + // TODO : fix this properly + if (mCoreObject) mCoreObject->onSetValue(value); + }); }); mConnection->makeConnectToModel(&SafeObject::valueChanged, [this](QVariant value) { mConnection->invokeToCore([this, value]() { mCoreObject->valueChanged(value); }); diff --git a/Linphone/tool/LinphoneEnums.hpp b/Linphone/tool/LinphoneEnums.hpp index 4d35ec81..8c861fbe 100644 --- a/Linphone/tool/LinphoneEnums.hpp +++ b/Linphone/tool/LinphoneEnums.hpp @@ -315,7 +315,6 @@ Q_DECLARE_METATYPE(LinphoneEnums::FriendCapability) Q_DECLARE_METATYPE(LinphoneEnums::MediaEncryption) Q_DECLARE_METATYPE(LinphoneEnums::ParticipantDeviceState) Q_DECLARE_METATYPE(LinphoneEnums::RecorderState) -Q_DECLARE_METATYPE(LinphoneEnums::RegistrationState) Q_DECLARE_METATYPE(LinphoneEnums::TunnelMode) Q_DECLARE_METATYPE(LinphoneEnums::TransportType) */ diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index 7cefb31f..733fc8c3 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -98,6 +98,15 @@ VariantObject *Utils::createCall(const QString &sipAddress, return data; } + +void Utils::setFirstLaunch(bool first) { + App::getInstance()->setFirstLaunch(first); +} + +bool Utils::getFirstLaunch() { + return App::getInstance()->getFirstLaunch(); +} + void Utils::openCallsWindow(CallGui *call) { if (call) App::getInstance()->getCallsWindow(QVariant::fromValue(call))->show(); } diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index d465cd5b..a11866b9 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -57,6 +57,8 @@ public: Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress, const QString &prepareTransfertAddress = "", const QHash &headers = {}); + Q_INVOKABLE static void setFirstLaunch(bool first); + Q_INVOKABLE static bool getFirstLaunch(); Q_INVOKABLE static void openCallsWindow(CallGui *call); Q_INVOKABLE static QQuickWindow *getMainWindow(); Q_INVOKABLE static QQuickWindow *getCallsWindow(CallGui *callGui); diff --git a/Linphone/view/App/Main.qml b/Linphone/view/App/Main.qml index db4f8e7d..1c0e9bba 100644 --- a/Linphone/view/App/Main.qml +++ b/Linphone/view/App/Main.qml @@ -2,7 +2,7 @@ import QtQuick 2.15 import QtQuick.Layouts 1.3 import QtQuick.Controls import Linphone -//import UI 1.0 +import UtilsCpp 1.0 Window { id: mainWindow @@ -10,6 +10,7 @@ Window { height: 982 * DefaultStyle.dp visible: true title: qsTr("Linphone") + // TODO : handle this bool when security mode is implemented property bool firstConnection: true function goToNewCall() { @@ -21,25 +22,23 @@ Window { mainWindowStackView.currentItem.transferCallSucceed() } - AccountProxy{ + AccountProxy { + // TODO : change this so it does not display the main page for one second + // when we fail trying to connect the first account (account is added and + // removed shortly after) id: accountProxy - onHaveAccountChanged: { - if(haveAccount) - mainWindowStackView.replace(mainPage, StackView.Immediate) - else - mainWindowStackView.replace(loginPage, StackView.Immediate) - } } StackView { id: mainWindowStackView anchors.fill: parent - initialItem: accountProxy.haveAccount ? mainPage : welcomePage + initialItem: accountProxy.haveAccount ? mainPage : UtilsCpp.getFirstLaunch() ? welcomePage : loginPage } Component { id: welcomePage WelcomePage { onStartButtonPressed: { mainWindowStackView.replace(loginPage)// Replacing the first item will destroy the old. + UtilsCpp.setFirstLaunch(false) } } } @@ -51,11 +50,7 @@ Window { onUseSIPButtonClicked: mainWindowStackView.push(sipLoginPage) onGoToRegister: mainWindowStackView.replace(registerPage) onConnectionSucceed: { - if (mainWindow.firstConnection) { - mainWindowStackView.replace(securityModePage) - } else { - mainWindowStackView.replace(mainPage) - } + mainWindowStackView.replace(mainPage) } } } @@ -66,11 +61,7 @@ Window { onGoToRegister: mainWindowStackView.replace(registerPage) onConnectionSucceed: { - if (mainWindow.firstConnection) { - mainWindowStackView.replace(securityModePage) - } else { - mainWindowStackView.replace(mainPage) - } + mainWindowStackView.replace(mainPage) } } } @@ -92,7 +83,9 @@ Window { Component { id: securityModePage SecurityModePage { + id: securePage onModeSelected: (index) => { + // TODO : connect to cpp part when ready var selectedMode = index == 0 ? "chiffrement" : "interoperable" console.debug("[SelectMode]User: User selected mode " + selectedMode) mainWindowStackView.replace(mainPage) @@ -103,7 +96,7 @@ Window { id: mainPage MainLayout { onAddAccountRequest: mainWindowStackView.replace(loginPage) + // StackView.onActivated: connectionSecured(0) // TODO : connect to cpp part when ready } } -} - +} \ No newline at end of file diff --git a/Linphone/view/Item/Account/Accounts.qml b/Linphone/view/Item/Account/Accounts.qml index e60bc429..4dc17709 100644 --- a/Linphone/view/Item/Account/Accounts.qml +++ b/Linphone/view/Item/Account/Accounts.qml @@ -11,21 +11,23 @@ Item { id: mainItem width: 517 * DefaultStyle.dp readonly property int topPadding: 23 * DefaultStyle.dp - readonly property int bottomPadding: 18 * DefaultStyle.dp + readonly property int bottomPadding: 23 * DefaultStyle.dp readonly property int leftPadding: 32 * DefaultStyle.dp readonly property int rightPadding: 32 * DefaultStyle.dp readonly property int spacing: 16 * DefaultStyle.dp signal addAccountRequest() - implicitHeight: list.contentHeight + topPadding + bottomPadding + 32 * DefaultStyle.dp + 1 + newAccountArea.height ColumnLayout{ + id: childLayout anchors.top: parent.top anchors.topMargin: mainItem.topPadding anchors.left: parent.left anchors.leftMargin: mainItem.leftPadding anchors.right: parent.right anchors.rightMargin: mainItem.rightPadding + anchors.bottom: parent.bottom + anchors.bottomMargin: mainItem.bottomPadding ListView{ id: list Layout.preferredHeight: contentHeight @@ -69,8 +71,10 @@ Item { EffectImage { id: newAccount source: AppIcons.plusCircle - Layout.fillHeight: true - Layout.preferredWidth: height + width: 32 * DefaultStyle.dp + height: 32 * DefaultStyle.dp + Layout.preferredWidth: 32 * DefaultStyle.dp + Layout.preferredHeight: 32 * DefaultStyle.dp Layout.alignment: Qt.AlignHCenter fillMode: Image.PreserveAspectFit colorizationColor: DefaultStyle.main2_500main diff --git a/Linphone/view/Item/BusyIndicator.qml b/Linphone/view/Item/BusyIndicator.qml index 1861c48c..16b1e696 100644 --- a/Linphone/view/Item/BusyIndicator.qml +++ b/Linphone/view/Item/BusyIndicator.qml @@ -12,6 +12,7 @@ Item { Control.BusyIndicator { id: busyIndicator running: mainItem.visible + anchors.centerIn: mainItem } MultiEffect { source: busyIndicator diff --git a/Linphone/view/Item/Call/CallContactsLists.qml b/Linphone/view/Item/Call/CallContactsLists.qml index dc798e1c..b9062a1a 100644 --- a/Linphone/view/Item/Call/CallContactsLists.qml +++ b/Linphone/view/Item/Call/CallContactsLists.qml @@ -55,9 +55,9 @@ Item { } Repeater { id: adresses - model: [{label: "SIP", address: startCallPopup.contact ? startCallPopup.contact.core.address : ""}, - {label: "Work", address: "06000000000"}, - {label: "Personal", address: "060000000"} + model: [{label: "SIP", address: startCallPopup.contact ? startCallPopup.contact.core.address : ""} + // {label: "Work", address: "06000000000"}, + // {label: "Personal", address: "060000000"} ] //account.adresses Button { id: channel @@ -235,6 +235,10 @@ Item { Layout.fillWidth: true id: contactList searchBarText: searchBar.text + onContactSelected: (contact) => { + startCallPopup.contact = contact + startCallPopup.open() + } } } ColumnLayout { @@ -254,6 +258,10 @@ Item { sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend } + onContactSelected: (contact) => { + startCallPopup.contact = contact + startCallPopup.open() + } } } Item { diff --git a/Linphone/view/Item/Contact/Avatar.qml b/Linphone/view/Item/Contact/Avatar.qml index 4b8bfebb..97cca337 100644 --- a/Linphone/view/Item/Contact/Avatar.qml +++ b/Linphone/view/Item/Contact/Avatar.qml @@ -27,8 +27,32 @@ StackView{ || (contact && contact.core.pictureUri) onHaveAvatarChanged: replace(haveAvatar ? avatar : initials, StackView.Immediate) + + property bool secured: false initialItem: haveAvatar ? avatar : initials + + Rectangle { + visible: mainItem.secured + anchors.fill: mainItem.currentItem + radius: mainItem.width / 2 + z: 1 + color: "transparent" + border { + width: 3 * DefaultStyle.dp + color: DefaultStyle.info_500_main + } + Image { + source: AppIcons.trusted + x: mainItem.width / 7 + width: mainItem.width / 4.5 + height: width + sourceSize.width: width + sourceSize.height: height + fillMode: Image.PreserveAspectFit + anchors.bottom: parent.bottom + } + } Component{ id: initials Rectangle { diff --git a/Linphone/view/Item/Contact/Contact.qml b/Linphone/view/Item/Contact/Contact.qml index 0a024499..f8f55d52 100644 --- a/Linphone/view/Item/Contact/Contact.qml +++ b/Linphone/view/Item/Contact/Contact.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Effects import QtQuick.Layouts +import QtQuick.Controls as Control import Linphone @@ -31,68 +32,76 @@ Rectangle{ onClicked: mainItem.avatarClicked() } } - ContactDescription{ - id: description - Layout.fillWidth: true + Item { + Layout.preferredWidth: 200 * DefaultStyle.dp Layout.fillHeight: true Layout.leftMargin: 10 * DefaultStyle.dp - account: mainItem.account - } - Item{ - id: registrationStatusItem - Layout.preferredWidth: 97 * DefaultStyle.dp - Layout.fillHeight: true - Rectangle{ - id: registrationStatus - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - width: Math.min(text.implicitWidth + (2 * 8 * DefaultStyle.dp), registrationStatusItem.width) - height: 24 * DefaultStyle.dp - color: DefaultStyle.main2_200 - radius: 90 * DefaultStyle.dp - Text{ - id: text - anchors.fill: parent - anchors.leftMargin: 8 * DefaultStyle.dp - anchors.rightMargin: 8 * DefaultStyle.dp - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - visible: mainItem.account - readonly property int mode : !mainItem.account || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Ok - ? 0 - : mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Cleared || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.None - ? 1 - : mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Progress || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Refreshing - ? 2 - : 3 - // Test texts - //Timer{ - // running: true - // interval: 1000 - // repeat: true - // onTriggered: text.mode = (++text.mode) % 4 - //} - font.weight: 300 * DefaultStyle.dp - font.pixelSize: 12 * DefaultStyle.dp - color: mode == 0 - ? DefaultStyle.success_500main - : mode == 1 - ? DefaultStyle.warning_600 - : mode == 2 - ? DefaultStyle.main2_500main - : DefaultStyle.danger_500main - text: mode == 0 - ? 'Connecté' - : mode == 1 - ? 'Désactivé' - : mode == 2 - ? 'Connexion...' - : 'Erreur' - } + Layout.rightMargin: 10 * DefaultStyle.dp + ContactDescription{ + id: description + anchors.fill: parent + account: mainItem.account } } + Control.Control { + id: registrationStatusItem + Layout.minimumWidth: 49 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + topPadding: 4 * DefaultStyle.dp + bottomPadding: 4 * DefaultStyle.dp + leftPadding: 8 * DefaultStyle.dp + rightPadding: 8 * DefaultStyle.dp + Layout.preferredWidth: text.implicitWidth + (2 * 8 * DefaultStyle.dp) + background: Rectangle{ + id: registrationStatus + anchors.fill: parent + color: DefaultStyle.main2_200 + radius: 90 * DefaultStyle.dp + } + contentItem: Text { + id: text + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + visible: mainItem.account + property int mode : !mainItem.account || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Ok + ? 0 + : mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Cleared || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.None + ? 1 + : mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Progress || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Refreshing + ? 2 + : 3 + // Test texts + // Timer{ + // running: true + // interval: 1000 + // repeat: true + // onTriggered: text.mode = (++text.mode) % 4 + // } + font.weight: 300 * DefaultStyle.dp + font.pixelSize: 12 * DefaultStyle.dp + color: mode == 0 + ? DefaultStyle.success_500main + : mode == 1 + ? DefaultStyle.warning_600 + : mode == 2 + ? DefaultStyle.main2_500main + : DefaultStyle.danger_500main + text: mode == 0 + ? qsTr("Connecté") + : mode == 1 + ? qsTr("Désactivé") + : mode == 2 + ? qsTr("Connexion...") + : qsTr("Erreur") + } + } + Item { + Layout.fillWidth: true + } Item{ - Layout.preferredWidth: 100 * DefaultStyle.dp + Layout.preferredWidth: 22 * DefaultStyle.dp + Layout.preferredHeight: 22 * DefaultStyle.dp Layout.fillHeight: true Rectangle{ id: unreadNotifications diff --git a/Linphone/view/Item/Contact/ContactDescription.qml b/Linphone/view/Item/Contact/ContactDescription.qml index 72a22fdb..65382f90 100644 --- a/Linphone/view/Item/Contact/ContactDescription.qml +++ b/Linphone/view/Item/Contact/ContactDescription.qml @@ -12,9 +12,9 @@ ColumnLayout{ property string topText: displayName ? displayName.value : '' property string bottomText: account ? account.core.identityAddress : '' spacing: 0 - Text{ + width: topTextItem.implicitWidth + Text { id: topTextItem - Layout.fillWidth: true Layout.fillHeight: true verticalAlignment: (bottomTextItem.visible?Text.AlignBottom:Text.AlignVCenter) visible: text != '' @@ -22,10 +22,13 @@ ColumnLayout{ font.pixelSize: 14 * DefaultStyle.dp color: DefaultStyle.main2_700 text: mainItem.topText + width: mainItem.width + Layout.preferredWidth: mainItem.width + wrapMode: Text.WrapAnywhere + maximumLineCount: 1 } - Text{ + Text { id: bottomTextItem - Layout.fillWidth: true Layout.fillHeight: true verticalAlignment: (topTextItem.visible?Text.AlignTop:Text.AlignVCenter) visible: text != '' @@ -33,5 +36,8 @@ ColumnLayout{ font.pixelSize: 12 * DefaultStyle.dp color: DefaultStyle.main2_400 text: mainItem.bottomText + Layout.preferredWidth: mainItem.width + maximumLineCount: 1 + wrapMode: Text.WrapAnywhere } } diff --git a/Linphone/view/Item/ContactsList.qml b/Linphone/view/Item/ContactsList.qml index f515b773..35ea66cd 100644 --- a/Linphone/view/Item/ContactsList.qml +++ b/Linphone/view/Item/ContactsList.qml @@ -16,6 +16,8 @@ ListView { property bool contactMenuVisible: true property bool initialHeadersVisible: true + signal contactSelected(var contact) + model: MagicSearchProxy { searchText: searchBarText.length === 0 ? "*" : searchBarText } @@ -40,6 +42,7 @@ ListView { } Item { width: mainItem.width + Layout.preferredWidth: mainItem.width height: 56 * DefaultStyle.dp RowLayout { anchors.fill: parent @@ -129,9 +132,7 @@ ListView { visible: contactArea.containsMouse || friendPopup.hovered } onClicked: { - startCallPopup.contact = modelData - startCallPopup.open() - // mainItem.callButtonPressed(modelData.core.address) + mainItem.contactSelected(modelData) } } } diff --git a/Linphone/view/Item/ErrorText.qml b/Linphone/view/Item/ErrorText.qml index 35944060..1bcb0861 100644 --- a/Linphone/view/Item/ErrorText.qml +++ b/Linphone/view/Item/ErrorText.qml @@ -8,6 +8,12 @@ Text { id: mainItem color: DefaultStyle.danger_500main opacity: 0 + function displayText() { + mainItem.state = "Visible" + } + function hideText() { + mainItem.state = "Invisible" + } font { pixelSize: 13 * DefaultStyle.dp weight: 600 * DefaultStyle.dp @@ -30,10 +36,6 @@ Text { property: "opacity" duration: 1000 } - // NumberAnimation { - // property: "visible" - // duration: 1100 - // } } ] Timer { @@ -48,7 +50,7 @@ Text { target: mainItem onTextChanged: { if (mainItem.text.length > 0) { - errorText.state = "Visible" + mainItem.state = "Visible" } } } diff --git a/Linphone/view/Item/Form/LoginForm.qml b/Linphone/view/Item/Form/LoginForm.qml index 73c205de..8a506308 100644 --- a/Linphone/view/Item/Form/LoginForm.qml +++ b/Linphone/view/Item/Form/LoginForm.qml @@ -1,5 +1,5 @@ import QtQuick 2.15 -import QtQuick.Layouts 1.0 +import QtQuick.Layouts import QtQuick.Controls as Control import Linphone @@ -24,32 +24,38 @@ ColumnLayout { value: DefaultStyle.danger_500main } } - TextInput { - id: password - label: "Password" - mandatory: true - hidden: true - enableErrorText: true - Binding on background.border.color { - when: errorText.opacity != 0 - value: DefaultStyle.danger_500main - } - Binding on textField.color { - when: errorText.opacity != 0 - value: DefaultStyle.danger_500main - } - } + Item { + Layout.preferredHeight: password.implicitHeight + TextInput { + id: password + label: "Password" + mandatory: true + hidden: true + enableErrorText: true - ErrorText { - id: errorText - Connections { - target: LoginPageCpp - onRegistrationStateChanged: { - if (LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.Failed) { - errorText.text = qsTr("Le couple identifiant mot de passe ne correspont pas") - } else if (LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.Ok) { - mainItem.connectionSucceed() + Binding on background.border.color { + when: errorText.opacity != 0 + value: DefaultStyle.danger_500main + } + Binding on textField.color { + when: errorText.opacity != 0 + value: DefaultStyle.danger_500main + } + } + + ErrorText { + anchors.bottom: password.bottom + id: errorText + Connections { + target: LoginPageCpp + onErrorMessageChanged: { + errorText.text = LoginPageCpp.errorMessage + } + onRegistrationStateChanged: { + if (LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.Ok) { + mainItem.connectionSucceed() + } } } } @@ -58,11 +64,43 @@ ColumnLayout { RowLayout { id: lastFormLineLayout Button { - text: qsTr("Connexion") + contentItem: StackLayout { + id: connectionButton + currentIndex: 0 + Text { + text: qsTr("Connexion") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font { + pixelSize: 18 * DefaultStyle.dp + weight: 600 * DefaultStyle.dp + } + color: DefaultStyle.grey_0 + } + BusyIndicator { + width: parent.height + height: parent.height + Layout.alignment: Qt.AlignCenter + indicatorColor: DefaultStyle.grey_0 + } + Connections { + target: LoginPageCpp + onRegistrationStateChanged: { + if (LoginPageCpp.registrationState != LinphoneEnums.RegistrationState.Progress) { + connectionButton.currentIndex = 0 + } + } + onErrorMessageChanged: { + connectionButton.currentIndex = 0 + } + } + } Layout.rightMargin: 20 * DefaultStyle.dp onClicked: { username.errorMessage = "" password.errorMessage = "" + errorText.text = "" if (username.text.length == 0 || password.text.length == 0) { if (username.text.length == 0) @@ -72,6 +110,7 @@ ColumnLayout { return } LoginPageCpp.login(username.text, password.text) + connectionButton.currentIndex = 1 } } Button { diff --git a/Linphone/view/Item/TextInput.qml b/Linphone/view/Item/TextInput.qml index 42e886fe..00217a53 100644 --- a/Linphone/view/Item/TextInput.qml +++ b/Linphone/view/Item/TextInput.qml @@ -18,6 +18,7 @@ ColumnLayout { property string initialText property bool enableErrorText: false + property bool errorTextVisible: errorText.opacity > 0 property alias textField: textField property alias background: input @@ -61,11 +62,11 @@ ColumnLayout { radius: 79 * DefaultStyle.dp color: mainItem.enableBackgroundColors ? DefaultStyle.grey_100 : "transparent" border.color: mainItem.enableBackgroundColors - ? errorText.opacity === 0 - ? textField.activeFocus + ? mainItem.errorTextVisible + ? DefaultStyle.danger_500main + : textField.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.grey_200 - : DefaultStyle.danger_500main : "transparent" Control.TextField { @@ -82,7 +83,7 @@ ColumnLayout { pixelSize: 14 * DefaultStyle.dp weight: 400 * DefaultStyle.dp } - color: errorText.opacity === 0 ? DefaultStyle.main2_600 : DefaultStyle.danger_500main + color: mainItem.errorTextVisible ? DefaultStyle.danger_500main : DefaultStyle.main2_600 selectByMouse: true validator: mainItem.validator background: Item { @@ -117,6 +118,6 @@ ColumnLayout { id: errorText visible: mainItem.enableErrorText text: mainItem.errorMessage - Layout.preferredWidth: mainItem.textInputWidth + Layout.preferredWidth: implicitWidth } } diff --git a/Linphone/view/Page/Login/RegisterCheckingPage.qml b/Linphone/view/Page/Login/RegisterCheckingPage.qml index 64a01a92..af7b126b 100644 --- a/Linphone/view/Page/Login/RegisterCheckingPage.qml +++ b/Linphone/view/Page/Login/RegisterCheckingPage.qml @@ -76,7 +76,6 @@ LoginLayout { required property int index Layout.preferredWidth: width Layout.preferredHeight: height - Component.onCompleted: console.log("completed", width, Layout.preferredWidth) onTextEdited: { console.log("textfield text", text, index) if (text.length > 0 ) { diff --git a/Linphone/view/Page/Login/WelcomePage.qml b/Linphone/view/Page/Login/WelcomePage.qml index 78114e68..0d02ed25 100644 --- a/Linphone/view/Page/Login/WelcomePage.qml +++ b/Linphone/view/Page/Login/WelcomePage.qml @@ -54,7 +54,7 @@ LoginLayout { } } } - centerContent: ColumnLayout { + centerContent: Item { id: centerLayout Layout.bottomMargin: 20 * DefaultStyle.dp Layout.fillWidth: false @@ -62,6 +62,7 @@ LoginLayout { Layout.leftMargin: 250 * DefaultStyle.dp Layout.topMargin: 165 * DefaultStyle.dp RowLayout { + id: carouselLayout Image { id: carouselImg Layout.rightMargin: 40 * DefaultStyle.dp @@ -104,10 +105,11 @@ LoginLayout { } Button { - Layout.topMargin: 20 * DefaultStyle.dp - Layout.bottomMargin: 20 * DefaultStyle.dp - Layout.leftMargin: (centerLayout.width - width) * DefaultStyle.dp - Layout.alignment: Qt.AlignBottom | Qt.AlignRight + anchors.top: carouselLayout.bottom + anchors.right: carouselLayout.right + anchors.topMargin: 20 * DefaultStyle.dp + anchors.bottomMargin: 20 * DefaultStyle.dp + anchors.leftMargin: (centerLayout.width - width) * DefaultStyle.dp y: centerLayout.implicitWidth - width text: carousel.currentIndex < (carousel.itemsCount - 1) ? qsTr("Suivant") : qsTr("Commencer") onClicked: {