summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoseph Donofry <joedonofry@gmail.com>2019-09-03 21:16:16 -0400
committerJoseph Donofry <joedonofry@gmail.com>2019-09-03 21:16:16 -0400
commit8e04197d5650faee90a69fdc94f8c9a10c700b7f (patch)
tree7e47c9d27a15a015d4f2cf33984d20f93efd8b5f
parentMinor tweak to one instance of QSettings not necessarily using the same setti... (diff)
parentMerge pull request #86 from Nheko-Reborn/avatar-memory-usage (diff)
downloadnheko-8e04197d5650faee90a69fdc94f8c9a10c700b7f.tar.xz
Merge branch '0.7.0-dev' of ssh://github.com/Nheko-Reborn/nheko into 0.7.0-dev
-rw-r--r--src/AvatarProvider.cpp55
-rw-r--r--src/AvatarProvider.h12
-rw-r--r--src/Cache.cpp5
-rw-r--r--src/Cache.h1
-rw-r--r--src/ChatPage.cpp38
-rw-r--r--src/ChatPage.h4
-rw-r--r--src/Logging.cpp2
-rw-r--r--src/Logging.h2
-rw-r--r--src/RoomInfoListItem.cpp9
-rw-r--r--src/RoomInfoListItem.h2
-rw-r--r--src/RoomList.cpp39
-rw-r--r--src/RoomList.h6
-rw-r--r--src/TopRoomBar.cpp5
-rw-r--r--src/TopRoomBar.h2
-rw-r--r--src/UserInfoWidget.cpp19
-rw-r--r--src/UserInfoWidget.h2
-rw-r--r--src/dialogs/MemberList.cpp12
-rw-r--r--src/dialogs/ReadReceipts.cpp8
-rw-r--r--src/dialogs/RoomSettings.cpp17
-rw-r--r--src/dialogs/RoomSettings.h4
-rw-r--r--src/dialogs/UserProfile.cpp6
-rw-r--r--src/popups/PopupItem.cpp26
-rw-r--r--src/timeline/.TimelineItem.cpp.swpbin0 -> 114688 bytes
-rw-r--r--src/timeline/TimelineItem.cpp22
-rw-r--r--src/timeline/TimelineItem.h8
-rw-r--r--src/ui/Avatar.cpp39
-rw-r--r--src/ui/Avatar.h7
27 files changed, 145 insertions, 207 deletions
diff --git a/src/AvatarProvider.cpp b/src/AvatarProvider.cpp
index 57b61c75..ec745c04 100644
--- a/src/AvatarProvider.cpp
+++ b/src/AvatarProvider.cpp
@@ -16,30 +16,44 @@
  */
 
 #include <QBuffer>
+#include <QPixmapCache>
 #include <memory>
+#include <unordered_map>
 
 #include "AvatarProvider.h"
 #include "Cache.h"
 #include "Logging.h"
 #include "MatrixClient.h"
 
-namespace AvatarProvider {
+static QPixmapCache avatar_cache;
 
+namespace AvatarProvider {
 void
-resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback callback)
+resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback callback)
 {
-        const auto key       = QString("%1 %2").arg(room_id).arg(user_id);
-        const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
+        avatar_cache.setCacheLimit(1024 * 1024);
 
-        if (!Cache::AvatarUrls.contains(key) || !cache::client())
+        const auto cacheKey = avatarUrl + "_size_" + size;
+
+        if (!cache::client())
                 return;
 
         if (avatarUrl.isEmpty())
                 return;
 
+        QPixmap pixmap;
+        if (avatar_cache.find(cacheKey, &pixmap)) {
+                nhlog::net()->info("cached pixmap {}", avatarUrl.toStdString());
+                callback(pixmap);
+                return;
+        }
+
         auto data = cache::client()->image(avatarUrl);
         if (!data.isNull()) {
-                callback(QImage::fromData(data));
+                pixmap.loadFromData(data);
+                avatar_cache.insert(cacheKey, pixmap);
+                nhlog::net()->info("loaded pixmap from disk cache {}", avatarUrl.toStdString());
+                callback(pixmap);
                 return;
         }
 
@@ -47,7 +61,12 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
         QObject::connect(proxy.get(),
                          &AvatarProxy::avatarDownloaded,
                          receiver,
-                         [callback](const QByteArray &data) { callback(QImage::fromData(data)); });
+                         [callback, cacheKey](const QByteArray &data) {
+                                 QPixmap pm;
+                                 pm.loadFromData(data);
+                                 avatar_cache.insert(cacheKey, pm);
+                                 callback(pm);
+                         });
 
         mtx::http::ThumbOpts opts;
         opts.width   = 256;
