mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 19:08:58 +03:00
Show previews for space rooms
This commit is contained in:
parent
ecd57df6e2
commit
9540d704e0
2 changed files with 213 additions and 25 deletions
|
@ -33,6 +33,27 @@ RoomlistModel::RoomlistModel(TimelineViewManager *parent)
|
||||||
&RoomlistModel::totalUnreadMessageCountUpdated,
|
&RoomlistModel::totalUnreadMessageCountUpdated,
|
||||||
ChatPage::instance(),
|
ChatPage::instance(),
|
||||||
&ChatPage::unreadMessages);
|
&ChatPage::unreadMessages);
|
||||||
|
|
||||||
|
connect(
|
||||||
|
this,
|
||||||
|
&RoomlistModel::fetchedPreview,
|
||||||
|
this,
|
||||||
|
[this](QString roomid, RoomInfo info) {
|
||||||
|
if (this->previewedRooms.contains(roomid)) {
|
||||||
|
this->previewedRooms.insert(roomid, std::move(info));
|
||||||
|
auto idx = this->roomidToIndex(roomid);
|
||||||
|
emit dataChanged(index(idx),
|
||||||
|
index(idx),
|
||||||
|
{
|
||||||
|
Roles::RoomName,
|
||||||
|
Roles::AvatarUrl,
|
||||||
|
Roles::IsSpace,
|
||||||
|
Roles::IsPreviewFetched,
|
||||||
|
Qt::DisplayRole,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray>
|
QHash<int, QByteArray>
|
||||||
|
@ -61,6 +82,16 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
if (index.row() >= 0 && static_cast<size_t>(index.row()) < roomids.size()) {
|
if (index.row() >= 0 && static_cast<size_t>(index.row()) < roomids.size()) {
|
||||||
auto roomid = roomids.at(index.row());
|
auto roomid = roomids.at(index.row());
|
||||||
|
|
||||||
|
if (role == Roles::ParentSpaces) {
|
||||||
|
auto parents = cache::client()->getParentRoomIds(roomid.toStdString());
|
||||||
|
QStringList list;
|
||||||
|
for (const auto &t : parents)
|
||||||
|
list.push_back(QString::fromStdString(t));
|
||||||
|
return list;
|
||||||
|
} else if (role == Roles::RoomId) {
|
||||||
|
return roomid;
|
||||||
|
}
|
||||||
|
|
||||||
if (models.contains(roomid)) {
|
if (models.contains(roomid)) {
|
||||||
auto room = models.value(roomid);
|
auto room = models.value(roomid);
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
@ -68,8 +99,6 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
return room->roomAvatarUrl();
|
return room->roomAvatarUrl();
|
||||||
case Roles::RoomName:
|
case Roles::RoomName:
|
||||||
return room->plainRoomName();
|
return room->plainRoomName();
|
||||||
case Roles::RoomId:
|
|
||||||
return room->roomId();
|
|
||||||
case Roles::LastMessage:
|
case Roles::LastMessage:
|
||||||
return room->lastMessage().body;
|
return room->lastMessage().body;
|
||||||
case Roles::Time:
|
case Roles::Time:
|
||||||
|
@ -88,6 +117,8 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
return false;
|
return false;
|
||||||
case Roles::IsSpace:
|
case Roles::IsSpace:
|
||||||
return room->isSpace();
|
return room->isSpace();
|
||||||
|
case Roles::IsPreview:
|
||||||
|
return false;
|
||||||
case Roles::Tags: {
|
case Roles::Tags: {
|
||||||
auto info = cache::singleRoomInfo(roomid.toStdString());
|
auto info = cache::singleRoomInfo(roomid.toStdString());
|
||||||
QStringList list;
|
QStringList list;
|
||||||
|
@ -95,14 +126,6 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
list.push_back(QString::fromStdString(t));
|
list.push_back(QString::fromStdString(t));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
case Roles::ParentSpaces: {
|
|
||||||
auto parents =
|
|
||||||
cache::client()->getParentRoomIds(roomid.toStdString());
|
|
||||||
QStringList list;
|
|
||||||
for (const auto &t : parents)
|
|
||||||
list.push_back(QString::fromStdString(t));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -113,8 +136,6 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
return QString::fromStdString(room.avatar_url);
|
return QString::fromStdString(room.avatar_url);
|
||||||
case Roles::RoomName:
|
case Roles::RoomName:
|
||||||
return QString::fromStdString(room.name);
|
return QString::fromStdString(room.name);
|
||||||
case Roles::RoomId:
|
|
||||||
return roomid;
|
|
||||||
case Roles::LastMessage:
|
case Roles::LastMessage:
|
||||||
return QString();
|
return QString();
|
||||||
case Roles::Time:
|
case Roles::Time:
|
||||||
|
@ -130,22 +151,78 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
return true;
|
return true;
|
||||||
case Roles::IsSpace:
|
case Roles::IsSpace:
|
||||||
return false;
|
return false;
|
||||||
|
case Roles::IsPreview:
|
||||||
|
return false;
|
||||||
case Roles::Tags:
|
case Roles::Tags:
|
||||||
return QStringList();
|
return QStringList();
|
||||||
case Roles::ParentSpaces: {
|
default:
|
||||||
auto parents =
|
return {};
|
||||||
cache::client()->getParentRoomIds(roomid.toStdString());
|
|
||||||
QStringList list;
|
|
||||||
for (const auto &t : parents)
|
|
||||||
list.push_back(QString::fromStdString(t));
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
} else if (previewedRooms.contains(roomid) &&
|
||||||
|
previewedRooms.value(roomid).has_value()) {
|
||||||
|
auto room = previewedRooms.value(roomid).value();
|
||||||
|
switch (role) {
|
||||||
|
case Roles::AvatarUrl:
|
||||||
|
return QString::fromStdString(room.avatar_url);
|
||||||
|
case Roles::RoomName:
|
||||||
|
return QString::fromStdString(room.name);
|
||||||
|
case Roles::LastMessage:
|
||||||
|
return tr("Previewing this room");
|
||||||
|
case Roles::Time:
|
||||||
|
return QString();
|
||||||
|
case Roles::Timestamp:
|
||||||
|
return QVariant(static_cast<quint64>(0));
|
||||||
|
case Roles::HasUnreadMessages:
|
||||||
|
case Roles::HasLoudNotification:
|
||||||
|
return false;
|
||||||
|
case Roles::NotificationCount:
|
||||||
|
return 0;
|
||||||
|
case Roles::IsInvite:
|
||||||
|
return false;
|
||||||
|
case Roles::IsSpace:
|
||||||
|
return room.is_space;
|
||||||
|
case Roles::IsPreview:
|
||||||
|
return true;
|
||||||
|
case Roles::IsPreviewFetched:
|
||||||
|
return true;
|
||||||
|
case Roles::Tags:
|
||||||
|
return QStringList();
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (role == Roles::IsPreview)
|
||||||
|
return true;
|
||||||
|
else if (role == Roles::IsPreviewFetched)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fetchPreview(roomid);
|
||||||
|
switch (role) {
|
||||||
|
case Roles::AvatarUrl:
|
||||||
|
return QString();
|
||||||
|
case Roles::RoomName:
|
||||||
|
return tr("No preview available");
|
||||||
|
case Roles::LastMessage:
|
||||||
|
return QString();
|
||||||
|
case Roles::Time:
|
||||||
|
return QString();
|
||||||
|
case Roles::Timestamp:
|
||||||
|
return QVariant(static_cast<quint64>(0));
|
||||||
|
case Roles::HasUnreadMessages:
|
||||||
|
case Roles::HasLoudNotification:
|
||||||
|
return false;
|
||||||
|
case Roles::NotificationCount:
|
||||||
|
return 0;
|
||||||
|
case Roles::IsInvite:
|
||||||
|
return false;
|
||||||
|
case Roles::IsSpace:
|
||||||
|
return false;
|
||||||
|
case Roles::Tags:
|
||||||
|
return QStringList();
|
||||||
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -248,25 +325,111 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
|
||||||
|
|
||||||
newRoom->updateLastMessage();
|
newRoom->updateLastMessage();
|
||||||
|
|
||||||
|
std::vector<QString> previewsToAdd;
|
||||||
|
if (newRoom->isSpace()) {
|
||||||
|
auto childs = cache::client()->getChildRoomIds(room_id.toStdString());
|
||||||
|
for (const auto &c : childs) {
|
||||||
|
auto id = QString::fromStdString(c);
|
||||||
|
if (!(models.contains(id) || invites.contains(id) ||
|
||||||
|
previewedRooms.contains(id))) {
|
||||||
|
previewsToAdd.push_back(std::move(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool wasInvite = invites.contains(room_id);
|
bool wasInvite = invites.contains(room_id);
|
||||||
if (!suppressInsertNotification && !wasInvite)
|
bool wasPreview = previewedRooms.contains(room_id);
|
||||||
beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size());
|
if (!suppressInsertNotification &&
|
||||||
|
((!wasInvite && !wasPreview) || !previewedRooms.empty()))
|
||||||
|
// if the old room was already in the list, don't add it. Also add all
|
||||||
|
// previews at the same time.
|
||||||
|
beginInsertRows(QModelIndex(),
|
||||||
|
(int)roomids.size(),
|
||||||
|
(int)(roomids.size() + previewsToAdd.size() -
|
||||||
|
((wasInvite || wasPreview) ? 0 : 1)));
|
||||||
|
|
||||||
models.insert(room_id, std::move(newRoom));
|
models.insert(room_id, std::move(newRoom));
|
||||||
|
|
||||||
if (wasInvite) {
|
if (wasInvite) {
|
||||||
auto idx = roomidToIndex(room_id);
|
auto idx = roomidToIndex(room_id);
|
||||||
invites.remove(room_id);
|
invites.remove(room_id);
|
||||||
emit dataChanged(index(idx), index(idx));
|
emit dataChanged(index(idx), index(idx));
|
||||||
|
} else if (wasPreview) {
|
||||||
|
auto idx = roomidToIndex(room_id);
|
||||||
|
previewedRooms.remove(room_id);
|
||||||
|
emit dataChanged(index(idx), index(idx));
|
||||||
} else {
|
} else {
|
||||||
roomids.push_back(room_id);
|
roomids.push_back(room_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto p : previewsToAdd) {
|
||||||
|
previewedRooms.insert(p, std::nullopt);
|
||||||
|
roomids.push_back(std::move(p));
|
||||||
|
}
|
||||||
|
|
||||||
if (!suppressInsertNotification && !wasInvite)
|
if (!suppressInsertNotification && !wasInvite)
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomlistModel::fetchPreview(QString roomid_) const
|
||||||
|
{
|
||||||
|
std::string roomid = roomid_.toStdString();
|
||||||
|
http::client()->get_state_event<mtx::events::state::Create>(
|
||||||
|
roomid,
|
||||||
|
"",
|
||||||
|
[this, roomid](const mtx::events::state::Create &c, mtx::http::RequestErr err) {
|
||||||
|
bool is_space = false;
|
||||||
|
if (!err) {
|
||||||
|
is_space = c.type == mtx::events::state::room_type::space;
|
||||||
|
}
|
||||||
|
|
||||||
|
http::client()->get_state_event<mtx::events::state::Avatar>(
|
||||||
|
roomid,
|
||||||
|
"",
|
||||||
|
[this, roomid, is_space](const mtx::events::state::Avatar &a,
|
||||||
|
mtx::http::RequestErr) {
|
||||||
|
auto avatar_url = a.url;
|
||||||
|
|
||||||
|
http::client()->get_state_event<mtx::events::state::Topic>(
|
||||||
|
roomid,
|
||||||
|
"",
|
||||||
|
[this, roomid, avatar_url, is_space](
|
||||||
|
const mtx::events::state::Topic &t, mtx::http::RequestErr) {
|
||||||
|
auto topic = t.topic;
|
||||||
|
http::client()->get_state_event<mtx::events::state::Name>(
|
||||||
|
roomid,
|
||||||
|
"",
|
||||||
|
[this, roomid, topic, avatar_url, is_space](
|
||||||
|
const mtx::events::state::Name &n,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->warn(
|
||||||
|
"Failed to fetch name event to "
|
||||||
|
"create preview for {}",
|
||||||
|
roomid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't even add a preview, if we got not a single
|
||||||
|
// response
|
||||||
|
if (n.name.empty() && avatar_url.empty() &&
|
||||||
|
topic.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
RoomInfo info{};
|
||||||
|
info.name = n.name;
|
||||||
|
info.is_space = is_space;
|
||||||
|
info.avatar_url = avatar_url;
|
||||||
|
info.topic = topic;
|
||||||
|
|
||||||
|
const_cast<RoomlistModel *>(this)->fetchedPreview(
|
||||||
|
QString::fromStdString(roomid), info);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RoomlistModel::sync(const mtx::responses::Rooms &rooms)
|
RoomlistModel::sync(const mtx::responses::Rooms &rooms)
|
||||||
{
|
{
|
||||||
|
@ -426,7 +589,9 @@ RoomlistModel::setCurrentRoom(QString roomid)
|
||||||
namespace {
|
namespace {
|
||||||
enum NotificationImportance : short
|
enum NotificationImportance : short
|
||||||
{
|
{
|
||||||
ImportanceDisabled = -1,
|
ImportanceDisabled = -3,
|
||||||
|
NoPreview = -2,
|
||||||
|
Preview = -1,
|
||||||
AllEventsRead = 0,
|
AllEventsRead = 0,
|
||||||
NewMessage = 1,
|
NewMessage = 1,
|
||||||
NewMentions = 2,
|
NewMentions = 2,
|
||||||
|
@ -448,6 +613,11 @@ FilteredRoomlistModel::calculateImportance(const QModelIndex &idx) const
|
||||||
return CurrentSpace;
|
return CurrentSpace;
|
||||||
else
|
else
|
||||||
return SubSpace;
|
return SubSpace;
|
||||||
|
} else if (sourceModel()->data(idx, RoomlistModel::IsPreview).toBool()) {
|
||||||
|
if (sourceModel()->data(idx, RoomlistModel::IsPreviewFetched).toBool())
|
||||||
|
return Preview;
|
||||||
|
else
|
||||||
|
return NoPreview;
|
||||||
} else if (sourceModel()->data(idx, RoomlistModel::IsInvite).toBool()) {
|
} else if (sourceModel()->data(idx, RoomlistModel::IsInvite).toBool()) {
|
||||||
return Invite;
|
return Invite;
|
||||||
} else if (!this->sortByImportance) {
|
} else if (!this->sortByImportance) {
|
||||||
|
@ -460,6 +630,7 @@ FilteredRoomlistModel::calculateImportance(const QModelIndex &idx) const
|
||||||
return AllEventsRead;
|
return AllEventsRead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FilteredRoomlistModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
FilteredRoomlistModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
{
|
{
|
||||||
|
@ -531,6 +702,12 @@ bool
|
||||||
FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) const
|
FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) const
|
||||||
{
|
{
|
||||||
if (filterType == FilterBy::Nothing) {
|
if (filterType == FilterBy::Nothing) {
|
||||||
|
if (sourceModel()
|
||||||
|
->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsPreview)
|
||||||
|
.toBool()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sourceModel()
|
if (sourceModel()
|
||||||
->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace)
|
->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace)
|
||||||
.toBool()) {
|
.toBool()) {
|
||||||
|
@ -560,6 +737,12 @@ FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) cons
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (filterType == FilterBy::Tag) {
|
} else if (filterType == FilterBy::Tag) {
|
||||||
|
if (sourceModel()
|
||||||
|
->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsPreview)
|
||||||
|
.toBool()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sourceModel()
|
if (sourceModel()
|
||||||
->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace)
|
->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace)
|
||||||
.toBool()) {
|
.toBool()) {
|
||||||
|
|
|
@ -37,6 +37,8 @@ public:
|
||||||
NotificationCount,
|
NotificationCount,
|
||||||
IsInvite,
|
IsInvite,
|
||||||
IsSpace,
|
IsSpace,
|
||||||
|
IsPreview,
|
||||||
|
IsPreviewFetched,
|
||||||
Tags,
|
Tags,
|
||||||
ParentSpaces,
|
ParentSpaces,
|
||||||
};
|
};
|
||||||
|
@ -87,15 +89,18 @@ private slots:
|
||||||
signals:
|
signals:
|
||||||
void totalUnreadMessageCountUpdated(int unreadMessages);
|
void totalUnreadMessageCountUpdated(int unreadMessages);
|
||||||
void currentRoomChanged();
|
void currentRoomChanged();
|
||||||
|
void fetchedPreview(QString roomid, RoomInfo info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
|
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
|
||||||
|
void fetchPreview(QString roomid) const;
|
||||||
|
|
||||||
TimelineViewManager *manager = nullptr;
|
TimelineViewManager *manager = nullptr;
|
||||||
std::vector<QString> roomids;
|
std::vector<QString> roomids;
|
||||||
QHash<QString, RoomInfo> invites;
|
QHash<QString, RoomInfo> invites;
|
||||||
QHash<QString, QSharedPointer<TimelineModel>> models;
|
QHash<QString, QSharedPointer<TimelineModel>> models;
|
||||||
std::map<QString, bool> roomReadStatus;
|
std::map<QString, bool> roomReadStatus;
|
||||||
|
QHash<QString, std::optional<RoomInfo>> previewedRooms;
|
||||||
|
|
||||||
QSharedPointer<TimelineModel> currentRoom_;
|
QSharedPointer<TimelineModel> currentRoom_;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue