diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp
index 2cba2990..ff3c92a3 100644
--- a/src/dialogs/RoomSettings.cpp
+++ b/src/dialogs/RoomSettings.cpp
@@ -1,7 +1,10 @@
#include <QApplication>
#include <QComboBox>
+#include <QFileDialog>
+#include <QImageReader>
#include <QLabel>
#include <QMessageBox>
+#include <QMimeDatabase>
#include <QPainter>
#include <QPixmap>
#include <QShowEvent>
@@ -356,6 +359,103 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
else
avatar_->setImage(avatarImg_);
+ if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) {
+ auto filter = new ClickableFilter(this);
+ avatar_->installEventFilter(filter);
+ avatar_->setCursor(Qt::PointingHandCursor);
+ connect(filter, &ClickableFilter::clicked, this, [this]() {
+ const auto fileName = QFileDialog::getOpenFileName(
+ this, tr("Select an avatar"), "", 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") {
+ displayErrorMessage(tr("The selected media is not an image"));
+ return;
+ }
+
+ if (!file.open(QIODevice::ReadOnly)) {
+ displayErrorMessage(
+ tr("Error while reading media: %1").arg(file.errorString()));
+ return;
+ }
+
+ if (spinner_) {
+ startLoadingSpinner();
+ resetErrorLabel();
+ }
+
+ // 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::displayErrorMessage);
+ connect(
+ proxy.get(), &ThreadProxy::avatarChanged, this, &RoomSettings::setAvatar);
+
+ 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 = room_id_.toStdString(),
+ content = std::move(bin)](const mtx::responses::ContentURI &res,
+ mtx::http::RequestErr err) {
+ if (err) {
+ 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<state::Avatar, EventType::RoomAvatar>(
+ 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->avatarChanged(QImage::fromData(content));
+ });
+ });
+ });
+ }
+
auto roomNameLabel = new QLabel(QString::fromStdString(info_.name), this);
roomNameLabel->setFont(doubleFont);
@@ -537,6 +637,19 @@ RoomSettings::canChangeNameAndTopic(const std::string &room_id, const std::strin
return false;
}
+bool
+RoomSettings::canChangeAvatar(const std::string &room_id, const std::string &user_id) const
+{
+ try {
+ return cache::client()->hasEnoughPowerLevel(
+ {EventType::RoomAvatar}, room_id, user_id);
+ } catch (const lmdb::error &e) {
+ nhlog::db()->warn("lmdb error: {}", e.what());
+ }
+
+ return false;
+}
+
void
RoomSettings::updateAccessRules(const std::string &room_id,
const mtx::events::state::JoinRules &join_rule,
@@ -597,6 +710,26 @@ RoomSettings::startLoadingSpinner()
}
void
+RoomSettings::displayErrorMessage(const QString &msg)
+{
+ stopLoadingSpinner();
+
+ errorLabel_->show();
+ errorLabel_->setText(msg);
+}
+
+void
+RoomSettings::setAvatar(const QImage &img)
+{
+ stopLoadingSpinner();
+
+ avatarImg_ = img;
+
+ if (avatar_)
+ avatar_->setImage(img);
+}
+
+void
RoomSettings::resetErrorLabel()
{
if (errorLabel_) {
|