diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index af1f7b23..298e0d18 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -573,7 +573,7 @@ EventStore::decryptEvent(const IdIndex &idx,
room_id_,
index.sender_key);
dummy.content.body =
- tr("-- Reply attack! This message index was reused! --").toStdString();
+ tr("-- Replay attack! This message index was reused! --").toStdString();
break;
case olm::DecryptionErrorCode::UnknownFingerprint:
// TODO: don't fail, just show in UI.
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index ddd238b9..af26a543 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -566,6 +566,25 @@ TimelineModel::fetchMore(const QModelIndex &)
}
void
+TimelineModel::syncState(const mtx::responses::State &s)
+{
+ using namespace mtx::events;
+
+ for (const auto &e : s.events) {
+ if (std::holds_alternative<StateEvent<state::Avatar>>(e))
+ emit roomAvatarUrlChanged();
+ else if (std::holds_alternative<StateEvent<state::Name>>(e))
+ emit roomNameChanged();
+ else if (std::holds_alternative<StateEvent<state::Topic>>(e))
+ emit roomTopicChanged();
+ else if (std::holds_alternative<StateEvent<state::Member>>(e)) {
+ emit roomAvatarUrlChanged();
+ emit roomNameChanged();
+ }
+ }
+}
+
+void
TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
{
if (timeline.events.empty())
@@ -574,6 +593,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
events.handleSync(timeline);
using namespace mtx::events;
+
for (auto e : timeline.events) {
if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) {
MegolmSessionIndex index;
@@ -597,6 +617,16 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
emit newCallEvent(event);
},
e);
+ else if (std::holds_alternative<StateEvent<state::Avatar>>(e))
+ emit roomAvatarUrlChanged();
+ else if (std::holds_alternative<StateEvent<state::Name>>(e))
+ emit roomNameChanged();
+ else if (std::holds_alternative<StateEvent<state::Topic>>(e))
+ emit roomTopicChanged();
+ else if (std::holds_alternative<StateEvent<state::Member>>(e)) {
+ emit roomAvatarUrlChanged();
+ emit roomNameChanged();
+ }
}
updateLastMessage();
}
@@ -737,12 +767,6 @@ TimelineModel::formatDateSeparator(QDate date) const
return date.toString(fmt);
}
-QString
-TimelineModel::escapeEmoji(QString str) const
-{
- return utils::replaceEmoji(str);
-}
-
void
TimelineModel::viewRawMessage(QString id) const
{
@@ -1440,7 +1464,7 @@ TimelineModel::formatTypingUsers(const std::vector<QString> &users, QColor bg)
QStringList uidWithoutLast;
auto formatUser = [this, bg](const QString &user_id) -> QString {
- auto uncoloredUsername = escapeEmoji(displayName(user_id));
+ auto uncoloredUsername = utils::replaceEmoji(displayName(user_id));
QString prefix =
QString("<font color=\"%1\">").arg(manager_->userColor(user_id, bg).name());
@@ -1490,7 +1514,7 @@ TimelineModel::formatJoinRuleEvent(QString id)
return "";
QString user = QString::fromStdString(event->sender);
- QString name = escapeEmoji(displayName(user));
+ QString name = utils::replaceEmoji(displayName(user));
switch (event->content.join_rule) {
case mtx::events::state::JoinRule::Public:
@@ -1515,7 +1539,7 @@ TimelineModel::formatGuestAccessEvent(QString id)
return "";
QString user = QString::fromStdString(event->sender);
- QString name = escapeEmoji(displayName(user));
+ QString name = utils::replaceEmoji(displayName(user));
switch (event->content.guest_access) {
case mtx::events::state::AccessState::CanJoin:
@@ -1540,7 +1564,7 @@ TimelineModel::formatHistoryVisibilityEvent(QString id)
return "";
QString user = QString::fromStdString(event->sender);
- QString name = escapeEmoji(displayName(user));
+ QString name = utils::replaceEmoji(displayName(user));
switch (event->content.history_visibility) {
case mtx::events::state::Visibility::WorldReadable:
@@ -1573,7 +1597,7 @@ TimelineModel::formatPowerLevelEvent(QString id)
return "";
QString user = QString::fromStdString(event->sender);
- QString name = escapeEmoji(displayName(user));
+ QString name = utils::replaceEmoji(displayName(user));
// TODO: power levels rendering is actually a bit complex. work on this later.
return tr("%1 has changed the room's permissions.").arg(name);
@@ -1602,7 +1626,7 @@ TimelineModel::formatMemberEvent(QString id)
}
QString user = QString::fromStdString(event->state_key);
- QString name = escapeEmoji(displayName(user));
+ QString name = utils::replaceEmoji(displayName(user));
QString rendered;
// see table https://matrix.org/docs/spec/client_server/latest#m-room-member
@@ -1675,3 +1699,37 @@ TimelineModel::formatMemberEvent(QString id)
return rendered;
}
+
+QString
+TimelineModel::roomName() const
+{
+ auto info = cache::getRoomInfo({room_id_.toStdString()});
+
+ if (!info.count(room_id_))
+ return "";
+ else
+ return QString::fromStdString(info[room_id_].name);
+}
+
+QString
+TimelineModel::roomAvatarUrl() const
+{
+ auto info = cache::getRoomInfo({room_id_.toStdString()});
+
+ if (!info.count(room_id_))
+ return "";
+ else
+ return QString::fromStdString(info[room_id_].avatar_url);
+}
+
+QString
+TimelineModel::roomTopic() const
+{
+ auto info = cache::getRoomInfo({room_id_.toStdString()});
+
+ if (!info.count(room_id_))
+ return "";
+ else
+ return utils::replaceEmoji(utils::linkifyMessage(
+ utils::escapeBlacklistedHtml(QString::fromStdString(info[room_id_].topic))));
+}
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 61d00df9..3234a20c 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -146,6 +146,9 @@ class TimelineModel : public QAbstractListModel
Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply)
Q_PROPERTY(
bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged)
+ Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
+ Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged)
+ Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
public:
explicit TimelineModel(TimelineViewManager *manager,
@@ -203,7 +206,6 @@ public:
Q_INVOKABLE QString formatGuestAccessEvent(QString id);
Q_INVOKABLE QString formatPowerLevelEvent(QString id);
- Q_INVOKABLE QString escapeEmoji(QString str) const;
Q_INVOKABLE void viewRawMessage(QString id) const;
Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
Q_INVOKABLE void openUserProfile(QString userid);
@@ -226,6 +228,7 @@ public:
void updateLastMessage();
void addEvents(const mtx::responses::Timeline &events);
+ void syncState(const mtx::responses::State &state);
template<class T>
void sendMessageEvent(const T &content, mtx::events::EventType eventType);
RelatedInfo relatedInfo(QString id);
@@ -262,6 +265,11 @@ public slots:
void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
void clearTimeline() { events.clearTimeline(); }
+ QString roomName() const;
+ QString roomTopic() const;
+ QString roomAvatarUrl() const;
+ QString roomId() const { return room_id_; }
+
private slots:
void addPendingMessage(mtx::events::collections::TimelineEvents event);
@@ -282,6 +290,10 @@ signals:
void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
void updateFlowEventId(std::string event_id);
+ void roomNameChanged();
+ void roomTopicChanged();
+ void roomAvatarUrlChanged();
+
private:
template<typename T>
void sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType);
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 97c119bf..03dd4773 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -13,6 +13,7 @@
#include "ColorImageProvider.h"
#include "DelegateChooser.h"
#include "Logging.h"
+#include "MainWindow.h"
#include "MatrixClient.h"
#include "MxcImageProvider.h"
#include "UserSettingsPage.h"
@@ -102,7 +103,7 @@ TimelineViewManager::userStatus(QString id) const
TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettings,
CallManager *callManager,
- QWidget *parent)
+ ChatPage *parent)
: imgProvider(new MxcImageProvider())
, colorImgProvider(new ColorImageProvider())
, blurhashProvider(new BlurhashProvider())
@@ -189,11 +190,8 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
view->engine()->addImageProvider("blurhash", blurhashProvider);
view->setSource(QUrl("qrc:///qml/TimelineView.qml"));
- connect(dynamic_cast<ChatPage *>(parent),
- &ChatPage::themeChanged,
- this,
- &TimelineViewManager::updateColorPalette);
- connect(dynamic_cast<ChatPage *>(parent),
+ connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
+ connect(parent,
&ChatPage::decryptSidebarChanged,
this,
&TimelineViewManager::updateEncryptedDescriptions);
@@ -295,7 +293,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
}
}
});
- connect(dynamic_cast<ChatPage *>(parent), &ChatPage::loggedOut, this, [this]() {
+ connect(parent, &ChatPage::loggedOut, this, [this]() {
isInitialSync_ = true;
emit initialSyncChanged(true);
});
@@ -313,6 +311,7 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
&TimelineModel::newCallEvent,
callManager_,
&CallManager::syncEvent);
+ room_model->syncState(room.state);
room_model->addEvents(room.timeline);
if (!isInitialSync_)
disconnect(room_model.data(),
@@ -363,6 +362,12 @@ TimelineViewManager::setHistoryView(const QString &room_id)
}
}
+QString
+TimelineViewManager::escapeEmoji(QString str) const
+{
+ return utils::replaceEmoji(str);
+}
+
void
TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) const
{
@@ -402,6 +407,28 @@ TimelineViewManager::openLink(QString link) const
}
void
+TimelineViewManager::openInviteUsersDialog()
+{
+ MainWindow::instance()->openInviteUsersDialog(
+ [this](const QStringList &invitees) { emit inviteUsers(invitees); });
+}
+void
+TimelineViewManager::openMemberListDialog() const
+{
+ MainWindow::instance()->openMemberListDialog(timeline_->roomId());
+}
+void
+TimelineViewManager::openLeaveRoomDialog() const
+{
+ MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId());
+}
+void
+TimelineViewManager::openRoomSettings() const
+{
+ MainWindow::instance()->openRoomSettings(timeline_->roomId());
+}
+
+void
TimelineViewManager::updateReadReceipts(const QString &room_id,
const std::vector<QString> &event_ids)
{
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 19406872..4779d3cd 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -22,6 +22,7 @@ class BlurhashProvider;
class CallManager;
class ColorImageProvider;
class UserSettings;
+class ChatPage;
class DeviceVerificationList : public QObject
{
@@ -45,11 +46,13 @@ class TimelineViewManager : public QObject
TimelineModel *timeline MEMBER timeline_ READ activeTimeline NOTIFY activeTimelineChanged)
Q_PROPERTY(
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
+ Q_PROPERTY(
+ bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged)
public:
TimelineViewManager(QSharedPointer<UserSettings> userSettings,
CallManager *callManager,
- QWidget *parent = nullptr);
+ ChatPage *parent = nullptr);
QWidget *getWidget() const { return container; }
void sync(const mtx::responses::Rooms &rooms);
@@ -59,14 +62,21 @@ public:
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
+ bool isNarrowView() const { return isNarrowView_; }
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const;
Q_INVOKABLE QColor userColor(QString id, QColor background);
+ Q_INVOKABLE QString escapeEmoji(QString str) const;
Q_INVOKABLE QString userPresence(QString id) const;
Q_INVOKABLE QString userStatus(QString id) const;
Q_INVOKABLE void openLink(QString link) const;
+ Q_INVOKABLE void openInviteUsersDialog();
+ Q_INVOKABLE void openMemberListDialog() const;
+ Q_INVOKABLE void openLeaveRoomDialog() const;
+ Q_INVOKABLE void openRoomSettings() const;
+
signals:
void clearRoomMessageCount(QString roomid);
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
@@ -79,6 +89,9 @@ signals:
QString userId,
QString deviceId,
bool isRequest = false);
+ void inviteUsers(QStringList users);
+ void showRoomList();
+ void narrowViewChanged();
public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
@@ -128,6 +141,23 @@ public slots:
timeline_->clearTimeline();
}
+ void enableBackButton()
+ {
+ if (isNarrowView_)
+ return;
+ isNarrowView_ = true;
+ emit narrowViewChanged();
+ }
+ void disableBackButton()
+ {
+ if (!isNarrowView_)
+ return;
+ isNarrowView_ = false;
+ emit narrowViewChanged();
+ }
+
+ void backToRooms() { emit showRoomList(); }
+
private:
#ifdef USE_QUICK_VIEW
QQuickView *view;
@@ -145,6 +175,7 @@ private:
CallManager *callManager_ = nullptr;
bool isInitialSync_ = true;
+ bool isNarrowView_ = false;
QSharedPointer<UserSettings> settings;
QHash<QString, QColor> userColors;
|