Leaving rooms implemented
both locally using the room menu in nheko, and reacting properly when leaving a room remotely from another client
This commit is contained in:
parent
7638e0f97d
commit
6b87574e45
@ -37,6 +37,8 @@ public:
|
||||
inline void unmount();
|
||||
inline QString memberDbName(const QString &roomid);
|
||||
|
||||
void removeRoom(const QString &roomid);
|
||||
|
||||
private:
|
||||
void setNextBatchToken(lmdb::txn &txn, const QString &token);
|
||||
void insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &state);
|
||||
|
@ -61,6 +61,8 @@ private slots:
|
||||
void changeTopRoomInfo(const QString &room_id);
|
||||
void startSync();
|
||||
void logout();
|
||||
void joinedRoom(const QString &room_id);
|
||||
void leftRoom(const QString &room_id);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
void messages(const QString &room_id, const QString &from_token, int limit = 20) noexcept;
|
||||
void uploadImage(const QString &roomid, const QString &filename);
|
||||
void joinRoom(const QString &roomIdOrAlias);
|
||||
void leaveRoom(const QString &roomId);
|
||||
|
||||
inline QUrl getHomeServer();
|
||||
inline int transactionId();
|
||||
@ -96,6 +97,7 @@ signals:
|
||||
void emoteSent(const QString &event_id, const QString &roomid, const int txn_id);
|
||||
void messagesRetrieved(const QString &room_id, const RoomMessages &msgs);
|
||||
void joinedRoom(const QString &room_id);
|
||||
void leftRoom(const QString &room_id);
|
||||
|
||||
private slots:
|
||||
void onResponse(QNetworkReply *reply);
|
||||
@ -118,6 +120,7 @@ private:
|
||||
UserAvatar,
|
||||
Versions,
|
||||
JoinRoom,
|
||||
LeaveRoom,
|
||||
};
|
||||
|
||||
// Response handlers.
|
||||
@ -136,6 +139,7 @@ private:
|
||||
void onUserAvatarResponse(QNetworkReply *reply);
|
||||
void onVersionsResponse(QNetworkReply *reply);
|
||||
void onJoinRoomResponse(QNetworkReply *reply);
|
||||
void onLeaveRoomResponse(QNetworkReply *reply);
|
||||
|
||||
// Client API prefix.
|
||||
QString clientApiUrl_;
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
|
||||
signals:
|
||||
void clicked(const QString &room_id);
|
||||
void leaveRoom(const QString &room_id);
|
||||
|
||||
public slots:
|
||||
void setPressedState(bool state);
|
||||
@ -86,6 +87,7 @@ private:
|
||||
|
||||
Menu *menu_;
|
||||
QAction *toggleNotifications_;
|
||||
QAction *leaveRoom_;
|
||||
|
||||
QSharedPointer<RoomSettings> roomSettings_;
|
||||
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
|
||||
void clear();
|
||||
|
||||
void removeRoom(const QString &room_id, bool reset);
|
||||
|
||||
signals:
|
||||
void roomChanged(const QString &room_id);
|
||||
void totalUnreadMessageCountUpdated(int count);
|
||||
@ -53,8 +55,6 @@ public slots:
|
||||
void highlightSelectedRoom(const QString &room_id);
|
||||
void updateUnreadMessageCount(const QString &roomid, int count);
|
||||
void updateRoomDescription(const QString &roomid, const DescInfo &info);
|
||||
|
||||
private slots:
|
||||
void closeJoinRoomDialog(bool isJoining, QString roomAlias);
|
||||
|
||||
private:
|
||||
|
@ -171,15 +171,42 @@ JoinedRoom::timeline() const
|
||||
return timeline_;
|
||||
}
|
||||
|
||||
class LeftRoom : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline State state() const;
|
||||
inline Timeline timeline() const;
|
||||
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
|
||||
private:
|
||||
State state_;
|
||||
Timeline timeline_;
|
||||
};
|
||||
|
||||
inline State
|
||||
LeftRoom::state() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
inline Timeline
|
||||
LeftRoom::timeline() const
|
||||
{
|
||||
return timeline_;
|
||||
}
|
||||
|
||||
// TODO: Add support for invited and left rooms.
|
||||
class Rooms : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QMap<QString, JoinedRoom> join() const;
|
||||
inline QMap<QString, LeftRoom> leave() const;
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
|
||||
private:
|
||||
QMap<QString, JoinedRoom> join_;
|
||||
QMap<QString, LeftRoom> leave_;
|
||||
};
|
||||
|
||||
inline QMap<QString, JoinedRoom>
|
||||
@ -188,6 +215,12 @@ Rooms::join() const
|
||||
return join_;
|
||||
}
|
||||
|
||||
inline QMap<QString, LeftRoom>
|
||||
Rooms::leave() const
|
||||
{
|
||||
return leave_;
|
||||
}
|
||||
|
||||
class SyncResponse : public Deserializable
|
||||
{
|
||||
public:
|
||||
|
@ -51,6 +51,9 @@ public:
|
||||
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
void leaveRoom();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
@ -65,6 +68,7 @@ private:
|
||||
|
||||
QMenu *menu_;
|
||||
QAction *toggleNotifications_;
|
||||
QAction *leaveRoom_;
|
||||
|
||||
FlatButton *settingsBtn_;
|
||||
|
||||
|
13
src/Cache.cc
13
src/Cache.cc
@ -153,6 +153,19 @@ Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &s
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cache::removeRoom(const QString &roomid)
|
||||
{
|
||||
auto txn = lmdb::txn::begin(env_, nullptr, 0);
|
||||
|
||||
lmdb::dbi_del(txn,
|
||||
roomDb_,
|
||||
lmdb::val(roomid.toUtf8(), roomid.toUtf8().size()),
|
||||
nullptr);
|
||||
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
QMap<QString, RoomState>
|
||||
Cache::states()
|
||||
{
|
||||
|
@ -114,6 +114,10 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
connect(user_info_widget_, SIGNAL(logout()), client_.data(), SLOT(logout()));
|
||||
connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout()));
|
||||
|
||||
connect(top_bar_, &TopRoomBar::leaveRoom, this, [=](){
|
||||
client_->leaveRoom(current_room_);
|
||||
});
|
||||
|
||||
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
|
||||
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit);
|
||||
connect(
|
||||
@ -190,6 +194,14 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
SIGNAL(ownAvatarRetrieved(const QPixmap &)),
|
||||
this,
|
||||
SLOT(setOwnAvatar(const QPixmap &)));
|
||||
connect(client_.data(),
|
||||
SIGNAL(joinedRoom(const QString &)),
|
||||
this,
|
||||
SLOT(joinedRoom(const QString &)));
|
||||
connect(client_.data(),
|
||||
SIGNAL(leftRoom(const QString &)),
|
||||
this,
|
||||
SLOT(leftRoom(const QString &)));
|
||||
|
||||
AvatarProvider::init(client);
|
||||
}
|
||||
@ -307,6 +319,7 @@ ChatPage::syncCompleted(const SyncResponse &response)
|
||||
oldState.update(room_state);
|
||||
state_manager_.insert(it.key(), oldState);
|
||||
} else {
|
||||
// TODO: Add newly joined room
|
||||
qWarning() << "New rooms cannot be added after initial sync, yet.";
|
||||
}
|
||||
|
||||
@ -314,6 +327,14 @@ ChatPage::syncCompleted(const SyncResponse &response)
|
||||
changeTopRoomInfo(it.key());
|
||||
}
|
||||
|
||||
auto leave = response.rooms().leave();
|
||||
|
||||
for (auto it = leave.constBegin(); it != leave.constEnd(); it++) {
|
||||
if (state_manager_.contains(it.key())) {
|
||||
leftRoom(it.key());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
cache_->setState(response.nextBatch(), state_manager_);
|
||||
} catch (const lmdb::error &e) {
|
||||
@ -537,6 +558,33 @@ ChatPage::showQuickSwitcher()
|
||||
quickSwitcherModal_->fadeIn();
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::joinedRoom(const QString &room_id)
|
||||
{
|
||||
RoomState room_state;
|
||||
|
||||
state_manager_.insert(room_id, room_state);
|
||||
settingsManager_.insert(room_id,
|
||||
QSharedPointer<RoomSettings>(new RoomSettings(room_id)));
|
||||
|
||||
this->changeTopRoomInfo(room_id);
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::leftRoom(const QString &room_id)
|
||||
{
|
||||
state_manager_.remove(room_id);
|
||||
settingsManager_.remove(room_id);
|
||||
try {
|
||||
cache_->removeRoom(room_id);
|
||||
} catch (const lmdb::error &e) {
|
||||
qCritical() << "The cache couldn't be updated: " << e.what();
|
||||
// TODO: Notify the user.
|
||||
cache_->unmount();
|
||||
}
|
||||
room_list_->removeRoom(room_id, room_id == current_room_);
|
||||
}
|
||||
|
||||
ChatPage::~ChatPage()
|
||||
{
|
||||
sync_timer_->stop();
|
||||
|
@ -480,6 +480,22 @@ MatrixClient::onJoinRoomResponse(QNetworkReply *reply)
|
||||
emit joinedRoom(room_id);
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::onLeaveRoomResponse(QNetworkReply *reply)
|
||||
{
|
||||
reply->deleteLater();
|
||||
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (status == 0 || status >= 400) {
|
||||
qWarning() << reply->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QString room_id = reply->property("room_id").toString();
|
||||
emit leftRoom(room_id);
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::onResponse(QNetworkReply *reply)
|
||||
{
|
||||
@ -529,6 +545,9 @@ MatrixClient::onResponse(QNetworkReply *reply)
|
||||
case Endpoint::JoinRoom:
|
||||
onJoinRoomResponse(reply);
|
||||
break;
|
||||
case Endpoint::LeaveRoom:
|
||||
onLeaveRoomResponse(reply);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -592,7 +611,11 @@ void
|
||||
MatrixClient::sync() noexcept
|
||||
{
|
||||
QJsonObject filter{ { "room",
|
||||
QJsonObject{ { "ephemeral", QJsonObject{ { "limit", 0 } } } } },
|
||||
QJsonObject{
|
||||
{ "include_leave", true },
|
||||
{ "ephemeral", QJsonObject{ { "limit", 0 } } }
|
||||
}
|
||||
},
|
||||
{ "presence", QJsonObject{ { "limit", 0 } } } };
|
||||
|
||||
QUrlQuery query;
|
||||
@ -887,3 +910,21 @@ MatrixClient::joinRoom(const QString &roomIdOrAlias)
|
||||
QNetworkReply *reply = post(request, "{}");
|
||||
reply->setProperty("endpoint", static_cast<int>(Endpoint::JoinRoom));
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::leaveRoom(const QString &roomId)
|
||||
{
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("access_token", token_);
|
||||
|
||||
QUrl endpoint(server_);
|
||||
endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/leave").arg(roomId));
|
||||
endpoint.setQuery(query);
|
||||
|
||||
QNetworkRequest request(endpoint);
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader,"application/json");
|
||||
|
||||
QNetworkReply *reply = post(request, "{}");
|
||||
reply->setProperty("room_id", roomId);
|
||||
reply->setProperty("endpoint", static_cast<int>(Endpoint::LeaveRoom));
|
||||
}
|
||||
|
@ -53,12 +53,17 @@ RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
||||
menu_ = new Menu(this);
|
||||
|
||||
toggleNotifications_ = new QAction(notificationText(), this);
|
||||
|
||||
connect(toggleNotifications_, &QAction::triggered, this, [=]() {
|
||||
roomSettings_->toggleNotifications();
|
||||
});
|
||||
|
||||
leaveRoom_ = new QAction(tr("Leave room"), this);
|
||||
connect(leaveRoom_, &QAction::triggered, this, [=](){
|
||||
emit leaveRoom(room_id);
|
||||
});
|
||||
|
||||
menu_->addAction(toggleNotifications_);
|
||||
menu_->addAction(leaveRoom_);
|
||||
}
|
||||
|
||||
QString
|
||||
|
@ -91,6 +91,20 @@ RoomList::clear()
|
||||
rooms_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
RoomList::removeRoom(const QString &room_id, bool reset)
|
||||
{
|
||||
rooms_.remove(room_id);
|
||||
|
||||
if (rooms_.isEmpty() || !reset)
|
||||
return;
|
||||
|
||||
auto first_room = rooms_.first();
|
||||
first_room->setPressedState(true);
|
||||
|
||||
emit roomChanged(rooms_.firstKey());
|
||||
}
|
||||
|
||||
void
|
||||
RoomList::updateUnreadMessageCount(const QString &roomid, int count)
|
||||
{
|
||||
@ -137,7 +151,11 @@ RoomList::setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &set
|
||||
RoomInfoListItem *room_item =
|
||||
new RoomInfoListItem(settings[room_id], state, room_id, scrollArea_);
|
||||
connect(
|
||||
room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom);
|
||||
room_item, &RoomInfoListItem::clicked,
|
||||
this, &RoomList::highlightSelectedRoom);
|
||||
connect(
|
||||
room_item, &RoomInfoListItem::leaveRoom,
|
||||
client_.data(), &MatrixClient::leaveRoom);
|
||||
|
||||
rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item));
|
||||
|
||||
|
42
src/Sync.cc
42
src/Sync.cc
@ -90,7 +90,6 @@ Rooms::deserialize(const QJsonValue &data)
|
||||
|
||||
for (auto it = join.constBegin(); it != join.constEnd(); it++) {
|
||||
JoinedRoom tmp_room;
|
||||
|
||||
try {
|
||||
tmp_room.deserialize(it.value());
|
||||
join_.insert(it.key(), tmp_room);
|
||||
@ -112,9 +111,22 @@ Rooms::deserialize(const QJsonValue &data)
|
||||
if (!object.value("leave").isObject()) {
|
||||
throw DeserializationException("rooms/leave must be a JSON object");
|
||||
}
|
||||
// TODO: Implement leave handling
|
||||
auto leave = object.value("leave").toObject();
|
||||
|
||||
for (auto it = leave.constBegin(); it != leave.constEnd(); it++) {
|
||||
LeftRoom tmp_room;
|
||||
|
||||
try {
|
||||
tmp_room.deserialize(it.value());
|
||||
leave_.insert(it.key(), tmp_room);
|
||||
} catch (DeserializationException &e) {
|
||||
qWarning() << e.what();
|
||||
qWarning() << "Skipping malformed object for room" << it.key();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
JoinedRoom::deserialize(const QJsonValue &data)
|
||||
@ -184,6 +196,32 @@ JoinedRoom::deserialize(const QJsonValue &data)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LeftRoom::deserialize(const QJsonValue &data)
|
||||
{
|
||||
if (!data.isObject())
|
||||
throw DeserializationException("LeftRoom is not a JSON object");
|
||||
|
||||
QJsonObject object = data.toObject();
|
||||
|
||||
if (!object.contains("state"))
|
||||
throw DeserializationException("join/state is missing");
|
||||
|
||||
if (!object.contains("timeline"))
|
||||
throw DeserializationException("join/timeline is missing");
|
||||
|
||||
if (!object.value("state").isObject())
|
||||
throw DeserializationException("join/state should be an object");
|
||||
|
||||
QJsonObject state = object.value("state").toObject();
|
||||
|
||||
if (!state.contains("events"))
|
||||
throw DeserializationException("join/state/events is missing");
|
||||
|
||||
state_.deserialize(state.value("events"));
|
||||
timeline_.deserialize(object.value("timeline"));
|
||||
}
|
||||
|
||||
void
|
||||
Event::deserialize(const QJsonValue &data)
|
||||
{
|
||||
|
@ -83,7 +83,13 @@ TopRoomBar::TopRoomBar(QWidget *parent)
|
||||
roomSettings_->toggleNotifications();
|
||||
});
|
||||
|
||||
leaveRoom_ = new QAction(tr("Leave room"), this);
|
||||
connect(leaveRoom_, &QAction::triggered, this, [=](){
|
||||
emit leaveRoom();
|
||||
});
|
||||
|
||||
menu_->addAction(toggleNotifications_);
|
||||
menu_->addAction(leaveRoom_);
|
||||
|
||||
connect(settingsBtn_, &QPushButton::clicked, this, [=]() {
|
||||
if (roomSettings_->isNotificationsEnabled())
|
||||
|
Loading…
Reference in New Issue
Block a user