mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 12:38:48 +03:00
Line to indicate first unread message (#1147)
* First draft of unread line feature. * Minor visual fix. * Removed unnecessary ternary operator. * Extended unread line functionality to work on minimised window or focusing another window. * Fix for unread line not showing when last read message is hidden. * Minor performance improvement. Fix for misbehaving event2order DB at application start. * Fix for possible performance issues when user has joined a large number of rooms. * Fix for breaking macos and clazy builds. * Changed on windows focus function to refresh unread line if room is unread. * Unread line is removed when user sends a message. * Linting. * Fixed unread line to work in standalone room windows. * Switch isRoomUnread for index 0. * Merged try/catch blocks. * Fix for crash on opening a room invite. * Call fullyReadEventId function when used instead of storing it and passing it through. * Function that was meant to sync the unread line was relying on an async function, oops. * Linting again. * More linting... * Minor changes.
This commit is contained in:
parent
02adcfdc38
commit
8071b192b8
11 changed files with 172 additions and 20 deletions
|
@ -458,6 +458,7 @@ Item {
|
||||||
encryptionError: wrapper.encryptionError
|
encryptionError: wrapper.encryptionError
|
||||||
timestamp: wrapper.timestamp
|
timestamp: wrapper.timestamp
|
||||||
status: wrapper.status
|
status: wrapper.status
|
||||||
|
index: wrapper.index
|
||||||
relatedEventCacheBuster: wrapper.relatedEventCacheBuster
|
relatedEventCacheBuster: wrapper.relatedEventCacheBuster
|
||||||
y: section.visible && section.active ? section.y + section.height : 0
|
y: section.visible && section.active ? section.y + section.height : 0
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,8 @@ Page {
|
||||||
timelineRoot: timelineView
|
timelineRoot: timelineView
|
||||||
windowTarget: roomWindowW
|
windowTarget: roomWindowW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onActiveChanged: { room.lastReadIdOnWindowFocus(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,12 +44,13 @@ AbstractButton {
|
||||||
required property int duration
|
required property int duration
|
||||||
required property var timestamp
|
required property var timestamp
|
||||||
required property int status
|
required property int status
|
||||||
|
required property int index
|
||||||
required property int relatedEventCacheBuster
|
required property int relatedEventCacheBuster
|
||||||
|
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 )
|
height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 )+unreadRow.height
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: (Settings.messageHoverHighlight && hovered) ? Nheko.colors.alternateBase : "transparent"
|
color: (Settings.messageHoverHighlight && hovered) ? Nheko.colors.alternateBase : "transparent"
|
||||||
|
@ -277,6 +278,7 @@ AbstractButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Reactions {
|
Reactions {
|
||||||
anchors {
|
anchors {
|
||||||
top: row.bottom
|
top: row.bottom
|
||||||
|
@ -292,4 +294,17 @@ AbstractButton {
|
||||||
reactions: r.reactions
|
reactions: r.reactions
|
||||||
eventId: r.eventId
|
eventId: r.eventId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: unreadRow
|
||||||
|
anchors {
|
||||||
|
top: reactionRow.bottom
|
||||||
|
topMargin: 5
|
||||||
|
}
|
||||||
|
color: Nheko.colors.highlight
|
||||||
|
width: row.maxWidth
|
||||||
|
visible: (r.index > 0 && (chat.model.fullyReadEventId == r.eventId))
|
||||||
|
height: visible ? 3 : 0
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1537,6 +1537,21 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Cache::getFullyReadEventId(const std::string &room_id)
|
||||||
|
{
|
||||||
|
auto txn = ro_txn(env_);
|
||||||
|
|
||||||
|
if (auto ev = getAccountData(txn, mtx::events::EventType::FullyRead, room_id)) {
|
||||||
|
if (auto fr =
|
||||||
|
std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::FullyRead>>(
|
||||||
|
&ev.value())) {
|
||||||
|
return fr->content.event_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::calculateRoomReadStatus()
|
Cache::calculateRoomReadStatus()
|
||||||
{
|
{
|
||||||
|
@ -1561,14 +1576,7 @@ Cache::calculateRoomReadStatus(const std::string &room_id)
|
||||||
const auto last_event_id = getLastEventId(txn, room_id);
|
const auto last_event_id = getLastEventId(txn, room_id);
|
||||||
const auto localUser = utils::localUser().toStdString();
|
const auto localUser = utils::localUser().toStdString();
|
||||||
|
|
||||||
std::string fullyReadEventId;
|
std::string fullyReadEventId = getFullyReadEventId(room_id);
|
||||||
if (auto ev = getAccountData(txn, mtx::events::EventType::FullyRead, room_id)) {
|
|
||||||
if (auto fr =
|
|
||||||
std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::FullyRead>>(
|
|
||||||
&ev.value())) {
|
|
||||||
fullyReadEventId = fr->content.event_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_event_id.empty() || fullyReadEventId.empty())
|
if (last_event_id.empty() || fullyReadEventId.empty())
|
||||||
return true;
|
return true;
|
||||||
|
@ -2503,6 +2511,50 @@ Cache::lastInvisibleEventAfter(const std::string &room_id, std::string_view even
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<uint64_t, std::string>>
|
||||||
|
Cache::lastVisibleEvent(const std::string &room_id, std::string_view event_id)
|
||||||
|
{
|
||||||
|
if (room_id.empty() || event_id.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto txn = ro_txn(env_);
|
||||||
|
lmdb::dbi orderDb;
|
||||||
|
lmdb::dbi eventOrderDb;
|
||||||
|
lmdb::dbi timelineDb;
|
||||||
|
try {
|
||||||
|
orderDb = getEventToOrderDb(txn, room_id);
|
||||||
|
eventOrderDb = getEventOrderDb(txn, room_id);
|
||||||
|
timelineDb = getMessageToOrderDb(txn, room_id);
|
||||||
|
|
||||||
|
std::string_view indexVal;
|
||||||
|
|
||||||
|
bool success = orderDb.get(txn, event_id, indexVal);
|
||||||
|
if (!success) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t idx = lmdb::from_sv<uint64_t>(indexVal);
|
||||||
|
std::string evId{event_id};
|
||||||
|
|
||||||
|
auto cursor = lmdb::cursor::open(txn, eventOrderDb);
|
||||||
|
if (cursor.get(indexVal, event_id, MDB_SET)) {
|
||||||
|
do {
|
||||||
|
evId = nlohmann::json::parse(event_id)["event_id"].get<std::string>();
|
||||||
|
std::string_view temp;
|
||||||
|
idx = lmdb::from_sv<uint64_t>(indexVal);
|
||||||
|
if (timelineDb.get(txn, evId, temp)) {
|
||||||
|
return std::pair{idx, evId};
|
||||||
|
}
|
||||||
|
} while (cursor.get(indexVal, event_id, MDB_PREV));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::pair{idx, evId};
|
||||||
|
} catch (lmdb::runtime_error &e) {
|
||||||
|
nhlog::db()->error("Failed to get last visible event after {}", event_id, e.what());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<uint64_t>
|
std::optional<uint64_t>
|
||||||
Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id)
|
Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id)
|
||||||
{
|
{
|
||||||
|
@ -5317,6 +5369,12 @@ lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id)
|
||||||
return instance_->lastInvisibleEventAfter(room_id, event_id);
|
return instance_->lastInvisibleEventAfter(room_id, event_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<uint64_t, std::string>>
|
||||||
|
lastVisibleEvent(const std::string &room_id, std::string_view event_id)
|
||||||
|
{
|
||||||
|
return instance_->lastVisibleEvent(room_id, event_id);
|
||||||
|
}
|
||||||
|
|
||||||
RoomInfo
|
RoomInfo
|
||||||
singleRoomInfo(const std::string &room_id)
|
singleRoomInfo(const std::string &room_id)
|
||||||
{
|
{
|
||||||
|
@ -5336,6 +5394,11 @@ getRoomInfo(const std::vector<std::string> &rooms)
|
||||||
|
|
||||||
//! Calculates which the read status of a room.
|
//! Calculates which the read status of a room.
|
||||||
//! Whether all the events in the timeline have been read.
|
//! Whether all the events in the timeline have been read.
|
||||||
|
std::string
|
||||||
|
getFullyReadEventId(const std::string &room_id)
|
||||||
|
{
|
||||||
|
return instance_->getFullyReadEventId(room_id);
|
||||||
|
}
|
||||||
bool
|
bool
|
||||||
calculateRoomReadStatus(const std::string &room_id)
|
calculateRoomReadStatus(const std::string &room_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,6 +152,8 @@ std::optional<uint64_t>
|
||||||
getEventIndex(const std::string &room_id, std::string_view event_id);
|
getEventIndex(const std::string &room_id, std::string_view event_id);
|
||||||
std::optional<std::pair<uint64_t, std::string>>
|
std::optional<std::pair<uint64_t, std::string>>
|
||||||
lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id);
|
lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id);
|
||||||
|
std::optional<std::pair<uint64_t, std::string>>
|
||||||
|
lastVisibleEvent(const std::string &room_id, std::string_view event_id);
|
||||||
|
|
||||||
RoomInfo
|
RoomInfo
|
||||||
singleRoomInfo(const std::string &room_id);
|
singleRoomInfo(const std::string &room_id);
|
||||||
|
@ -160,6 +162,8 @@ getRoomInfo(const std::vector<std::string> &rooms);
|
||||||
|
|
||||||
//! Calculates which the read status of a room.
|
//! Calculates which the read status of a room.
|
||||||
//! Whether all the events in the timeline have been read.
|
//! Whether all the events in the timeline have been read.
|
||||||
|
std::string
|
||||||
|
getFullyReadEventId(const std::string &room_id);
|
||||||
bool
|
bool
|
||||||
calculateRoomReadStatus(const std::string &room_id);
|
calculateRoomReadStatus(const std::string &room_id);
|
||||||
void
|
void
|
||||||
|
|
|
@ -169,6 +169,7 @@ public:
|
||||||
|
|
||||||
//! Calculates which the read status of a room.
|
//! Calculates which the read status of a room.
|
||||||
//! Whether all the events in the timeline have been read.
|
//! Whether all the events in the timeline have been read.
|
||||||
|
std::string getFullyReadEventId(const std::string &room_id);
|
||||||
bool calculateRoomReadStatus(const std::string &room_id);
|
bool calculateRoomReadStatus(const std::string &room_id);
|
||||||
void calculateRoomReadStatus();
|
void calculateRoomReadStatus();
|
||||||
|
|
||||||
|
@ -212,6 +213,8 @@ public:
|
||||||
std::optional<uint64_t> getEventIndex(const std::string &room_id, std::string_view event_id);
|
std::optional<uint64_t> getEventIndex(const std::string &room_id, std::string_view event_id);
|
||||||
std::optional<std::pair<uint64_t, std::string>>
|
std::optional<std::pair<uint64_t, std::string>>
|
||||||
lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id);
|
lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id);
|
||||||
|
std::optional<std::pair<uint64_t, std::string>>
|
||||||
|
lastVisibleEvent(const std::string &room_id, std::string_view event_id);
|
||||||
std::optional<std::string> getTimelineEventId(const std::string &room_id, uint64_t index);
|
std::optional<std::string> getTimelineEventId(const std::string &room_id, uint64_t index);
|
||||||
std::optional<uint64_t> getArrivalIndex(const std::string &room_id, std::string_view event_id);
|
std::optional<uint64_t> getArrivalIndex(const std::string &room_id, std::string_view event_id);
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,9 @@ public:
|
||||||
|
|
||||||
void startChat(QString userid, std::optional<bool> encryptionEnabled);
|
void startChat(QString userid, std::optional<bool> encryptionEnabled);
|
||||||
|
|
||||||
|
//! Check if the given room is currently open.
|
||||||
|
bool isRoomActive(const QString &room_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool handleMatrixUri(QString uri);
|
bool handleMatrixUri(QString uri);
|
||||||
bool handleMatrixUri(const QUrl &uri);
|
bool handleMatrixUri(const QUrl &uri);
|
||||||
|
@ -193,9 +196,6 @@ private:
|
||||||
void getProfileInfo();
|
void getProfileInfo();
|
||||||
void getBackupVersion();
|
void getBackupVersion();
|
||||||
|
|
||||||
//! Check if the given room is currently open.
|
|
||||||
bool isRoomActive(const QString &room_id);
|
|
||||||
|
|
||||||
using UserID = QString;
|
using UserID = QString;
|
||||||
using Membership = mtx::events::StateEvent<mtx::events::state::Member>;
|
using Membership = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
using Memberships = std::map<std::string, Membership>;
|
using Memberships = std::map<std::string, Membership>;
|
||||||
|
|
|
@ -283,6 +283,14 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
|
||||||
QSharedPointer<TimelineModel> newRoom(new TimelineModel(manager, room_id));
|
QSharedPointer<TimelineModel> newRoom(new TimelineModel(manager, room_id));
|
||||||
newRoom->setDecryptDescription(ChatPage::instance()->userSettings()->decryptSidebar());
|
newRoom->setDecryptDescription(ChatPage::instance()->userSettings()->decryptSidebar());
|
||||||
|
|
||||||
|
connect(this,
|
||||||
|
&RoomlistModel::currentRoomChanged,
|
||||||
|
newRoom.data(),
|
||||||
|
&TimelineModel::updateLastReadId);
|
||||||
|
connect(MainWindow::instance(),
|
||||||
|
&MainWindow::activeChanged,
|
||||||
|
newRoom.data(),
|
||||||
|
&TimelineModel::lastReadIdOnWindowFocus);
|
||||||
connect(newRoom.data(),
|
connect(newRoom.data(),
|
||||||
&TimelineModel::newEncryptedImage,
|
&TimelineModel::newEncryptedImage,
|
||||||
MainWindow::instance()->imageProvider(),
|
MainWindow::instance()->imageProvider(),
|
||||||
|
@ -383,7 +391,7 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
|
||||||
currentRoomPreview_->roomid() == room_id) {
|
currentRoomPreview_->roomid() == room_id) {
|
||||||
currentRoom_ = models.value(room_id);
|
currentRoom_ = models.value(room_id);
|
||||||
currentRoomPreview_.reset();
|
currentRoomPreview_.reset();
|
||||||
emit currentRoomChanged();
|
emit currentRoomChanged(room_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto p : previewsToAdd) {
|
for (auto p : previewsToAdd) {
|
||||||
|
@ -644,7 +652,7 @@ RoomlistModel::clear()
|
||||||
invites.clear();
|
invites.clear();
|
||||||
roomids.clear();
|
roomids.clear();
|
||||||
currentRoom_ = nullptr;
|
currentRoom_ = nullptr;
|
||||||
emit currentRoomChanged();
|
emit currentRoomChanged("");
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,14 +751,14 @@ RoomlistModel::setCurrentRoom(QString roomid)
|
||||||
if (roomid.isEmpty()) {
|
if (roomid.isEmpty()) {
|
||||||
currentRoom_ = nullptr;
|
currentRoom_ = nullptr;
|
||||||
currentRoomPreview_ = {};
|
currentRoomPreview_ = {};
|
||||||
emit currentRoomChanged();
|
emit currentRoomChanged("");
|
||||||
}
|
}
|
||||||
|
|
||||||
nhlog::ui()->debug("Trying to switch to: {}", roomid.toStdString());
|
nhlog::ui()->debug("Trying to switch to: {}", roomid.toStdString());
|
||||||
if (models.contains(roomid)) {
|
if (models.contains(roomid)) {
|
||||||
currentRoom_ = models.value(roomid);
|
currentRoom_ = models.value(roomid);
|
||||||
currentRoomPreview_.reset();
|
currentRoomPreview_.reset();
|
||||||
emit currentRoomChanged();
|
emit currentRoomChanged(currentRoom_->roomId());
|
||||||
nhlog::ui()->debug("Switched to: {}", roomid.toStdString());
|
nhlog::ui()->debug("Switched to: {}", roomid.toStdString());
|
||||||
} else if (invites.contains(roomid) || previewedRooms.contains(roomid)) {
|
} else if (invites.contains(roomid) || previewedRooms.contains(roomid)) {
|
||||||
currentRoom_ = nullptr;
|
currentRoom_ = nullptr;
|
||||||
|
@ -781,7 +789,7 @@ RoomlistModel::setCurrentRoom(QString roomid)
|
||||||
currentRoomPreview_->roomid_.toStdString());
|
currentRoomPreview_->roomid_.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit currentRoomChanged();
|
emit currentRoomChanged("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ public slots:
|
||||||
{
|
{
|
||||||
currentRoom_ = nullptr;
|
currentRoom_ = nullptr;
|
||||||
currentRoomPreview_.reset();
|
currentRoomPreview_.reset();
|
||||||
emit currentRoomChanged();
|
emit currentRoomChanged("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -124,7 +124,7 @@ private slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void totalUnreadMessageCountUpdated(int unreadMessages);
|
void totalUnreadMessageCountUpdated(int unreadMessages);
|
||||||
void currentRoomChanged();
|
void currentRoomChanged(QString currentRoomId);
|
||||||
void fetchedPreview(QString roomid, RoomInfo info);
|
void fetchedPreview(QString roomid, RoomInfo info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -218,7 +218,7 @@ public slots:
|
||||||
void updateHiddenTagsAndSpaces();
|
void updateHiddenTagsAndSpaces();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentRoomChanged();
|
void currentRoomChanged(QString currentRoomId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
short int calculateImportance(const QModelIndex &idx) const;
|
short int calculateImportance(const QModelIndex &idx) const;
|
||||||
|
|
|
@ -427,6 +427,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
|
||||||
setPaginationInProgress(false);
|
setPaginationInProgress(false);
|
||||||
updateLastMessage();
|
updateLastMessage();
|
||||||
});
|
});
|
||||||
|
connect(&events, &EventStore::fetchedMore, this, &TimelineModel::checkAfterFetch);
|
||||||
connect(&events,
|
connect(&events,
|
||||||
&EventStore::startDMVerification,
|
&EventStore::startDMVerification,
|
||||||
this,
|
this,
|
||||||
|
@ -977,6 +978,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
||||||
emit encryptionChanged();
|
emit encryptionChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLastMessage();
|
updateLastMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,6 +1372,48 @@ TimelineModel::markEventsAsRead(const std::vector<QString> &event_ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::updateLastReadId(QString currentRoomId)
|
||||||
|
{
|
||||||
|
if (currentRoomId == room_id_) {
|
||||||
|
last_event_id = cache::getFullyReadEventId(room_id_.toStdString());
|
||||||
|
auto lastVisibleEventIndexAndId =
|
||||||
|
cache::lastVisibleEvent(room_id_.toStdString(), last_event_id);
|
||||||
|
if (lastVisibleEventIndexAndId) {
|
||||||
|
fullyReadEventId_ = lastVisibleEventIndexAndId->second;
|
||||||
|
emit fullyReadEventIdChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::lastReadIdOnWindowFocus()
|
||||||
|
{
|
||||||
|
/* this stops it from removing the line when focusing another window
|
||||||
|
* and from removing the line when refocusing nheko */
|
||||||
|
if (ChatPage::instance()->isRoomActive(room_id_) &&
|
||||||
|
cache::calculateRoomReadStatus(room_id_.toStdString())) {
|
||||||
|
updateLastReadId(room_id_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if the event2order db didn't have the messages we needed when the room was opened
|
||||||
|
* try again after these new messages were fetched
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TimelineModel::checkAfterFetch()
|
||||||
|
{
|
||||||
|
if (fullyReadEventId_.empty()) {
|
||||||
|
auto lastVisibleEventIndexAndId =
|
||||||
|
cache::lastVisibleEvent(room_id_.toStdString(), last_event_id);
|
||||||
|
if (lastVisibleEventIndexAndId) {
|
||||||
|
fullyReadEventId_ = lastVisibleEventIndexAndId->second;
|
||||||
|
emit fullyReadEventIdChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void
|
void
|
||||||
TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType)
|
TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType)
|
||||||
|
@ -1550,6 +1594,9 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event)
|
||||||
event);
|
event);
|
||||||
|
|
||||||
std::visit(SendMessageVisitor{this}, event);
|
std::visit(SendMessageVisitor{this}, event);
|
||||||
|
|
||||||
|
fullyReadEventId_ = this->EventId;
|
||||||
|
emit fullyReadEventIdChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -189,6 +189,7 @@ class TimelineModel : public QAbstractListModel
|
||||||
Q_PROPERTY(QStringList widgetLinks READ widgetLinks NOTIFY widgetLinksChanged)
|
Q_PROPERTY(QStringList widgetLinks READ widgetLinks NOTIFY widgetLinksChanged)
|
||||||
Q_PROPERTY(int roomMemberCount READ roomMemberCount NOTIFY roomMemberCountChanged)
|
Q_PROPERTY(int roomMemberCount READ roomMemberCount NOTIFY roomMemberCountChanged)
|
||||||
Q_PROPERTY(bool isEncrypted READ isEncrypted NOTIFY encryptionChanged)
|
Q_PROPERTY(bool isEncrypted READ isEncrypted NOTIFY encryptionChanged)
|
||||||
|
Q_PROPERTY(QString fullyReadEventId READ fullyReadEventId NOTIFY fullyReadEventIdChanged)
|
||||||
Q_PROPERTY(bool isSpace READ isSpace CONSTANT)
|
Q_PROPERTY(bool isSpace READ isSpace CONSTANT)
|
||||||
Q_PROPERTY(int trustlevel READ trustlevel NOTIFY trustlevelChanged)
|
Q_PROPERTY(int trustlevel READ trustlevel NOTIFY trustlevelChanged)
|
||||||
Q_PROPERTY(bool isDirect READ isDirect NOTIFY isDirectChanged)
|
Q_PROPERTY(bool isDirect READ isDirect NOTIFY isDirectChanged)
|
||||||
|
@ -325,6 +326,7 @@ public:
|
||||||
|
|
||||||
bool isSpace() const { return isSpace_; }
|
bool isSpace() const { return isSpace_; }
|
||||||
bool isEncrypted() const { return isEncrypted_; }
|
bool isEncrypted() const { return isEncrypted_; }
|
||||||
|
QString fullyReadEventId() const { return QString::fromStdString(fullyReadEventId_); }
|
||||||
crypto::Trust trustlevel() const;
|
crypto::Trust trustlevel() const;
|
||||||
int roomMemberCount() const;
|
int roomMemberCount() const;
|
||||||
bool isDirect() const { return roomMemberCount() <= 2; }
|
bool isDirect() const { return roomMemberCount() <= 2; }
|
||||||
|
@ -344,6 +346,9 @@ public slots:
|
||||||
int currentIndex() const { return idToIndex(currentId); }
|
int currentIndex() const { return idToIndex(currentId); }
|
||||||
void eventShown();
|
void eventShown();
|
||||||
void markEventsAsRead(const std::vector<QString> &event_ids);
|
void markEventsAsRead(const std::vector<QString> &event_ids);
|
||||||
|
void updateLastReadId(QString currentRoomId);
|
||||||
|
void lastReadIdOnWindowFocus();
|
||||||
|
void checkAfterFetch();
|
||||||
QVariantMap getDump(const QString &eventId, const QString &relatedTo) const;
|
QVariantMap getDump(const QString &eventId, const QString &relatedTo) const;
|
||||||
void updateTypingUsers(const std::vector<QString> &users)
|
void updateTypingUsers(const std::vector<QString> &users)
|
||||||
{
|
{
|
||||||
|
@ -427,6 +432,7 @@ signals:
|
||||||
void updateFlowEventId(std::string event_id);
|
void updateFlowEventId(std::string event_id);
|
||||||
|
|
||||||
void encryptionChanged();
|
void encryptionChanged();
|
||||||
|
void fullyReadEventIdChanged();
|
||||||
void trustlevelChanged();
|
void trustlevelChanged();
|
||||||
void roomNameChanged();
|
void roomNameChanged();
|
||||||
void roomTopicChanged();
|
void roomTopicChanged();
|
||||||
|
@ -480,6 +486,8 @@ private:
|
||||||
bool m_paginationInProgress = false;
|
bool m_paginationInProgress = false;
|
||||||
bool isSpace_ = false;
|
bool isSpace_ = false;
|
||||||
bool isEncrypted_ = false;
|
bool isEncrypted_ = false;
|
||||||
|
std::string last_event_id;
|
||||||
|
std::string fullyReadEventId_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
@ -497,6 +505,7 @@ TimelineModel::sendMessageEvent(const T &content, mtx::events::EventType eventTy
|
||||||
msgCopy.type = eventType;
|
msgCopy.type = eventType;
|
||||||
emit newMessageToSend(msgCopy);
|
emit newMessageToSend(msgCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetReply();
|
resetReply();
|
||||||
resetEdit();
|
resetEdit();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue