Merge pull request #86 from Nheko-Reborn/avatar-memory-usage

Try to reduce memory usage by reusing avatar pixmaps
This commit is contained in:
DeepBlueV7.X 2019-08-30 23:15:09 +00:00 committed by GitHub
commit 5be967fb1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 146 additions and 208 deletions

View File

@ -16,30 +16,44 @@
*/ */
#include <QBuffer> #include <QBuffer>
#include <QPixmapCache>
#include <memory> #include <memory>
#include <unordered_map>
#include "AvatarProvider.h" #include "AvatarProvider.h"
#include "Cache.h" #include "Cache.h"
#include "Logging.h" #include "Logging.h"
#include "MatrixClient.h" #include "MatrixClient.h"
static QPixmapCache avatar_cache;
namespace AvatarProvider { namespace AvatarProvider {
void 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); avatar_cache.setCacheLimit(1024 * 1024);
const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
if (!Cache::AvatarUrls.contains(key) || !cache::client()) const auto cacheKey = avatarUrl + "_size_" + size;
if (!cache::client())
return; return;
if (avatarUrl.isEmpty()) if (avatarUrl.isEmpty())
return; 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); auto data = cache::client()->image(avatarUrl);
if (!data.isNull()) { 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; return;
} }
@ -47,7 +61,12 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
QObject::connect(proxy.get(), QObject::connect(proxy.get(),
&AvatarProxy::avatarDownloaded, &AvatarProxy::avatarDownloaded,
receiver, 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; mtx::http::ThumbOpts opts;
opts.width = 256; 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); cache::client()->saveImage(opts.mxc_url, res);
auto data = QByteArray(res.data(), res.size()); nhlog::net()->info("downloaded pixmap {}", opts.mxc_url);
emit proxy->avatarDownloaded(data);
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);
}
} }

View File

@ -17,7 +17,7 @@
#pragma once #pragma once
#include <QImage> #include <QPixmap>
#include <functional> #include <functional>
class AvatarProxy : public QObject class AvatarProxy : public QObject
@ -28,9 +28,15 @@ signals:
void avatarDownloaded(const QByteArray &data); void avatarDownloaded(const QByteArray &data);
}; };
using AvatarCallback = std::function<void(QImage)>; using AvatarCallback = std::function<void(QPixmap)>;
namespace AvatarProvider { namespace AvatarProvider {
void 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);
} }

View File

@ -1830,10 +1830,7 @@ Cache::searchRooms(const std::string &query, std::uint8_t max_items)
std::vector<RoomSearchResult> results; std::vector<RoomSearchResult> results;
for (auto it = items.begin(); it != end; it++) { for (auto it = items.begin(); it != end; it++) {
results.push_back( results.push_back(RoomSearchResult{it->second.first, it->second.second});
RoomSearchResult{it->second.first,
it->second.second,
QImage::fromData(image(txn, it->second.second.avatar_url))});
} }
txn.commit(); txn.commit();

View File

@ -153,7 +153,6 @@ struct RoomSearchResult
{ {
std::string room_id; std::string room_id;
RoomInfo info; RoomInfo info;
QImage img;
}; };
Q_DECLARE_METATYPE(RoomSearchResult) Q_DECLARE_METATYPE(RoomSearchResult)

View File

