chatgui: remember last read message, restore scroll position, show unread count badge
Store read/scroll positions per channel via ui_state table (key-value). Draw red +N badge on channel list items for unread messages. Fix getMessages() to fetch last N messages (was fetching first N).
This commit is contained in:
1 parent
de14f82048
commit
86d227bffe
10 files changed
+158
-12
No files matched your search
@@ -167,6 +167,11 @@ MessageList::MessageList(DbManager* db, QWidget *parent)
|
||||
|
||||
void MessageList::loadChannel(const QString& channelId) {
|
||||
QWidget* prevFocus = QApplication::focusWidget();
|
||||
|
||||
/* Save state of current channel before switching */
|
||||
if (!m_currentChannelId.isEmpty() && m_currentChannelId != channelId)
|
||||
saveChannelState();
|
||||
|
||||
m_model->clear();
|
||||
m_avatarCache.clear();
|
||||
m_currentChannelId = channelId;
|
||||
@@ -174,9 +179,6 @@ void MessageList::loadChannel(const QString& channelId) {
|
||||
|
||||
auto msgs = m_db->getMessages(channelId, 100);
|
||||
|
||||
struct ReactionKey { qint64 msgId; quint64 node; QString emoji; };
|
||||
QHash<qint64, QHash<QString, QList<QColor>>> reactMap;
|
||||
|
||||
for (const auto& m : msgs) {
|
||||
AccountRow acc = m_db->getAccount(m.authorNodeId);
|
||||
QString author = m_db->getDisplayName(m.authorNodeId);
|
||||
@@ -194,11 +196,12 @@ void MessageList::loadChannel(const QString& channelId) {
|
||||
auto *item = new QStandardItem();
|
||||
setMsg(item, author, QString::fromUtf8(m.data), time, avatar, false,
|
||||
false, QString(), QString(), reacts);
|
||||
item->setData(m.id, MsgIdRole);
|
||||
m_model->appendRow(item);
|
||||
}
|
||||
|
||||
if (m_model->rowCount() > 0)
|
||||
m_view->scrollToBottom();
|
||||
restoreScrollPosition(channelId);
|
||||
|
||||
if (prevFocus)
|
||||
prevFocus->setFocus();
|
||||
else
|
||||
@@ -238,3 +241,60 @@ void MessageList::addMessage(const QString& channelId, quint64 authorNodeId,
|
||||
|
||||
m_view->scrollToBottom();
|
||||
}
|
||||
|
||||
void MessageList::saveChannelState() {
|
||||
if (m_currentChannelId.isEmpty() || m_model->rowCount() == 0) return;
|
||||
|
||||
int vpHeight = m_view->viewport()->height();
|
||||
QModelIndex topIdx = m_view->indexAt(QPoint(0, 0));
|
||||
QModelIndex bottomIdx = m_view->indexAt(QPoint(0, vpHeight - 1));
|
||||
|
||||
qint64 lastReadMsgId = 0;
|
||||
qint64 lastPosMsgId = 0;
|
||||
|
||||
if (topIdx.isValid())
|
||||
lastPosMsgId = topIdx.data(MsgIdRole).toLongLong();
|
||||
if (bottomIdx.isValid())
|
||||
lastReadMsgId = bottomIdx.data(MsgIdRole).toLongLong();
|
||||
else if (m_model->rowCount() > 0)
|
||||
lastReadMsgId = m_model->item(m_model->rowCount() - 1)->data(MsgIdRole).toLongLong();
|
||||
|
||||
if (lastReadMsgId == 0 && lastPosMsgId == 0) return;
|
||||
|
||||
QByteArray cid = m_currentChannelId.toUtf8();
|
||||
auto saveKey = [&cid](const char* suffix, qint64 val) {
|
||||
QByteArray key = "ch_" + cid + suffix;
|
||||
QByteArray valStr = QByteArray::number(val);
|
||||
size_t klen = key.size(), vlen = valStr.size();
|
||||
size_t total = klen + 1 + vlen + 1;
|
||||
if (total > 256) return;
|
||||
void* arg = u_malloc(total);
|
||||
memcpy(arg, key.constData(), klen + 1);
|
||||
memcpy((char*)arg + klen + 1, valStr.constData(), vlen + 1);
|
||||
gui_bridge_post_uasync_fn(chat_core_save_ui_state_trampoline, arg);
|
||||
};
|
||||
|
||||
if (lastReadMsgId > 0) saveKey("_last_read", lastReadMsgId);
|
||||
if (lastPosMsgId > 0) saveKey("_last_pos", lastPosMsgId);
|
||||
}
|
||||
|
||||
void MessageList::restoreScrollPosition(const QString& channelId) {
|
||||
if (!m_db || m_model->rowCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 lastPosMsgId = m_db->getUiStateInt64(
|
||||
QStringLiteral("ch_%1_last_pos").arg(channelId), 0);
|
||||
|
||||
if (lastPosMsgId > 0) {
|
||||
for (int row = 0; row < m_model->rowCount(); row++) {
|
||||
QStandardItem* item = m_model->item(row);
|
||||
if (item && item->data(MsgIdRole).toLongLong() == lastPosMsgId) {
|
||||
m_view->scrollTo(m_model->index(row, 0), QAbstractItemView::PositionAtTop);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_view->scrollToBottom();
|
||||
}
|
||||
Reference in new issue
Block a user