Add accounts management page
This commit is contained in:
134
qml/AccountsPage.qml
Normal file
134
qml/AccountsPage.qml
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
|
||||
*
|
||||
* SPDX-LicenseIdentifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
|
||||
import Spectral 0.1
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
title: i18n("Accounts")
|
||||
|
||||
ListView {
|
||||
model: AccountListModel { }
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
Kirigami.BasicListItem {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
text: model.user.defaultName
|
||||
subtitle: model.user.id
|
||||
icon: model.connection.user.avatarMediaId ? "image://mxc/" + model.connection.user.avatarMediaId : "im-user"
|
||||
|
||||
onClicked: {
|
||||
Controller.connection = model.connection
|
||||
pageStack.layers.pop()
|
||||
}
|
||||
}
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Edit this account")
|
||||
iconName: "document-edit"
|
||||
onTriggered: {
|
||||
userEditSheet.connection = model.connection
|
||||
userEditSheet.open()
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Logout")
|
||||
iconName: "im-kick-user"
|
||||
onTriggered: {
|
||||
Controller.logout(model.connection)
|
||||
if(Controller.accountCount === 1)
|
||||
pageStack.layers.pop()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Controller
|
||||
function onConnectionAdded() {
|
||||
if (pageStack.layers.depth > 2)
|
||||
pageStack.layers.pop()
|
||||
}
|
||||
function onPasswordStatus(status) {
|
||||
if(status == Controller.Success)
|
||||
showPassiveNotification(i18n("Password changed successfully"))
|
||||
else if(status == Controller.Wrong)
|
||||
showPassiveNotification(i18n("Wrong password entered"))
|
||||
else
|
||||
showPassiveNotification(i18n("Unknown problem while trying to change password"))
|
||||
}
|
||||
}
|
||||
|
||||
actions.main: Kirigami.Action {
|
||||
text: i18n("Add an account")
|
||||
iconName: "list-add-user"
|
||||
onTriggered: pageStack.layers.push("qrc:/qml/LoginPage.qml")
|
||||
}
|
||||
|
||||
Kirigami.OverlaySheet {
|
||||
id: userEditSheet
|
||||
|
||||
property var connection
|
||||
|
||||
header: Kirigami.Heading {
|
||||
text: i18n("Edit Account")
|
||||
}
|
||||
|
||||
Kirigami.FormLayout {
|
||||
anchors.top: passwordsMessage.bottom
|
||||
Controls.TextField {
|
||||
id: name
|
||||
text: userEditSheet.connection.localUser.defaultName
|
||||
Kirigami.FormData.label: i18n("Name:")
|
||||
}
|
||||
Controls.TextField {
|
||||
id: currentPassword
|
||||
Kirigami.FormData.label: i18n("Current Password:")
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
Controls.TextField {
|
||||
id: newPassword
|
||||
Kirigami.FormData.label: i18n("New Password:")
|
||||
echoMode: TextInput.Password
|
||||
|
||||
}
|
||||
Controls.TextField {
|
||||
id: confirmPassword
|
||||
Kirigami.FormData.label: i18n("Confirm new Password:")
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: i18n("Save")
|
||||
onClicked: {
|
||||
if(userEditSheet.connection.localUser.defaultName !== name.text)
|
||||
userEditSheet.connection.localUser.user.defaultName = name.text
|
||||
if(currentPassword.text !== "" && newPassword.text !== "" && confirmPassword.text !== "") {
|
||||
if(newPassword.text === confirmPassword.text) {
|
||||
Controller.changePassword(userEditSheet.connection, currentPassword.text, newPassword.text)
|
||||
} else {
|
||||
showPassiveNotification(i18n("Passwords do not match"))
|
||||
return
|
||||
}
|
||||
}
|
||||
userEditSheet.close()
|
||||
currentPassword.text = ""
|
||||
newPassword.text = ""
|
||||
confirmPassword.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
qml/main.qml
12
qml/main.qml
@@ -33,6 +33,12 @@ Kirigami.ApplicationWindow {
|
||||
iconName: "help-about"
|
||||
onTriggered: pageStack.layers.push(aboutPage)
|
||||
enabled: pageStack.layers.currentItem.title !== i18n("About")
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Accounts")
|
||||
iconName: "im-user"
|
||||
onTriggered: pageStack.layers.push("qrc:/qml/AccountsPage.qml")
|
||||
enabled: pageStack.layers.currentItem.title !== i18n("Accounts")
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -82,6 +88,12 @@ Kirigami.ApplicationWindow {
|
||||
pageStack.replace(roomListComponent);
|
||||
}
|
||||
}
|
||||
|
||||
onConnectionDropped: {
|
||||
if(Controller.accountCount === 0)
|
||||
pageStack.replace("qrc:/qml/LoginPage.qml")
|
||||
}
|
||||
|
||||
onErrorOccured: showPassiveNotification(error + ": " + detail)
|
||||
}
|
||||
|
||||
|
||||
1
res.qrc
1
res.qrc
@@ -7,6 +7,7 @@
|
||||
<file>qml/RoomPage.qml</file>
|
||||
<file>qml/ChatTextInput.qml</file>
|
||||
<file>qml/RoomListContextMenu.qml</file>
|
||||
<file>qml/AccountsPage.qml</file>
|
||||
<file>imports/Spectral/Component/Emoji/EmojiPicker.qml</file>
|
||||
<file>imports/Spectral/Component/Emoji/qmldir</file>
|
||||
<file>imports/Spectral/Component/Timeline/MessageDelegate.qml</file>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "csapi/joining.h"
|
||||
#include "csapi/logout.h"
|
||||
#include "csapi/profile.h"
|
||||
#include "csapi/registration.h"
|
||||
#include "events/eventcontent.h"
|
||||
#include "events/roommessageevent.h"
|
||||
#include "settings.h"
|
||||
@@ -173,6 +174,8 @@ void Controller::logout(Connection *conn)
|
||||
Q_EMIT conn->loggedOut();
|
||||
if (!m_connections.isEmpty())
|
||||
setConnection(m_connections[0]);
|
||||
else
|
||||
setConnection(nullptr);
|
||||
});
|
||||
connect(logoutJob, &LogoutJob::failure, this, [=] {
|
||||
Q_EMIT errorOccured("Server-side Logout Failed", logoutJob->errorString());
|
||||
@@ -424,3 +427,44 @@ KAboutData Controller::aboutData() const
|
||||
{
|
||||
return m_aboutData;
|
||||
}
|
||||
|
||||
void Controller::changePassword(Connection *connection, const QString ¤tPassword, const QString &newPassword)
|
||||
{
|
||||
NeochatChangePasswordJob *job = connection->callApi<NeochatChangePasswordJob>(newPassword, false);
|
||||
connect(job, &BaseJob::result, this, [this, job, currentPassword, newPassword, connection] {
|
||||
if(job->error() == 103) {
|
||||
QJsonObject replyData = job->jsonData();
|
||||
QJsonObject authData;
|
||||
authData["session"] = replyData["session"];
|
||||
authData["password"] = currentPassword;
|
||||
authData["type"] = "m.login.password";
|
||||
authData["user"] = connection->user()->id();
|
||||
QJsonObject identifier = {{"type", "m.id.user"}, {"user", connection->user()->id()}};
|
||||
authData["identifier"] = identifier;
|
||||
NeochatChangePasswordJob *innerJob = connection->callApi<NeochatChangePasswordJob>(newPassword, false, authData);
|
||||
connect(innerJob, &BaseJob::success, this, [this]() {
|
||||
Q_EMIT passwordStatus(PasswordStatus::Success);
|
||||
});
|
||||
connect(innerJob, &BaseJob::failure, this, [innerJob, this] () {
|
||||
if(innerJob->jsonData()["errcode"] == "M_FORBIDDEN") {
|
||||
Q_EMIT passwordStatus(PasswordStatus::Wrong);
|
||||
} else {
|
||||
Q_EMIT passwordStatus(PasswordStatus::Other);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString& newPassword,
|
||||
bool logoutDevices,
|
||||
const Omittable<QJsonObject>& auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"),
|
||||
QStringLiteral("/_matrix/client/r0") % "/account/password")
|
||||
{
|
||||
QJsonObject _data;
|
||||
addParam<>(_data, QStringLiteral("new_password"), newPassword);
|
||||
addParam<IfNotEmpty>(_data, QStringLiteral("logout_devices"), logoutDevices);
|
||||
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
|
||||
setRequestData(std::move(_data));
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
Q_INVOKABLE void loginWithCredentials(QString, QString, QString, QString);
|
||||
Q_INVOKABLE void loginWithAccessToken(QString, QString, QString, QString);
|
||||
|
||||
Q_INVOKABLE void changePassword(Connection *connection, const QString ¤tPassword, const QString &newPassword);
|
||||
|
||||
QVector<Connection *> connections() const
|
||||
{
|
||||
return m_connections;
|
||||
@@ -108,6 +110,13 @@ public:
|
||||
void setAboutData(KAboutData aboutData);
|
||||
KAboutData aboutData() const;
|
||||
|
||||
enum PasswordStatus {
|
||||
Success,
|
||||
Wrong,
|
||||
Other
|
||||
};
|
||||
Q_ENUM(PasswordStatus);
|
||||
|
||||
private:
|
||||
explicit Controller(QObject *parent = nullptr);
|
||||
~Controller();
|
||||
@@ -143,6 +152,7 @@ Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
void isOnlineChanged();
|
||||
void aboutDataChanged();
|
||||
void passwordStatus(PasswordStatus status);
|
||||
|
||||
public Q_SLOTS:
|
||||
void logout(Quotient::Connection *conn);
|
||||
@@ -154,4 +164,12 @@ public Q_SLOTS:
|
||||
void markAllMessagesAsRead(Quotient::Connection *conn);
|
||||
};
|
||||
|
||||
//TODO libQuotient 0.7: Drop
|
||||
class NeochatChangePasswordJob : public BaseJob {
|
||||
public:
|
||||
explicit NeochatChangePasswordJob(const QString& newPassword,
|
||||
bool logoutDevices,
|
||||
const Omittable<QJsonObject>& auth = none);
|
||||
};
|
||||
|
||||
#endif // CONTROLLER_H
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
#include "spectraluser.h"
|
||||
|
||||
#include "csapi/profile.h"
|
||||
|
||||
QColor SpectralUser::color()
|
||||
{
|
||||
return QColor::fromHslF(hueF(), 0.7, 0.5, 1);
|
||||
}
|
||||
//TODO libQuotient 0.7: remove default name
|
||||
void SpectralUser::setDefaultName(QString defaultName)
|
||||
{
|
||||
rename(defaultName);
|
||||
connect(this, &Quotient::User::defaultNameChanged, this, [this]() {
|
||||
m_defaultName = "";
|
||||
qDebug() << "asdf";
|
||||
Q_EMIT nameChanged();
|
||||
});
|
||||
}
|
||||
|
||||
QString SpectralUser::defaultName()
|
||||
{
|
||||
if(m_defaultName.isEmpty()) {
|
||||
GetDisplayNameJob *job = connection()->callApi<GetDisplayNameJob>(id());
|
||||
connect(job, &BaseJob::success, this, [this, job] {
|
||||
if(job->displayname().isEmpty())
|
||||
m_defaultName = id();
|
||||
else
|
||||
m_defaultName = job->displayname();
|
||||
Q_EMIT nameChanged();
|
||||
});
|
||||
}
|
||||
return m_defaultName;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ class SpectralUser : public User
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor color READ color CONSTANT)
|
||||
Q_PROPERTY(QString defaultName READ defaultName WRITE setDefaultName NOTIFY nameChanged)
|
||||
public:
|
||||
SpectralUser(QString userId, Connection *connection)
|
||||
: User(userId, connection)
|
||||
@@ -19,6 +20,16 @@ public:
|
||||
}
|
||||
|
||||
QColor color();
|
||||
|
||||
//TODO libQuotient 0.7: remove
|
||||
void setDefaultName(QString defaultName);
|
||||
QString defaultName();
|
||||
|
||||
Q_SIGNALS:
|
||||
void nameChanged();
|
||||
|
||||
private:
|
||||
QString m_defaultName;
|
||||
};
|
||||
|
||||
#endif // SpectralUser_H
|
||||
|
||||
Reference in New Issue
Block a user