Reenable invites

This commit is contained in:
Nicolas Werner 2021-05-24 14:04:07 +02:00
parent 6112badb08
commit c290b0747f
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
14 changed files with 260 additions and 51 deletions

View file

@ -141,6 +141,8 @@ Page {
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 0 spacing: 0
visible: !model.isInvite
height: visible ? 0 : undefined
ElidedLabel { ElidedLabel {
color: roomItem.unimportantText color: roomItem.unimportantText
@ -182,6 +184,60 @@ Page {
} }
RowLayout {
Layout.fillWidth: true
spacing: Nheko.paddingMedium
visible: model.isInvite
enabled: visible
height: visible ? 0 : undefined
ElidedLabel {
elideWidth: textContent.width / 2 - 2 * Nheko.paddingMedium
fullText: qsTr("Accept")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
leftPadding: Nheko.paddingMedium
rightPadding: Nheko.paddingMedium
color: Nheko.colors.brightText
TapHandler {
onSingleTapped: Rooms.acceptInvite(model.roomId)
}
background: Rectangle {
color: Nheko.theme.alternateButton
radius: height / 2
}
}
ElidedLabel {
Layout.alignment: Qt.AlignRight
elideWidth: textContent.width / 2 - 2 * Nheko.paddingMedium
fullText: qsTr("Decline")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
leftPadding: Nheko.paddingMedium
rightPadding: Nheko.paddingMedium
color: Nheko.colors.brightText
TapHandler {
onSingleTapped: Rooms.declineInvite(model.roomId)
}
background: Rectangle {
color: Nheko.theme.alternateButton
radius: height / 2
}
}
Item {
Layout.fillWidth: true
}
}
} }
} }

View file

