File indexing completed on 2024-05-12 16:27:21

0001 /*
0002    SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "avatarcachemanager.h"
0008 #include "emoticons/emojimanager.h"
0009 #include "rocketchataccount.h"
0010 #include "ruqolawidgets_debug.h"
0011 #include <QPainter>
0012 #include <QWidget>
0013 
0014 AvatarCacheManager::AvatarCacheManager(const Utils::AvatarType avatarType, QObject *parent)
0015     : QObject(parent)
0016     , mAvatarType(avatarType)
0017     , mEmojiFont(Utils::emojiFontName())
0018 {
0019 }
0020 
0021 AvatarCacheManager::~AvatarCacheManager() = default;
0022 
0023 qreal AvatarCacheManager::checkIfNeededToClearCache(const QWidget *widget) const
0024 {
0025     const auto dpr = widget->devicePixelRatioF();
0026     if (dpr != mAvatarCache.dpr) {
0027         mAvatarCache.dpr = dpr;
0028         mAvatarCache.cache.clear();
0029     }
0030     return dpr;
0031 }
0032 
0033 void AvatarCacheManager::slotAvatarChanged(const Utils::AvatarInfo &info)
0034 {
0035     if ((info.avatarType == mAvatarType) || (mAvatarType == Utils::AvatarType::UserAndRoom)) {
0036         const QString iconUrlStr = mRocketChatAccount->avatarUrl(info);
0037         if (iconUrlStr.isEmpty()) {
0038             return;
0039         }
0040         auto &cache = mAvatarCache.cache;
0041         auto downScaled = cache.findCachedPixmap(iconUrlStr);
0042         if (!downScaled.isNull()) {
0043             mAvatarCache.cache.remove(iconUrlStr);
0044             mRocketChatAccount->updateAvatarCache(info);
0045         }
0046     }
0047 }
0048 
0049 void AvatarCacheManager::setCurrentRocketChatAccount(RocketChatAccount *currentRocketChatAccount)
0050 {
0051     if (mRocketChatAccount) {
0052         disconnect(mRocketChatAccount, nullptr, this, nullptr);
0053     }
0054 
0055     mRocketChatAccount = currentRocketChatAccount;
0056     connect(mRocketChatAccount, &RocketChatAccount::avatarWasChanged, this, &AvatarCacheManager::slotAvatarChanged);
0057 }
0058 
0059 QPixmap AvatarCacheManager::makeAvatarEmojiPixmap(const QString &emojiStr, const QWidget *widget, const Utils::AvatarInfo &info, int maxHeight) const
0060 {
0061     const auto dpr = checkIfNeededToClearCache(widget);
0062     auto &cache = mAvatarCache.cache;
0063 
0064     auto downScaled = cache.findCachedPixmap(emojiStr);
0065     if (downScaled.isNull()) {
0066         auto *emojiManager = mRocketChatAccount->emojiManager();
0067         const TextEmoticonsCore::UnicodeEmoticon emoticon = emojiManager->unicodeEmoticonForEmoji(emojiStr);
0068         if (emoticon.isValid()) {
0069             const QFontMetrics fm(mEmojiFont);
0070             const QSize size = fm.boundingRect(emoticon.unicode()).size();
0071 
0072             // qDebug() << " size " << size << "emojiStr "<< emojiStr << " emoticon.unicode() " <<emoticon.unicode() <<
0073             // fm.horizontalAdvance(emoticon.unicode()); boundingRect can return a width == 0 for existing character as :warning: emoji.
0074             QPixmap fullScale(fm.horizontalAdvance(emoticon.unicode()), size.height());
0075 
0076             fullScale.fill(Qt::white);
0077             QPainter painter(&fullScale);
0078             painter.setFont(mEmojiFont);
0079             painter.drawText(fullScale.rect(), Qt::AlignCenter, emoticon.unicode());
0080             downScaled = fullScale.scaledToHeight(maxHeight * dpr, Qt::SmoothTransformation);
0081             downScaled.setDevicePixelRatio(dpr);
0082             cache.insertCachedPixmap(emojiStr, downScaled);
0083         } else {
0084             return makeAvatarPixmap(widget, info, maxHeight);
0085         }
0086     }
0087     return downScaled;
0088 }
0089 
0090 void AvatarCacheManager::clearCache()
0091 {
0092     mAvatarCache.cache.clear();
0093 }
0094 
0095 void AvatarCacheManager::setMaxEntries(int maxEntries)
0096 {
0097     mAvatarCache.cache.setMaxEntries(maxEntries);
0098 }
0099 
0100 QPixmap AvatarCacheManager::makeAvatarUrlPixmap(const QWidget *widget, const QString &url, int maxHeight) const
0101 {
0102     const QUrl iconUrlStr = mRocketChatAccount->previewUrlFromLocalCache(url);
0103     if (iconUrlStr.isEmpty()) {
0104         return {};
0105     }
0106 
0107     const auto dpr = checkIfNeededToClearCache(widget);
0108 
0109     auto &cache = mAvatarCache.cache;
0110 
0111     auto downScaled = cache.findCachedPixmap(iconUrlStr.toLocalFile());
0112     if (downScaled.isNull()) {
0113         const QUrl iconUrl(iconUrlStr);
0114         Q_ASSERT(iconUrl.isLocalFile());
0115         QPixmap fullScale;
0116         if (!fullScale.load(iconUrl.toLocalFile())) {
0117             qCWarning(RUQOLAWIDGETS_LOG) << "Could not load" << iconUrl.toLocalFile();
0118             return {};
0119         }
0120         downScaled = fullScale.scaledToHeight(maxHeight * dpr, Qt::SmoothTransformation);
0121         downScaled.setDevicePixelRatio(dpr);
0122         cache.insertCachedPixmap(iconUrlStr.toLocalFile(), downScaled);
0123     }
0124     return downScaled;
0125 }
0126 
0127 QPixmap AvatarCacheManager::makeAvatarPixmap(const QWidget *widget, const Utils::AvatarInfo &info, int maxHeight) const
0128 {
0129     const QString iconUrlStr = mRocketChatAccount->avatarUrl(info);
0130     if (iconUrlStr.isEmpty()) {
0131         return {};
0132     }
0133 
0134     const auto dpr = checkIfNeededToClearCache(widget);
0135 
0136     auto &cache = mAvatarCache.cache;
0137 
0138     auto downScaled = cache.findCachedPixmap(iconUrlStr);
0139     if (downScaled.isNull()) {
0140         const QUrl iconUrl(iconUrlStr);
0141         Q_ASSERT(iconUrl.isLocalFile());
0142         QPixmap fullScale;
0143         if (!fullScale.load(iconUrl.toLocalFile())) {
0144             qCWarning(RUQOLAWIDGETS_LOG) << "Could not load" << iconUrl.toLocalFile();
0145             return {};
0146         }
0147         downScaled = fullScale.scaledToHeight(maxHeight * dpr, Qt::SmoothTransformation);
0148         downScaled.setDevicePixelRatio(dpr);
0149         cache.insertCachedPixmap(iconUrlStr, downScaled);
0150     }
0151     return downScaled;
0152 }
0153 
0154 #include "moc_avatarcachemanager.cpp"