Port login to FormCard

This commit is contained in:
Tobias Fella
2023-08-27 09:54:12 +00:00
parent 96582a12bc
commit dbc10685f0
10 changed files with 205 additions and 178 deletions

View File

@@ -87,7 +87,11 @@ void Login::init()
Q_EMIT isLoggingInChanged();
});
connect(m_connection, &Connection::loginError, this, [this](QString error, const QString &) {
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
if (error == QStringLiteral("Invalid username or password")) {
setInvalidPassword(true);
} else {
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
}
m_isLoggingIn = false;
Q_EMIT isLoggingInChanged();
});
@@ -133,6 +137,7 @@ QString Login::password() const
void Login::setPassword(const QString &password)
{
setInvalidPassword(false);
m_password = password;
Q_EMIT passwordChanged();
}
@@ -199,4 +204,15 @@ bool Login::isLoggedIn() const
return m_isLoggedIn;
}
void Login::setInvalidPassword(bool invalid)
{
m_invalidPassword = invalid;
Q_EMIT isInvalidPasswordChanged();
}
bool Login::isInvalidPassword() const
{
return m_invalidPassword;
}
#include "moc_login.cpp"

View File

@@ -73,6 +73,11 @@ class Login : public QObject
*/
Q_PROPERTY(bool isLoggedIn READ isLoggedIn NOTIFY isLoggedInChanged)
/**
* @brief Whether the password (or the username) is invalid.
*/
Q_PROPERTY(bool isInvalidPassword READ isInvalidPassword NOTIFY isInvalidPasswordChanged)
public:
explicit Login(QObject *parent = nullptr);
@@ -100,6 +105,9 @@ public:
bool isLoggedIn() const;
bool isInvalidPassword() const;
void setInvalidPassword(bool invalid);
Q_INVOKABLE void login();
Q_INVOKABLE void loginWithSso();
@@ -116,6 +124,7 @@ Q_SIGNALS:
void testingChanged();
void isLoggingInChanged();
void isLoggedInChanged();
void isInvalidPasswordChanged();
private:
void setHomeserverReachable(bool reachable);
@@ -131,4 +140,5 @@ private:
bool m_testing = false;
bool m_isLoggingIn = false;
bool m_isLoggedIn = false;
bool m_invalidPassword = false;
};

View File