@ -774,12 +774,12 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
} }
void void
ChatPage::updateTopBarAvatar(const QString &roomid, const QPixmap &img) ChatPage::updateTopBarAvatar(const QString &roomid, const QString &img)
{ {
if (current_room_ != roomid) if (current_room_ != roomid)
return; return;
top_bar_->updateRoomAvatar(img.toImage()); top_bar_->updateRoomAvatar(img);
} }
void void
@ -807,7 +807,7 @@ ChatPage::changeTopRoomInfo(const QString &room_id)
if (img.isNull()) if (img.isNull())
top_bar_->updateRoomAvatarFromName(name); top_bar_->updateRoomAvatarFromName(name);
else else
top_bar_->updateRoomAvatar(img); top_bar_->updateRoomAvatar(avatar_url);
} catch (const lmdb::error &e) { } catch (const lmdb::error &e) {
nhlog::ui()->error("failed to change top bar room info: {}", e.what()); 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)); emit setUserDisplayName(QString::fromStdString(res.display_name));
if (cache::client()) { emit setUserAvatar(QString::fromStdString(res.avatar_url));
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())));
});
}); });
http::client()->joined_groups( http::client()->joined_groups(

View File

@ -129,7 +129,7 @@ signals:
void ownProfileOk(); void ownProfileOk();
void setUserDisplayName(const QString &name); void setUserDisplayName(const QString &name);
void setUserAvatar(const QImage &avatar); void setUserAvatar(const QString &avatar);
void loggedOut(); void loggedOut();
void trySyncCb(); void trySyncCb();
@ -159,7 +159,7 @@ signals:
private slots: private slots:
void showUnreadMessageNotification(int count); 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 changeTopRoomInfo(const QString &room_id);
void logout(); void logout();
void removeRoom(const QString &room_id); void removeRoom(const QString &room_id);

View File

@ -16,6 +16,8 @@ constexpr auto MAX_LOG_FILES = 3;
} }
namespace nhlog { namespace nhlog {
bool enable_debug_log_from_commandline = false;
void void
init(const std::string &file_path) init(const std::string &file_path)
{ {

View File

@ -18,4 +18,6 @@ db();
std::shared_ptr<spdlog::logger> std::shared_ptr<spdlog::logger>
crypto(); crypto();
extern bool enable_debug_log_from_commandline;
} }

View File

@ -21,6 +21,7 @@
#include <QPainter> #include <QPainter>
#include <QtGlobal> #include <QtGlobal>
#include "AvatarProvider.h"
#include "Cache.h" #include "Cache.h"
#include "Config.h" #include "Config.h"
#include "RoomInfoListItem.h" #include "RoomInfoListItem.h"
@ -434,10 +435,12 @@ RoomInfoListItem::mousePressEvent(QMouseEvent *event)
} }
void void
RoomInfoListItem::setAvatar(const QImage &img) RoomInfoListItem::setAvatar(const QString &avatar_url)
{ {
roomAvatar_ = utils::scaleImageToPixmap(img, IconSize); AvatarProvider::resolve(avatar_url, IconSize, this, [this](const QPixmap &img) {
update(); roomAvatar_ = img;
update();
});
} }
void void

View File

@ -73,7 +73,7 @@ public:
bool isPressed() const { return isPressed_; } bool isPressed() const { return isPressed_; }
int unreadMessageCount() const { return unreadMsgCount_; } int unreadMessageCount() const { return unreadMsgCount_; }
void setAvatar(const QImage &avatar_image); void setAvatar(const QString &avatar_url);
void setDescriptionMessage(const DescInfo &info); void setDescriptionMessage(const DescInfo &info);
DescInfo lastMessageInfo() const { return lastMsgInfo_; } DescInfo lastMessageInfo() const { return lastMsgInfo_; }

View File

@ -89,40 +89,7 @@ RoomList::updateAvatar(const QString &room_id, const QString &url)
if (url.isEmpty()) if (url.isEmpty())
return; return;
QByteArray savedImgData; emit updateRoomAvatarCb(room_id, url);
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);
}
} }
void void
@ -252,7 +219,7 @@ RoomList::highlightSelectedRoom(const QString &room_id)
} }
void void
RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img) RoomList::updateRoomAvatar(const QString &roomid, const QString &img)
{ {
if (!roomExists(roomid)) { if (!roomExists(roomid)) {
nhlog::ui()->warn("avatar update on non-existent room_id: {}", nhlog::ui()->warn("avatar update on non-existent room_id: {}",
@ -260,7 +227,7 @@ RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
return; return;
} }
rooms_[roomid]->setAvatar(img.toImage()); rooms_[roomid]->setAvatar(img);
// Used to inform other widgets for the new image data. // Used to inform other widgets for the new image data.
emit roomAvatarChanged(roomid, img); emit roomAvatarChanged(roomid, img);

View File

@ -61,12 +61,12 @@ signals:
void totalUnreadMessageCountUpdated(int count); void totalUnreadMessageCountUpdated(int count);
void acceptInvite(const QString &room_id); void acceptInvite(const QString &room_id);
void declineInvite(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 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: 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 highlightSelectedRoom(const QString &room_id);
void updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount); void updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount);
void updateRoomDescription(const QString &roomid, const DescInfo &info); void updateRoomDescription(const QString &roomid, const DescInfo &info);

View File

@ -46,9 +46,8 @@ TopRoomBar::TopRoomBar(QWidget *parent)
topLayout_->setContentsMargins( topLayout_->setContentsMargins(
2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin); 2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, fontHeight * 2);
avatar_->setLetter(""); avatar_->setLetter("");
avatar_->setSize(fontHeight * 2);
textLayout_ = new QVBoxLayout(); textLayout_ = new QVBoxLayout();
textLayout_->setSpacing(0); textLayout_->setSpacing(0);
@ -183,7 +182,7 @@ TopRoomBar::reset()
} }
void void
TopRoomBar::updateRoomAvatar(const QImage &avatar_image) TopRoomBar::updateRoomAvatar(const QString &avatar_image)
{ {
avatar_->setImage(avatar_image); avatar_->setImage(avatar_image);
update(); update();

View File

@ -44,7 +44,7 @@ class TopRoomBar : public QWidget
public: public:
TopRoomBar(QWidget *parent = 0); TopRoomBar(QWidget *parent = 0);
void updateRoomAvatar(const QImage &avatar_image); void updateRoomAvatar(const QString &avatar_image);
void updateRoomAvatar(const QIcon &icon); void updateRoomAvatar(const QIcon &icon);
void updateRoomName(const QString &name); void updateRoomName(const QString &name);
void updateRoomTopic(QString topic); void updateRoomTopic(QString topic);

View File

@ -52,10 +52,9 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
textLayout_->setSpacing(widgetMargin / 2); textLayout_->setSpacing(widgetMargin / 2);
textLayout_->setContentsMargins(widgetMargin * 2, widgetMargin, widgetMargin, widgetMargin); textLayout_->setContentsMargins(widgetMargin * 2, widgetMargin, widgetMargin, widgetMargin);
userAvatar_ = new Avatar(this); userAvatar_ = new Avatar(this, fontHeight * 2.5);
userAvatar_->setObjectName("userAvatar"); userAvatar_->setObjectName("userAvatar");
userAvatar_->setLetter(QChar('?')); userAvatar_->setLetter(QChar('?'));
userAvatar_->setSize(fontHeight * 2.5);
QFont nameFont; QFont nameFont;
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1); nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);
@ -134,14 +133,6 @@ UserInfoWidget::reset()
userAvatar_->setLetter(QChar('?')); userAvatar_->setLetter(QChar('?'));
} }
void
UserInfoWidget::setAvatar(const QImage &img)
{
avatar_image_ = img;
userAvatar_->setImage(img);
update();
}
void void
UserInfoWidget::setDisplayName(const QString &name) UserInfoWidget::setDisplayName(const QString &name)
{ {
@ -160,6 +151,14 @@ UserInfoWidget::setUserId(const QString &userid)
{ {
user_id_ = userid; user_id_ = userid;
userIdLabel_->setText(userid); userIdLabel_->setText(userid);
update();
}
void
UserInfoWidget::setAvatar(const QString &url)
{
userAvatar_->setImage(url);
update();
} }
void void

View File

@ -33,9 +33,9 @@ class UserInfoWidget : public QWidget
public: public:
UserInfoWidget(QWidget *parent = 0); UserInfoWidget(QWidget *parent = 0);
void setAvatar(const QImage &img);
void setDisplayName(const QString &name); void setDisplayName(const QString &name);
void setUserId(const QString &userid); void setUserId(const QString &userid);
void setAvatar(const QString &url);
void reset(); void reset();

View File

@ -9,7 +9,6 @@
#include "dialogs/MemberList.h" #include "dialogs/MemberList.h"
#include "AvatarProvider.h"
#include "Cache.h" #include "Cache.h"
#include "ChatPage.h" #include "ChatPage.h"
#include "Config.h" #include "Config.h"
@ -28,17 +27,10 @@ MemberItem::MemberItem(const RoomMember &member, QWidget *parent)
textLayout_->setMargin(0); textLayout_->setMargin(0);
textLayout_->setSpacing(0); textLayout_->setSpacing(0);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 44);
avatar_->setSize(44);
avatar_->setLetter(utils::firstChar(member.display_name)); avatar_->setLetter(utils::firstChar(member.display_name));
if (!member.avatar.isNull()) avatar_->setImage(ChatPage::instance()->currentRoom(), member.user_id);
avatar_->setImage(member.avatar);
else
AvatarProvider::resolve(ChatPage::instance()->currentRoom(),
member.user_id,
this,
[this](const QImage &img) { avatar_->setImage(img); });
QFont nameFont; QFont nameFont;
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1); nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);

