summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeepBlueV7.X <nicolas.werner@hotmail.de>2020-05-01 00:21:13 +0200
committerGitHub <noreply@github.com>2020-05-01 00:21:13 +0200
commit00c4d2629aadc38fb6cecb67922d12085988cfc9 (patch)
tree4462ebb39f7a5aa0626ed4f26ac292bd963e9de0
parentStrip reply fallback from plain text body (diff)
parentOptimize RoomList sorting (diff)
downloadnheko-00c4d2629aadc38fb6cecb67922d12085988cfc9.tar.xz
Merge pull request #188 from Nheko-Reborn/optimize-cpu-usage
Optimize cpu usage
-rw-r--r--resources/qml/TimelineView.qml18
-rw-r--r--src/Cache.cpp147
-rw-r--r--src/Cache.h15
-rw-r--r--src/CacheStructs.h3
-rw-r--r--src/Cache_p.h12
-rw-r--r--src/RoomInfoListItem.cpp7
-rw-r--r--src/RoomList.cpp57
-rw-r--r--src/RoomList.h1
-rw-r--r--src/Utils.cpp8
-rw-r--r--src/timeline/TimelineModel.cpp3
10 files changed, 57 insertions, 214 deletions
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index c42cd6e9..7df2ed0b 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -17,6 +17,10 @@ Page {
 
 	palette: colors
 
+	FontMetrics {
+		id: fontMetrics
+	}
+
 	Settings {
 		id: settings
 		category: "user"
@@ -116,10 +120,10 @@ Page {
 
 			boundsBehavior: Flickable.StopAtBounds
 
-            ScrollHelper {
-                flickable: parent
-                anchors.fill: parent
-            }
+			ScrollHelper {
+				flickable: parent
+				anchors.fill: parent
+			}
 
 			Shortcut {
 				sequence: StandardKey.MoveToPreviousPage
@@ -256,7 +260,7 @@ Page {
 		Rectangle {
 			id: chatFooter
 
-			height: Math.max(16, footerContent.height)
+			height: Math.max(fontMetrics.height * 1.2, footerContent.height)
 			anchors.left: parent.left
 			anchors.right: parent.right
 			anchors.bottom: parent.bottom
@@ -326,8 +330,4 @@ Page {
 			}
 		}
 	}
-
-    FontMetrics {
-        id: fontMetrics
-    }
 }
diff --git a/src/Cache.cpp b/src/Cache.cpp
index bdca76f2..eb5c93aa 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -62,6 +62,7 @@ constexpr auto SYNC_STATE_DB("sync_state");
 //! Read receipts per room/event.
 constexpr auto READ_RECEIPTS_DB("read_receipts");
 constexpr auto NOTIFICATIONS_DB("sent_notifications");
+//! TODO: delete pending_receipts database on old cache versions
 
 //! Encryption related databases.
 
@@ -703,70 +704,6 @@ Cache::setCurrentFormat()
         txn.commit();
 }
 
-std::vector<QString>
-Cache::pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id)
-{
-        auto db = getPendingReceiptsDb(txn);
-
-        std::string key, unused;
-        std::vector<QString> pending;
-
-        auto cursor = lmdb::cursor::open(txn, db);
-        while (cursor.get(key, unused, MDB_NEXT)) {
-                ReadReceiptKey receipt;
-                try {
-                        receipt = json::parse(key);
-                } catch (const nlohmann::json::exception &e) {
-                        nhlog::db()->warn("pendingReceiptsEvents: {}", e.what());
-                        continue;
-                }
-
-                if (receipt.room_id == room_id)
-                        pending.emplace_back(QString::fromStdString(receipt.event_id));
-        }
-
-        cursor.close();
-
-        return pending;
-}
-
-void
-Cache::removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id)
-{
-        auto db = getPendingReceiptsDb(txn);
-
-        ReadReceiptKey receipt_key{event_id, room_id};
-        auto key = json(receipt_key).dump();
-
-        try {
-                lmdb::dbi_del(txn, db, lmdb::val(key.data(), key.size()), nullptr);
-        } catch (const lmdb::error &e) {
-                nhlog::db()->critical("removePendingReceipt: {}", e.what());
-        }
-}
-
-void
-Cache::addPendingReceipt(const QString &room_id, const QString &event_id)
-{
-        auto txn = lmdb::txn::begin(env_);
-        auto db  = getPendingReceiptsDb(txn);
-
-        ReadReceiptKey receipt_key{event_id.toStdString(), room_id.toStdString()};
-        auto key = json(receipt_key).dump();
-        std::string empty;
-
-        try {
-                lmdb::dbi_put(txn,
-                              db,
-                              lmdb::val(key.data(), key.size()),
-                              lmdb::val(empty.data(), empty.size()));
-        } catch (const lmdb::error &e) {
-                nhlog::db()->critical("addPendingReceipt: {}", e.what());
-        }
-
-        txn.commit();
-}
-
 CachedReceipts
 Cache::readReceipts(const QString &event_id, const QString &room_id)
 {
@@ -802,30 +739,6 @@ Cache::readReceipts(const QString &event_id, const QString &room_id)
         return receipts;
 }
 
-std::vector<QString>
-Cache::filterReadEvents(const QString &room_id,
-                        const std::vector<QString> &event_ids,
-                        const std::string &excluded_user)
-{
-        std::vector<QString> read_events;
-
-        for (const auto &event : event_ids) {
-                auto receipts = readReceipts(event, room_id);
-
-                if (receipts.size() == 0)
-                        continue;
-
-                if (receipts.size() == 1) {
-                        if (receipts.begin()->second == excluded_user)
-                                continue;
-                }
-
-                read_events.emplace_back(event);
-        }
-
-        return read_events;
-}
-
 void
 Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Receipts &receipts)
 {
@@ -882,27 +795,6 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
 }
 
 void
-Cache::notifyForReadReceipts(const std::string &room_id)
-{
-        auto txn = lmdb::txn::begin(env_);
-
-        QSettings settings;
-        auto local_user = settings.value("auth/user_id").toString();
-
-        auto matches = filterReadEvents(QString::fromStdString(room_id),
-                                        pendingReceiptsEvents(txn, room_id),
-                                        local_user.toStdString());
-
-        for (const auto &m : matches)
-                removePendingReceipt(txn, room_id, m.toStdString());
-
-        if (!matches.empty())
-                emit newReadReceipts(QString::fromStdString(room_id), matches);
-
-        txn.commit();
-}
-
-void
 Cache::calculateRoomReadStatus()
 {
         const auto joined_rooms = joinedRooms();
@@ -1019,7 +911,12 @@ Cache::saveState(const mtx::responses::Sync &res)
         std::map<QString, bool> readStatus;
 
         for (const auto &room : res.rooms.join) {
-                notifyForReadReceipts(room.first);
+                if (!room.second.ephemeral.receipts.empty()) {
+                        std::vector<QString> receipts;
+                        for (const auto &receipt : room.second.ephemeral.receipts)
+                                receipts.push_back(QString::fromStdString(receipt.first));
+                        emit newReadReceipts(QString::fromStdString(room.first), receipts);
+                }
                 readStatus.emplace(QString::fromStdString(room.first),
                                    calculateRoomReadStatus(room.first));
         }
@@ -2634,36 +2531,6 @@ readReceipts(const QString &event_id, const QString &room_id)
         return instance_->readReceipts(event_id, room_id);
 }
 
-//! Filter the events that have at least one read receipt.
-std::vector<QString>
-filterReadEvents(const QString &room_id,
-                 const std::vector<QString> &event_ids,
-                 const std::string &excluded_user)
-{
-        return instance_->filterReadEvents(room_id, event_ids, excluded_user);
-}
-//! Add event for which we are expecting some read receipts.
-void
-addPendingReceipt(const QString &room_id, const QString &event_id)
-{
-        instance_->addPendingReceipt(room_id, event_id);
-}
-void
-removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id)
-{
-        instance_->removePendingReceipt(txn, room_id, event_id);
-}
-void
-notifyForReadReceipts(const std::string &room_id)
-{
-        instance_->notifyForReadReceipts(room_id);
-}
-std::vector<QString>
-pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id)
-{
-        return instance_->pendingReceiptsEvents(txn, room_id);
-}
-
 QByteArray
 image(const QString &url)
 {
diff --git a/src/Cache.h b/src/Cache.h
index bb042ea9..99c63550 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -154,21 +154,6 @@ using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>
 UserReceipts
 readReceipts(const QString &event_id, const QString &room_id);
 
-//! Filter the events that have at least one read receipt.
-std::vector<QString>
-filterReadEvents(const QString &room_id,
-                 const std::vector<QString> &event_ids,
-                 const std::string &excluded_user);
-//! Add event for which we are expecting some read receipts.
-void
-addPendingReceipt(const QString &room_id, const QString &event_id);
-void
-removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id);
-void
-notifyForReadReceipts(const std::string &room_id);
-std::vector<QString>
-pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
-
 QByteArray
 image(const QString &url);
 QByteArray
