diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index a1fbfa41..4cb9eb10 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -17,6 +17,7 @@ ApplicationWindow {
minimumHeight: 420
palette: colors
color: colors.window
+ title: profile.isGlobalUserProfile ? "Global User Profile" : "Room User Profile"
Shortcut {
sequence: StandardKey.Cancel
@@ -40,13 +41,42 @@ ApplicationWindow {
onClicked: TimelineManager.openImageOverlay(TimelineManager.timeline.avatarUrl(userid), TimelineManager.timeline.data.id)
}
- Label {
+ TextInput {
+ id: displayUsername
+
+ property bool isUsernameEditingAllowed
+
+ readOnly: !isUsernameEditingAllowed
text: profile.displayName
- fontSizeMode: Text.HorizontalFit
font.pixelSize: 20
color: TimelineManager.userColor(profile.userid, colors.window)
font.bold: true
Layout.alignment: Qt.AlignHCenter
+ selectByMouse: true
+
+ onAccepted: {
+ profile.changeUsername(displayUsername.text)
+ displayUsername.isUsernameEditingAllowed = false
+ }
+
+ ImageButton {
+ visible: profile.isSelf
+ anchors.leftMargin: 5
+ anchors.left: displayUsername.right
+ anchors.verticalCenter: displayUsername.verticalCenter
+ image: displayUsername.isUsernameEditingAllowed ? ":/icons/icons/ui/checkmark.png" : ":/icons/icons/ui/edit.png"
+
+ onClicked: {
+ if (displayUsername.isUsernameEditingAllowed) {
+ profile.changeUsername(displayUsername.text)
+ displayUsername.isUsernameEditingAllowed = false
+ } else {
+ displayUsername.isUsernameEditingAllowed = true
+ displayUsername.focus = true
+ displayUsername.selectAll()
+ }
+ }
+ }
}
MatrixText {
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 4e472a3a..07ed3941 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -111,7 +111,11 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
connect(sidebarActions_, &SideBarActions::joinRoom, this, &ChatPage::joinRoom);
connect(sidebarActions_, &SideBarActions::createRoom, this, &ChatPage::createRoom);
- user_info_widget_ = new UserInfoWidget(sideBar_);
+ user_info_widget_ = new UserInfoWidget(sideBar_);
+ connect(user_info_widget_, &UserInfoWidget::openGlobalUserProfile, this, [this]() {
+ view_manager_->activeTimeline()->openUserProfile(utils::localUser(), true);
+ });
+
user_mentions_popup_ = new popups::UserMentions();
room_list_ = new RoomList(userSettings, sideBar_);
connect(room_list_, &RoomList::joinRoom, this, &ChatPage::joinRoom);
diff --git a/src/UserInfoWidget.cpp b/src/UserInfoWidget.cpp
index f8e94431..5bcb44a9 100644
--- a/src/UserInfoWidget.cpp
+++ b/src/UserInfoWidget.cpp
@@ -125,6 +125,10 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
ChatPage::instance()->setStatus(text);
});
+ auto userProfileAction = menu->addAction(tr("User Profile Settings"));
+ connect(
+ userProfileAction, &QAction::triggered, this, [this]() { emit openGlobalUserProfile(); });
+
#if 0 // disable presence menu until issues in synapse are resolved
auto setAutoPresence = menu->addAction(tr("Set presence automatically"));
connect(setAutoPresence, &QAction::triggered, this, []() {
diff --git a/src/UserInfoWidget.h b/src/UserInfoWidget.h
index 03ab2cf0..bfcfbc0b 100644
--- a/src/UserInfoWidget.h
+++ b/src/UserInfoWidget.h
@@ -51,6 +51,9 @@ protected:
void paintEvent(QPaintEvent *event) override;
void contextMenuEvent(QContextMenuEvent *) override;
+signals:
+ void openGlobalUserProfile();
+
private:
Avatar *userAvatar_;
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 4346b0b2..79cf5184 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -799,9 +799,9 @@ TimelineModel::viewDecryptedRawMessage(QString id) const
}
void
-TimelineModel::openUserProfile(QString userid)
+TimelineModel::openUserProfile(QString userid, bool global)
{
- emit openProfile(new UserProfile(room_id_, userid, manager_, this));
+ emit openProfile(new UserProfile(global ? "" : room_id_, userid, manager_, this));
}
void
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 35e62eb4..51b8049e 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -212,7 +212,7 @@ public:
Q_INVOKABLE void viewRawMessage(QString id) const;
Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
- Q_INVOKABLE void openUserProfile(QString userid);
+ Q_INVOKABLE void openUserProfile(QString userid, bool global = false);
Q_INVOKABLE void replyAction(QString id);
Q_INVOKABLE void readReceiptsAction(QString id) const;
Q_INVOKABLE void redactEvent(QString id);
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 08219a38..3872294a 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -7,6 +7,8 @@
#include "mtx/responses/crypto.hpp"
#include "timeline/TimelineModel.h"
#include "timeline/TimelineViewManager.h"
+#include <mtx/responses.hpp>
+#include <mtx/responses/common.hpp>
UserProfile::UserProfile(QString roomid,
QString userid,
@@ -44,6 +46,23 @@ UserProfile::UserProfile(QString roomid,
}
deviceList_.reset(deviceList_.deviceList_);
});
+
+ connect(this,
+ &UserProfile::globalUsernameRetrieved,
+ this,
+ &UserProfile::setGlobalUsername,
+ Qt::QueuedConnection);
+
+ http::client()->get_profile(
+ userid_.toStdString(),
+ [this](const mtx::responses::Profile &res, mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn("failed to retrieve own profile info");
+ return;
+ }
+
+ emit globalUsernameRetrieved(QString::fromStdString(res.display_name));
+ });
}
QHash<int, QByteArray>
@@ -97,7 +116,7 @@ UserProfile::userid()
QString
UserProfile::displayName()
{
- return cache::displayName(roomid_, userid_);
+ return isGlobalUserProfile() ? globalUsername : cache::displayName(roomid_, userid_);
}
QString
@@ -107,6 +126,12 @@ UserProfile::avatarUrl()
}
bool
+UserProfile::isGlobalUserProfile() const
+{
+ return roomid_ == "";
+}
+
+bool
UserProfile::getUserStatus()
{
return isUserVerified;
@@ -214,6 +239,40 @@ UserProfile::startChat()
}
void
+UserProfile::changeUsername(QString username)
+{
+ if (isGlobalUserProfile()) {
+ // change global
+ http::client()->set_displayname(
+ username.toStdString(), [this](mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn("could not change username");
+ return;
+ }
+ });
+ } else {
+ // change room username
+ mtx::events::state::Member member;
+ member.display_name = username.toStdString();
+ member.avatar_url =
+ cache::avatarUrl(roomid_,
+ QString::fromStdString(http::client()->user_id().to_string()))
+ .toStdString();
+ member.membership = mtx::events::state::Membership::Join;
+
+ http::client()->send_state_event(
+ roomid_.toStdString(),
+ http::client()->user_id().to_string(),
+ member,
+ [](mtx::responses::EventId, mtx::http::RequestErr err) {
+ if (err)
+ nhlog::net()->error("Failed to set room displayname: {}",
+ err->matrix_error.error);
+ });
+ }
+}
+
+void
UserProfile::verify(QString device)
{
if (!device.isEmpty())
@@ -228,3 +287,10 @@ UserProfile::unverify(QString device)
{
cache::markDeviceUnverified(userid_.toStdString(), device.toStdString());
}
+
+void
+UserProfile::setGlobalUsername(const QString &globalUser)
+{
+ globalUsername = globalUser;
+ emit displayNameChanged();
+}
\ No newline at end of file
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 19527310..11f588b6 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -79,10 +79,11 @@ private:
class UserProfile : public QObject
{
Q_OBJECT
- Q_PROPERTY(QString displayName READ displayName CONSTANT)
+ Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
Q_PROPERTY(QString userid READ userid CONSTANT)
Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
+ Q_PROPERTY(bool isGlobalUserProfile READ isGlobalUserProfile CONSTANT)
Q_PROPERTY(bool isUserVerified READ getUserStatus NOTIFY userStatusChanged)
Q_PROPERTY(
bool userVerificationEnabled READ userVerificationEnabled NOTIFY userStatusChanged)
@@ -98,6 +99,7 @@ public:
QString userid();
QString displayName();
QString avatarUrl();
+ bool isGlobalUserProfile() const;
bool getUserStatus();
bool userVerificationEnabled() const;
bool isSelf() const;
@@ -109,12 +111,19 @@ public:
// Q_INVOKABLE void ignoreUser();
Q_INVOKABLE void kickUser();
Q_INVOKABLE void startChat();
+ Q_INVOKABLE void changeUsername(QString username);
signals:
void userStatusChanged();
+ void displayNameChanged();
+ void globalUsernameRetrieved(const QString &globalUser);
+
+protected slots:
+ void setGlobalUsername(const QString &globalUser);
private:
QString roomid_, userid_;
+ QString globalUsername;
DeviceInfoModel deviceList_;
bool isUserVerified = false;
bool hasMasterKey = false;
|