View File

@ -37,8 +37,7 @@ ReceiptItem::ReceiptItem(QWidget *parent,
auto displayName = Cache::displayName(room_id, user_id); auto displayName = Cache::displayName(room_id, user_id);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 44);
avatar_->setSize(44);
avatar_->setLetter(utils::firstChar(displayName)); avatar_->setLetter(utils::firstChar(displayName));
// If it's a matrix id we use the second letter. // If it's a matrix id we use the second letter.
@ -56,10 +55,7 @@ ReceiptItem::ReceiptItem(QWidget *parent,
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addLayout(textLayout_, 1); topLayout_->addLayout(textLayout_, 1);
AvatarProvider::resolve(ChatPage::instance()->currentRoom(), avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
user_id,
this,
[this](const QImage &img) { avatar_->setImage(img); });
} }
void void

View File

@ -350,12 +350,12 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
keyRequestsToggle_->hide(); keyRequestsToggle_->hide();
} }
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 128);
avatar_->setSize(128);
if (avatarImg_.isNull()) if (avatarImg_.isNull())
avatar_->setLetter(utils::firstChar(QString::fromStdString(info_.name))); avatar_->setLetter(utils::firstChar(QString::fromStdString(info_.name)));
else else
avatar_->setImage(avatarImg_); avatar_->setImage(room_id_,
QString::fromStdString(http::client()->user_id().to_string()));
if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) { if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) {
auto filter = new ClickableFilter(this); auto filter = new ClickableFilter(this);
@ -487,7 +487,7 @@ RoomSettings::retrieveRoomInfo()
try { try {
usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString()); usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString());
info_ = cache::client()->singleRoomInfo(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) { } catch (const lmdb::error &e) {
nhlog::db()->warn("failed to retrieve room info from cache: {}", nhlog::db()->warn("failed to retrieve room info from cache: {}",
room_id_.toStdString()); room_id_.toStdString());
@ -633,14 +633,13 @@ RoomSettings::displayErrorMessage(const QString &msg)
} }
void void
RoomSettings::setAvatar(const QImage &img) RoomSettings::setAvatar()
{ {
stopLoadingSpinner(); stopLoadingSpinner();
avatarImg_ = img;
if (avatar_) if (avatar_)
avatar_->setImage(img); avatar_->setImage(room_id_,
QString::fromStdString(http::client()->user_id().to_string()));
} }
void void
@ -733,7 +732,7 @@ RoomSettings::updateAvatar()
return; return;
} }
emit proxy->avatarChanged(QImage::fromData(content)); emit proxy->avatarChanged();
}); });
}); });
} }

View File

@ -52,7 +52,7 @@ class ThreadProxy : public QObject
signals: signals:
void error(const QString &msg); void error(const QString &msg);
void avatarChanged(const QImage &img); void avatarChanged();
void nameEventSent(const QString &); void nameEventSent(const QString &);
void topicEventSent(); void topicEventSent();
}; };
@ -140,7 +140,7 @@ private:
void resetErrorLabel(); void resetErrorLabel();
void displayErrorMessage(const QString &msg); void displayErrorMessage(const QString &msg);
void setAvatar(const QImage &img); void setAvatar();
void setupEditButton(); void setupEditButton();
//! Retrieve the current room information from cache. //! Retrieve the current room information from cache.
void retrieveRoomInfo(); void retrieveRoomInfo();

View File

@ -114,9 +114,8 @@ UserProfile::UserProfile(QWidget *parent)
btnLayout->setSpacing(8); btnLayout->setSpacing(8);
btnLayout->setMargin(0); btnLayout->setMargin(0);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 128);
avatar_->setLetter("X"); avatar_->setLetter("X");
avatar_->setSize(128);
QFont font; QFont font;
font.setPointSizeF(font.pointSizeF() * 2); font.setPointSizeF(font.pointSizeF() * 2);
@ -210,8 +209,7 @@ UserProfile::init(const QString &userId, const QString &roomId)
displayNameLabel_->setText(displayName); displayNameLabel_->setText(displayName);
avatar_->setLetter(utils::firstChar(displayName)); avatar_->setLetter(utils::firstChar(displayName));
AvatarProvider::resolve( avatar_->setImage(roomId, userId);
roomId, userId, this, [this](const QImage &img) { avatar_->setImage(img); });
auto localUser = utils::localUser(); auto localUser = utils::localUser();

