mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-29 14:18:49 +03:00
shifted room avatar changing
This commit is contained in:
parent
473b14ed0f
commit
a7d7d18e92
5 changed files with 242 additions and 23 deletions
|
@ -33,12 +33,53 @@ ApplicationWindow {
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
url: ""
|
url: roomSettings.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
height: 130
|
height: 130
|
||||||
width: 130
|
width: 130
|
||||||
displayName: ""
|
|
||||||
userid: ""
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
onClicked: {
|
||||||
|
if(roomSettings.canChangeAvatar) {
|
||||||
|
roomSettings.updateAvatar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
running: roomSettings.isLoading
|
||||||
|
visible: roomSettings.isLoading
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: errorText
|
||||||
|
text: "Error Text"
|
||||||
|
color: "red"
|
||||||
|
visible: opacity > 0
|
||||||
|
opacity: 0
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: hideErrorAnimation
|
||||||
|
running: false
|
||||||
|
PauseAnimation {
|
||||||
|
duration: 4000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: errorText
|
||||||
|
property: 'opacity'
|
||||||
|
to: 0
|
||||||
|
duration: 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections{
|
||||||
|
target: roomSettings
|
||||||
|
onDisplayError: {
|
||||||
|
errorText.text = errorMessage
|
||||||
|
errorText.opacity = 1
|
||||||
|
hideErrorAnimation.restart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
|
@ -143,10 +143,10 @@ EditModal::applyClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace mtx::events;
|
using namespace mtx::events;
|
||||||
auto proxy = std::make_shared<ThreadProxy>();
|
auto proxy = std::make_shared<ThreadProxya>();
|
||||||
connect(proxy.get(), &ThreadProxy::topicEventSent, this, &EditModal::topicEventSent);
|
connect(proxy.get(), &ThreadProxya::topicEventSent, this, &EditModal::topicEventSent);
|
||||||
connect(proxy.get(), &ThreadProxy::nameEventSent, this, &EditModal::nameEventSent);
|
connect(proxy.get(), &ThreadProxya::nameEventSent, this, &EditModal::nameEventSent);
|
||||||
connect(proxy.get(), &ThreadProxy::error, this, &EditModal::error);
|
connect(proxy.get(), &ThreadProxya::error, this, &EditModal::error);
|
||||||
|
|
||||||
if (newName != initialName_ && !newName.isEmpty()) {
|
if (newName != initialName_ && !newName.isEmpty()) {
|
||||||
state::Name body;
|
state::Name body;
|
||||||
|
@ -810,9 +810,9 @@ RoomSettingsOld::updateAvatar()
|
||||||
|
|
||||||
// Events emitted from the http callbacks (different threads) will
|
// Events emitted from the http callbacks (different threads) will
|
||||||
// be queued back into the UI thread through this proxy object.
|
// be queued back into the UI thread through this proxy object.
|
||||||
auto proxy = std::make_shared<ThreadProxy>();
|
auto proxy = std::make_shared<ThreadProxya>();
|
||||||
connect(proxy.get(), &ThreadProxy::error, this, &RoomSettingsOld::displayErrorMessage);
|
connect(proxy.get(), &ThreadProxya::error, this, &RoomSettingsOld::displayErrorMessage);
|
||||||
connect(proxy.get(), &ThreadProxy::avatarChanged, this, &RoomSettingsOld::setAvatar);
|
connect(proxy.get(), &ThreadProxya::avatarChanged, this, &RoomSettingsOld::setAvatar);
|
||||||
|
|
||||||
const auto bin = file.peek(file.size());
|
const auto bin = file.peek(file.size());
|
||||||
const auto payload = std::string(bin.data(), bin.size());
|
const auto payload = std::string(bin.data(), bin.size());
|
||||||
|
|
|
@ -40,7 +40,7 @@ protected:
|
||||||
|
|
||||||
/// Convenience class which connects events emmited from threads
|
/// Convenience class which connects events emmited from threads
|
||||||
/// outside of main with the UI code.
|
/// outside of main with the UI code.
|
||||||
class ThreadProxy : public QObject
|
class ThreadProxya : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "RoomSettings.h"
|
#include "RoomSettings.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <QStandardPaths>
|
||||||
#include <mtx/responses/common.hpp>
|
#include <mtx/responses/common.hpp>
|
||||||
#include <mtx/responses/media.hpp>
|
#include <mtx/responses/media.hpp>
|
||||||
|
|
||||||
|
@ -84,6 +88,18 @@ RoomSettings::roomVersion() const
|
||||||
return QString::fromStdString(info_.version);
|
return QString::fromStdString(info_.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RoomSettings::isLoading() const
|
||||||
|
{
|
||||||
|
return isLoading_;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
RoomSettings::roomAvatarUrl()
|
||||||
|
{
|
||||||
|
return QString::fromStdString(info_.avatar_url);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
RoomSettings::memberCount() const
|
RoomSettings::memberCount() const
|
||||||
{
|
{
|
||||||
|
@ -96,7 +112,6 @@ RoomSettings::retrieveRoomInfo()
|
||||||
try {
|
try {
|
||||||
usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString());
|
usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString());
|
||||||
info_ = cache::singleRoomInfo(roomid_.toStdString());
|
info_ = cache::singleRoomInfo(roomid_.toStdString());
|
||||||
// setAvatar();
|
|
||||||
} catch (const lmdb::error &) {
|
} catch (const lmdb::error &) {
|
||||||
nhlog::db()->warn("failed to retrieve room info from cache: {}",
|
nhlog::db()->warn("failed to retrieve room info from cache: {}",
|
||||||
roomid_.toStdString());
|
roomid_.toStdString());
|
||||||
|
@ -143,9 +158,9 @@ RoomSettings::enableEncryption()
|
||||||
room_id,
|
room_id,
|
||||||
err->matrix_error.error,
|
err->matrix_error.error,
|
||||||
status_code);
|
status_code);
|
||||||
//emit enableEncryptionError(
|
emit displayError(
|
||||||
// tr("Failed to enable encryption: %1")
|
tr("Failed to enable encryption: %1")
|
||||||
// .arg(QString::fromStdString(err->matrix_error.error)));
|
.arg(QString::fromStdString(err->matrix_error.error)));
|
||||||
usesEncryption_ = false;
|
usesEncryption_ = false;
|
||||||
emit encryptionChanged();
|
emit encryptionChanged();
|
||||||
return;
|
return;
|
||||||
|
@ -172,6 +187,33 @@ RoomSettings::canChangeJoinRules() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RoomSettings::canChangeNameAndTopic() const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return cache::hasEnoughPowerLevel({EventType::RoomName, EventType::RoomTopic},
|
||||||
|
roomid_.toStdString(),
|
||||||
|
utils::localUser().toStdString());
|
||||||
|
} catch (const lmdb::error &e) {
|
||||||
|
nhlog::db()->warn("lmdb error: {}", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RoomSettings::canChangeAvatar() const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return cache::hasEnoughPowerLevel(
|
||||||
|
{EventType::RoomAvatar}, roomid_.toStdString(), utils::localUser().toStdString());
|
||||||
|
} catch (const lmdb::error &e) {
|
||||||
|
nhlog::db()->warn("lmdb error: {}", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RoomSettings::isEncryptionEnabled() const
|
RoomSettings::isEncryptionEnabled() const
|
||||||
{
|
{
|
||||||
|
@ -269,8 +311,8 @@ RoomSettings::updateAccessRules(const std::string &room_id,
|
||||||
const mtx::events::state::JoinRules &join_rule,
|
const mtx::events::state::JoinRules &join_rule,
|
||||||
const mtx::events::state::GuestAccess &guest_access)
|
const mtx::events::state::GuestAccess &guest_access)
|
||||||
{
|
{
|
||||||
// startLoadingSpinner();
|
isLoading_ = true;
|
||||||
// resetErrorLabel();
|
emit loadingChanged();
|
||||||
|
|
||||||
http::client()->send_state_event(
|
http::client()->send_state_event(
|
||||||
room_id,
|
room_id,
|
||||||
|
@ -281,8 +323,9 @@ RoomSettings::updateAccessRules(const std::string &room_id,
|
||||||
nhlog::net()->warn("failed to send m.room.join_rule: {} {}",
|
nhlog::net()->warn("failed to send m.room.join_rule: {} {}",
|
||||||
static_cast<int>(err->status_code),
|
static_cast<int>(err->status_code),
|
||||||
err->matrix_error.error);
|
err->matrix_error.error);
|
||||||
// emit showErrorMessage(QString::fromStdString(err->matrix_error.error));
|
emit displayError(QString::fromStdString(err->matrix_error.error));
|
||||||
|
isLoading_ = false;
|
||||||
|
emit loadingChanged();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,13 +337,115 @@ RoomSettings::updateAccessRules(const std::string &room_id,
|
||||||
nhlog::net()->warn("failed to send m.room.guest_access: {} {}",
|
nhlog::net()->warn("failed to send m.room.guest_access: {} {}",
|
||||||
static_cast<int>(err->status_code),
|
static_cast<int>(err->status_code),
|
||||||
err->matrix_error.error);
|
err->matrix_error.error);
|
||||||
// emit showErrorMessage(
|
emit displayError(
|
||||||
// QString::fromStdString(err->matrix_error.error));
|
QString::fromStdString(err->matrix_error.error));
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit signal that stops loading spinner and reset error label
|
isLoading_ = false;
|
||||||
|
emit loadingChanged();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomSettings::stopLoading()
|
||||||
|
{
|
||||||
|
isLoading_ = false;
|
||||||
|
emit loadingChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomSettings::avatarChanged()
|
||||||
|
{
|
||||||
|
retrieveRoomInfo();
|
||||||
|
emit avatarUrlChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomSettings::updateAvatar()
|
||||||
|
{
|
||||||
|
const QString picturesFolder =
|
||||||
|
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
|
||||||
|
const QString fileName = QFileDialog::getOpenFileName(
|
||||||
|
nullptr, tr("Select an avatar"), picturesFolder, tr("All Files (*)"));
|
||||||
|
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QMimeDatabase db;
|
||||||
|
QMimeType mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchContent);
|
||||||
|
|
||||||
|
const auto format = mime.name().split("/")[0];
|
||||||
|
|
||||||
|
QFile file{fileName, this};
|
||||||
|
if (format != "image") {
|
||||||
|
emit displayError(tr("The selected file is not an image"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
emit displayError(tr("Error while reading file: %1").arg(file.errorString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading_ = true;
|
||||||
|
emit loadingChanged();
|
||||||
|
|
||||||
|
// Events emitted from the http callbacks (different threads) will
|
||||||
|
// be queued back into the UI thread through this proxy object.
|
||||||
|
auto proxy = std::make_shared<ThreadProxy>();
|
||||||
|
connect(proxy.get(), &ThreadProxy::error, this, &RoomSettings::displayError);
|
||||||
|
connect(proxy.get(), &ThreadProxy::avatarChanged, this, &RoomSettings::avatarChanged);
|
||||||
|
connect(proxy.get(), &ThreadProxy::stopLoading, this, &RoomSettings::stopLoading);
|
||||||
|
|
||||||
|
const auto bin = file.peek(file.size());
|
||||||
|
const auto payload = std::string(bin.data(), bin.size());
|
||||||
|
const auto dimensions = QImageReader(&file).size();
|
||||||
|
|
||||||
|
// First we need to create a new mxc URI
|
||||||
|
// (i.e upload media to the Matrix content repository) for the new avatar.
|
||||||
|
http::client()->upload(
|
||||||
|
payload,
|
||||||
|
mime.name().toStdString(),
|
||||||
|
QFileInfo(fileName).fileName().toStdString(),
|
||||||
|
[proxy = std::move(proxy),
|
||||||
|
dimensions,
|
||||||
|
payload,
|
||||||
|
mimetype = mime.name().toStdString(),
|
||||||
|
size = payload.size(),
|
||||||
|
room_id = roomid_.toStdString(),
|
||||||
|
content = std::move(bin)](const mtx::responses::ContentURI &res,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
emit proxy->stopLoading();
|
||||||
|
emit proxy->error(
|
||||||
|
tr("Failed to upload image: %s")
|
||||||
|
.arg(QString::fromStdString(err->matrix_error.error)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace mtx::events;
|
||||||
|
state::Avatar avatar_event;
|
||||||
|
avatar_event.image_info.w = dimensions.width();
|
||||||
|
avatar_event.image_info.h = dimensions.height();
|
||||||
|
avatar_event.image_info.mimetype = mimetype;
|
||||||
|
avatar_event.image_info.size = size;
|
||||||
|
avatar_event.url = res.content_uri;
|
||||||
|
|
||||||
|
http::client()->send_state_event(
|
||||||
|
room_id,
|
||||||
|
avatar_event,
|
||||||
|
[content = std::move(content), proxy = std::move(proxy)](
|
||||||
|
const mtx::responses::EventId &, mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
emit proxy->error(
|
||||||
|
tr("Failed to upload image: %s")
|
||||||
|
.arg(QString::fromStdString(err->matrix_error.error)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit proxy->stopLoading();
|
||||||
|
emit proxy->avatarChanged();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -7,16 +7,34 @@
|
||||||
|
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
|
|
||||||
|
/// Convenience class which connects events emmited from threads
|
||||||
|
/// outside of main with the UI code.
|
||||||
|
class ThreadProxy : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void error(const QString &msg);
|
||||||
|
void avatarChanged();
|
||||||
|
void nameEventSent(const QString &);
|
||||||
|
void topicEventSent();
|
||||||
|
void stopLoading();
|
||||||
|
};
|
||||||
|
|
||||||
class RoomSettings : public QObject
|
class RoomSettings : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString roomName READ roomName CONSTANT)
|
Q_PROPERTY(QString roomName READ roomName CONSTANT)
|
||||||
Q_PROPERTY(QString roomId READ roomId CONSTANT)
|
Q_PROPERTY(QString roomId READ roomId CONSTANT)
|
||||||
Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT)
|
Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT)
|
||||||
|
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged)
|
||||||
Q_PROPERTY(int memberCount READ memberCount CONSTANT)
|
Q_PROPERTY(int memberCount READ memberCount CONSTANT)
|
||||||
Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged)
|
Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged)
|
||||||
Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged)
|
Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged)
|
||||||
|
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
|
||||||
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
|
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
|
||||||
|
Q_PROPERTY(bool canChangeNameAndTopic READ canChangeNameAndTopic CONSTANT)
|
||||||
|
Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT)
|
||||||
Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged)
|
Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged)
|
||||||
Q_PROPERTY(bool respondsToKeyRequests READ respondsToKeyRequests NOTIFY keyRequestsChanged)
|
Q_PROPERTY(bool respondsToKeyRequests READ respondsToKeyRequests NOTIFY keyRequestsChanged)
|
||||||
|
|
||||||
|
@ -26,24 +44,38 @@ public:
|
||||||
QString roomName() const;
|
QString roomName() const;
|
||||||
QString roomId() const;
|
QString roomId() const;
|
||||||
QString roomVersion() const;
|
QString roomVersion() const;
|
||||||
|
QString roomAvatarUrl();
|
||||||
int memberCount() const;
|
int memberCount() const;
|
||||||
int notifications();
|
int notifications();
|
||||||
int accessJoinRules();
|
int accessJoinRules();
|
||||||
bool respondsToKeyRequests();
|
bool respondsToKeyRequests();
|
||||||
|
bool isLoading() const;
|
||||||
//! Whether the user has enough power level to send m.room.join_rules events.
|
//! Whether the user has enough power level to send m.room.join_rules events.
|
||||||
bool canChangeJoinRules() const;
|
bool canChangeJoinRules() const;
|
||||||
|
//! Whether the user has enough power level to send m.room.name & m.room.topic events.
|
||||||
|
bool canChangeNameAndTopic() const;
|
||||||
|
//! Whether the user has enough power level to send m.room.avatar event.
|
||||||
|
bool canChangeAvatar() const;
|
||||||
bool isEncryptionEnabled() const;
|
bool isEncryptionEnabled() const;
|
||||||
|
|
||||||
Q_INVOKABLE void changeNotifications(int currentIndex);
|
Q_INVOKABLE void changeNotifications(int currentIndex);
|
||||||
Q_INVOKABLE void changeAccessRules(int index);
|
Q_INVOKABLE void changeAccessRules(int index);
|
||||||
Q_INVOKABLE void changeKeyRequestsPreference(bool isOn);
|
Q_INVOKABLE void changeKeyRequestsPreference(bool isOn);
|
||||||
Q_INVOKABLE void enableEncryption();
|
Q_INVOKABLE void enableEncryption();
|
||||||
|
Q_INVOKABLE void updateAvatar();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void notificationsChanged();
|
void notificationsChanged();
|
||||||
void accessJoinRulesChanged();
|
void accessJoinRulesChanged();
|
||||||
void keyRequestsChanged();
|
void keyRequestsChanged();
|
||||||
void encryptionChanged();
|
void encryptionChanged();
|
||||||
|
void avatarUrlChanged();
|
||||||
|
void loadingChanged();
|
||||||
|
void displayError(const QString &errorMessage);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void avatarChanged();
|
||||||
|
void stopLoading();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void retrieveRoomInfo();
|
void retrieveRoomInfo();
|
||||||
|
@ -54,6 +86,7 @@ private:
|
||||||
private:
|
private:
|
||||||
QString roomid_;
|
QString roomid_;
|
||||||
bool usesEncryption_ = false;
|
bool usesEncryption_ = false;
|
||||||
|
bool isLoading_ = false;
|
||||||
RoomInfo info_;
|
RoomInfo info_;
|
||||||
int notifications_ = 0;
|
int notifications_ = 0;
|
||||||
int accessRules_ = 0;
|
int accessRules_ = 0;
|
||||||
|
|
Loading…
Reference in a new issue