File indexing completed on 2024-12-01 04:36:50
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"