diff --git a/src/callparticipantsmodel.cpp b/src/callparticipantsmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be2a20a11404b706b415e89e4106e5db20cd3b4d --- /dev/null +++ b/src/callparticipantsmodel.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "callparticipantsmodel.h" + +#include "lrcinstance.h" +#include "qtutils.h" + +#include <QAbstractListModel> +#include <QObject> +#include <QQmlEngine> +#include <QSortFilterProxyModel> +#include <QQuickItem> + +CallParticipantsModel::CallParticipantsModel(LRCInstance* instance, QObject* parent) + : QAbstractListModel(parent) + , lrcInstance_(instance) +{} + +int +CallParticipantsModel::rowCount(const QModelIndex& parent) const +{ + if (parent.isValid()) + return 0; + return participants_.size(); +} + +QVariant +CallParticipantsModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + using namespace CallParticipant; + auto participant = participants_.at(index.row()); + + switch (role) { + case Role::Uri: + return QVariant::fromValue(participant.item.value("uri")); + case Role::BestName: + return QVariant::fromValue(participant.item.value("bestName")); + case Role::Active: + return QVariant::fromValue(participant.item.value("active")); + case Role::AudioLocalMuted: + return QVariant::fromValue(participant.item.value("audioLocalMuted")); + case Role::AudioModeratorMuted: + return QVariant::fromValue(participant.item.value("audioModeratorMuted")); + case Role::VideoMuted: + return QVariant::fromValue(participant.item.value("videoMuted")); + case Role::IsModerator: + return QVariant::fromValue(participant.item.value("isModerator")); + case Role::IsLocal: + return QVariant::fromValue(participant.item.value("isLocal")); + case Role::IsContact: + return QVariant::fromValue(participant.item.value("isContact")); + case Role::Avatar: + return QVariant::fromValue(participant.item.value("avatar")); + case Role::SinkId: + return QVariant::fromValue(participant.item.value("sinkId")); + case Role::HandRaised: + return QVariant::fromValue(participant.item.value("handRaised")); + } + return QVariant(); +} + +QHash<int, QByteArray> +CallParticipantsModel::roleNames() const +{ + using namespace CallParticipant; + QHash<int, QByteArray> roles; +#define X(role) roles[role] = #role; + CALL_PARTICIPANTS_ROLES +#undef X + return roles; +} + +void +CallParticipantsModel::addParticipant(int index, const QVariant& infos) +{ + auto it = participants_.begin() + index; + participants_.insert(it, CallParticipant::Item {infos.toJsonObject()}); + + beginInsertRows(QModelIndex(), index, index); + endInsertRows(); + + callId_ = participants_[index].item["callId"].toString(); +} + +void +CallParticipantsModel::updateParticipant(int index, const QVariant& infos) +{ + if (participants_.size() <= index) + return; + auto it = participants_.begin() + index; + (*it) = CallParticipant::Item {infos.toJsonObject()}; + + callId_ = participants_[index].item["callId"].toString(); + Q_EMIT updateParticipant(it->item.toVariantMap()); +} + +void +CallParticipantsModel::removeParticipant(int index) +{ + callId_ = participants_[index].item["callId"].toString(); + + auto it = participants_.begin() + index; + participants_.erase(it); + + beginRemoveRows(QModelIndex(), index, index); + endRemoveRows(); +} + +void +CallParticipantsModel::setParticipants(const QString& callId, const QVariantList& participants) +{ + if (callId_ == callId) + return; + + callId_ = callId; + + participants_.clear(); + beginResetModel(); + endResetModel(); + + if (!participants.isEmpty()) + int idx = 0; + for (const auto& participant : participants) { + addParticipant(idx, participant); + idx++; + } + } +} + +void +CallParticipantsModel::resetParticipants(const QString& callId, const QVariantList& participants) +{ + if (callId == callId_) + setParticipants(callId, participants); +} diff --git a/src/callparticipantsmodel.h b/src/callparticipantsmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..d4acee0596e73d72248ccc8cc478dd17097b795b --- /dev/null +++ b/src/callparticipantsmodel.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "lrcinstance.h" +#include "qtutils.h" + +#include <QAbstractListModel> +#include <QObject> +#include <QQmlEngine> +#include <QSortFilterProxyModel> +#include <QQuickItem> +#include <QJsonObject> + +#define CALL_PARTICIPANTS_ROLES \ + X(Uri) \ + X(Device) \ + X(SinkId) \ + X(BestName) \ + X(Avatar) \ + X(Active) \ + X(XPosition) \ + X(YPosition) \ + X(Width) \ + X(Height) \ + X(AudioLocalMuted) \ + X(AudioModeratorMuted) \ + X(VideoMuted) \ + X(IsModerator) \ + X(IsLocal) \ + X(IsContact) \ + X(HandRaised) + +namespace CallParticipant { +Q_NAMESPACE +enum Role { + DummyRole = Qt::UserRole + 1, +#define X(role) role, + CALL_PARTICIPANTS_ROLES +#undef X +}; +Q_ENUM_NS(Role) + +struct Item +{ + QJsonObject item; + + bool operator==(const Item& a) const + { + return (item == a.item); + } +}; +} // namespace CallParticipant + +class CallParticipantsModel : public QAbstractListModel +{ + Q_OBJECT +public: + CallParticipantsModel(LRCInstance* instance, QObject* parent = nullptr); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + void updateParticipant(int index, const QVariant& infos); + void addParticipant(int index, const QVariant& infos); + void removeParticipant(int index); + void setParticipants(const QString& callId, const QVariantList& participants); + void resetParticipants(const QString& callId, const QVariantList& participants); + +Q_SIGNALS: + void updateParticipant(QVariant participantInfos); + +private: + LRCInstance* lrcInstance_ {nullptr}; + + QList<CallParticipant::Item> participants_ {}; + QString callId_; +};