@@ -6,16 +6,19 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
Kirigami.LoadingPlaceholder {
property var showContinueButton: false
property var showBackButton: false
QQC2.Label {
LoginStep {
id: root
FormCard.FormTextDelegate {
text: i18n("Please wait. This might take a little while.")
}
FormCard.AbstractFormDelegate {
contentItem: QQC2.BusyIndicator {}
background: null
}
Connections {
target: Controller

View File

@@ -7,43 +7,34 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
LoginStep {
id: login
id: root
showContinueButton: true
showBackButton: false
title: i18nc("@title", "Login")
message: i18n("Enter your Matrix ID")
onActiveFocusChanged: if (activeFocus) matrixIdField.forceActiveFocus()
Component.onCompleted: {
LoginHelper.matrixId = ""
}
Kirigami.FormLayout {
QQC2.TextField {
id: matrixIdField
Kirigami.FormData.label: i18n("Matrix ID:")
placeholderText: "@user:matrix.org"
Accessible.name: i18n("Matrix ID")
onTextChanged: {
LoginHelper.matrixId = text
}
FormCard.FormTextFieldDelegate {
id: matrixIdField
label: i18n("Matrix ID:")
placeholderText: "@user:example.org"
Accessible.name: i18n("Matrix ID")
onTextChanged: {
LoginHelper.matrixId = text
}
Component.onCompleted: {
matrixIdField.forceActiveFocus()
}
Keys.onReturnPressed: {
login.action.trigger()
}
Keys.onReturnPressed: {
root.action.trigger()
}
}
action: Kirigami.Action {
nextAction: Kirigami.Action {
text: LoginHelper.isLoggedIn ? i18n("Already logged in") : (LoginHelper.testing && matrixIdField.acceptableInput) ? i18n("Loading…") : i18nc("@action:button", "Continue")
onTriggered: {
if (LoginHelper.supportsSso && LoginHelper.supportsPassword) {
@@ -56,4 +47,10 @@ LoginStep {
}
enabled: LoginHelper.homeserverReachable
}
// TODO: enable once we have registration
// previousAction: Kirigami.Action {
// onTriggered: {
// root.processed("qrc:/Login.qml")
// }
// }
}

View File

@@ -4,28 +4,26 @@
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
LoginStep {
id: loginMethod
id: root
title: i18n("Login Methods")
onActiveFocusChanged: if (activeFocus) loginPasswordButton.forceActiveFocus()
Layout.alignment: Qt.AlignHCenter
QQC2.Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Login with password")
Layout.preferredWidth: Kirigami.Units.gridUnit * 12
FormCard.FormButtonDelegate {
id: loginPasswordButton
text: i18nc("@action:button", "Login with password")
onClicked: processed("qrc:/Password.qml")
}
QQC2.Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Login with single sign-on")
Layout.preferredWidth: Kirigami.Units.gridUnit * 12
FormCard.FormButtonDelegate {
id: loginSsoButton
text: i18nc("@action:button", "Login with single sign-on")
onClicked: processed("qrc:/Sso.qml")
}
}

View File

@@ -6,25 +6,22 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
LoginStep {
id: loginRegister
id: root
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
QQC2.Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Login")
Layout.preferredWidth: Kirigami.Units.gridUnit * 12
onClicked: processed("qrc:/Login.qml")
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Login")
onClicked: root.processed("qrc:/Login.qml")
}
QQC2.Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Register")
Layout.preferredWidth: Kirigami.Units.gridUnit * 12
onClicked: processed("qrc:/Homeserver.qml")
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Register")
onClicked: root.processed("qrc:/Homeserver.qml")
}
}

View File

@@ -7,21 +7,25 @@ import QtQuick.Layouts 1.14
/// Step for the login/registration flow
ColumnLayout {
id: root
property string title: i18n("Welcome")
property string message: i18n("Welcome")
property bool showContinueButton: false
property bool showBackButton: false
property bool acceptable: false
property string previousUrl: ""
/// Set to true if the login step does not have any controls. This will ensure that the focus remains on the "continue" button
property bool noControls: false
/// Process this module, this is called by the continue button.
/// Should call \sa processed when it finish successfully.
property QQC2.Action action: null
property QQC2.Action nextAction: null
/// Go to the previous module. This is called by the "go back" button.
/// If no "go back" button should be shown, this should be null.
property QQC2.Action previousAction: null
/// Called when switching to the next step.
signal processed(url nextUrl)
/// Show a message in a banner at the top of the page.
signal showMessage(string message)
signal clearError()
}

View File

@@ -6,25 +6,12 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
LoginStep {
id: password
title: i18nc("@title", "Password")
message: i18n("Enter your password")
showContinueButton: true
showBackButton: true
previousUrl: LoginHelper.isLoggingIn ? "" : LoginHelper.supportsSso ? "qrc:/LoginMethod.qml" : "qrc:/Login.qml"
action: Kirigami.Action {
text: i18nc("@action:button", "Login")
enabled: passwordField.text.length > 0 && !LoginHelper.isLoggingIn
onTriggered: {
LoginHelper.login();
}
}
id: root
Connections {
target: LoginHelper
@@ -33,20 +20,32 @@ LoginStep {
}
}
Kirigami.FormLayout {
Kirigami.PasswordField {
id: passwordField
onTextChanged: LoginHelper.password = text
enabled: !LoginHelper.isLoggingIn
Accessible.name: i18n("Password")
onActiveFocusChanged: if(activeFocus) passwordField.forceActiveFocus()
Component.onCompleted: {
passwordField.forceActiveFocus()
}
FormCard.FormTextFieldDelegate {
id: passwordField
Keys.onReturnPressed: {
password.action.trigger()
}
label: i18n("Password:")
onTextChanged: LoginHelper.password = text
enabled: !LoginHelper.isLoggingIn
echoMode: TextInput.Password
Accessible.name: i18n("Password")
statusMessage: LoginHelper.isInvalidPassword ? i18n("Invalid username or password") : ""
Keys.onReturnPressed: {
root.action.trigger()
}
}
nextAction: Kirigami.Action {
text: i18nc("@action:button", "Login")
enabled: passwordField.text.length > 0 && !LoginHelper.isLoggingIn
onTriggered: {
root.clearError()
LoginHelper.login();
}
}
previousAction: Kirigami.Action {
onTriggered: processed("qrc:/Login.qml")
}
}

View File

@@ -6,47 +6,38 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.12 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
LoginStep {
id: root
title: i18nc("@title", "Login")
message: i18n("Login with single sign-on")
noControls: true
Kirigami.FormLayout {
Connections {
target: LoginHelper
function onSsoUrlChanged() {
UrlHelper.openUrl(LoginHelper.ssoUrl)
root.showMessage(i18n("Complete the authentication steps in your browser"))
loginButton.enabled = true
loginButton.text = i18n("Login")
}
function onConnected() {
processed("qrc:/Loading.qml")
}
Component.onCompleted: LoginHelper.loginWithSso()
Connections {
target: LoginHelper
function onSsoUrlChanged() {
UrlHelper.openUrl(LoginHelper.ssoUrl)
}
RowLayout {
QQC2.Button {
text: i18nc("@action:button", "Back")
onClicked: {
module.source = "qrc:/Login.qml"
}
}
QQC2.Button {
id: loginButton
text: i18n("Login")
onClicked: {
LoginHelper.loginWithSso()
loginButton.enabled = false
loginButton.text = i18n("Loading…")
}
Component.onCompleted: forceActiveFocus()
Keys.onReturnPressed: clicked()
}
function onConnected() {
processed("qrc:/Loading.qml")
}
}
FormCard.FormTextDelegate {
text: i18n("Continue the login process in your browser.")
}
previousAction: Kirigami.Action {
onTriggered: processed("qrc:/Login.qml")
}
nextAction: Kirigami.Action {
text: i18nc("@action:button", "Re-open SSO URL")
onTriggered: UrlHelper.openUrl(LoginHelper.ssoUrl)
}
}

View File

@@ -6,15 +6,16 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.neochat 1.0
Kirigami.ScrollablePage {
id: welcomePage
FormCard.FormCardPage {
id: root
property alias currentStep: module.item
title: module.item.title ?? i18n("Welcome")
title: i18n("Welcome")
header: QQC2.Control {
contentItem: Kirigami.InlineMessage {
@@ -25,79 +26,90 @@ Kirigami.ScrollablePage {
}
}
Component.onCompleted: LoginHelper.init()
FormCard.FormCard {
id: contentCard
Connections {
target: LoginHelper
function onErrorOccured(message) {
headerMessage.text = message;
headerMessage.visible = true;
headerMessage.type = Kirigami.MessageType.Error;
FormCard.AbstractFormDelegate {
contentItem: Kirigami.Icon {
source: "org.kde.neochat"
Layout.fillWidth: true
Layout.preferredHeight: Kirigami.Units.gridUnit * 16
}
background: Item {}
onActiveFocusChanged: if (activeFocus) module.item.forceActiveFocus()
}
}
Connections {
target: Controller
function onInitiated() {
pageStack.layers.pop();
FormCard.FormTextDelegate {
id: welcomeMessage
text: AccountRegistry.accountCount > 0 ? i18n("Log in to a different account.") : i18n("Welcome to NeoChat! Continue by logging in.")
}
}
ColumnLayout {
Kirigami.Icon {
source: "org.kde.neochat"
Layout.fillWidth: true
Layout.preferredHeight: Kirigami.Units.gridUnit * 16
}
QQC2.Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 25
text: module.item.message ?? module.item.title ?? i18n("Welcome to Matrix")
FormCard.FormDelegateSeparator {
above: welcomeMessage
}
Loader {
id: module
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
source: "qrc:/Login.qml"
onSourceChanged: {
headerMessage.visible = false
headerMessage.text = ""
}
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
QQC2.Button {
text: i18nc("@action:button", "Back")
Connections {
target: currentStep
enabled: welcomePage.currentStep.previousUrl !== ""
visible: welcomePage.currentStep.showBackButton
Layout.alignment: Qt.AlignHCenter
onClicked: {
module.source = welcomePage.currentStep.previousUrl
function onProcessed(nextUrl) {
module.source = nextUrl;
headerMessage.text = "";
headerMessage.visible = false;
if (!module.item.noControls) {
module.item.forceActiveFocus()
} else {
continueButton.forceActiveFocus()
}
}
function onShowMessage(message) {
headerMessage.text = message;
headerMessage.visible = true;
headerMessage.type = Kirigami.MessageType.Information;
}
function onClearError() {
headerMessage.text = "";
headerMessage.visible = false;
}
}
QQC2.Button {
id: continueButton
enabled: welcomePage.currentStep.acceptable
visible: welcomePage.currentStep.showContinueButton
action: welcomePage.currentStep.action
Connections {
target: LoginHelper
function onErrorOccured(message) {
headerMessage.text = message;
headerMessage.visible = message.length > 0;
headerMessage.type = Kirigami.MessageType.Error;
}
}
}
Connections {
target: currentStep
FormCard.FormDelegateSeparator {
below: continueButton
}
function onProcessed(nextUrl) {
module.source = nextUrl;
}
function onShowMessage(message) {
headerMessage.text = message;
headerMessage.visible = true;
headerMessage.type = Kirigami.MessageType.Information;
}
FormCard.FormButtonDelegate {
id: continueButton
text: root.currentStep.nextAction ? root.currentStep.nextAction.text : i18nc("@action:button", "Continue")
visible: root.currentStep.nextAction
onClicked: root.currentStep.nextAction.trigger()
icon.name: "arrow-right"
enabled: root.currentStep.nextAction ? root.currentStep.nextAction.enabled : false
}
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Go back")
visible: root.currentStep.previousAction
onClicked: root.currentStep.previousAction.trigger()
icon.name: "arrow-left"
enabled: root.currentStep.previousAction ? root.currentStep.previousAction.enabled : false
}
}
Component.onCompleted: {
LoginHelper.init()
module.item.forceActiveFocus()
}
}