@@ -67,8 +86,26 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
 
                   cache::client()->saveImage(opts.mxc_url, res);
 
-                  auto data = QByteArray(res.data(), res.size());
-                  emit proxy->avatarDownloaded(data);
+                  nhlog::net()->info("downloaded pixmap {}", opts.mxc_url);
+
+                  emit proxy->avatarDownloaded(QByteArray(res.data(), res.size()));
           });
 }
+
+void
+resolve(const QString &room_id,
+        const QString &user_id,
+        int size,
+        QObject *receiver,
+        AvatarCallback callback)
+{
+        const auto key       = QString("%1 %2").arg(room_id).arg(user_id);
+        const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
+        const auto cacheKey  = avatarUrl + "_size_" + size;
+
+        if (!Cache::AvatarUrls.contains(key) || !cache::client())
+                return;
+
+        resolve(avatarUrl, size, receiver, callback);
+}
 }
diff --git a/src/AvatarProvider.h b/src/AvatarProvider.h
index 4b4e15e9..47ed028e 100644
--- a/src/AvatarProvider.h
+++ b/src/AvatarProvider.h
@@ -17,7 +17,7 @@
 
 #pragma once
 
-#include <QImage>
+#include <QPixmap>
 #include <functional>
 
 class AvatarProxy : public QObject
@@ -28,9 +28,15 @@ signals:
         void avatarDownloaded(const QByteArray &data);
 };
 
-using AvatarCallback = std::function<void(QImage)>;
+using AvatarCallback = std::function<void(QPixmap)>;
 
 namespace AvatarProvider {
 void
-resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback cb);
+resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback cb);
+void
+resolve(const QString &room_id,
+        const QString &user_id,
+        int size,
+        QObject *receiver,
+        AvatarCallback cb);
 }
diff --git a/src/Cache.cpp b/src/Cache.cpp
index ef0f951e..083dbe89 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1830,10 +1830,7 @@ Cache::searchRooms(const std::string &query, std::uint8_t max_items)
 
         std::vector<RoomSearchResult> results;
         for (auto it = items.begin(); it != end; it++) {
-                results.push_back(
-                  RoomSearchResult{it->second.first,
-                                   it->second.second,
-                                   QImage::fromData(image(txn, it->second.second.avatar_url))});
+                results.push_back(RoomSearchResult{it->second.first, it->second.second});
         }
 
         txn.commit();
diff --git a/src/Cache.h b/src/Cache.h
index 302bb65b..0da49793 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -153,7 +153,6 @@ struct RoomSearchResult
 {
         std::string room_id;
         RoomInfo info;
-        QImage img;
 };
 
 Q_DECLARE_METATYPE(RoomSearchResult)
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 2ed64b6b..21ded4b3 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -774,12 +774,12 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
 }
 
 void
-ChatPage::updateTopBarAvatar(const QString &roomid, const QPixmap &img)
+ChatPage::updateTopBarAvatar(const QString &roomid, const QString &img)
 {
         if (current_room_ != roomid)
                 return;
 
-        top_bar_->updateRoomAvatar(img.toImage());
+        top_bar_->updateRoomAvatar(img);
 }
 
 void
@@ -807,7 +807,7 @@ ChatPage::changeTopRoomInfo(const QString &room_id)
                 if (img.isNull())
                         top_bar_->updateRoomAvatarFromName(name);
                 else