@ -2045,21 +2045,57 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
return fallbackDesc; return fallbackDesc;
} }
std::map<QString, bool> QHash<QString, RoomInfo>
Cache::invites() Cache::invites()
{ {
std::map<QString, bool> result; QHash<QString, RoomInfo> result;
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto cursor = lmdb::cursor::open(txn, invitesDb_); auto cursor = lmdb::cursor::open(txn, invitesDb_);
std::string_view room_id, unused; std::string_view room_id, room_data;
while (cursor.get(room_id, unused, MDB_NEXT)) while (cursor.get(room_id, room_data, MDB_NEXT)) {
result.emplace(QString::fromStdString(std::string(room_id)), true); try {
RoomInfo tmp = json::parse(room_data);
tmp.member_count = getInviteMembersDb(txn, std::string(room_id)).size(txn);
result.insert(QString::fromStdString(std::string(room_id)), std::move(tmp));
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse room info for invite: "
"room_id ({}), {}: {}",
room_id,
std::string(room_data),
e.what());
}
}
cursor.close(); cursor.close();
txn.commit();
return result;
}
std::optional<RoomInfo>
Cache::invite(std::string_view roomid)
{
std::optional<RoomInfo> result;
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
std::string_view room_data;
if (invitesDb_.get(txn, roomid, room_data)) {
try {
RoomInfo tmp = json::parse(room_data);
tmp.member_count = getInviteMembersDb(txn, std::string(roomid)).size(txn);
result = std::move(tmp);
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse room info for invite: "
"room_id ({}), {}: {}",
roomid,
std::string(room_data),
e.what());
}
}
return result; return result;
} }
@ -4064,7 +4100,7 @@ roomInfo(bool withInvites)
{ {
return instance_->roomInfo(withInvites); return instance_->roomInfo(withInvites);
} }
std::map<QString, bool> QHash<QString, RoomInfo>
invites() invites()
{ {
return instance_->invites(); return instance_->invites();

View file

@ -62,7 +62,7 @@ joinedRooms();
QMap<QString, RoomInfo> QMap<QString, RoomInfo>
roomInfo(bool withInvites = true); roomInfo(bool withInvites = true);
std::map<QString, bool> QHash<QString, RoomInfo>
invites(); invites();
//! Calculate & return the name of the room. //! Calculate & return the name of the room.

View file

@ -70,7 +70,8 @@ public:
QMap<QString, RoomInfo> roomInfo(bool withInvites = true); QMap<QString, RoomInfo> roomInfo(bool withInvites = true);
std::optional<mtx::events::state::CanonicalAlias> getRoomAliases(const std::string &roomid); std::optional<mtx::events::state::CanonicalAlias> getRoomAliases(const std::string &roomid);
std::map<QString, bool> invites(); QHash<QString, RoomInfo> invites();
std::optional<RoomInfo> invite(std::string_view roomid);
//! Calculate & return the name of the room. //! Calculate & return the name of the room.
QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);

View file

@ -313,7 +313,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
connect(this, connect(this,
&ChatPage::initializeEmptyViews, &ChatPage::initializeEmptyViews,
view_manager_, view_manager_,
&TimelineViewManager::initWithMessages); &TimelineViewManager::initializeRoomlist);
connect(this, connect(this,
&ChatPage::initializeMentions, &ChatPage::initializeMentions,
user_mentions_popup_, user_mentions_popup_,
@ -554,7 +554,7 @@ ChatPage::loadStateFromCache()
try { try {
olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY); olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
emit initializeEmptyViews(cache::client()->roomIds()); emit initializeEmptyViews();
emit initializeRoomList(cache::roomInfo()); emit initializeRoomList(cache::roomInfo());
emit initializeMentions(cache::getTimelineMentions()); emit initializeMentions(cache::getTimelineMentions());
emit syncTags(cache::roomInfo().toStdMap()); emit syncTags(cache::roomInfo().toStdMap());

View file

@ -147,7 +147,7 @@ signals:
void initializeRoomList(QMap<QString, RoomInfo>); void initializeRoomList(QMap<QString, RoomInfo>);
void initializeViews(const mtx::responses::Rooms &rooms); void initializeViews(const mtx::responses::Rooms &rooms);
void initializeEmptyViews(const std::vector<QString> &roomIds); void initializeEmptyViews();
void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs); void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs);
void syncUI(const mtx::responses::Rooms &rooms); void syncUI(const mtx::responses::Rooms &rooms);
void syncRoomlist(const std::map<QString, RoomInfo> &updates); void syncRoomlist(const std::map<QString, RoomInfo> &updates);

View file

@ -183,7 +183,7 @@ RoomList::initialize(const QMap<QString, RoomInfo> &info)
} }
void void
RoomList::cleanupInvites(const std::map<QString, bool> &invites) RoomList::cleanupInvites(const QHash<QString, RoomInfo> &invites)
{ {
if (invites.size() == 0) if (invites.size() == 0)
return; return;

View file

@ -48,7 +48,7 @@ public:
//! Show all the available rooms. //! Show all the available rooms.
void removeFilter(const std::set<QString> &roomsToHide); void removeFilter(const std::set<QString> &roomsToHide);
void updateRoom(const QString &room_id, const RoomInfo &info); void updateRoom(const QString &room_id, const RoomInfo &info);
void cleanupInvites(const std::map<QString, bool> &invites); void cleanupInvites(const QHash<QString, RoomInfo> &invites);
signals: signals:
void roomChanged(const QString &room_id); void roomChanged(const QString &room_id);

View file

@ -57,31 +57,64 @@ 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());
auto room = models.value(roomid);
switch (role) { if (models.contains(roomid)) {
case Roles::AvatarUrl: auto room = models.value(roomid);
return room->roomAvatarUrl(); switch (role) {
case Roles::RoomName: case Roles::AvatarUrl:
return room->plainRoomName(); return room->roomAvatarUrl();
case Roles::RoomId: case Roles::RoomName:
return room->roomId(); return room->plainRoomName();
case Roles::LastMessage: case Roles::RoomId:
return room->lastMessage().body; return room->roomId();
case Roles::Time: case Roles::LastMessage:
return room->lastMessage().descriptiveTime; return room->lastMessage().body;
case Roles::Timestamp: case Roles::Time:
return QVariant(static_cast<quint64>(room->lastMessage().timestamp)); return room->lastMessage().descriptiveTime;
case Roles::HasUnreadMessages: case Roles::Timestamp:
return this->roomReadStatus.count(roomid) && return QVariant(
this->roomReadStatus.at(roomid); static_cast<quint64>(room->lastMessage().timestamp));
case Roles::HasLoudNotification: case Roles::HasUnreadMessages:
return room->hasMentions(); return this->roomReadStatus.count(roomid) &&
case Roles::NotificationCount: this->roomReadStatus.at(roomid);
return room->notificationCount(); case Roles::HasLoudNotification:
case Roles::IsInvite: return room->hasMentions();
case Roles::IsSpace: case Roles::NotificationCount:
return false; return room->notificationCount();
default: case Roles::IsInvite:
case Roles::IsSpace:
return false;
default:
return {};
}
} else if (invites.contains(roomid)) {
auto room = invites.value(roomid);
switch (role) {
case Roles::AvatarUrl:
return QString::fromStdString(room.avatar_url);
case Roles::RoomName:
return QString::fromStdString(room.name);
case Roles::RoomId:
return roomid;
case Roles::LastMessage:
return room.msgInfo.body;
case Roles::Time:
return room.msgInfo.descriptiveTime;
case Roles::Timestamp:
return QVariant(static_cast<quint64>(room.msgInfo.timestamp));
case Roles::HasUnreadMessages:
case Roles::HasLoudNotification:
return false;
case Roles::NotificationCount:
return 0;
case Roles::IsInvite:
return true;
case Roles::IsSpace:
return false;
default:
return {};
}
} else {
return {}; return {};
} }
} else { } else {
@ -109,7 +142,7 @@ RoomlistModel::updateReadStatus(const std::map<QString, bool> roomReadStatus_)
Roles::HasUnreadMessages, Roles::HasUnreadMessages,
}); });
} }
}; }
void void
RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification) RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
{ {
@ -186,11 +219,21 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
newRoom->updateLastMessage(); newRoom->updateLastMessage();
if (!suppressInsertNotification) bool wasInvite = invites.contains(room_id);
if (!suppressInsertNotification && !wasInvite)
beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size()); beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size());
models.insert(room_id, std::move(newRoom)); models.insert(room_id, std::move(newRoom));
roomids.push_back(room_id);
if (!suppressInsertNotification) if (wasInvite) {
auto idx = roomidToIndex(room_id);
invites.remove(room_id);
emit dataChanged(index(idx), index(idx));
} else {
roomids.push_back(room_id);
}
if (!suppressInsertNotification && !wasInvite)
endInsertRows(); endInsertRows();
} }
} }
@ -234,20 +277,50 @@ RoomlistModel::sync(const mtx::responses::Rooms &rooms)
if (idx != -1) { if (idx != -1) {
beginRemoveRows(QModelIndex(), idx, idx); beginRemoveRows(QModelIndex(), idx, idx);
roomids.erase(roomids.begin() + idx); roomids.erase(roomids.begin() + idx);
models.remove(QString::fromStdString(room_id)); if (models.contains(QString::fromStdString(room_id)))
models.remove(QString::fromStdString(room_id));
else if (invites.contains(QString::fromStdString(room_id)))
invites.remove(QString::fromStdString(room_id));
endRemoveRows(); endRemoveRows();
} }
} }
for (const auto &[room_id, room] : rooms.invite) {
(void)room_id;
auto qroomid = QString::fromStdString(room_id);
auto invite = cache::client()->invite(room_id);
if (!invite)
continue;
if (invites.contains(qroomid)) {
invites[qroomid] = *invite;
auto idx = roomidToIndex(qroomid);
emit dataChanged(index(idx), index(idx));
} else {
beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size());
invites.insert(qroomid, *invite);
roomids.push_back(std::move(qroomid));
endInsertRows();
}
}
} }
void void
RoomlistModel::initializeRooms(const std::vector<QString> &roomIds_) RoomlistModel::initializeRooms()
{ {
beginResetModel(); beginResetModel();
models.clear(); models.clear();
roomids.clear(); roomids.clear();
for (const auto &id : roomIds_) invites.clear();
invites = cache::client()->invites();
for (const auto &id : invites.keys())
roomids.push_back(id);
for (const auto &id : cache::client()->roomIds())
addRoom(id, true); addRoom(id, true);
endResetModel(); endResetModel();
} }
@ -256,10 +329,42 @@ RoomlistModel::clear()
{ {
beginResetModel(); beginResetModel();
models.clear(); models.clear();
invites.clear();
roomids.clear(); roomids.clear();
endResetModel(); endResetModel();
} }
void
RoomlistModel::acceptInvite(QString roomid)
{
if (invites.contains(roomid)) {
auto idx = roomidToIndex(roomid);
if (idx != -1) {
beginRemoveRows(QModelIndex(), idx, idx);
roomids.erase(roomids.begin() + idx);
invites.remove(roomid);
endRemoveRows();
ChatPage::instance()->joinRoom(roomid);
}
}
}
void
RoomlistModel::declineInvite(QString roomid)
{
if (invites.contains(roomid)) {
auto idx = roomidToIndex(roomid);
if (idx != -1) {
beginRemoveRows(QModelIndex(), idx, idx);
roomids.erase(roomids.begin() + idx);
invites.remove(roomid);
endRemoveRows();
ChatPage::instance()->leaveRoom(roomid);
}
}
}
namespace { namespace {
enum NotificationImportance : short enum NotificationImportance : short
{ {

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <CacheStructs.h>
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QHash> #include <QHash>
#include <QSharedPointer> #include <QSharedPointer>
@ -51,7 +52,7 @@ public:
} }
public slots: public slots:
void initializeRooms(const std::vector<QString> &roomids); void initializeRooms();
void sync(const mtx::responses::Rooms &rooms); void sync(const mtx::responses::Rooms &rooms);
void clear(); void clear();
int roomidToIndex(QString roomid) int roomidToIndex(QString roomid)
@ -63,6 +64,8 @@ public slots:
return -1; return -1;
} }
void acceptInvite(QString roomid);
void declineInvite(QString roomid);
private slots: private slots:
void updateReadStatus(const std::map<QString, bool> roomReadStatus_); void updateReadStatus(const std::map<QString, bool> roomReadStatus_);
@ -75,6 +78,7 @@ private:
TimelineViewManager *manager = nullptr; TimelineViewManager *manager = nullptr;
std::vector<QString> roomids; std::vector<QString> roomids;
QHash<QString, RoomInfo> invites;
QHash<QString, QSharedPointer<TimelineModel>> models; QHash<QString, QSharedPointer<TimelineModel>> models;
std::map<QString, bool> roomReadStatus; std::map<QString, bool> roomReadStatus;
@ -94,6 +98,8 @@ public slots:
return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid))) return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid)))
.row(); .row();
} }
void acceptInvite(QString roomid) { roomlistmodel->acceptInvite(roomid); }
void declineInvite(QString roomid) { roomlistmodel->declineInvite(roomid); }
private: private:
short int calculateImportance(const QModelIndex &idx) const; short int calculateImportance(const QModelIndex &idx) const;

