mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
Implement media cache
This commit is contained in:
parent
54091cf403
commit
29bd8b71d1
6 changed files with 63 additions and 35 deletions
|
@ -24,23 +24,26 @@
|
||||||
|
|
||||||
class MatrixClient;
|
class MatrixClient;
|
||||||
class TimelineItem;
|
class TimelineItem;
|
||||||
|
class Cache;
|
||||||
|
|
||||||
class AvatarProvider : public QObject
|
class AvatarProvider : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void init(QSharedPointer<MatrixClient> client) { client_ = client; }
|
static void init(QSharedPointer<MatrixClient> client, QSharedPointer<Cache> cache)
|
||||||
|
{
|
||||||
|
client_ = client;
|
||||||
|
cache_ = cache;
|
||||||
|
}
|
||||||
//! The callback is called with the downloaded avatar for the given user
|
//! The callback is called with the downloaded avatar for the given user
|
||||||
//! or the avatar is downloaded first and then saved for re-use.
|
//! or the avatar is downloaded first and then saved for re-use.
|
||||||
static void resolve(const QString &room_id,
|
static void resolve(const QString &room_id,
|
||||||
const QString &userId,
|
const QString &userId,
|
||||||
QObject *receiver,
|
QObject *receiver,
|
||||||
std::function<void(QImage)> callback);
|
std::function<void(QImage)> callback);
|
||||||
//! Remove all saved data.
|
|
||||||
static void clear() { avatars_.clear(); };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QSharedPointer<MatrixClient> client_;
|
static QSharedPointer<MatrixClient> client_;
|
||||||
static QHash<QString, QImage> avatars_;
|
static QSharedPointer<Cache> cache_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,8 +51,8 @@ constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||||
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(mtx::responses::Rooms);
|
Q_DECLARE_METATYPE(mtx::responses::Rooms)
|
||||||
Q_DECLARE_METATYPE(std::vector<std::string>);
|
Q_DECLARE_METATYPE(std::vector<std::string>)
|
||||||
|
|
||||||
class ChatPage : public QWidget
|
class ChatPage : public QWidget
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,12 +15,15 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include "AvatarProvider.h"
|
#include "AvatarProvider.h"
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
|
||||||
QSharedPointer<MatrixClient> AvatarProvider::client_;
|
QSharedPointer<MatrixClient> AvatarProvider::client_;
|
||||||
QHash<QString, QImage> AvatarProvider::avatars_;
|
QSharedPointer<Cache> AvatarProvider::cache_;
|
||||||
|
|
||||||
void
|
void
|
||||||
AvatarProvider::resolve(const QString &room_id,
|
AvatarProvider::resolve(const QString &room_id,
|
||||||
|
@ -28,21 +31,22 @@ AvatarProvider::resolve(const QString &room_id,
|
||||||
QObject *receiver,
|
QObject *receiver,
|
||||||
std::function<void(QImage)> callback)
|
std::function<void(QImage)> callback)
|
||||||
{
|
{
|
||||||
const auto key = QString("%1 %2").arg(room_id).arg(user_id);
|
const auto key = QString("%1 %2").arg(room_id).arg(user_id);
|
||||||
|
const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
|
||||||
|
|
||||||
if (!Cache::AvatarUrls.contains(key))
|
if (!Cache::AvatarUrls.contains(key) || cache_.isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (avatars_.contains(key)) {
|
if (avatarUrl.isEmpty())
|
||||||
auto img = avatars_[key];
|
return;
|
||||||
|
|
||||||
if (!img.isNull()) {
|
auto data = cache_->image(avatarUrl);
|
||||||
callback(img);
|
if (!data.isNull()) {
|
||||||
return;
|
callback(QImage::fromData(data));
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto proxy = client_->fetchUserAvatar(Cache::avatarUrl(room_id, user_id));
|
auto proxy = client_->fetchUserAvatar(avatarUrl);
|
||||||
|
|
||||||
if (proxy.isNull())
|
if (proxy.isNull())
|
||||||
return;
|
return;
|
||||||
|
@ -50,9 +54,16 @@ AvatarProvider::resolve(const QString &room_id,
|
||||||
connect(proxy.data(),
|
connect(proxy.data(),
|
||||||
&DownloadMediaProxy::avatarDownloaded,
|
&DownloadMediaProxy::avatarDownloaded,
|
||||||
receiver,
|
receiver,
|
||||||
[user_id, proxy, callback, key](const QImage &img) {
|
[user_id, proxy, callback, avatarUrl](const QImage &img) {
|
||||||
proxy->deleteLater();
|
proxy->deleteLater();
|
||||||
avatars_.insert(key, img);
|
QtConcurrent::run([img, avatarUrl]() {
|
||||||
|
QByteArray data;
|
||||||
|
QBuffer buffer(&data);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
img.save(&buffer, "PNG");
|
||||||
|
|
||||||
|
cache_->saveImage(avatarUrl, data);
|
||||||
|
});
|
||||||
callback(img);
|
callback(img);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,9 @@ Cache::saveImage(const QString &url, const QByteArray &image)
|
||||||
QByteArray
|
QByteArray
|
||||||
Cache::image(const QString &url) const
|
Cache::image(const QString &url) const
|
||||||
{
|
{
|
||||||
|
if (url.isEmpty())
|
||||||
|
return QByteArray();
|
||||||
|
|
||||||
auto key = url.toUtf8();
|
auto key = url.toUtf8();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -160,7 +163,7 @@ Cache::image(const QString &url) const
|
||||||
|
|
||||||
return QByteArray(image.data(), image.size());
|
return QByteArray(image.data(), image.size());
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
qCritical() << "image:" << e.what();
|
qCritical() << "image:" << e.what() << url;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
|
|
|
@ -399,8 +399,6 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client,
|
||||||
this,
|
this,
|
||||||
&ChatPage::setGroupViewState);
|
&ChatPage::setGroupViewState);
|
||||||
|
|
||||||
AvatarProvider::init(client);
|
|
||||||
|
|
||||||
connect(this, &ChatPage::continueSync, this, [this](const QString &next_batch) {
|
connect(this, &ChatPage::continueSync, this, [this](const QString &next_batch) {
|
||||||
syncTimeoutTimer_->start(SYNC_RETRY_TIMEOUT);
|
syncTimeoutTimer_->start(SYNC_RETRY_TIMEOUT);
|
||||||
client_->setNextBatchToken(next_batch);
|
client_->setNextBatchToken(next_batch);
|
||||||
|
@ -461,7 +459,6 @@ ChatPage::resetUI()
|
||||||
top_bar_->reset();
|
top_bar_->reset();
|
||||||
user_info_widget_->reset();
|
user_info_widget_->reset();
|
||||||
view_manager_->clearAll();
|
view_manager_->clearAll();
|
||||||
AvatarProvider::clear();
|
|
||||||
|
|
||||||
showUnreadMessageNotification(0);
|
showUnreadMessageNotification(0);
|
||||||
}
|
}
|
||||||
|
@ -497,6 +494,8 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
||||||
room_list_->setCache(cache_);
|
room_list_->setCache(cache_);
|
||||||
text_input_->setCache(cache_);
|
text_input_->setCache(cache_);
|
||||||
|
|
||||||
|
AvatarProvider::init(client_, cache_);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cache_->setup();
|
cache_->setup();
|
||||||
|
|
||||||
|
@ -584,21 +583,30 @@ ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_na
|
||||||
user_info_widget_->setUserId(userid);
|
user_info_widget_->setUserId(userid);
|
||||||
user_info_widget_->setDisplayName(display_name);
|
user_info_widget_->setDisplayName(display_name);
|
||||||
|
|
||||||
if (avatar_url.isValid()) {
|
if (!avatar_url.isValid())
|
||||||
auto proxy = client_->fetchUserAvatar(avatar_url);
|
return;
|
||||||
|
|
||||||
if (proxy.isNull())
|
if (!cache_.isNull()) {
|
||||||
|
auto data = cache_->image(avatar_url.toString());
|
||||||
|
if (!data.isNull()) {
|
||||||
|
user_info_widget_->setAvatar(QImage::fromData(data));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
proxy->setParent(this);
|
|
||||||
connect(proxy.data(),
|
|
||||||
&DownloadMediaProxy::avatarDownloaded,
|
|
||||||
this,
|
|
||||||
[this, proxy](const QImage &img) {
|
|
||||||
proxy->deleteLater();
|
|
||||||
user_info_widget_->setAvatar(img);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto proxy = client_->fetchUserAvatar(avatar_url);
|
||||||
|
|
||||||
|
if (proxy.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
proxy->setParent(this);
|
||||||
|
connect(proxy.data(),
|
||||||
|
&DownloadMediaProxy::avatarDownloaded,
|
||||||
|
this,
|
||||||
|
[this, proxy](const QImage &img) {
|
||||||
|
proxy->deleteLater();
|
||||||
|
user_info_widget_->setAvatar(img);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -661,8 +669,8 @@ ChatPage::loadStateFromCache()
|
||||||
try {
|
try {
|
||||||
cache_->populateMembers();
|
cache_->populateMembers();
|
||||||
|
|
||||||
emit initializeRoomList(cache_->roomInfo());
|
|
||||||
emit initializeEmptyViews(cache_->joinedRooms());
|
emit initializeEmptyViews(cache_->joinedRooms());
|
||||||
|
emit initializeRoomList(cache_->roomInfo());
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
std::cout << "load cache error:" << e.what() << '\n';
|
std::cout << "load cache error:" << e.what() << '\n';
|
||||||
// TODO Clear cache and restart.
|
// TODO Clear cache and restart.
|
||||||
|
|
|
@ -621,6 +621,9 @@ MatrixClient::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url)
|
||||||
void
|
void
|
||||||
MatrixClient::fetchCommunityAvatar(const QString &communityId, const QUrl &avatar_url)
|
MatrixClient::fetchCommunityAvatar(const QString &communityId, const QUrl &avatar_url)
|
||||||
{
|
{
|
||||||
|
if (avatar_url.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
QList<QString> url_parts = avatar_url.toString().split("mxc://");
|
QList<QString> url_parts = avatar_url.toString().split("mxc://");
|
||||||
|
|
||||||
if (url_parts.size() != 2) {
|
if (url_parts.size() != 2) {
|
||||||
|
|
Loading…
Reference in a new issue