View File

@ -11,7 +11,7 @@ constexpr int PopupItemMargin = 3;
PopupItem::PopupItem(QWidget *parent) PopupItem::PopupItem(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, avatar_{new Avatar(this)} , avatar_{new Avatar(this, conf::popup::avatar)}
, hovering_{false} , hovering_{false}
{ {
setMouseTracking(true); setMouseTracking(true);
@ -40,7 +40,6 @@ UserItem::UserItem(QWidget *parent)
: PopupItem(parent) : PopupItem(parent)
{ {
userName_ = new QLabel("Placeholder", this); userName_ = new QLabel("Placeholder", this);
avatar_->setSize(conf::popup::avatar);
avatar_->setLetter("P"); avatar_->setLetter("P");
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addWidget(userName_, 1); topLayout_->addWidget(userName_, 1);
@ -52,7 +51,6 @@ UserItem::UserItem(QWidget *parent, const QString &user_id)
{ {
auto displayName = Cache::displayName(ChatPage::instance()->currentRoom(), userId_); auto displayName = Cache::displayName(ChatPage::instance()->currentRoom(), userId_);
avatar_->setSize(conf::popup::avatar);
avatar_->setLetter(utils::firstChar(displayName)); avatar_->setLetter(utils::firstChar(displayName));
// If it's a matrix id we use the second letter. // If it's a matrix id we use the second letter.
@ -87,16 +85,7 @@ UserItem::updateItem(const QString &user_id)
void void
UserItem::resolveAvatar(const QString &user_id) UserItem::resolveAvatar(const QString &user_id)
{ {
AvatarProvider::resolve( avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
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_);
});
} }
void void
@ -116,7 +105,6 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
auto name = QFontMetrics(QFont()).elidedText( auto name = QFontMetrics(QFont()).elidedText(
QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10); QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10);
avatar_->setSize(conf::popup::avatar + 6);
avatar_->setLetter(utils::firstChar(name)); avatar_->setLetter(utils::firstChar(name));
roomName_ = new QLabel(name, this); roomName_ = new QLabel(name, this);
@ -125,8 +113,7 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addWidget(roomName_, 1); topLayout_->addWidget(roomName_, 1);
if (!res.img.isNull()) avatar_->setImage(QString::fromStdString(res.info.avatar_url));
avatar_->setImage(res.img);
} }
void void
@ -141,10 +128,7 @@ RoomItem::updateItem(const RoomSearchResult &result)
roomName_->setText(name); roomName_->setText(name);
if (!result.img.isNull()) avatar_->setImage(QString::fromStdString(result.info.avatar_url));
avatar_->setImage(result.img);
else
avatar_->setLetter(utils::firstChar(name));
} }
void void
@ -154,4 +138,4 @@ RoomItem::mousePressEvent(QMouseEvent *event)
emit clicked(selectedText()); emit clicked(selectedText());
QWidget::mousePressEvent(event); QWidget::mousePressEvent(event);
} }

Binary file not shown.

View File