-                        top_bar_->updateRoomAvatar(img);
+                        top_bar_->updateRoomAvatar(avatar_url);
 
         } catch (const lmdb::error &e) {
                 nhlog::ui()->error("failed to change top bar room info: {}", e.what());
@@ -1337,37 +1337,7 @@ ChatPage::getProfileInfo()
 
                   emit setUserDisplayName(QString::fromStdString(res.display_name));
 
-                  if (cache::client()) {
-                          auto data = cache::client()->image(res.avatar_url);
-                          if (!data.isNull()) {
-                                  emit setUserAvatar(QImage::fromData(data));
-                                  return;
-                          }
-                  }
-
-                  if (res.avatar_url.empty())
-                          return;
-
-                  http::client()->download(
-                    res.avatar_url,
-                    [this, res](const std::string &data,
-                                const std::string &,
-                                const std::string &,
-                                mtx::http::RequestErr err) {
-                            if (err) {
-                                    nhlog::net()->warn(
-                                      "failed to download user avatar: {} - {}",
-                                      mtx::errors::to_string(err->matrix_error.errcode),
-                                      err->matrix_error.error);
-                                    return;
-                            }
-
-                            if (cache::client())
-                                    cache::client()->saveImage(res.avatar_url, data);
-
-                            emit setUserAvatar(
-                              QImage::fromData(QByteArray(data.data(), data.size())));
-                    });
+                  emit setUserAvatar(QString::fromStdString(res.avatar_url));
           });
 
         http::client()->joined_groups(
diff --git a/src/ChatPage.h b/src/ChatPage.h
index 189af387..e41ae1ae 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -129,7 +129,7 @@ signals:
 
         void ownProfileOk();
         void setUserDisplayName(const QString &name);
-        void setUserAvatar(const QImage &avatar);
+        void setUserAvatar(const QString &avatar);
         void loggedOut();
 
         void trySyncCb();
@@ -159,7 +159,7 @@ signals:
 
 private slots:
         void showUnreadMessageNotification(int count);
-        void updateTopBarAvatar(const QString &roomid, const QPixmap &img);
+        void updateTopBarAvatar(const QString &roomid, const QString &img);
         void changeTopRoomInfo(const QString &room_id);
         void logout();
         void removeRoom(const QString &room_id);
diff --git a/src/Logging.cpp b/src/Logging.cpp
index 686274d8..32287582 100644
--- a/src/Logging.cpp
+++ b/src/Logging.cpp
@@ -16,6 +16,8 @@ constexpr auto MAX_LOG_FILES = 3;
 }
 
 namespace nhlog {
+bool enable_debug_log_from_commandline = false;
+
 void
 init(const std::string &file_path)
 {
diff --git a/src/Logging.h b/src/Logging.h
index 2feae60d..e54f3c3f 100644
--- a/src/Logging.h
+++ b/src/Logging.h
@@ -18,4 +18,6 @@ db();
 
 std::shared_ptr<spdlog::logger>
 crypto();
+
+extern bool enable_debug_log_from_commandline;
 }
diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp
index 9bcce134..dbcd6806 100644
--- a/src/RoomInfoListItem.cpp
+++ b/src/RoomInfoListItem.cpp
@@ -21,6 +21,7 @@
 #include <QPainter>
 #include <QtGlobal>
 
+#include "AvatarProvider.h"
 #include "Cache.h"
 #include "Config.h"
 #include "RoomInfoListItem.h"
@@ -434,10 +435,12 @@ RoomInfoListItem::mousePressEvent(QMouseEvent *event)
 }
 
 void
-RoomInfoListItem::setAvatar(const QImage &img)
+RoomInfoListItem::setAvatar(const QString &avatar_url)
 {
-        roomAvatar_ = utils::scaleImageToPixmap(img, IconSize);
-        update();
+        AvatarProvider::resolve(avatar_url, IconSize, this, [this](const QPixmap &img) {
+                roomAvatar_ = img;
+                update();
+        });
 }
 
 void
diff --git a/src/RoomInfoListItem.h b/src/RoomInfoListItem.h
index 40c938c1..54e02a76 100644
--- a/src/RoomInfoListItem.h
+++ b/src/RoomInfoListItem.h
@@ -73,7 +73,7 @@ public:
         bool isPressed() const { return isPressed_; }
         int unreadMessageCount() const { return unreadMsgCount_; }
 
-        void setAvatar(const QImage &avatar_image);
+        void setAvatar(const QString &avatar_url);
         void setDescriptionMessage(const DescInfo &info);
         DescInfo lastMessageInfo() const { return lastMsgInfo_; }
 
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index 1abf3533..c5e05621 100644
--- a/src/RoomList.cpp
+++ b/src/RoomList.cpp
@@ -89,40 +89,7 @@ RoomList::updateAvatar(const QString &room_id, const QString &url)
         if (url.isEmpty())
                 return;
 
-        QByteArray savedImgData;
-
-        if (cache::client())
-                savedImgData = cache::client()->image(url);
-
-        if (savedImgData.isEmpty()) {
-                mtx::http::ThumbOpts opts;
-                opts.mxc_url = url.toStdString();
-                http::client()->get_thumbnail(
-                  opts, [room_id, opts, this](const std::string &res, mtx::http::RequestErr err) {
-                          if (err) {
-                                  nhlog::net()->warn(
-                                    "failed to download room avatar: {} {} {}",
-                                    opts.mxc_url,
-                                    mtx::errors::to_string(err->matrix_error.errcode),
-                                    err->matrix_error.error);
-                                  return;
-                          }
-
-                          if (cache::client())
-                                  cache::client()->saveImage(opts.mxc_url, res);
-
-                          auto data = QByteArray(res.data(), res.size());
-                          QPixmap pixmap;
-                          pixmap.loadFromData(data);
-
-                          emit updateRoomAvatarCb(room_id, pixmap);
-                  });
-        } else {
-                QPixmap img;
-                img.loadFromData(savedImgData);
-
-                updateRoomAvatar(room_id, img);
-        }
+        emit updateRoomAvatarCb(room_id, url);
 }
 
 void
@@ -252,7 +219,7 @@ RoomList::highlightSelectedRoom(const QString &room_id)
 }
 
 void
-RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
+RoomList::updateRoomAvatar(const QString &roomid, const QString &img)
 {
         if (!roomExists(roomid)) {
                 nhlog::ui()->warn("avatar update on non-existent room_id: {}",
@@ -260,7 +227,7 @@ RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
                 return;
         }
 
-        rooms_[roomid]->setAvatar(img.toImage());
+        rooms_[roomid]->setAvatar(img);
 
         // Used to inform other widgets for the new image data.
         emit roomAvatarChanged(roomid, img);
diff --git a/src/RoomList.h b/src/RoomList.h
index 155a969c..95fc0d9b 100644
--- a/src/RoomList.h
+++ b/src/RoomList.h
@@ -61,12 +61,12 @@ signals:
         void totalUnreadMessageCountUpdated(int count);
         void acceptInvite(const QString &room_id);
         void declineInvite(const QString &room_id);
-        void roomAvatarChanged(const QString &room_id, const QPixmap &img);
+        void roomAvatarChanged(const QString &room_id, const QString &img);
         void joinRoom(const QString &room_id);
-        void updateRoomAvatarCb(const QString &room_id, const QPixmap &img);
+        void updateRoomAvatarCb(const QString &room_id, const QString &img);
 
 public slots:
-        void updateRoomAvatar(const QString &roomid, const QPixmap &img);
+        void updateRoomAvatar(const QString &roomid, const QString &img);
         void highlightSelectedRoom(const QString &room_id);
         void updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount);
         void updateRoomDescription(const QString &roomid, const DescInfo &info);
diff --git a/src/TopRoomBar.cpp b/src/TopRoomBar.cpp
index a8049e3a..712fe9aa 100644
--- a/src/TopRoomBar.cpp
+++ b/src/TopRoomBar.cpp
@@ -46,9 +46,8 @@ TopRoomBar::TopRoomBar(QWidget *parent)
         topLayout_->setContentsMargins(
           2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin);
 
-        avatar_ = new Avatar(this);
+        avatar_ = new Avatar(this, fontHeight * 2);
         avatar_->setLetter("");
-        avatar_->setSize(fontHeight * 2);
 
         textLayout_ = new QVBoxLayout();
         textLayout_->setSpacing(0);
@@ -183,7 +182,7 @@ TopRoomBar::reset()
 }
 
 void
-TopRoomBar::updateRoomAvatar(const QImage &avatar_image)
+TopRoomBar::updateRoomAvatar(const QString &avatar_image)
 {
         avatar_->setImage(avatar_image);
         update();
diff --git a/src/TopRoomBar.h b/src/TopRoomBar.h
index 5f2c936e..3243064e 100644
--- a/src/TopRoomBar.h
+++ b/src/TopRoomBar.h
@@ -44,7 +44,7 @@ class TopRoomBar : public QWidget
 public:
         TopRoomBar(QWidget *parent = 0);
 
-        void updateRoomAvatar(const QImage &avatar_image);
+        void updateRoomAvatar(const QString &avatar_image);
         void updateRoomAvatar(const QIcon &icon);
         void updateRoomName(const QString &name);
         void updateRoomTopic(QString topic);
diff --git a/src/UserInfoWidget.cpp b/src/UserInfoWidget.cpp
index 5345fb2a..19d7478e 100644
--- a/src/UserInfoWidget.cpp
+++ b/src/UserInfoWidget.cpp
@@ -52,10 +52,9 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
         textLayout_->setSpacing(widgetMargin / 2);
         textLayout_->setContentsMargins(widgetMargin * 2, widgetMargin, widgetMargin, widgetMargin);
 
-        userAvatar_ = new Avatar(this);
+        userAvatar_ = new Avatar(this, fontHeight * 2.5);
         userAvatar_->setObjectName("userAvatar");
         userAvatar_->setLetter(QChar('?'));
-        userAvatar_->setSize(fontHeight * 2.5);
 
         QFont nameFont;
         nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);
@@ -135,14 +134,6 @@ UserInfoWidget::reset()
 }
 
 void
