From c2411af6c9f17a281cea7d06ae1d1cd4323b0207 Mon Sep 17 00:00:00 2001 From: Ming Rui Zhang <mingrui.zhang@savoirfairelinux.com> Date: Tue, 8 Sep 2020 15:50:58 -0400 Subject: [PATCH] settings: fix username registration Make username registration line edit a common component Gitlab: #56 Change-Id: Icb5dc1c8acc6d56f699f9a1cc4ebee6976f5eae1 --- qml.qrc | 1 + src/commoncomponents/MaterialButton.qml | 129 ++++++++------- src/commoncomponents/UsernameLineEdit.qml | 95 +++++++++++ src/constant/JamiTheme.qml | 2 +- .../CurrentAccountSettingsScrollPage.qml | 153 ++++-------------- src/utils.cpp | 14 -- src/utils.h | 2 - src/wizardview/WizardView.qml | 53 +----- .../components/CreateAccountPage.qml | 40 ++--- 9 files changed, 210 insertions(+), 279 deletions(-) create mode 100644 src/commoncomponents/UsernameLineEdit.qml diff --git a/qml.qrc b/qml.qrc index fcc6b2d32..e4d6e5009 100644 --- a/qml.qrc +++ b/qml.qrc @@ -111,5 +111,6 @@ <file>src/constant/JamiQmlUtils.qml</file> <file>src/wizardview/components/AccountCreationStepIndicator.qml</file> <file>src/commoncomponents/SpinnerButton.qml</file> + <file>src/commoncomponents/UsernameLineEdit.qml</file> </qresource> </RCC> diff --git a/src/commoncomponents/MaterialButton.qml b/src/commoncomponents/MaterialButton.qml index 969a3c54f..69903a6e0 100644 --- a/src/commoncomponents/MaterialButton.qml +++ b/src/commoncomponents/MaterialButton.qml @@ -19,7 +19,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtGraphicalEffects 1.15 -import QtQuick.Layouts 1.15 import "../constant" @@ -27,7 +26,7 @@ Button { id: root property alias fontCapitalization: buttonText.font.capitalization - property alias source: root.icon.source + property alias source: buttonImage.source property string toolTipText: "" property var color: "transparent" property var hoveredColor: undefined @@ -37,80 +36,92 @@ Button { property var preferredWidth: 400 property var preferredHeight: 36 + property var minimumIconTextSpacing: 10 + property var iconPreferredHeight: 18 + property var iconPreferredWidth: 18 property int elide: Text.ElideRight font.kerning: true - icon.source: "" - icon.height: 18 - icon.width: 18 - hoverEnabled: hoveredColor !== undefined contentItem: Item { Rectangle { anchors.fill: parent color: "transparent" - RowLayout { - anchors.fill: parent - anchors.centerIn: parent - AnimatedImage { - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - Layout.leftMargin: 8 - Layout.preferredHeight: root.icon.height - Layout.preferredWidth: root.icon.width - - source: animatedImageSource - playing: true - paused: false - fillMode: Image.PreserveAspectFit - mipmap: true - visible: animatedImageSource !== "" - } + AnimatedImage { + id: buttonAnimatedImage + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: JamiTheme.preferredMarginSize / 2 - Image { - source: root.icon.source - Layout.preferredWidth: root.icon.width - Layout.preferredHeight: root.icon.height - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - Layout.leftMargin: JamiTheme.preferredMarginSize / 2 - layer { - enabled: true - effect: ColorOverlay { - id: overlay - color:{ - if (!outlined) - return "white" - if (hovered && root.hoveredColor) - return root.hoveredColor - if (checked && root.pressedColor) - return root.pressedColor - return root.color - } + height: iconPreferredHeight + width: iconPreferredWidth + + source: animatedImageSource + playing: true + paused: false + fillMode: Image.PreserveAspectFit + mipmap: true + visible: animatedImageSource.length !== 0 + } + + Image { + id: buttonImage + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: JamiTheme.preferredMarginSize / 2 + + height: iconPreferredHeight + width: iconPreferredWidth + + visible: source.toString().length !== 0 + layer { + enabled: true + effect: ColorOverlay { + id: overlay + color:{ + if (!outlined) + return "white" + if (hovered && root.hoveredColor) + return root.hoveredColor + if (checked && root.pressedColor) + return root.pressedColor + return root.color } } } - Text { - id: buttonText - - Layout.rightMargin: root.icon.width + JamiTheme.preferredMarginSize / 2 - text: root.text - elide: root.elide - color: { - if (!outlined) - return "white" - if (hovered && root.hoveredColor) - return root.hoveredColor - if (checked && root.pressedColor) - return root.pressedColor - return root.color - } - font: root.font - Layout.fillWidth: true - horizontalAlignment: Text.AlignHCenter + } + + Text { + id: buttonText + + anchors.centerIn: parent + + width: { + var iconWidth = (buttonAnimatedImage.visible || buttonImage.visible) ? + iconPreferredWidth : 0 + return (parent.width / 2 - iconWidth - + JamiTheme.preferredMarginSize / 2 - minimumIconTextSpacing) * 2 + } + + text: root.text + elide: root.elide + color: { + if (!outlined) + return "white" + if (hovered && root.hoveredColor) + return root.hoveredColor + if (checked && root.pressedColor) + return root.pressedColor + return root.color } + font: root.font + horizontalAlignment: Text.AlignHCenter } } } diff --git a/src/commoncomponents/UsernameLineEdit.qml b/src/commoncomponents/UsernameLineEdit.qml new file mode 100644 index 000000000..a2834d94c --- /dev/null +++ b/src/commoncomponents/UsernameLineEdit.qml @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import net.jami.Models 1.0 + +MaterialLineEdit { + id: root + + enum NameRegistrationState { + BLANK, + INVALID, + TAKEN, + FREE, + SEARCHING + } + + property int nameRegistrationState: UsernameLineEdit.NameRegistrationState.BLANK + + Connections { + id: registeredNameFoundConnection + + target: ClientWrapper.nameDirectory + + function onRegisteredNameFound(status, address, name) { + if (text === name) { + switch(status) { + case NameDirectory.LookupStatus.NOT_FOUND: + nameRegistrationState = UsernameLineEdit.NameRegistrationState.FREE + break + case NameDirectory.LookupStatus.ERROR: + case NameDirectory.LookupStatus.INVALID_NAME: + case NameDirectory.LookupStatus.INVALID: + nameRegistrationState = UsernameLineEdit.NameRegistrationState.INVALID + break + case NameDirectory.LookupStatus.SUCCESS: + nameRegistrationState = UsernameLineEdit.NameRegistrationState.TAKEN + break + } + } + } + } + + Timer { + id: lookupTimer + + repeat: false + interval: 200 + + onTriggered: { + if (text.length !== 0 && readOnly === false) { + nameRegistrationState = UsernameLineEdit.NameRegistrationState.SEARCHING + ClientWrapper.nameDirectory.lookupName("", text) + } else { + nameRegistrationState = UsernameLineEdit.NameRegistrationState.BLANK + } + } + } + + selectByMouse: true + font.pointSize: 9 + font.kerning: true + + borderColorMode: { + switch (nameRegistrationState){ + case UsernameLineEdit.NameRegistrationState.BLANK: + return MaterialLineEdit.NORMAL + case UsernameLineEdit.NameRegistrationState.INVALID: + case UsernameLineEdit.NameRegistrationState.TAKEN: + return MaterialLineEdit.ERROR + case UsernameLineEdit.NameRegistrationState.FREE: + return MaterialLineEdit.RIGHT + case UsernameLineEdit.NameRegistrationState.SEARCHING: + return MaterialLineEdit.SEARCHING + } + } + + onTextChanged: lookupTimer.restart() +} diff --git a/src/constant/JamiTheme.qml b/src/constant/JamiTheme.qml index 69eaf3560..f2ca80a0d 100644 --- a/src/constant/JamiTheme.qml +++ b/src/constant/JamiTheme.qml @@ -83,7 +83,7 @@ Item { property int splitViewHandlePreferredWidth: 4 property int textFontSize: 9 - property int settingsFontSize: 10 + property int settingsFontSize: 9 property int buttonFontSize: 9 property int headerFontSize: 13 property int titleFontSize: 16 diff --git a/src/settingsview/components/CurrentAccountSettingsScrollPage.qml b/src/settingsview/components/CurrentAccountSettingsScrollPage.qml index ef38c8e61..ba555342c 100644 --- a/src/settingsview/components/CurrentAccountSettingsScrollPage.qml +++ b/src/settingsview/components/CurrentAccountSettingsScrollPage.qml @@ -33,30 +33,15 @@ import "../../commoncomponents" Rectangle { id: root - enum RegName { - BLANK, - INVALIDFORM, - TAKEN, - FREE, - SEARCHING - } - - property int regNameUi: CurrentAccountSettingsScrollPage.BLANK property string registeredName: "" property bool registeredIdNeedsSet: false - property int refreshVariable : 0 property int preferredColumnWidth : root.width / 2 - 50 signal navigateToMainView signal navigateToNewWizardView signal backArrowClicked - function refreshRelevantUI(){ - refreshVariable++ - refreshVariable-- - } - function updateAccountInfoDisplayed() { setAvatar() @@ -86,7 +71,6 @@ Rectangle { if (advanceSettingsView.visible) { advanceSettingsView.updateAccountInfoDisplayedAdvance() } - refreshRelevantUI() } function connectCurrentAccount() { @@ -161,63 +145,6 @@ Rectangle { } } - // slots - function verifyRegisteredNameSlot() { - if (ClientWrapper.SettingsAdapter.get_CurrentAccountInfo_RegisteredName() !== "") { - regNameUi = CurrentAccountSettingsScrollPage.BLANK - } else { - registeredName = ClientWrapper.utilsAdaptor.stringSimplifier( - currentRegisteredID.text) - if (registeredName !== "") { - if (ClientWrapper.utilsAdaptor.validateRegNameForm(registeredName)) { - regNameUi = CurrentAccountSettingsScrollPage.SEARCHING - lookUpLabelTimer.restart() - } else { - regNameUi = CurrentAccountSettingsScrollPage.INVALIDFORM - } - } else { - regNameUi = CurrentAccountSettingsScrollPage.BLANK - } - } - } - - Timer { - id: lookUpLabelTimer - - interval: 300 - onTriggered: { - beforeNameLookup() - } - } - - function beforeNameLookup() { - ClientWrapper.nameDirectory.lookupName("", registeredName) - } - - Connections { - target: ClientWrapper.nameDirectory - enabled: true - - function onRegisteredNameFound(status, address, name) { - afterNameLookup(status, name) - } - } - - function afterNameLookup(status, regName) { - if (registeredName === regName && regName.length > 2) { - switch (status) { - case NameDirectory.LookupStatus.NOT_FOUND: - regNameUi = CurrentAccountSettingsScrollPage.FREE - break - default: - regNameUi = CurrentAccountSettingsScrollPage.TAKEN - break - } - } else { - regNameUi = CurrentAccountSettingsScrollPage.BLANK - } - } - function setAccEnableSlot(state) { ClientWrapper.accountModel.setAccountEnabled(ClientWrapper.utilsAdaptor.getCurrAccId(), state) } @@ -317,14 +244,11 @@ Rectangle { onAccepted: { registeredIdNeedsSet = false + currentRegisteredID.nameRegistrationState = + UsernameLineEdit.NameRegistrationState.BLANK } } - function slotRegisterName() { - refreshRelevantUI() - nameRegistrationDialog.openNameRegistrationDialog(registeredName) - } - LinkDeviceDialog{ id: linkDeviceDialog @@ -582,7 +506,7 @@ Rectangle { readOnly: true selectByMouse: true - text: { currentRingIDText.elidedText } + text: currentRingIDText.elidedText horizontalAlignment: Text.AlignRight verticalAlignment: Text.AlignVCenter @@ -601,9 +525,7 @@ Rectangle { elide: Text.ElideRight elideWidth: root.width - idLabel.width -JamiTheme.preferredMarginSize*4 - text: { refreshVariable - return ClientWrapper.SettingsAdapter.getCurrentAccount_Profile_Info_Uri() - } + text: ClientWrapper.SettingsAdapter.getCurrentAccount_Profile_Info_Uri() } } } @@ -623,67 +545,52 @@ Rectangle { maxWidth: width } - MaterialLineEdit { + UsernameLineEdit { id: currentRegisteredID Layout.alignment: Qt.AlignRight Layout.preferredHeight: JamiTheme.preferredFieldHeight Layout.fillWidth: true - placeholderText: { refreshVariable - var result = true ? - qsTr("Type here to register a username") : "" - return result} - + placeholderText: registeredIdNeedsSet ? + qsTr("Type here to register a username") : "" text: { - refreshVariable - if (!registeredIdNeedsSet){ + if (!registeredIdNeedsSet) return ClientWrapper.SettingsAdapter.get_CurrentAccountInfo_RegisteredName() - } else { + else return "" - } } - selectByMouse: true - readOnly: { refreshVariable - return !registeredIdNeedsSet} - - font.pointSize: JamiTheme.settingsFontSize - font.kerning: true - font.bold: { refreshVariable - return !registeredIdNeedsSet} + readOnly: !registeredIdNeedsSet + font.bold: !registeredIdNeedsSet horizontalAlignment: registeredIdNeedsSet ? Text.AlignLeft : Text.AlignRight verticalAlignment: Text.AlignVCenter padding: 8 + } + } - borderColorMode: { - switch (regNameUi) { - case CurrentAccountSettingsScrollPage.INVALIDFORM: - case CurrentAccountSettingsScrollPage.TAKEN: - return InfoLineEdit.ERROR - case CurrentAccountSettingsScrollPage.FREE: - return InfoLineEdit.RIGHT - case CurrentAccountSettingsScrollPage.BLANK: - case CurrentAccountSettingsScrollPage.SEARCHING: - default: - return InfoLineEdit.NORMAL - } - } + MaterialButton { + id: btnRegisterName - onImageClicked: { - slotRegisterName() - } + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.rightMargin: currentRegisteredID.width / 2 - width / 2 + Layout.preferredWidth: 120 + Layout.preferredHeight: 30 - onTextEdited: { - verifyRegisteredNameSlot() - } + visible: registeredIdNeedsSet && + currentRegisteredID.nameRegistrationState === + UsernameLineEdit.NameRegistrationState.FREE - onEditingFinished: { - verifyRegisteredNameSlot() - } - } + text: qsTr("Register") + toolTipText: qsTr("Register the username") + color: JamiTheme.buttonTintedGrey + hoveredColor: JamiTheme.buttonTintedGreyHovered + pressedColor: JamiTheme.buttonTintedGreyPressed + + onClicked: nameRegistrationDialog.openNameRegistrationDialog( + currentRegisteredID.text) } } diff --git a/src/utils.cpp b/src/utils.cpp index ba66fd6b7..bf500554a 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1075,20 +1075,6 @@ UtilsAdapter::getCallStatusStr(int statusInt) return lrc::api::call::to_string(status); } -// returns true if name is valid registered name -bool -UtilsAdapter::validateRegNameForm(const QString& regName) -{ - QRegularExpression regExp(" "); - - if (regName.size() > 2 && !regName.contains(regExp)) { - return true; - - } else { - return false; - } -} - QString UtilsAdapter::getStringUTF8(QString string) { diff --git a/src/utils.h b/src/utils.h index 4a8dfc4c3..f99a1ff47 100644 --- a/src/utils.h +++ b/src/utils.h @@ -424,10 +424,8 @@ public: Q_INVOKABLE const QString getCallId(const QString& accountId, const QString& convUid); Q_INVOKABLE const QString getCallStatusStr(int statusInt); Q_INVOKABLE QString getStringUTF8(QString string); - Q_INVOKABLE bool validateRegNameForm(const QString& regName); Q_INVOKABLE QString getRecordQualityString(int value); Q_INVOKABLE QString getCurrentPath(); - Q_INVOKABLE QString stringSimplifier(QString input) { return input.simplified(); } Q_INVOKABLE QString toNativeSeparators(QString inputDir) { diff --git a/src/wizardview/WizardView.qml b/src/wizardview/WizardView.qml index 7e0fd9aa7..402ff355b 100644 --- a/src/wizardview/WizardView.qml +++ b/src/wizardview/WizardView.qml @@ -40,14 +40,6 @@ Rectangle { CONNECTMANAGER } - enum NameRegistrationState { - BLANK, - INVALID, - TAKEN, - FREE, - SEARCHING - } - enum WizardViewPageIndex { WELCOMEPAGE = 0, CREATEACCOUNTPAGE, @@ -120,35 +112,11 @@ Rectangle { } } - Connections { - id: registeredNameFoundConnection - - target: ClientWrapper.nameDirectory - - function onRegisteredNameFound(status, address, name) { - if (registeredName === name) { - switch(status) { - case NameDirectory.LookupStatus.NOT_FOUND: - createAccountPage.nameRegistrationUIState = WizardView.FREE - break - case NameDirectory.LookupStatus.ERROR: - case NameDirectory.LookupStatus.INVALID_NAME: - case NameDirectory.LookupStatus.INVALID: - createAccountPage.nameRegistrationUIState = WizardView.INVALID - break - case NameDirectory.LookupStatus.SUCCESS: - createAccountPage.nameRegistrationUIState = WizardView.TAKEN - break - } - } - } - } - function changePageQML(pageIndex) { controlPanelStackView.currentIndex = pageIndex if (pageIndex === WizardView.WizardViewPageIndex.WELCOMEPAGE) { fileToImport = "" - createAccountPage.nameRegistrationUIState = WizardView.BLANK + createAccountPage.nameRegistrationUIState = UsernameLineEdit.NameRegistrationState.BLANK } else if (pageIndex === WizardView.WizardViewPageIndex.CREATEACCOUNTPAGE) { createAccountPage.initializeOnShowUp() } else if (pageIndex === WizardView.WizardViewPageIndex.CREATESIPACCOUNTPAGE) { @@ -232,28 +200,9 @@ Rectangle { changePageQML(WizardView.WizardViewPageIndex.PROFILEPAGE) } - onText_usernameEditAliasChanged: lookupTimer.restart() - onLeavePage: { changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE) } - - Timer { - id: lookupTimer - - repeat: false - interval: 200 - - onTriggered: { - registeredName = createAccountPage.text_usernameEditAlias - if (registeredName.length !== 0) { - createAccountPage.nameRegistrationUIState = WizardView.SEARCHING - ClientWrapper.nameDirectory.lookupName("", registeredName) - } else { - createAccountPage.nameRegistrationUIState = WizardView.BLANK - } - } - } } CreateSIPAccountPage { diff --git a/src/wizardview/components/CreateAccountPage.qml b/src/wizardview/components/CreateAccountPage.qml index 39ced2f30..d1cb60184 100644 --- a/src/wizardview/components/CreateAccountPage.qml +++ b/src/wizardview/components/CreateAccountPage.qml @@ -30,7 +30,7 @@ Rectangle { id: root property alias text_usernameEditAlias: usernameEdit.text - property int nameRegistrationUIState: WizardView.BLANK + property alias nameRegistrationUIState: usernameEdit.nameRegistrationState property alias text_passwordEditAlias: passwordEdit.text signal createAccount @@ -127,7 +127,7 @@ Rectangle { } } - MaterialLineEdit { + UsernameLineEdit { id: usernameEdit Layout.topMargin: 15 @@ -135,24 +135,7 @@ Rectangle { Layout.preferredWidth: chooseUsernameButton.width Layout.alignment: Qt.AlignHCenter - selectByMouse: true placeholderText: qsTr("Choose your username") - font.pointSize: 9 - font.kerning: true - - borderColorMode: { - switch (nameRegistrationUIState){ - case WizardView.BLANK: - return MaterialLineEdit.NORMAL - case WizardView.INVALID: - case WizardView.TAKEN: - return MaterialLineEdit.ERROR - case WizardView.FREE: - return MaterialLineEdit.RIGHT - case WizardView.SEARCHING: - return MaterialLineEdit.SEARCHING - } - } } Label { @@ -162,13 +145,13 @@ Rectangle { text: { switch(nameRegistrationUIState){ - case WizardView.BLANK: - case WizardView.SEARCHING: - case WizardView.FREE: + case UsernameLineEdit.NameRegistrationState.BLANK: + case UsernameLineEdit.NameRegistrationState.SEARCHING: + case UsernameLineEdit.NameRegistrationState.FREE: return "" - case WizardView.INVALID: + case UsernameLineEdit.NameRegistrationState.INVALID: return qsTr("Invalid username") - case WizardView.TAKEN: + case UsernameLineEdit.NameRegistrationState.TAKEN: return qsTr("Username already taken") } } @@ -184,14 +167,15 @@ Rectangle { Layout.preferredHeight: preferredHeight text: qsTr("CHOOSE USERNAME") - enabled: nameRegistrationUIState === WizardView.FREE - color: nameRegistrationUIState === WizardView.FREE ? JamiTheme.wizardBlueButtons : - JamiTheme.buttonTintedGreyInactive + enabled: nameRegistrationUIState === UsernameLineEdit.NameRegistrationState.FREE + color: nameRegistrationUIState === UsernameLineEdit.NameRegistrationState.FREE ? + JamiTheme.wizardBlueButtons : + JamiTheme.buttonTintedGreyInactive hoveredColor: JamiTheme.buttonTintedBlueHovered pressedColor: JamiTheme.buttonTintedBluePressed onClicked: { - if (nameRegistrationUIState === WizardView.FREE) + if (nameRegistrationUIState === UsernameLineEdit.NameRegistrationState.FREE) createAccountStack.currentIndex = createAccountStack.currentIndex + 1 } } -- GitLab