@ -326,8 +326,7 @@ TimelineItem::TimelineItem(mtx::events::MessageType ty,
generateBody(userid, displayName, formatted_body); generateBody(userid, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(userid);
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -509,8 +508,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice
generateBody(sender, displayName, formatted_body); generateBody(sender, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -558,8 +556,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote>
generateBody(sender, displayName, formatted_body); generateBody(sender, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -607,8 +604,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text>
generateBody(sender, displayName, formatted_body); generateBody(sender, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -793,9 +789,8 @@ TimelineItem::setupAvatarLayout(const QString &userName)
QFont f; QFont f;
f.setPointSizeF(f.pointSizeF()); f.setPointSizeF(f.pointSizeF());
userAvatar_ = new Avatar(this); userAvatar_ = new Avatar(this, QFontMetrics(f).height() * 2);
userAvatar_->setLetter(QChar(userName[0]).toUpper()); userAvatar_->setLetter(QChar(userName[0]).toUpper());
userAvatar_->setSize(QFontMetrics(f).height() * 2);
// TODO: The provided user name should be a UserId class // TODO: The provided user name should be a UserId class
if (userName[0] == '@' && userName.size() > 1) if (userName[0] == '@' && userName.size() > 1)
@ -822,12 +817,12 @@ TimelineItem::setupSimpleLayout()
} }
void void
TimelineItem::setUserAvatar(const QImage &avatar) TimelineItem::setUserAvatar(const QString &userid)
{ {
if (userAvatar_ == nullptr) if (userAvatar_ == nullptr)
return; return;
userAvatar_->setImage(avatar); userAvatar_->setImage(room_id_, userid);
} }
void void
@ -911,8 +906,7 @@ TimelineItem::addAvatar()
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(userid);
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} }
void void

View File

@ -215,7 +215,7 @@ public:
void setBackgroundColor(const QColor &color) { backgroundColor_ = color; } void setBackgroundColor(const QColor &color) { backgroundColor_ = color; }
QColor backgroundColor() const { return backgroundColor_; } QColor backgroundColor() const { return backgroundColor_; }
void setUserAvatar(const QImage &pixmap); void setUserAvatar(const QString &userid);
DescInfo descriptionMessage() const { return descriptionMsg_; } DescInfo descriptionMessage() const { return descriptionMsg_; }
QString eventId() const { return event_id_; } QString eventId() const { return event_id_; }
void setEventId(const QString &event_id) { event_id_ = 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, ""); generateBody(userid, displayName, "");
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(userid);
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
setupSimpleLayout(); setupSimpleLayout();
} }
@ -381,8 +380,7 @@ TimelineItem::setupWidgetLayout(Widget *widget, const Event &event, bool withSen
generateBody(sender, displayName, ""); generateBody(sender, displayName, "");
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
setupSimpleLayout(); setupSimpleLayout();
} }

View File

@ -1,12 +1,13 @@
#include <QPainter> #include <QPainter>
#include "AvatarProvider.h"
#include "Utils.h" #include "Utils.h"
#include "ui/Avatar.h" #include "ui/Avatar.h"
Avatar::Avatar(QWidget *parent) Avatar::Avatar(QWidget *parent, int size)
: QWidget(parent) : QWidget(parent)
, size_(size)
{ {
size_ = ui::AvatarSize;
type_ = ui::AvatarType::Letter; type_ = ui::AvatarType::Letter;
letter_ = "A"; letter_ = "A";
@ -60,21 +61,6 @@ Avatar::setBackgroundColor(const QColor &color)
background_color_ = color; background_color_ = color;
} }
void
Avatar::setSize(int size)
{
size_ = size;
if (!image_.isNull())
pixmap_ = utils::scaleImageToPixmap(image_, size_);
QFont _font(font());
_font.setPointSizeF(size_ * (ui::FontSize) / 40);
setFont(_font);
update();
}
void void
Avatar::setLetter(const QString &letter) Avatar::setLetter(const QString &letter)
{ {
@ -84,12 +70,23 @@ Avatar::setLetter(const QString &letter)
} }
void void
Avatar::setImage(const QImage &image) Avatar::setImage(const QString &avatar_url)
{ {
image_ = image; AvatarProvider::resolve(avatar_url, size_, this, [this](QPixmap pm) {
type_ = ui::AvatarType::Image; type_ = ui::AvatarType::Image;
pixmap_ = utils::scaleImageToPixmap(image_, size_); pixmap_ = pm;
update(); update();
});
}
void
Avatar::setImage(const QString &room, const QString &user)
{
AvatarProvider::resolve(room, user, size_, this, [this](QPixmap pm) {
type_ = ui::AvatarType::Image;
pixmap_ = pm;
update();
});
} }
void void

View File

@ -15,13 +15,13 @@ class Avatar : public QWidget
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
public: public:
explicit Avatar(QWidget *parent = 0); explicit Avatar(QWidget *parent = 0, int size = ui::AvatarSize);
void setBackgroundColor(const QColor &color); void setBackgroundColor(const QColor &color);
void setIcon(const QIcon &icon); 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 setLetter(const QString &letter);
void setSize(int size);
void setTextColor(const QColor &color); void setTextColor(const QColor &color);
QColor backgroundColor() const; QColor backgroundColor() const;
@ -41,7 +41,6 @@ private:
QColor background_color_; QColor background_color_;
QColor text_color_; QColor text_color_;
QIcon icon_; QIcon icon_;
QImage image_;
QPixmap pixmap_; QPixmap pixmap_;
int size_; int size_;
}; };