View file

@ -499,9 +499,9 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s
} }
void void
TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds) TimelineViewManager::initializeRoomlist()
{ {
rooms->initializeRooms(roomIds); rooms->initializeRooms();
} }
void void

View file

@ -100,7 +100,7 @@ signals:
public slots: public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids); void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
void receivedSessionKey(const std::string &room_id, const std::string &session_id); void receivedSessionKey(const std::string &room_id, const std::string &session_id);
void initWithMessages(const std::vector<QString> &roomIds); void initializeRoomlist();
void chatFocusChanged(bool focused) void chatFocusChanged(bool focused)
{ {
isWindowFocused_ = focused; isWindowFocused_ = focused;

View file

@ -60,12 +60,15 @@ Theme::Theme(std::string_view theme)
separator_ = p.mid().color(); separator_ = p.mid().color();
if (theme == "light") { if (theme == "light") {
sidebarBackground_ = QColor("#233649"); sidebarBackground_ = QColor("#233649");
alternateButton_ = QColor("#ccc");
red_ = QColor("#a82353"); red_ = QColor("#a82353");
} else if (theme == "dark") { } else if (theme == "dark") {
sidebarBackground_ = QColor("#2d3139"); sidebarBackground_ = QColor("#2d3139");
alternateButton_ = QColor("#414A59");
red_ = QColor("#a82353"); red_ = QColor("#a82353");
} else { } else {
sidebarBackground_ = p.window().color(); sidebarBackground_ = p.window().color();
alternateButton_ = p.dark().color();
red_ = QColor("red"); red_ = QColor("red");
} }
} }

View file

@ -65,6 +65,7 @@ class Theme : public QPalette
{ {
Q_GADGET Q_GADGET
Q_PROPERTY(QColor sidebarBackground READ sidebarBackground CONSTANT) Q_PROPERTY(QColor sidebarBackground READ sidebarBackground CONSTANT)
Q_PROPERTY(QColor alternateButton READ alternateButton CONSTANT)
Q_PROPERTY(QColor separator READ separator CONSTANT) Q_PROPERTY(QColor separator READ separator CONSTANT)
Q_PROPERTY(QColor red READ red CONSTANT) Q_PROPERTY(QColor red READ red CONSTANT)
public: public:
@ -73,9 +74,10 @@ public:
static QPalette paletteFromTheme(std::string_view theme); static QPalette paletteFromTheme(std::string_view theme);
QColor sidebarBackground() const { return sidebarBackground_; } QColor sidebarBackground() const { return sidebarBackground_; }
QColor alternateButton() const { return alternateButton_; }
QColor separator() const { return separator_; } QColor separator() const { return separator_; }
QColor red() const { return red_; } QColor red() const { return red_; }
private: private:
QColor sidebarBackground_, separator_, red_; QColor sidebarBackground_, separator_, red_, alternateButton_;
}; };