You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

112 lines
3.8 KiB

#include "memberlistmodel.h"
#include "../db/db_manager.h"
#include <QPainter>
#include <QFont>
#include <QTimer>
MemberListModel::MemberListModel(DbManager* db, QObject* parent)
: QAbstractListModel(parent), m_db(db) {}
int MemberListModel::rowCount(const QModelIndex& parent) const {
(void)parent;
return m_totalCount;
}
QVariant MemberListModel::data(const QModelIndex& index, int role) const {
if (!index.isValid() || index.row() < 0 || index.row() >= m_totalCount)
return {};
auto it = m_cache.find(index.row());
if (it != m_cache.end()) {
if (role == Qt::DisplayRole) return it->name;
if (role == Qt::DecorationRole) return QVariant::fromValue(QIcon(it->avatar));
if (role == Qt::ToolTipRole)
return QString(it->online ? "online" : "offline") + " | 0x" +
QString("%1").arg(it->nodeId, 16, 16, QChar('0'));
return {};
}
if (role == Qt::DisplayRole) {
scheduleBatch(index.row());
return QStringLiteral("\u2026");
}
return {};
}
void MemberListModel::setChannel(const QString& channelId) {
beginResetModel();
m_channelId = channelId;
m_totalCount = m_db ? m_db->getChannelMemberCount(channelId) : 0;
m_cache.clear();
m_pendingFrom = -1;
endResetModel();
if (m_totalCount > 0) scheduleBatch(0);
}
void MemberListModel::refresh() { if (!m_channelId.isEmpty()) setChannel(m_channelId); }
void MemberListModel::scheduleBatch(int centerRow) const {
if (m_pendingFrom >= 0) return;
int from = centerRow - BATCH / 2;
if (from < 0) from = 0;
int maxFrom = m_totalCount - BATCH;
if (from > maxFrom) from = maxFrom > 0 ? maxFrom : 0;
const_cast<MemberListModel*>(this)->m_pendingFrom = from;
const_cast<MemberListModel*>(this)->m_pendingCount = BATCH;
QTimer::singleShot(0, const_cast<MemberListModel*>(this), &MemberListModel::loadPendingBatch);
}
void MemberListModel::loadPendingBatch() {
if (m_pendingFrom < 0) return;
int from = m_pendingFrom, count = m_pendingCount;
m_pendingFrom = -1;
loadBatch(from, count);
}
void MemberListModel::loadBatch(int from, int count) {
if (!m_db || m_channelId.isEmpty()) return;
int maxFrom = m_totalCount - count;
if (from > maxFrom) from = maxFrom > 0 ? maxFrom : 0;
auto members = m_db->getChannelMembers(m_channelId, from, count);
for (int i = 0; i < members.size(); i++) {
int row = from + i;
MemberListItem& item = m_cache[row];
item.nodeId = members[i].nodeId;
item.online = members[i].online;
QString shortId = QString("%1").arg(members[i].nodeId, 8, 16, QChar('0')).right(4).toUpper();
item.name = members[i].name.isEmpty() ? shortId : members[i].name;
QColor c = members[i].online ? QColor("#4CAF50") : QColor("#9E9E9E");
item.avatar = makeAvatar(c, item.name[0]);
}
evictDistant(from + BATCH / 2);
int last = from + (int)members.size() - 1;
if (last >= from) emit dataChanged(index(from), index(last));
}
void MemberListModel::evictDistant(int centerRow) {
if (m_cache.size() <= MAX_CACHE) return;
int half = MAX_CACHE / 2;
QList<int> toRemove;
for (auto it = m_cache.begin(); it != m_cache.end(); ++it)
if (qAbs(it.key() - centerRow) > half)
toRemove.append(it.key());
for (int k : toRemove) m_cache.remove(k);
}
QPixmap MemberListModel::makeAvatar(QColor color, QChar letter) const {
QPixmap pm(24, 24);
pm.fill(Qt::transparent);
QPainter p(&pm);
p.setRenderHint(QPainter::Antialiasing);
p.setBrush(color);
p.setPen(Qt::NoPen);
p.drawEllipse(2, 2, 20, 20);
p.setPen(Qt::white);
QFont f; f.setBold(true); f.setPixelSize(12);
p.setFont(f);
p.drawText(QRect(0, 0, 24, 24), Qt::AlignCenter, QString(letter));
p.end();
return pm;
}