Track radio speakers independently of member list refreshes
This commit is contained in:
1 parent
376695e410
commit
5cbab70035
2 files changed
+59
-8
No files matched your search
@@ -1,5 +1,6 @@
|
||||
#include <QCoreApplication>
|
||||
#include "memberlistmodel.h"
|
||||
#include "debug_ui.h"
|
||||
#include "avatars/avatarmanager.h"
|
||||
#include "../transport/gui_bridge.h"
|
||||
#include <QPainter>
|
||||
@@ -76,6 +77,7 @@ QVariant MemberListModel::data(const QModelIndex& index, int role) const {
|
||||
if (role == Qt::UserRole + 2) return it->isSelf;
|
||||
if (role == Qt::UserRole + 3) return it->flags;
|
||||
if (role == Qt::UserRole + 4) return (bool)it->storage;
|
||||
if (role == RadioSpeakingRole) return it->isSelf ? m_selfTransmitting : m_radioTalkers.contains(it->nodeId);
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
@@ -83,6 +85,11 @@ QVariant MemberListModel::data(const QModelIndex& index, int role) const {
|
||||
|
||||
void MemberListModel::setChannel(const QString& channelId, bool isOwner) {
|
||||
beginResetModel();
|
||||
if (m_channelId != channelId) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "radio members: channel %s -> %s cleared talkers=%d self_tx=%d",
|
||||
qPrintable(m_channelId), qPrintable(channelId), int(m_radioTalkers.size()), m_selfTransmitting);
|
||||
m_radioTalkers.clear(); m_radioActive = false; m_selfTransmitting = false;
|
||||
}
|
||||
m_channelId = channelId;
|
||||
m_isOwner = isOwner;
|
||||
m_totalCount = 0;
|
||||
@@ -188,12 +195,7 @@ void MemberListModel::onMemberUpdated(const QString& chId, const uint8_t* data)
|
||||
|
||||
if ((item.flags & CHAT_MEMBER_FLAG_DELETED) && !m_isOwner) {
|
||||
/* deleted member — remove from non-owner's list */
|
||||
if (row >= 0) {
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_cache.remove(row);
|
||||
m_totalCount--;
|
||||
endRemoveRows();
|
||||
}
|
||||
onMemberRemoved(chId, item.nodeId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -202,24 +204,64 @@ void MemberListModel::onMemberUpdated(const QString& chId, const uint8_t* data)
|
||||
emit dataChanged(index(row), index(row));
|
||||
} else {
|
||||
/* new member — add at end */
|
||||
row = m_totalCount++;
|
||||
m_cache[row] = item;
|
||||
row = m_totalCount;
|
||||
beginInsertRows(QModelIndex(), row, row);
|
||||
m_cache[row] = item;
|
||||
m_totalCount++;
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
|
||||
void MemberListModel::onMemberRemoved(const QString& chId, uint64_t nodeId) {
|
||||
if (chId != m_channelId) return;
|
||||
if (m_radioTalkers.remove(nodeId))
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "radio members: removed talker ch=%s node=%016llx",
|
||||
qPrintable(chId), (unsigned long long)nodeId);
|
||||
|
||||
for (auto it = m_cache.begin(); it != m_cache.end(); ++it) {
|
||||
if (it->nodeId == nodeId) {
|
||||
int row = it.key();
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_cache.remove(row);
|
||||
for (int next = row + 1; next < m_totalCount; ++next) m_cache[next - 1] = m_cache.take(next);
|
||||
m_totalCount--;
|
||||
endRemoveRows();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Состояние собственного TX берём из аудио-движка: оно включает PTT и VAD. */
|
||||
void MemberListModel::setRadioState(quint64 groupId, bool active, bool transmitting) {
|
||||
active = active && groupId != 0 && groupId == m_channelId.toULongLong();
|
||||
transmitting = active && transmitting;
|
||||
if (m_radioActive == active && m_selfTransmitting == transmitting) return;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "radio members: state ch=%s group=%016llx active=%d self_tx=%d talkers=%d",
|
||||
qPrintable(m_channelId), (unsigned long long)groupId, active, transmitting, int(m_radioTalkers.size()));
|
||||
m_radioActive = active; m_selfTransmitting = transmitting;
|
||||
if (!active) m_radioTalkers.clear();
|
||||
if (m_totalCount) emit dataChanged(index(0), index(m_totalCount - 1), {RadioSpeakingRole});
|
||||
}
|
||||
|
||||
/* START может прийти до списка участников; STOP снимает только указанный источник. */
|
||||
void MemberListModel::onRadioTalk(quint64 groupId, quint64 nodeId, bool on) {
|
||||
if (!groupId || !nodeId) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_RADIO, "radio members: invalid talk group=%016llx node=%016llx on=%d",
|
||||
(unsigned long long)groupId, (unsigned long long)nodeId, on);
|
||||
return;
|
||||
}
|
||||
if (groupId != m_channelId.toULongLong() || (on && !m_radioActive)) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "radio members: ignored talk ch=%s group=%016llx node=%016llx on=%d active=%d",
|
||||
qPrintable(m_channelId), (unsigned long long)groupId, (unsigned long long)nodeId, on, m_radioActive);
|
||||
return;
|
||||
}
|
||||
if (m_radioTalkers.contains(nodeId) == on) return;
|
||||
if (on) m_radioTalkers.insert(nodeId);
|
||||
else m_radioTalkers.remove(nodeId);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "radio members: talk ch=%s node=%016llx on=%d talkers=%d",
|
||||
qPrintable(m_channelId), (unsigned long long)nodeId, on, int(m_radioTalkers.size()));
|
||||
for (auto it = m_cache.cbegin(); it != m_cache.cend(); ++it) if (it->nodeId == nodeId) {
|
||||
emit dataChanged(index(it.key()), index(it.key()), {RadioSpeakingRole});
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user