-UserInfoWidget::setAvatar(const QImage &img)
-{
-        avatar_image_ = img;
-        userAvatar_->setImage(img);
-        update();
-}
-
-void
 UserInfoWidget::setDisplayName(const QString &name)
 {
         if (name.isEmpty())
@@ -160,6 +151,14 @@ UserInfoWidget::setUserId(const QString &userid)
 {
         user_id_ = userid;
         userIdLabel_->setText(userid);
+        update();
+}
+
+void
+UserInfoWidget::setAvatar(const QString &url)
+{
+        userAvatar_->setImage(url);
+        update();
 }
 
 void
diff --git a/src/UserInfoWidget.h b/src/UserInfoWidget.h
index 65de7be9..263dd0c2 100644
--- a/src/UserInfoWidget.h
+++ b/src/UserInfoWidget.h
@@ -33,9 +33,9 @@ class UserInfoWidget : public QWidget
 public:
         UserInfoWidget(QWidget *parent = 0);
 
-        void setAvatar(const QImage &img);
         void setDisplayName(const QString &name);
         void setUserId(const QString &userid);
+        void setAvatar(const QString &url);
 
         void reset();
 
diff --git a/src/dialogs/MemberList.cpp b/src/dialogs/MemberList.cpp
index 88a95403..9e973efa 100644
--- a/src/dialogs/MemberList.cpp
+++ b/src/dialogs/MemberList.cpp
@@ -9,7 +9,6 @@
 
 #include "dialogs/MemberList.h"
 
-#include "AvatarProvider.h"
 #include "Cache.h"
 #include "ChatPage.h"
 #include "Config.h"
@@ -28,17 +27,10 @@ MemberItem::MemberItem(const RoomMember &member, QWidget *parent)
         textLayout_->setMargin(0);
         textLayout_->setSpacing(0);
 
-        avatar_ = new Avatar(this);
-        avatar_->setSize(44);
+        avatar_ = new Avatar(this, 44);
         avatar_->setLetter(utils::firstChar(member.display_name));
 
-        if (!member.avatar.isNull())
-                avatar_->setImage(member.avatar);
-        else
-                AvatarProvider::resolve(ChatPage::instance()->currentRoom(),
-                                        member.user_id,
-                                        this,
-                                        [this](const QImage &img) { avatar_->setImage(img); });
+        avatar_->setImage(ChatPage::instance()->currentRoom(), member.user_id);
 
         QFont nameFont;
         nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);
diff --git a/src/dialogs/ReadReceipts.cpp b/src/dialogs/ReadReceipts.cpp
index 5a0d98c7..58ad59c3 100644
--- a/src/dialogs/ReadReceipts.cpp
+++ b/src/dialogs/ReadReceipts.cpp
@@ -37,8 +37,7 @@ ReceiptItem::ReceiptItem(QWidget *parent,
 
         auto displayName = Cache::displayName(room_id, user_id);
 
-        avatar_ = new Avatar(this);
-        avatar_->setSize(44);
+        avatar_ = new Avatar(this, 44);
         avatar_->setLetter(utils::firstChar(displayName));
 
         // If it's a matrix id we use the second letter.
@@ -56,10 +55,7 @@ ReceiptItem::ReceiptItem(QWidget *parent,
         topLayout_->addWidget(avatar_);
         topLayout_->addLayout(textLayout_, 1);
 
-        AvatarProvider::resolve(ChatPage::instance()->currentRoom(),
-                                user_id,
-                                this,
-                                [this](const QImage &img) { avatar_->setImage(img); });
+        avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
 }
 
 void
diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp
index 1fe5904b..00b034cc 100644
--- a/src/dialogs/RoomSettings.cpp
+++ b/src/dialogs/RoomSettings.cpp
@@ -350,12 +350,12 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
                 keyRequestsToggle_->hide();
         }
 
-        avatar_ = new Avatar(this);
-        avatar_->setSize(128);
+        avatar_ = new Avatar(this, 128);
         if (avatarImg_.isNull())
                 avatar_->setLetter(utils::firstChar(QString::fromStdString(info_.name)));
         else
-                avatar_->setImage(avatarImg_);
+                avatar_->setImage(room_id_,
+                                  QString::fromStdString(http::client()->user_id().to_string()));
 
         if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) {
                 auto filter = new ClickableFilter(this);
@@ -487,7 +487,7 @@ RoomSettings::retrieveRoomInfo()
         try {
                 usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString());
                 info_           = cache::client()->singleRoomInfo(room_id_.toStdString());
-                setAvatar(QImage::fromData(cache::client()->image(info_.avatar_url)));
+                setAvatar();
         } catch (const lmdb::error &e) {
                 nhlog::db()->warn("failed to retrieve room info from cache: {}",
                                   room_id_.toStdString());
@@ -633,14 +633,13 @@ RoomSettings::displayErrorMessage(const QString &msg)
 }
 
 void