diff --git a/src/CacheStructs.h b/src/CacheStructs.h
index 2051afc8..ab7bbc71 100644
--- a/src/CacheStructs.h
+++ b/src/CacheStructs.h
@@ -39,7 +39,8 @@ struct DescInfo
         QString event_id;
         QString userid;
         QString body;
-        QString timestamp;
+        QString descriptiveTime;
+        uint64_t timestamp;
         QDateTime datetime;
 };
 
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 6eae45a9..982099ea 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -137,18 +137,6 @@ public:
         using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
         UserReceipts readReceipts(const QString &event_id, const QString &room_id);
 
-        //! Filter the events that have at least one read receipt.
-        std::vector<QString> filterReadEvents(const QString &room_id,
-                                              const std::vector<QString> &event_ids,
-                                              const std::string &excluded_user);
-        //! Add event for which we are expecting some read receipts.
-        void addPendingReceipt(const QString &room_id, const QString &event_id);
-        void removePendingReceipt(lmdb::txn &txn,
-                                  const std::string &room_id,
-                                  const std::string &event_id);
-        void notifyForReadReceipts(const std::string &room_id);
-        std::vector<QString> pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
-
         QByteArray image(const QString &url) const;
         QByteArray image(lmdb::txn &txn, const std::string &url) const;
         void saveImage(const std::string &url, const std::string &data);
diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp
index 13c7b54d..ee8d532d 100644
--- a/src/RoomInfoListItem.cpp
+++ b/src/RoomInfoListItem.cpp
@@ -187,10 +187,11 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
                 QFont tsFont;
                 tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9);
 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
-                const int msgStampWidth = QFontMetrics(tsFont).width(lastMsgInfo_.timestamp) + 4;
+                const int msgStampWidth =
+                  QFontMetrics(tsFont).width(lastMsgInfo_.descriptiveTime) + 4;
 #else
                 const int msgStampWidth =
-                  QFontMetrics(tsFont).horizontalAdvance(lastMsgInfo_.timestamp) + 4;
+                  QFontMetrics(tsFont).horizontalAdvance(lastMsgInfo_.descriptiveTime) + 4;
 #endif
                 // We use the full width of the widget if there is no unread msg bubble.
                 const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0;
@@ -227,7 +228,7 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
 
                         p.setFont(tsFont);
                         p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y),
-                                   lastMsgInfo_.timestamp);
+                                   lastMsgInfo_.descriptiveTime);
                         p.restore();
                 } else {
                         int btnWidth = (width() - wm.iconSize - 6 * wm.padding) / 2;
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index 764fabb4..617710c4 100644
--- a/src/RoomList.cpp
+++ b/src/RoomList.cpp
@@ -82,7 +82,9 @@ RoomList::addRoom(const QString &room_id, const RoomInfo &info)
                 MainWindow::instance()->openLeaveRoomDialog(room_id);
         });
 
-        rooms_.emplace(room_id, QSharedPointer<RoomInfoListItem>(room_item));
+        QSharedPointer<RoomInfoListItem> roomWidget(room_item);
+        rooms_.emplace(room_id, roomWidget);
+        rooms_sort_cache_.push_back(roomWidget);
 
         if (!info.avatar_url.empty())
                 updateAvatar(room_id, QString::fromStdString(info.avatar_url));
@@ -100,6 +102,14 @@ RoomList::updateAvatar(const QString &room_id, const QString &url)
 void
 RoomList::removeRoom(const QString &room_id, bool reset)
 {
+        auto roomIt = rooms_.find(room_id);
+        for (auto roomSortIt = rooms_sort_cache_.begin(); roomSortIt != rooms_sort_cache_.end();
+             ++roomSortIt) {
+                if (roomIt->second == *roomSortIt) {
+                        rooms_sort_cache_.erase(roomSortIt);
+                        break;
+                }
+        }
         rooms_.erase(room_id);
 
         if (rooms_.empty() || !reset)
@@ -336,7 +346,8 @@ RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info)
 
 struct room_sort
 {
-        bool operator()(const RoomInfoListItem *a, const RoomInfoListItem *b) const
+        bool operator()(const QSharedPointer<RoomInfoListItem> a,
+                        const QSharedPointer<RoomInfoListItem> b) const
         {
                 // Sort by "importance" (i.e. invites before mentions before
                 // notifs before new events before old events), then secondly
@@ -351,12 +362,10 @@ struct room_sort
 
                 // Now sort by recency
                 // Zero if empty, otherwise the time that the event occured
-                const uint64_t a_recency = a->lastMessageInfo().userid.isEmpty()
-                                             ? 0
-                                             : a->lastMessageInfo().datetime.toMSecsSinceEpoch();
-                const uint64_t b_recency = b->lastMessageInfo().userid.isEmpty()
-                                             ? 0
-                                             : b->lastMessageInfo().datetime.toMSecsSinceEpoch();
+                const uint64_t a_recency =
+                  a->lastMessageInfo().userid.isEmpty() ? 0 : a->lastMessageInfo().timestamp;
+                const uint64_t b_recency =
+                  b->lastMessageInfo().userid.isEmpty() ? 0 : b->lastMessageInfo().timestamp;
                 return a_recency > b_recency;
         }
 };
@@ -366,27 +375,17 @@ RoomList::sortRoomsByLastMessage()
 {
         isSortPending_ = false;
 
-        std::multiset<RoomInfoListItem *, room_sort> times;
+        std::sort(begin(rooms_sort_cache_), end(rooms_sort_cache_), room_sort{});
 
-        for (int ii = 0; ii < contentsLayout_->count(); ++ii) {
-                auto room = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(ii)->widget());
+        int newIndex = 0;
+        for (const auto &roomWidget : rooms_sort_cache_) {
+                const auto currentIndex = contentsLayout_->indexOf(roomWidget.get());
 
-                if (!room)
-                        continue;
-                else
-                        times.insert(room);
-        }
-
-        for (auto it = times.cbegin(); it != times.cend(); ++it) {
-                const auto roomWidget   = *it;
-                const auto currentIndex = contentsLayout_->indexOf(roomWidget);
-                const auto newIndex     = std::distance(times.cbegin(), it);
-
-                if (currentIndex == newIndex)
-                        continue;
-
-                contentsLayout_->removeWidget(roomWidget);
-                contentsLayout_->insertWidget(newIndex, roomWidget);
+                if (currentIndex != newIndex) {
+                        contentsLayout_->removeWidget(roomWidget.get());
+                        contentsLayout_->insertWidget(newIndex, roomWidget.get());
+                }
+                newIndex++;
         }
 }
 
@@ -500,7 +499,9 @@ RoomList::addInvitedRoom(const QString &room_id, const RoomInfo &info)
         connect(room_item, &RoomInfoListItem::acceptInvite, this, &RoomList::acceptInvite);
         connect(room_item, &RoomInfoListItem::declineInvite, this, &RoomList::declineInvite);
 
-        rooms_.emplace(room_id, QSharedPointer<RoomInfoListItem>(room_item));
+        QSharedPointer<RoomInfoListItem> roomWidget(room_item);
+        rooms_.emplace(room_id, roomWidget);
+        rooms_sort_cache_.push_back(roomWidget);
 
         updateAvatar(room_id, QString::fromStdString(info.avatar_url));
 
diff --git a/src/RoomList.h b/src/RoomList.h
index a0151f92..d3470666 100644
--- a/src/RoomList.h
+++ b/src/RoomList.h
@@ -100,6 +100,7 @@ private:
         OverlayModal *joinRoomModal_;
 
         std::map<QString, QSharedPointer<RoomInfoListItem>> rooms_;
+        std::vector<QSharedPointer<RoomInfoListItem>> rooms_sort_cache_;
         QString selectedRoom_;
 
         bool isSortPending_ = false;
diff --git a/src/Utils.cpp b/src/Utils.cpp
index f0a8d61b..7f11a8cd 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -41,6 +41,7 @@ createDescriptionInfo(const Event &event, const QString &localUser, const QStrin
           utils::messageDescription<T>(
             username, QString::fromStdString(msg.content.body).trimmed(), sender == localUser),
           utils::descriptiveTime(ts),
+          msg.origin_server_ts,
           ts};
 }
 
@@ -184,9 +185,10 @@ utils::getMessageDescription(const TimelineEvent &event,
                 info.userid = sender;
                 info.body   = QString(" %1").arg(
                   messageDescription<Encrypted>(username, "", sender == localUser));
-                info.timestamp = utils::descriptiveTime(ts);
-                info.event_id  = QString::fromStdString(msg->event_id);
-                info.datetime  = ts;
+                info.timestamp       = msg->origin_server_ts;
+                info.descriptiveTime = utils::descriptiveTime(ts);
+                info.event_id        = QString::fromStdString(msg->event_id);
+                info.datetime        = ts;
 
                 return info;
         }
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 97b95258..d68adf92 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -173,9 +173,6 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
                 // mark our messages as read
                 readEvent(event_id.toStdString());
 
-                // ask to be notified for read receipts
-                cache::addPendingReceipt(room_id_, event_id);
-
                 emit dataChanged(index(idx, 0), index(idx, 0));
 
                 if (pending.size() > 0)