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
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; |
|
}
|
|
|