-RoomSettings::setAvatar(const QImage &img)
+RoomSettings::setAvatar()
 {
         stopLoadingSpinner();
 
-        avatarImg_ = img;
-
         if (avatar_)
-                avatar_->setImage(img);
+                avatar_->setImage(room_id_,
+                                  QString::fromStdString(http::client()->user_id().to_string()));
 }
 
 void
@@ -733,7 +732,7 @@ RoomSettings::updateAvatar()
                                     return;
                             }
 
-                            emit proxy->avatarChanged(QImage::fromData(content));
+                            emit proxy->avatarChanged();
                     });
           });
 }
diff --git a/src/dialogs/RoomSettings.h b/src/dialogs/RoomSettings.h
index 6667b68b..e1807ba1 100644
--- a/src/dialogs/RoomSettings.h
+++ b/src/dialogs/RoomSettings.h
@@ -52,7 +52,7 @@ class ThreadProxy : public QObject
 
 signals:
         void error(const QString &msg);
-        void avatarChanged(const QImage &img);
+        void avatarChanged();
         void nameEventSent(const QString &);
         void topicEventSent();
 };
@@ -140,7 +140,7 @@ private:
         void resetErrorLabel();
         void displayErrorMessage(const QString &msg);
 
-        void setAvatar(const QImage &img);
+        void setAvatar();
         void setupEditButton();
         //! Retrieve the current room information from cache.
         void retrieveRoomInfo();
diff --git a/src/dialogs/UserProfile.cpp b/src/dialogs/UserProfile.cpp
index 6aea96a8..5ad3afa2 100644
--- a/src/dialogs/UserProfile.cpp
+++ b/src/dialogs/UserProfile.cpp
@@ -114,9 +114,8 @@ UserProfile::UserProfile(QWidget *parent)
         btnLayout->setSpacing(8);
         btnLayout->setMargin(0);
 
-        avatar_ = new Avatar(this);
+        avatar_ = new Avatar(this, 128);
         avatar_->setLetter("X");
-        avatar_->setSize(128);
 
         QFont font;
         font.setPointSizeF(font.pointSizeF() * 2);
@@ -210,8 +209,7 @@ UserProfile::init(const QString &userId, const QString &roomId)
         displayNameLabel_->setText(displayName);
         avatar_->setLetter(utils::firstChar(displayName));
 
-        AvatarProvider::resolve(
-          roomId, userId, this, [this](const QImage &img) { avatar_->setImage(img); });
+        avatar_->setImage(roomId, userId);
 
         auto localUser = utils::localUser();
 
diff --git a/src/popups/PopupItem.cpp b/src/popups/PopupItem.cpp
index f905983a..c4d4327f 100644
--- a/src/popups/PopupItem.cpp
+++ b/src/popups/PopupItem.cpp
@@ -11,7 +11,7 @@ constexpr int PopupItemMargin = 3;
 
 PopupItem::PopupItem(QWidget *parent)
   : QWidget(parent)
-  , avatar_{new Avatar(this)}
+  , avatar_{new Avatar(this, conf::popup::avatar)}
   , hovering_{false}
 {
         setMouseTracking(true);
@@ -40,7 +40,6 @@ UserItem::UserItem(QWidget *parent)
   : PopupItem(parent)
 {
         userName_ = new QLabel("Placeholder", this);
-        avatar_->setSize(conf::popup::avatar);
         avatar_->setLetter("P");
         topLayout_->addWidget(avatar_);
         topLayout_->addWidget(userName_, 1);
@@ -52,7 +51,6 @@ UserItem::UserItem(QWidget *parent, const QString &user_id)
 {
         auto displayName = Cache::displayName(ChatPage::instance()->currentRoom(), userId_);
 
-        avatar_->setSize(conf::popup::avatar);
         avatar_->setLetter(utils::firstChar(displayName));
 
         // If it's a matrix id we use the second letter.
@@ -87,16 +85,7 @@ UserItem::updateItem(const QString &user_id)
 void
 UserItem::resolveAvatar(const QString &user_id)
 {
-        AvatarProvider::resolve(
-          ChatPage::instance()->currentRoom(), userId_, this, [this, user_id](const QImage &img) {
-                  // The user on the widget when the avatar is resolved,
-                  // might be different from the user that made the call.
-                  if (user_id == userId_)
-                          avatar_->setImage(img);
-                  else
-                          // We try to resolve the avatar again.
-                          resolveAvatar(userId_);
-          });
+        avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
 }
 
 void
@@ -116,7 +105,6 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
         auto name = QFontMetrics(QFont()).elidedText(
           QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10);
 
-        avatar_->setSize(conf::popup::avatar + 6);
         avatar_->setLetter(utils::firstChar(name));
 
         roomName_ = new QLabel(name, this);
@@ -125,8 +113,7 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
         topLayout_->addWidget(avatar_);
         topLayout_->addWidget(roomName_, 1);
 
-        if (!res.img.isNull())
-                avatar_->setImage(res.img);
+        avatar_->setImage(QString::fromStdString(res.info.avatar_url));
 }
 
 void
@@ -141,10 +128,7 @@ RoomItem::updateItem(const RoomSearchResult &result)
 
         roomName_->setText(name);
 
-        if (!result.img.isNull())
-                avatar_->setImage(result.img);
-        else
-                avatar_->setLetter(utils::firstChar(name));
+        avatar_->setImage(QString::fromStdString(result.info.avatar_url));
 }
 
 void
@@ -154,4 +138,4 @@ RoomItem::mousePressEvent(QMouseEvent *event)
                 emit clicked(selectedText());
 
         QWidget::mousePressEvent(event);
-}
\ No newline at end of file
+}
diff --git a/src/timeline/.TimelineItem.cpp.swp b/src/timeline/.TimelineItem.cpp.swp
new file mode 100644
index 00000000..75e03aeb
--- /dev/null
+++ b/src/timeline/.TimelineItem.cpp.swp
Binary files differdiff --git a/src/timeline/TimelineItem.cpp b/src/timeline/TimelineItem.cpp
index dd3b48c3..7916bd80 100644
--- a/src/timeline/TimelineItem.cpp
+++ b/src/timeline/TimelineItem.cpp
@@ -326,8 +326,7 @@ TimelineItem::TimelineItem(mtx::events::MessageType ty,
                 generateBody(userid, displayName, formatted_body);
                 setupAvatarLayout(displayName);
 
-                AvatarProvider::resolve(
-                  room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
+                setUserAvatar(userid);
         } else {
                 generateBody(formatted_body);
                 setupSimpleLayout();
@@ -509,8 +508,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice
                 generateBody(sender, displayName, formatted_body);
                 setupAvatarLayout(displayName);
 
-                AvatarProvider::resolve(
-                  room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
+                setUserAvatar(sender);
         } else {
                 generateBody(formatted_body);
                 setupSimpleLayout();
@@ -558,8 +556,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote>
                 generateBody(sender, displayName, formatted_body);
                 setupAvatarLayout(displayName);
 
-                AvatarProvider::resolve(
-                  room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
+                setUserAvatar(sender);
         } else {
                 generateBody(formatted_body);
                 setupSimpleLayout();
@@ -607,8 +604,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text>
                 generateBody(sender, displayName, formatted_body);
                 setupAvatarLayout(displayName);
 
-                AvatarProvider::resolve(
-                  room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
+                setUserAvatar(sender);
         } else {
                 generateBody(formatted_body);
                 setupSimpleLayout();
@@ -793,9 +789,8 @@ TimelineItem::setupAvatarLayout(const QString &userName)
         QFont f;
         f.setPointSizeF(f.pointSizeF());
 
-        userAvatar_ = new Avatar(this);
+        userAvatar_ = new Avatar(this, QFontMetrics(f).height() * 2);
         userAvatar_->setLetter(QChar(userName[0]).toUpper());
-        userAvatar_->setSize(QFontMetrics(f).height() * 2);
 
         // TODO: The provided user name should be a UserId class
         if (userName[0] == '@' && userName.size() > 1)
@@ -822,12 +817,12 @@ TimelineItem::setupSimpleLayout()
 }
 
 void
-TimelineItem::setUserAvatar(const QImage &avatar)
+TimelineItem::setUserAvatar(const QString &userid)
 {
         if (userAvatar_ == nullptr)
                 return;
 
-        userAvatar_->setImage(avatar);
+        userAvatar_->setImage(room_id_, userid);
 }
 
 void
@@ -911,8 +906,7 @@ TimelineItem::addAvatar()
 
         setupAvatarLayout(displayName);
 
-        AvatarProvider::resolve(
-          room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
+        setUserAvatar(userid);
 }
 
 void
diff --git a/src/timeline/TimelineItem.h b/src/timeline/TimelineItem.h
index fe354000..356976e5 100644
--- a/src/timeline/TimelineItem.h
+++ b/src/timeline/TimelineItem.h
@@ -215,7 +215,7 @@ public:
         void setBackgroundColor(const QColor &color) { backgroundColor_ = color; }
         QColor backgroundColor() const { return backgroundColor_; }
 
-        void setUserAvatar(const QImage &pixmap);
+        void setUserAvatar(const QString &userid);
         DescInfo descriptionMessage() const { return descriptionMsg_; }
         QString eventId() const { return event_id_; }
         void setEventId(const QString &event_id) { event_id_ = event_id; }
@@ -336,8 +336,7 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget, const QString &userid, bool
                 generateBody(userid, displayName, "");
                 setupAvatarLayout(displayName);
 
-                AvatarProvider::resolve(
-                  room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
+                setUserAvatar(userid);
         } else {
                 setupSimpleLayout();
         }
@@ -381,8 +380,7 @@ TimelineItem::setupWidgetLayout(Widget *widget, const Event &event, bool withSen
                 generateBody(sender, displayName, "");
                 setupAvatarLayout(displayName);
 
-                AvatarProvider::resolve(
-                  room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
+                setUserAvatar(sender);
         } else {
                 setupSimpleLayout();
         }
diff --git a/src/ui/Avatar.cpp b/src/ui/Avatar.cpp
index 4b4cd272..98bf21c6 100644
--- a/src/ui/Avatar.cpp
+++ b/src/ui/Avatar.cpp
@@ -1,12 +1,13 @@
 #include <QPainter>
 
+#include "AvatarProvider.h"
 #include "Utils.h"
 #include "ui/Avatar.h"
 
-Avatar::Avatar(QWidget *parent)
+Avatar::Avatar(QWidget *parent, int size)
   : QWidget(parent)
+  , size_(size)
 {
-        size_   = ui::AvatarSize;
         type_   = ui::AvatarType::Letter;
         letter_ = "A";
 
@@ -61,35 +62,31 @@ Avatar::setBackgroundColor(const QColor &color)
 }
 
 void
-Avatar::setSize(int size)
+Avatar::setLetter(const QString &letter)
 {
-        size_ = size;
-
-        if (!image_.isNull())
-                pixmap_ = utils::scaleImageToPixmap(image_, size_);
-
-        QFont _font(font());
-        _font.setPointSizeF(size_ * (ui::FontSize) / 40);
-
-        setFont(_font);
+        letter_ = letter;
+        type_   = ui::AvatarType::Letter;
         update();
 }
 
 void
-Avatar::setLetter(const QString &letter)
+Avatar::setImage(const QString &avatar_url)
 {
-        letter_ = letter;
-        type_   = ui::AvatarType::Letter;
-        update();
+        AvatarProvider::resolve(avatar_url, size_, this, [this](QPixmap pm) {
+                type_   = ui::AvatarType::Image;
+                pixmap_ = pm;
+                update();
+        });
 }
 
 void
-Avatar::setImage(const QImage &image)
+Avatar::setImage(const QString &room, const QString &user)
 {
-        image_  = image;
-        type_   = ui::AvatarType::Image;
-        pixmap_ = utils::scaleImageToPixmap(image_, size_);
-        update();
+        AvatarProvider::resolve(room, user, size_, this, [this](QPixmap pm) {
+                type_   = ui::AvatarType::Image;
+                pixmap_ = pm;
+                update();
+        });
 }
 
 void
diff --git a/src/ui/Avatar.h b/src/ui/Avatar.h
index 41967af5..a643c8c4 100644
--- a/src/ui/Avatar.h
+++ b/src/ui/Avatar.h
@@ -15,13 +15,13 @@ class Avatar : public QWidget
         Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
 
 public:
-        explicit Avatar(QWidget *parent = 0);
+        explicit Avatar(QWidget *parent = 0, int size = ui::AvatarSize);
 
         void setBackgroundColor(const QColor &color);
         void setIcon(const QIcon &icon);
-        void setImage(const QImage &image);
+        void setImage(const QString &avatar_url);
+        void setImage(const QString &room, const QString &user);
         void setLetter(const QString &letter);
-        void setSize(int size);
         void setTextColor(const QColor &color);
 
         QColor backgroundColor() const;
@@ -41,7 +41,6 @@ private:
         QColor background_color_;
         QColor text_color_;
         QIcon icon_;
-        QImage image_;
         QPixmap pixmap_;
         int size_;
 };