Load the initial cache data without blocking the UI

remotes/origin/HEAD
Konstantinos Sideris 7 years ago
parent c123bada94
commit c59cd0e80b
  1. 1
      CMakeLists.txt
  2. 14
      include/Cache.h
  3. 2
      include/RoomState.h
  4. 9
      src/Cache.cc
  5. 63
      src/ChatPage.cc

@ -277,6 +277,7 @@ qt5_wrap_cpp(MOC_HEADERS
include/ui/ThemeManager.h include/ui/ThemeManager.h
include/AvatarProvider.h include/AvatarProvider.h
include/Cache.h
include/ChatPage.h include/ChatPage.h
include/CommunitiesListItem.h include/CommunitiesListItem.h
include/CommunitiesList.h include/CommunitiesList.h

@ -18,11 +18,12 @@
#pragma once #pragma once
#include <QDir> #include <QDir>
#include <QMap>
#include <json.hpp> #include <json.hpp>
#include <lmdb++.h> #include <lmdb++.h>
#include <mtx/responses.hpp> #include <mtx/responses.hpp>
class RoomState; #include "RoomState.h"
//! Used to uniquely identify a list of read receipts. //! Used to uniquely identify a list of read receipts.
struct ReadReceiptKey struct ReadReceiptKey
@ -44,17 +45,19 @@ from_json(const json &j, ReadReceiptKey &key)
key.room_id = j.at("room_id").get<std::string>(); key.room_id = j.at("room_id").get<std::string>();
} }
class Cache class Cache : public QObject
{ {
Q_OBJECT
public: public:
Cache(const QString &userId); Cache(const QString &userId, QObject *parent = nullptr);
void setState(const QString &nextBatchToken, void setState(const QString &nextBatchToken,
const QMap<QString, QSharedPointer<RoomState>> &states); const QMap<QString, QSharedPointer<RoomState>> &states);
bool isInitialized() const; bool isInitialized() const;
QString nextBatchToken() const; QString nextBatchToken() const;
QMap<QString, RoomState> states(); void states();
using Invites = std::map<std::string, mtx::responses::InvitedRoom>; using Invites = std::map<std::string, mtx::responses::InvitedRoom>;
Invites invites(); Invites invites();
@ -86,6 +89,9 @@ public:
QByteArray image(const QString &url) const; QByteArray image(const QString &url) const;
void saveImage(const QString &url, const QByteArray &data); void saveImage(const QString &url, const QByteArray &data);
signals:
void statesLoaded(QMap<QString, RoomState> states);
private: private:
void setNextBatchToken(lmdb::txn &txn, const QString &token); void setNextBatchToken(lmdb::txn &txn, const QString &token);
void insertRoomState(lmdb::txn &txn, void insertRoomState(lmdb::txn &txn,

@ -77,6 +77,8 @@ private:
QString userAvatar_; QString userAvatar_;
}; };
Q_DECLARE_METATYPE(RoomState)
template<class Collection> template<class Collection>
void void
RoomState::updateFromEvents(const std::vector<Collection> &collection) RoomState::updateFromEvents(const std::vector<Collection> &collection)

@ -33,8 +33,9 @@ static const lmdb::val CACHE_FORMAT_VERSION_KEY("cache_format_version");
using CachedReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>; using CachedReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
using Receipts = std::map<std::string, std::map<std::string, uint64_t>>; using Receipts = std::map<std::string, std::map<std::string, uint64_t>>;
Cache::Cache(const QString &userId) Cache::Cache(const QString &userId, QObject *parent)
: env_{nullptr} : QObject{parent}
, env_{nullptr}
, stateDb_{0} , stateDb_{0}
, roomDb_{0} , roomDb_{0}
, invitesDb_{0} , invitesDb_{0}
@ -248,7 +249,7 @@ Cache::removeInvite(const QString &room_id)
txn.commit(); txn.commit();
} }
QMap<QString, RoomState> void
Cache::states() Cache::states()
{ {
QMap<QString, RoomState> states; QMap<QString, RoomState> states;
@ -301,7 +302,7 @@ Cache::states()
txn.commit(); txn.commit();
return states; emit statesLoaded(states);
} }
void void

@ -648,46 +648,51 @@ ChatPage::loadStateFromCache()
qDebug() << "Restored nextBatchToken" << cache_->nextBatchToken(); qDebug() << "Restored nextBatchToken" << cache_->nextBatchToken();
client_->setNextBatchToken(cache_->nextBatchToken()); client_->setNextBatchToken(cache_->nextBatchToken());
// Fetch all the joined room's state. qRegisterMetaType<QMap<QString, RoomState>>();
auto rooms = cache_->states();
for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) { QtConcurrent::run(cache_.data(), &Cache::states);
auto roomState = QSharedPointer<RoomState>(new RoomState(it.value()));
// Clean up and prepare state for use. connect(cache_.data(), &Cache::statesLoaded, this, [this](QMap<QString, RoomState> rooms) {
roomState->removeLeaveMemberships(); qDebug() << "Cache data loaded";
roomState->resolveName();
roomState->resolveAvatar();
// Save the current room state. for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) {
roomStates_.insert(it.key(), roomState); auto roomState = QSharedPointer<RoomState>(new RoomState(it.value()));
// Create or restore the settings for this room. // Clean up and prepare state for use.
roomSettings_.insert(it.key(), roomState->removeLeaveMemberships();
QSharedPointer<RoomSettings>(new RoomSettings(it.key()))); roomState->resolveName();
roomState->resolveAvatar();
// Resolve user avatars. // Save the current room state.
for (const auto membership : roomState->memberships) { roomStates_.insert(it.key(), roomState);
updateUserDisplayName(membership.second);
updateUserAvatarUrl(membership.second); // Create or restore the settings for this room.
roomSettings_.insert(
it.key(), QSharedPointer<RoomSettings>(new RoomSettings(it.key())));
// Resolve user avatars.
for (const auto membership : roomState->memberships) {
updateUserDisplayName(membership.second);
updateUserAvatarUrl(membership.second);
}
} }
}
// Initializing empty timelines. // Initializing empty timelines.
view_manager_->initialize(rooms.keys()); view_manager_->initialize(rooms.keys());
// Initialize room list from the restored state and settings. // Initialize room list from the restored state and settings.
room_list_->setInitialRooms(roomSettings_, roomStates_); room_list_->setInitialRooms(roomSettings_, roomStates_);
room_list_->syncInvites(cache_->invites()); room_list_->syncInvites(cache_->invites());
// Check periodically if the timelines have been loaded. // Check periodically if the timelines have been loaded.
consensusTimer_->start(CONSENSUS_TIMEOUT); consensusTimer_->start(CONSENSUS_TIMEOUT);
// Show the content if consensus can't be achieved. // Show the content if consensus can't be achieved.
showContentTimer_->start(SHOW_CONTENT_TIMEOUT); showContentTimer_->start(SHOW_CONTENT_TIMEOUT);
// Start receiving events. // Start receiving events.
client_->sync(); client_->sync();
});
} }
void void

Loading…
Cancel
Save