Skip to content
Snippets Groups Projects
Commit 0d700d99 authored by kamathmanu's avatar kamathmanu
Browse files

Implemented Room Directory model to store and provide QML view with public room data from mtxclient

parent d955444d
No related branches found
No related tags found
No related merge requests found
......@@ -361,6 +361,7 @@ set(SRC_FILES
src/UserSettingsPage.cpp
src/UsersModel.cpp
src/RoomsModel.cpp
src/RoomDirectoryModel.cpp
src/Utils.cpp
src/WebRTCSession.cpp
src/WelcomePage.cpp
......@@ -567,6 +568,7 @@ qt5_wrap_cpp(MOC_HEADERS
src/UserSettingsPage.h
src/UsersModel.h
src/RoomsModel.h
src/RoomDirectoryModel.h
src/WebRTCSession.h
src/WelcomePage.h
)
......
// SPDX-FileCopyrightText: 2021 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "RoomDirectoryModel.h"
#include "ChatPage.h"
#include <algorithm>
RoomDirectoryModel::RoomDirectoryModel(QObject *parent, const std::string &s)
: QAbstractListModel(parent)
, server_(s)
, canFetchMore_(true)
{
connect(this, &RoomDirectoryModel::fetchedRoomsBatch, this, &RoomDirectoryModel::displayRooms, Qt::QueuedConnection);
}
QHash<int, QByteArray>
RoomDirectoryModel::roleNames() const
{
return {
{Roles::Name, "name"},
{Roles::Id, "roomid"},
{Roles::AvatarUrl, "avatarUrl"},
{Roles::Topic, "topic"},
{Roles::MemberCount, "numMembers"},
{Roles::Previewable, "canPreview"},};
}
void
RoomDirectoryModel::resetDisplayedData()
{
beginResetModel();
prevBatch_ = "";
nextBatch_ = "";
canFetchMore_ = true;
beginRemoveRows(QModelIndex(), 0 , static_cast<int> (publicRoomsData_.size()));
publicRoomsData_.clear();
endRemoveRows();
endResetModel();
}
void
RoomDirectoryModel::setMatrixServer(const QString &s)
{
server_ = s.toStdString();
nhlog::ui()->debug("Received matrix server: {}", server_);
resetDisplayedData();
}
void
RoomDirectoryModel::setSearchTerm(const QString &f)
{
userSearchString_ = f.toStdString();
nhlog::ui()->debug("Received user query: {}", userSearchString_);
resetDisplayedData();
}
std::vector<std::string>
RoomDirectoryModel::getViasForRoom(const std::vector<std::string> &aliases)
{
std::vector<std::string> vias;
vias.reserve(aliases.size());
std::transform(aliases.begin(), aliases.end(),
std::back_inserter(vias), [](const auto &alias) {
const auto roomAliasDelimiter = ":";
return alias.substr(alias.find(roomAliasDelimiter) + 1);
});
return vias;
}
void
RoomDirectoryModel::joinRoom(const int &index)
{
if (index >= 0 && static_cast<size_t> (index) < publicRoomsData_.size())
{
const auto &chunk = publicRoomsData_[index];
nhlog::ui()->debug("'Joining room {}", chunk.room_id);
ChatPage::instance()->joinRoomVia(chunk.room_id, getViasForRoom(chunk.aliases));
}
}
QVariant
RoomDirectoryModel::data(const QModelIndex &index, int role) const
{
if (hasIndex(index.row(), index.column(), index.parent()))
{
const auto &room_chunk = publicRoomsData_[index.row()];
switch (role)
{
case Roles::Name:
return QString::fromStdString(room_chunk.name);
case Roles::Id:
return QString::fromStdString(room_chunk.room_id);
case Roles::AvatarUrl:
return QString::fromStdString(room_chunk.avatar_url);
case Roles::Topic:
return QString::fromStdString(room_chunk.topic);
case Roles::MemberCount:
return QVariant::fromValue(room_chunk.num_joined_members);
case Roles::Previewable:
return QVariant::fromValue(room_chunk.world_readable);
}
}
return {};
}
void
RoomDirectoryModel::fetchMore(const QModelIndex &)
{
nhlog::net()->debug("Fetching more rooms from mtxclient...");
nhlog::net()->debug("Prev batch: {} | Next batch: {}", prevBatch_, nextBatch_);
mtx::requests::PublicRooms req;
req.limit = limit_;
req.since = prevBatch_;
req.filter.generic_search_term = userSearchString_;
// req.third_party_instance_id = third_party_instance_id;
auto requested_server = server_;
http::client()->post_public_rooms(req, [requested_server, this, req]
(const mtx::responses::PublicRooms &res,
mtx::http::RequestErr err)
{
if (err) {
nhlog::net()->error
("Failed to retrieve rooms from mtxclient - {} - {} - {}",
mtx::errors::to_string(err->matrix_error.errcode),
err->matrix_error.error,
err->parse_error);
} else if ( req.filter.generic_search_term == this->userSearchString_
&& req.since == this->prevBatch_
&& requested_server == this->server_) {
nhlog::net()->debug("signalling chunk to GUI thread");
emit fetchedRoomsBatch(res.chunk, res.prev_batch, res.next_batch);
}
}, requested_server);
}
void
RoomDirectoryModel::displayRooms(std::vector<mtx::responses::PublicRoomsChunk> fetched_rooms,
const std::string &prev_batch, const std::string &next_batch)
{
nhlog::net()->debug("Prev batch: {} | Next batch: {}", prevBatch_, nextBatch_);
nhlog::net()->debug("NP batch: {} | NN batch: {}", prev_batch, next_batch);
if (fetched_rooms.empty()) {
nhlog::net()->error("mtxclient helper thread yielded empty chunk!");
return;
}
beginInsertRows(QModelIndex(), static_cast<int> (publicRoomsData_.size()), static_cast<int> (publicRoomsData_.size() + fetched_rooms.size()) - 1);
this->publicRoomsData_.insert(this->publicRoomsData_.end(), fetched_rooms.begin(), fetched_rooms.end());
endInsertRows();
if (next_batch.empty()) {
canFetchMore_ = false;
}
prevBatch_ = std::exchange(nextBatch_, next_batch);
}
\ No newline at end of file
// SPDX-FileCopyrightText: 2021 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QAbstractListModel>
#include <QHash>
#include <QString>
#include <vector>
#include <string>
#include "MatrixClient.h"
#include <mtxclient/http/errors.hpp>
#include <mtx/responses/public_rooms.hpp>
#include "Logging.h"
namespace mtx::http {
using RequestErr = const std::optional<mtx::http::ClientError> &;
}
namespace mtx::responses {
struct PublicRooms;
}
class RoomDirectoryModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit RoomDirectoryModel
(QObject *parent = nullptr, const std::string &s = "");
enum Roles {
Name = Qt::UserRole,
Id,
AvatarUrl,
Topic,
MemberCount,
Previewable
};
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role) const override;
inline int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
(void) parent;
return static_cast<int> (publicRoomsData_.size());
}
inline bool canFetchMore(const QModelIndex &) const override
{
nhlog::net()->debug("determining if can fetch more");
return canFetchMore_;
}
void fetchMore(const QModelIndex &) override;
Q_INVOKABLE void joinRoom(const int &index = -1);
signals:
void fetchedRoomsBatch(std::vector<mtx::responses::PublicRoomsChunk> rooms,
const std::string &prev_batch, const std::string &next_batch);
void serverChanged();
void searchTermEntered();
public slots:
void displayRooms(std::vector<mtx::responses::PublicRoomsChunk> rooms,
const std::string &prev, const std::string &next);
void setMatrixServer(const QString &s = "");
void setSearchTerm(const QString &f);
private:
static constexpr size_t limit_ = 50;
std::string server_;
std::string userSearchString_;
std::string prevBatch_;
std::string nextBatch_;
bool canFetchMore_;
std::vector<mtx::responses::PublicRoomsChunk> publicRoomsData_;
std::vector<std::string> getViasForRoom(const std::vector<std::string> &room);
void resetDisplayedData();
};
\ No newline at end of file
......@@ -26,6 +26,8 @@
#include "MainWindow.h"
#include "MatrixClient.h"
#include "MxcImageProvider.h"
#include "ReadReceiptsModel.h"
#include "RoomDirectoryModel.h"
#include "RoomsModel.h"
#include "SingleImagePackModel.h"
#include "UserSettingsPage.h"
......@@ -39,6 +41,7 @@
Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
Q_DECLARE_METATYPE(std::vector<mtx::responses::PublicRoomsChunk>)
namespace msgs = mtx::events::msg;
......@@ -150,6 +153,8 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
qRegisterMetaType<mtx::events::msg::KeyVerificationStart>();
qRegisterMetaType<CombinedImagePackModel *>();
qRegisterMetaType<std::vector<mtx::responses::PublicRoomsChunk>>();
qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
"im.nheko",
1,
......@@ -273,6 +278,9 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
"EmojiCategory",
"Error: Only enums");
qmlRegisterType<RoomDirectoryModel>(
"im.nheko.RoomDirectoryModel", 1, 0, "RoomDirectoryModel");
#ifdef USE_QUICK_VIEW
view = new QQuickView(parent);
container = QWidget::createWindowContainer(view, parent);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment