Rework Data models to fit SDK : eg. ChatModel into ChatRoomModel

Use models as it is from QML and avoid to use data translations (using address to get chat room replaced by using directly the chat room)
Use SDK chat room handlers on ChatRooms instead of general Core Handlers
Use a timeline as a proxy of chat rooms
Move events managments like unread messages or missed call to chat rooms

Add Chat rooms list and proxy, Participants
Add prototype for managing secure chat room
Add secure group chats feature
Convert some deprecated functions
Fix contacts display name and allow to show a subject instead of an address

Qt bug workaround : remove annoying warnings on Qt 5.15.1 and later
Fix secure group chat creation by adding the conference factory address to linphonerc and to the settings panel
This commit is contained in:
Julien Wadel 2021-05-07 21:08:38 +02:00
parent 0850c59395
commit 8cb6261cb3
54 changed files with 1840 additions and 589 deletions

View file

@ -122,8 +122,9 @@ set(SOURCES
src/components/calls/CallsListProxyModel.cpp
src/components/camera/Camera.cpp
src/components/camera/CameraPreview.cpp
src/components/chat/ChatModel.cpp
src/components/chat/ChatProxyModel.cpp
src/components/chat-room/ChatRoomModel.cpp
src/components/chat-room/ChatRoomListModel.cpp
src/components/chat-room/ChatRoomProxyModel.cpp
src/components/codecs/AbstractCodecsModel.cpp
src/components/codecs/AudioCodecsModel.cpp
src/components/codecs/VideoCodecsModel.cpp
@ -153,6 +154,7 @@ set(SOURCES
src/components/other/colors/Colors.cpp
src/components/other/text-to-speech/TextToSpeech.cpp
src/components/other/units/Units.cpp
src/components/participant/ParticipantModel.cpp
src/components/presence/OwnPresenceModel.cpp
src/components/presence/Presence.cpp
src/components/search/SearchHandler.cpp
@ -198,8 +200,9 @@ set(HEADERS
src/components/calls/CallsListProxyModel.hpp
src/components/camera/Camera.hpp
src/components/camera/CameraPreview.hpp
src/components/chat/ChatModel.hpp
src/components/chat/ChatProxyModel.hpp
src/components/chat-room/ChatRoomModel.hpp
src/components/chat-room/ChatRoomListModel.hpp
src/components/chat-room/ChatRoomProxyModel.hpp
src/components/codecs/AbstractCodecsModel.hpp
src/components/codecs/AudioCodecsModel.hpp
src/components/codecs/VideoCodecsModel.hpp
@ -231,6 +234,7 @@ set(HEADERS
src/components/other/desktop-tools/DesktopTools.hpp
src/components/other/text-to-speech/TextToSpeech.hpp
src/components/other/units/Units.hpp
src/components/participant/ParticipantModel.hpp
src/components/presence/OwnPresenceModel.hpp
src/components/presence/Presence.hpp
src/components/search/SearchHandler.hpp

View file

@ -432,6 +432,7 @@
<file>ui/views/App/Main/Dialogs/AuthenticationRequest.qml</file>
<file>ui/views/App/Main/Dialogs/ManageAccount.js</file>
<file>ui/views/App/Main/Dialogs/ManageAccounts.qml</file>
<file>ui/views/App/Main/Dialogs/ManageChatRoom.qml</file>
<file>ui/views/App/Main/Home.qml</file>
<file>ui/views/App/Main/HistoryView.qml</file>
<file>ui/views/App/Main/HistoryView.js</file>

View file

@ -582,17 +582,17 @@ void App::registerTypes () {
qInfo() << QStringLiteral("Registering types...");
qRegisterMetaType<shared_ptr<linphone::ProxyConfig>>();
qRegisterMetaType<ChatModel::EntryType>();
qRegisterMetaType<ChatRoomModel::EntryType>();
qRegisterMetaType<shared_ptr<linphone::SearchResult>>();
qRegisterMetaType<std::list<std::shared_ptr<linphone::SearchResult> > >();
qRegisterMetaType<std::shared_ptr<ChatModel>>();
qRegisterMetaType<std::shared_ptr<ChatRoomModel>>();
registerType<AssistantModel>("AssistantModel");
registerType<AuthenticationNotifier>("AuthenticationNotifier");
registerType<CallsListProxyModel>("CallsListProxyModel");
registerType<Camera>("Camera");
registerType<CameraPreview>("CameraPreview");
registerType<ChatProxyModel>("ChatProxyModel");
registerType<ChatRoomProxyModel>("ChatRoomProxyModel");
registerType<ConferenceHelperModel>("ConferenceHelperModel");
registerType<ConferenceModel>("ConferenceModel");
registerType<ContactsListProxyModel>("ContactsListProxyModel");
@ -616,7 +616,7 @@ void App::registerTypes () {
registerSingletonType<VideoCodecsModel>("VideoCodecsModel");
registerUncreatableType<CallModel>("CallModel");
registerUncreatableType<ChatModel>("ChatModel");
registerUncreatableType<ChatRoomModel>("ChatRoomModel");
registerUncreatableType<ConferenceHelperModel::ConferenceAddModel>("ConferenceAddModel");
registerUncreatableType<ContactModel>("ContactModel");
registerUncreatableType<ContactsImporterModel>("ContactsImporterModel");

View file

@ -23,6 +23,7 @@
#include <QDateTime>
#include <QThread>
#include <QMessageBox>
#include <QLoggingCategory>
#include "config.h"
@ -192,7 +193,7 @@ void Logger::enable (bool status) {
void Logger::init (const shared_ptr<linphone::Config> &config) {
if (mInstance)
return;
QLoggingCategory::setFilterRules("qt.qml.connections.warning=false");
const QString folder = SettingsModel::getLogsFolder(config);
Q_ASSERT(!folder.isEmpty());

View file

@ -28,7 +28,7 @@
#include "calls/CallsListProxyModel.hpp"
#include "camera/Camera.hpp"
#include "camera/CameraPreview.hpp"
#include "chat/ChatProxyModel.hpp"
#include "chat-room/ChatRoomProxyModel.hpp"
#include "codecs/AudioCodecsModel.hpp"
#include "codecs/VideoCodecsModel.hpp"
#include "conference/ConferenceAddModel.hpp"

View file

@ -26,6 +26,8 @@
#include "app/App.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/notifier/Notifier.hpp"
@ -112,6 +114,13 @@ QString CallModel::getFullLocalAddress () const {
}
// -----------------------------------------------------------------------------
ContactModel *CallModel::getContactModel() const{
auto contact = CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(QString::fromStdString(mCall->getRemoteAddress()->asString()));
return contact;
}
// -----------------------------------------------------------------------------
void CallModel::setRecordFile (const shared_ptr<linphone::CallParams> &callParams) {
callParams->setRecordFile(Utils::appStringToCoreString(
CoreManager::getInstance()->getSettingsModel()->getSavedCallsFolder()

View file

@ -26,6 +26,7 @@
#include "../search/SearchHandler.hpp"
// =============================================================================
class ContactModel;
class CallModel : public QObject {
Q_OBJECT;
@ -34,6 +35,12 @@ class CallModel : public QObject {
Q_PROPERTY(QString localAddress READ getLocalAddress CONSTANT);
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged);
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress CONSTANT);
Q_PROPERTY(ContactModel *contact READ getContactModel CONSTANT )/*
Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged)
Q_PROPERTY(int presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged)*/
Q_PROPERTY(CallStatus status READ getStatus NOTIFY statusChanged);
Q_PROPERTY(QString callError READ getCallError NOTIFY callErrorChanged);
@ -98,6 +105,8 @@ public:
QString getLocalAddress () const;
QString getFullPeerAddress () const;
QString getFullLocalAddress () const;
ContactModel *getContactModel() const;
bool isInConference () const {
return mIsInConference;

View file

@ -183,6 +183,29 @@ bool CallsListModel::launchSecureChat (const QString &sipAddress) const {
*/
return false;
}
bool CallsListModel::createSecureChat (const QString& subject, const QString &participantAddress) const{
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(participantAddress));
if (!address)
return false;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
std::shared_ptr<const linphone::Address> localAddress;
participants.push_back(address);
auto proxy = core->getDefaultProxyConfig();
params->enableEncryption(true);
params->setSubject(subject.toStdString());
params->setBackend(linphone::ChatRoomBackend::FlexisipChat);
params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime);
params->enableGroup(true);
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
return chatRoom != nullptr;
}
// -----------------------------------------------------------------------------
int CallsListModel::getRunningCallsNumber () const {

View file

@ -45,6 +45,7 @@ public:
Q_INVOKABLE void launchAudioCall (const QString &sipAddress, const QHash<QString, QString> &headers = {}) const;
Q_INVOKABLE void launchVideoCall (const QString &sipAddress) const;
Q_INVOKABLE bool launchSecureChat (const QString &sipAddress) const;
Q_INVOKABLE bool createSecureChat (const QString& subject, const QString &participantAddress) const;
Q_INVOKABLE int getRunningCallsNumber () const;

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QTimer>
#include "app/App.hpp"
#include "components/conference/ConferenceAddModel.hpp"
#include "components/conference/ConferenceHelperModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/Utils.hpp"
#include "ChatRoomListModel.hpp"
#include "ChatRoomModel.hpp"
// =============================================================================
using namespace std;
namespace {
// Delay before removing call in ms.
constexpr int DelayBeforeRemoveCall = 3000;
}
// -----------------------------------------------------------------------------
ChatRoomListModel::ChatRoomListModel (QObject *parent) : QAbstractListModel(parent) {
}
int ChatRoomListModel::rowCount (const QModelIndex &) const {
return mList.count();
}
QHash<int, QByteArray> ChatRoomListModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$chatRoom";
return roles;
}
QVariant ChatRoomListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mList[row]);
return QVariant();
}
// -----------------------------------------------------------------------------
bool ChatRoomListModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
}
bool ChatRoomListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mList.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mList.takeAt(row)->deleteLater();
endRemoveRows();
return true;
}
// -----------------------------------------------------------------------------

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef _CHAT_ROOM_LIST_MODEL_H_
#define _CHAT_ROOM_LIST_MODEL_H_
#include <linphone++/linphone.hh>
#include <QAbstractListModel>
// =============================================================================
class ChatRoomModel;
class ChatRoomListModel : public QAbstractListModel {
Q_OBJECT;
public:
ChatRoomListModel (QObject *parent = Q_NULLPTR);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
QList<ChatRoomModel *> mList;
};
#endif // _CHAT_ROOM_LIST_MODEL_H_

View file

@ -34,14 +34,19 @@
#include "app/App.hpp"
#include "app/paths/Paths.hpp"
#include "app/providers/ThumbnailProvider.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/notifier/Notifier.hpp"
#include "components/settings/SettingsModel.hpp"
#include "components/participant/ParticipantModel.hpp"
#include "components/presence/Presence.hpp"
#include "utils/QExifImageHeader.hpp"
#include "utils/Utils.hpp"
#include "ChatModel.hpp"
#include "ChatRoomModel.hpp"
// =============================================================================
@ -204,9 +209,9 @@ static inline void fillMessageEntry (QVariantMap &dest, const shared_ptr<linphon
// It can exist messages with a not delivered status. It's a linphone core bug.
linphone::ChatMessage::State state = message->getState();
if (state == linphone::ChatMessage::State::InProgress)
dest["status"] = ChatModel::MessageStatusNotDelivered;
dest["status"] = ChatRoomModel::MessageStatusNotDelivered;
else
dest["status"] = static_cast<ChatModel::MessageStatus>(message->getState());
dest["status"] = static_cast<ChatRoomModel::MessageStatus>(message->getState());
shared_ptr<const linphone::Content> content = message->getFileTransferInformation();
if (content) {
@ -220,39 +225,39 @@ static inline void fillMessageEntry (QVariantMap &dest, const shared_ptr<linphon
}
static inline void fillCallStartEntry (QVariantMap &dest, const shared_ptr<linphone::CallLog> &callLog) {
dest["type"] = ChatModel::CallEntry;
dest["type"] = ChatRoomModel::CallEntry;
dest["timestamp"] = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
dest["isOutgoing"] = callLog->getDir() == linphone::Call::Dir::Outgoing;
dest["status"] = static_cast<ChatModel::CallStatus>(callLog->getStatus());
dest["status"] = static_cast<ChatRoomModel::CallStatus>(callLog->getStatus());
dest["isStart"] = true;
}
static inline void fillCallEndEntry (QVariantMap &dest, const shared_ptr<linphone::CallLog> &callLog) {
dest["type"] = ChatModel::CallEntry;
dest["type"] = ChatRoomModel::CallEntry;
dest["timestamp"] = QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000);
dest["isOutgoing"] = callLog->getDir() == linphone::Call::Dir::Outgoing;
dest["status"] = static_cast<ChatModel::CallStatus>(callLog->getStatus());
dest["status"] = static_cast<ChatRoomModel::CallStatus>(callLog->getStatus());
dest["isStart"] = false;
}
// -----------------------------------------------------------------------------
class ChatModel::MessageHandlers : public linphone::ChatMessageListener {
friend class ChatModel;
class ChatRoomModel::MessageHandlers : public linphone::ChatMessageListener {
friend class ChatRoomModel;
public:
MessageHandlers (ChatModel *chatModel) : mChatModel(chatModel) {}
MessageHandlers (ChatRoomModel *ChatRoomModel) : mChatRoomModel(ChatRoomModel) {}
private:
QList<ChatEntryData>::iterator findMessageEntry (const shared_ptr<linphone::ChatMessage> &message) {
return find_if(mChatModel->mEntries.begin(), mChatModel->mEntries.end(), [&message](const ChatEntryData &entry) {
return find_if(mChatRoomModel->mEntries.begin(), mChatRoomModel->mEntries.end(), [&message](const ChatEntryData &entry) {
return entry.second == message;
});
}
void signalDataChanged (const QList<ChatEntryData>::iterator &it) {
int row = int(distance(mChatModel->mEntries.begin(), it));
emit mChatModel->dataChanged(mChatModel->index(row, 0), mChatModel->index(row, 0));
int row = int(distance(mChatRoomModel->mEntries.begin(), it));
emit mChatRoomModel->dataChanged(mChatRoomModel->index(row, 0), mChatRoomModel->index(row, 0));
}
shared_ptr<linphone::Buffer> onFileTransferSend (
@ -271,11 +276,11 @@ private:
size_t offset,
size_t
) override {
if (!mChatModel)
if (!mChatRoomModel)
return;
auto it = findMessageEntry(message);
if (it == mChatModel->mEntries.end())
if (it == mChatRoomModel->mEntries.end())
return;
(*it).first["fileOffset"] = quint64(offset);
@ -284,11 +289,11 @@ private:
}
void onMsgStateChanged (const shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state) override {
if (!mChatModel)
if (!mChatRoomModel)
return;
auto it = findMessageEntry(message);
if (it == mChatModel->mEntries.end())
if (it == mChatRoomModel->mEntries.end())
return;
// File message downloaded.
@ -304,12 +309,12 @@ private:
signalDataChanged(it);
}
ChatModel *mChatModel;
ChatRoomModel *mChatRoomModel;
};
// -----------------------------------------------------------------------------
ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure) {
/*
ChatRoomModel::ChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure) {
CoreManager *coreManager = CoreManager::getInstance();
mCoreHandlers = coreManager->getHandlers();
@ -319,21 +324,10 @@ ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress, c
shared_ptr<linphone::Factory> factory(linphone::Factory::get());
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list<std::shared_ptr<linphone::Address>> participants;
//params->enableEncryption(isSecure);
//if(isSecure){
// params->setBackend(linphone::ChatRoomBackend::FlexisipChat);
// params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime);
// }
mChatRoom = core->searchChatRoom(params, factory->createAddress(localAddress.toStdString())
, factory->createAddress(peerAddress.toStdString())
, participants);
/*
mChatRoom = core->getChatRoom(
factory->createAddress(peerAddress.toStdString()),
factory->createAddress(localAddress.toStdString())
);*/
Q_ASSERT(mChatRoom);
handleIsComposingChanged(mChatRoom);
@ -358,7 +352,7 @@ ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress, c
for (auto &callLog : core->getCallHistory(mChatRoom->getPeerAddress(), mChatRoom->getLocalAddress()))
insertCall(callLog);
qInfo() << QStringLiteral("ChatModel (%1, %2) loaded in %3 milliseconds.")
qInfo() << QStringLiteral("ChatRoomModel (%1, %2) loaded in %3 milliseconds.")
.arg(peerAddress).arg(localAddress).arg(timer.elapsed());
// Rebind lost handlers
@ -371,15 +365,16 @@ ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress, c
}
{
CoreHandlers *coreHandlers = mCoreHandlers.get();
QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &ChatModel::handleMessageReceived);
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatModel::handleCallStateChanged);
QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &ChatModel::handleIsComposingChanged);
QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &ChatRoomModel::handleMessageReceived);
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatRoomModel::handleCallStateChanged);
QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &ChatRoomModel::handleIsComposingChanged);
}
if(!mChatRoom)
qWarning("TOTO A");
}
*/
ChatModel::ChatModel (std::shared_ptr<linphone::ChatRoom> chatRoom){
ChatRoomModel::ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom){
CoreManager *coreManager = CoreManager::getInstance();
mCoreHandlers = coreManager->getHandlers();
@ -394,8 +389,12 @@ ChatModel::ChatModel (std::shared_ptr<linphone::ChatRoom> chatRoom){
mChatRoom = chatRoom;
Q_ASSERT(mChatRoom);
setLastUpdateTime(QDateTime::fromMSecsSinceEpoch(chatRoom->getLastUpdateTime()));
setUnreadMessagesCount(chatRoom->getUnreadMessagesCount());
mMissedCallsCount = 0;
handleIsComposingChanged(mChatRoom);
//handleIsComposingChanged(mChatRoom);
// Get messages.
mEntries.clear();
@ -430,30 +429,35 @@ ChatModel::ChatModel (std::shared_ptr<linphone::ChatRoom> chatRoom){
}
{
CoreHandlers *coreHandlers = mCoreHandlers.get();
QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &ChatModel::handleMessageReceived);
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatModel::handleCallStateChanged);
QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &ChatModel::handleIsComposingChanged);
//QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &ChatRoomModel::handleMessageReceived);
QObject::connect(coreHandlers, &CoreHandlers::callCreated, this, &ChatRoomModel::handleCallCreated);
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatRoomModel::handleCallStateChanged);
//QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &ChatRoomModel::handleIsComposingChanged);
}
if(mChatRoom){
std::list<std::shared_ptr<linphone::Participant>> participants = mChatRoom->getParticipants();
for(auto it = participants.begin() ; it != participants.end() ; ++it){
mParticipants << new ParticipantModel(*it, this);
}
}
if(!mChatRoom)
qWarning("TOTO B");
}
ChatModel::~ChatModel () {
mMessageHandlers->mChatModel = nullptr;
ChatRoomModel::~ChatRoomModel () {
mMessageHandlers->mChatRoomModel = nullptr;
}
QHash<int, QByteArray> ChatModel::roleNames () const {
QHash<int, QByteArray> ChatRoomModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Roles::ChatEntry] = "$chatEntry";
roles[Roles::SectionDate] = "$sectionDate";
return roles;
}
int ChatModel::rowCount (const QModelIndex &) const {
int ChatRoomModel::rowCount (const QModelIndex &) const {
return mEntries.count();
}
QVariant ChatModel::data (const QModelIndex &index, int role) const {
QVariant ChatRoomModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mEntries.count())
@ -473,11 +477,11 @@ QVariant ChatModel::data (const QModelIndex &index, int role) const {
return QVariant();
}
bool ChatModel::removeRow (int row, const QModelIndex &) {
bool ChatRoomModel::removeRow (int row, const QModelIndex &) {
return removeRows(row, 1);
}
bool ChatModel::removeRows (int row, int count, const QModelIndex &parent) {
bool ChatRoomModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mEntries.count())
@ -500,46 +504,111 @@ bool ChatModel::removeRows (int row, int count, const QModelIndex &parent) {
return true;
}
QString ChatModel::getPeerAddress () const {
QString ChatRoomModel::getPeerAddress () const {
return Utils::coreStringToAppString(
mChatRoom->getPeerAddress()->asStringUriOnly()
);
}
QString ChatModel::getLocalAddress () const {
QString ChatRoomModel::getLocalAddress () const {
return Utils::coreStringToAppString(
mChatRoom->getLocalAddress()->asStringUriOnly()
);
}
QString ChatModel::getFullPeerAddress () const {
QString ChatRoomModel::getFullPeerAddress () const {
if(!mChatRoom)
qWarning("TOTO Z");
return QString::fromStdString(mChatRoom->getPeerAddress()->asString());
}
QString ChatModel::getFullLocalAddress () const {
QString ChatRoomModel::getFullLocalAddress () const {
return QString::fromStdString(mChatRoom->getLocalAddress()->asString());
}
void ChatModel::setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure) {
QString ChatRoomModel::getSubject () const {
return QString::fromStdString(mChatRoom->getSubject());
}
QString ChatRoomModel::getUsername () const {
std::string username = mChatRoom->getSubject();
if(username != ""){
return QString::fromStdString(username);
}
if( mChatRoom->getNbParticipants() == 1){
auto participants = mChatRoom->getParticipants();
auto contact = CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(QString::fromStdString((*participants.begin())->getAddress()->asString()));
if(contact)
return contact->getVcardModel()->getUsername();
}
username = mChatRoom->getPeerAddress()->getDisplayName();
if(username != "")
return QString::fromStdString(username);
username = mChatRoom->getPeerAddress()->getUsername();
if(username != "")
return QString::fromStdString(username);
return QString::fromStdString(mChatRoom->getPeerAddress()->asStringUriOnly());
}
QString ChatRoomModel::getAvatar () const {
if( mChatRoom->getNbParticipants() == 1){
auto participants = mChatRoom->getParticipants();
auto contact = CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(QString::fromStdString((*participants.begin())->getAddress()->asString()));
if(contact)
return contact->getVcardModel()->getAvatar();
}
return "";
}
int ChatRoomModel::getPresenceStatus() const {
if( mChatRoom->getNbParticipants() == 1){
auto participants = mChatRoom->getParticipants();
auto contact = CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(QString::fromStdString((*participants.begin())->getAddress()->asString()));
if(contact)
return contact->getPresenceLevel();
else
return 0;
}else
return 0;
//return Presence::getPresenceLevel(1);
//return mChatRoom->getConsolidatedPresence();
}
void ChatRoomModel::setLastUpdateTime(const QDateTime& lastUpdateDate) {
if(mLastUpdateTime != lastUpdateDate ) {
mLastUpdateTime = lastUpdateDate;
emit lastUpdateTimeChanged();
}
}
void ChatRoomModel::setUnreadMessagesCount(const int& count){
if(count != mUnreadMessagesCount){
mUnreadMessagesCount = count;
emit unreadMessagesCountChanged();
}
}
void ChatRoomModel::setMissedCallsCount(const int& count){
if(count != mMissedCallsCount){
mMissedCallsCount = count;
emit missedCallsCountChanged();
}
}
void ChatRoomModel::leaveChatRoom (){
mChatRoom->leave();
mChatRoom->getCore()->deleteChatRoom(mChatRoom);
}
/*
void ChatRoomModel::setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure) {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Factory> factory(linphone::Factory::get());
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list<std::shared_ptr<linphone::Address>> participants;
//params->enableEncryption(isSecure);
//if(isSecure){
// params->setBackend(linphone::ChatRoomBackend::FlexisipChat);
// params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime);
// }
mChatRoom = core->searchChatRoom(params, factory->createAddress(localAddress.toStdString())
, factory->createAddress(peerAddress.toStdString())
, participants);
/*
mChatRoom = core->getChatRoom(
factory->createAddress(peerAddress.toStdString()),
factory->createAddress(localAddress.toStdString())
);*/
Q_ASSERT(mChatRoom);
handleIsComposingChanged(mChatRoom);
@ -564,26 +633,36 @@ void ChatModel::setSipAddresses (const QString &peerAddress, const QString &loca
for (auto &callLog : core->getCallHistory(mChatRoom->getPeerAddress(), mChatRoom->getLocalAddress()))
insertCall(callLog);
qInfo() << QStringLiteral("ChatModel (%1, %2) loaded in %3 milliseconds.")
qInfo() << QStringLiteral("ChatRoomModel (%1, %2) loaded in %3 milliseconds.")
.arg(peerAddress).arg(localAddress).arg(timer.elapsed());
if(!mChatRoom)
qWarning("TOTO C");
}
*/
bool ChatModel::getIsSecure() const{
bool ChatRoomModel::getIsSecure() const{
return mChatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Encrypted
|| mChatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Safe;
}
bool ChatModel::getIsRemoteComposing () const {
bool ChatRoomModel::getIsRemoteComposing () const {
return mIsRemoteComposing;
}
//QList<ParticipantModel *> ChatRoomModel::getParticipants() const{
QString ChatRoomModel::getParticipants() const{
QStringList participants;
for(auto it = mParticipants.begin() ; it != mParticipants.end() ; ++it)
participants << (*it)->getAddress();
return participants.join(",");
}
// -----------------------------------------------------------------------------
void ChatModel::removeEntry (int id) {
void ChatRoomModel::removeEntry (int id) {
qInfo() << QStringLiteral("Removing chat entry: %1 of (%2, %3).")
.arg(id).arg(getPeerAddress()).arg(getLocalAddress());
@ -591,7 +670,7 @@ void ChatModel::removeEntry (int id) {
qWarning() << QStringLiteral("Unable to remove chat entry: %1").arg(id);
}
void ChatModel::removeAllEntries () {
void ChatRoomModel::removeAllEntries () {
qInfo() << QStringLiteral("Removing all chat entries of: (%1, %2).")
.arg(getPeerAddress()).arg(getLocalAddress());
@ -610,19 +689,18 @@ void ChatModel::removeAllEntries () {
// -----------------------------------------------------------------------------
void ChatModel::sendMessage (const QString &message) {
shared_ptr<linphone::ChatMessage> _message = mChatRoom->createMessage("");
_message->getContents().begin()->get()->setStringBuffer(message.toUtf8().toStdString());
void ChatRoomModel::sendMessage (const QString &message) {
shared_ptr<linphone::ChatMessage> _message = mChatRoom->createMessageFromUtf8("");
_message->getContents().begin()->get()->setUtf8Text(message.toUtf8().toStdString());
_message->removeListener(mMessageHandlers);// Remove old listener if already exists
_message->addListener(mMessageHandlers);
insertMessageAtEnd(_message);
_message->send();
emit messageSent(_message);
}
void ChatModel::resendMessage (int id) {
void ChatRoomModel::resendMessage (int id) {
if (id < 0 || id > mEntries.count()) {
qWarning() << QStringLiteral("Entry %1 not exists.").arg(id);
return;
@ -652,7 +730,7 @@ void ChatModel::resendMessage (int id) {
}
}
void ChatModel::sendFileMessage (const QString &path) {
void ChatRoomModel::sendFileMessage (const QString &path) {
QFile file(path);
if (!file.exists())
return;
@ -682,7 +760,6 @@ void ChatModel::sendFileMessage (const QString &path) {
createThumbnail(message);
insertMessageAtEnd(message);
message->send();
emit messageSent(message);
@ -690,7 +767,7 @@ void ChatModel::sendFileMessage (const QString &path) {
// -----------------------------------------------------------------------------
void ChatModel::downloadFile (int id) {
void ChatRoomModel::downloadFile (int id) {
const ChatEntryData entry = getFileMessageEntry(id);
if (!entry.second)
return;
@ -734,7 +811,7 @@ void ChatModel::downloadFile (int id) {
}
}
void ChatModel::openFile (int id, bool showDirectory) {
void ChatRoomModel::openFile (int id, bool showDirectory) {
const ChatEntryData entry = getFileMessageEntry(id);
if (!entry.second)
return;
@ -750,27 +827,29 @@ void ChatModel::openFile (int id, bool showDirectory) {
}
}
bool ChatModel::fileWasDownloaded (int id) {
bool ChatRoomModel::fileWasDownloaded (int id) {
const ChatEntryData entry = getFileMessageEntry(id);
return entry.second && ::fileWasDownloaded(static_pointer_cast<linphone::ChatMessage>(entry.second));
}
void ChatModel::compose () {
void ChatRoomModel::compose () {
mChatRoom->compose();
}
void ChatModel::resetMessageCount () {
void ChatRoomModel::resetMessageCount () {
if (mChatRoom->getUnreadMessagesCount() > 0){
mChatRoom->markAsRead();// Marking as read is only for messages. Not for calls.
setUnreadMessagesCount(mChatRoom->getUnreadMessagesCount());
}
mMissedCallsCount = 0;
emit messageCountReset();
}
std::shared_ptr<linphone::ChatRoom> ChatModel::getChatRoom(){
std::shared_ptr<linphone::ChatRoom> ChatRoomModel::getChatRoom(){
return mChatRoom;
}
// -----------------------------------------------------------------------------
const ChatModel::ChatEntryData ChatModel::getFileMessageEntry (int id) {
const ChatRoomModel::ChatEntryData ChatRoomModel::getFileMessageEntry (int id) {
if (id < 0 || id > mEntries.count()) {
qWarning() << QStringLiteral("Entry %1 not exists.").arg(id);
return ChatEntryData();
@ -793,18 +872,18 @@ const ChatModel::ChatEntryData ChatModel::getFileMessageEntry (int id) {
// -----------------------------------------------------------------------------
void ChatModel::removeEntry (ChatEntryData &entry) {
void ChatRoomModel::removeEntry (ChatEntryData &entry) {
int type = entry.first["type"].toInt();
switch (type) {
case ChatModel::MessageEntry: {
case ChatRoomModel::MessageEntry: {
shared_ptr<linphone::ChatMessage> message = static_pointer_cast<linphone::ChatMessage>(entry.second);
removeFileMessageThumbnail(message);
mChatRoom->deleteMessage(message);
break;
}
case ChatModel::CallEntry: {
case ChatRoomModel::CallEntry: {
if (entry.first["status"].toInt() == CallStatusSuccess) {
// WARNING: Unable to remove symmetric call here. (start/end)
// We are between `beginRemoveRows` and `endRemoveRows`.
@ -829,7 +908,7 @@ void ChatModel::removeEntry (ChatEntryData &entry) {
}
}
void ChatModel::insertCall (const shared_ptr<linphone::CallLog> &callLog) {
void ChatRoomModel::insertCall (const shared_ptr<linphone::CallLog> &callLog) {
linphone::Call::Status status = callLog->getStatus();
auto insertEntry = [this](
@ -862,7 +941,7 @@ void ChatModel::insertCall (const shared_ptr<linphone::CallLog> &callLog) {
}
}
void ChatModel::insertMessageAtEnd (const shared_ptr<linphone::ChatMessage> &message) {
void ChatRoomModel::insertMessageAtEnd (const shared_ptr<linphone::ChatMessage> &message) {
int row = mEntries.count();
beginInsertRows(QModelIndex(), row, row);
@ -879,27 +958,95 @@ void ChatModel::insertMessageAtEnd (const shared_ptr<linphone::ChatMessage> &mes
// -----------------------------------------------------------------------------
void ChatModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::Call::State state) {
if (
(state == linphone::Call::State::End || state == linphone::Call::State::Error) &&
mChatRoom == CoreManager::getInstance()->getCore()->findChatRoom(call->getRemoteAddress(), mChatRoom->getLocalAddress())
)
insertCall(call->getCallLog());
void ChatRoomModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::Call::State state) {
if (state == linphone::Call::State::End || state == linphone::Call::State::Error){
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list<std::shared_ptr<linphone::Address>> participants;
auto chatRoom = core->searchChatRoom(params, mChatRoom->getLocalAddress()
, call->getRemoteAddress()
, participants);
if( mChatRoom == chatRoom){
insertCall(call->getCallLog());
setMissedCallsCount(mMissedCallsCount+1);
}
//mChatRoom == CoreManager::getInstance()->getCore()->findChatRoom(call->getRemoteAddress(), mChatRoom->getLocalAddress())
}
}
void ChatModel::handleIsComposingChanged (const shared_ptr<linphone::ChatRoom> &chatRoom) {
if (mChatRoom == chatRoom) {
bool isRemoteComposing = mChatRoom->isRemoteComposing();
if (isRemoteComposing != mIsRemoteComposing) {
mIsRemoteComposing = isRemoteComposing;
void ChatRoomModel::handleCallCreated(const shared_ptr<linphone::Call> &call){
}
//----------------------------------------------------------
//------ CHAT ROOM HANDLERS
//----------------------------------------------------------
void ChatRoomModel::onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & remoteAddress, bool isComposing){
if (isComposing != mIsRemoteComposing) {
mIsRemoteComposing = isComposing;
emit isRemoteComposingChanged(mIsRemoteComposing);
}
}
}
void ChatModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &message) {
if (mChatRoom == message->getChatRoom()) {
insertMessageAtEnd(message);
emit messageReceived(message);
}
void ChatRoomModel::onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){
setUnreadMessagesCount(chatRoom->getUnreadMessagesCount());
/*
insertMessageAtEnd(message);
emit messageReceived(message);*/
}
void ChatRoomModel::onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
qWarning() << "New Event" <<(int) eventLog->getType();
if( eventLog->getType() == linphone::EventLog::Type::ConferenceCallEnd ){
setMissedCallsCount(mMissedCallsCount+1);
}
/*auto message = eventLog->getChatMessage();
if(message){
insertMessageAtEnd(message);
emit messageReceived(message);
}*/
}
void ChatRoomModel::onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) {
auto message = eventLog->getChatMessage();
if(message){
insertMessageAtEnd(message);
emit messageReceived(message);
setLastUpdateTime(QDateTime::fromMSecsSinceEpoch(chatRoom->getLastUpdateTime()));
}
}
void ChatRoomModel::onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
auto message = eventLog->getChatMessage();
if(message){
insertMessageAtEnd(message);
emit messageReceived(message);
setLastUpdateTime(QDateTime::fromMSecsSinceEpoch(chatRoom->getLastUpdateTime()));
}
}
void ChatRoomModel::onChatMessageSent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
/*auto message = eventLog->getChatMessage();
if(message){
insertMessageAtEnd(message);
emit messageReceived(message);
}*/
}
void ChatRoomModel::onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onParticipantRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState){}
void ChatRoomModel::onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onSubjectChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) {
emit subjectChanged(getSubject());
emit usernameChanged(getUsername());
}
void ChatRoomModel::onUndecryptableMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){}
void ChatRoomModel::onParticipantDeviceAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onParticipantDeviceRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onConferenceLeft(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onEphemeralEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void ChatRoomModel::onConferenceAddressGeneration(const std::shared_ptr<linphone::ChatRoom> & chatRoom){}
void ChatRoomModel::onParticipantRegistrationSubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress){}
void ChatRoomModel::onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress){}
void ChatRoomModel::onChatMessageShouldBeStored(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){}
void ChatRoomModel::onChatMessageParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state){}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef CHAT_ROOM_MODEL_H_
#define CHAT_ROOM_MODEL_H_
#include <linphone++/linphone.hh>
#include <QAbstractListModel>
#include <QDateTime>
// =============================================================================
// Fetch all N messages of a ChatRoom.
// =============================================================================
class CoreHandlers;
class ParticipantModel;
class ChatRoomModel : public QAbstractListModel, public linphone::ChatRoomListener {
class MessageHandlers;
Q_OBJECT;
public:
enum Roles {
ChatEntry = Qt::DisplayRole,
SectionDate
};
enum EntryType {
GenericEntry,
MessageEntry,
CallEntry
};
Q_ENUM(EntryType);
enum CallStatus {
CallStatusDeclined = int(linphone::Call::Status::Declined),
CallStatusMissed = int(linphone::Call::Status::Missed),
CallStatusSuccess = int(linphone::Call::Status::Success),
CallStatusAborted = int(linphone::Call::Status::Aborted),
CallStatusEarlyAborted = int(linphone::Call::Status::EarlyAborted),
CallStatusAcceptedElsewhere = int(linphone::Call::Status::AcceptedElsewhere),
CallStatusDeclinedElsewhere = int(linphone::Call::Status::DeclinedElsewhere)
};
Q_ENUM(CallStatus);
enum MessageStatus {
MessageStatusDelivered = int(linphone::ChatMessage::State::Delivered),
MessageStatusDeliveredToUser = int(linphone::ChatMessage::State::DeliveredToUser),
MessageStatusDisplayed = int(linphone::ChatMessage::State::Displayed),
MessageStatusFileTransferDone = int(linphone::ChatMessage::State::FileTransferDone),
MessageStatusFileTransferError = int(linphone::ChatMessage::State::FileTransferError),
MessageStatusFileTransferInProgress = int(linphone::ChatMessage::State::FileTransferInProgress),
MessageStatusIdle = int(linphone::ChatMessage::State::Idle),
MessageStatusInProgress = int(linphone::ChatMessage::State::InProgress),
MessageStatusNotDelivered = int(linphone::ChatMessage::State::NotDelivered)
};
Q_ENUM(MessageStatus);
Q_PROPERTY(QString participants READ getParticipants NOTIFY participantsChanged);
Q_PROPERTY(QString subject READ getSubject NOTIFY subjectChanged)
Q_PROPERTY(QDateTime lastUpdateTime MEMBER mLastUpdateTime WRITE setLastUpdateTime NOTIFY lastUpdateTimeChanged)
Q_PROPERTY(int unreadMessagesCount MEMBER mUnreadMessagesCount WRITE setUnreadMessagesCount NOTIFY unreadMessagesCountChanged)
Q_PROPERTY(int missedCallsCount MEMBER mMissedCallsCount WRITE setMissedCallsCount NOTIFY missedCallsCountChanged)
Q_PROPERTY(bool isComposing MEMBER mIsRemoteComposing NOTIFY isRemoteComposingChanged)
Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged)
Q_PROPERTY(int presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged)
//ChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom);
~ChatRoomModel ();
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role) const override;
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
Q_INVOKABLE QString getPeerAddress () const;
Q_INVOKABLE QString getLocalAddress () const;
Q_INVOKABLE QString getFullPeerAddress () const;
Q_INVOKABLE QString getFullLocalAddress () const;
QString getSubject () const;
QString getUsername () const;
QString getAvatar () const;
int getPresenceStatus() const;
void setLastUpdateTime(const QDateTime& lastUpdateDate);
void setUnreadMessagesCount(const int& count);
void setMissedCallsCount(const int& count);
Q_INVOKABLE void leaveChatRoom ();
bool getIsSecure() const;
bool getIsRemoteComposing () const;
//Q_INVOKABLE QList<ParticipantModel*> getParticipants()const
Q_INVOKABLE QString getParticipants()const;
void removeEntry (int id);
void removeAllEntries ();
void sendMessage (const QString &message);
void resendMessage (int id);
void sendFileMessage (const QString &path);
void downloadFile (int id);
void openFile (int id, bool showDirectory = false);
void openFileDirectory (int id) {
openFile(id, true);
}
bool fileWasDownloaded (int id);
void compose ();
void resetMessageCount ();
std::shared_ptr<linphone::ChatRoom> getChatRoom();
QDateTime mLastUpdateTime;
int mUnreadMessagesCount;
int mMissedCallsCount;
//-------------------- CHAT ROOM HANDLER
virtual void onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & remoteAddress, bool isComposing) override;
virtual void onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessageSent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState) override;
virtual void onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onSubjectChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onUndecryptableMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onParticipantDeviceAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantDeviceRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onConferenceLeft(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onEphemeralEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onConferenceAddressGeneration(const std::shared_ptr<linphone::ChatRoom> & chatRoom) override;
virtual void onParticipantRegistrationSubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress) override;
virtual void onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress) override;
virtual void onChatMessageShouldBeStored(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onChatMessageParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state) override;
signals:
bool isRemoteComposingChanged (bool status);
void allEntriesRemoved ();
void lastEntryRemoved ();
void messageSent (const std::shared_ptr<linphone::ChatMessage> &message);
void messageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
void messageCountReset ();
void focused ();
void fullPeerAddressChanged();
void participantsChanged();
void subjectChanged(QString subject);
void usernameChanged(QString username);
void avatarChanged(QString avatar);
void presenceStatusChanged(int presenceStatus);
void lastUpdateTimeChanged();
void unreadMessagesCountChanged();
void missedCallsCountChanged();
private:
typedef QPair<QVariantMap, std::shared_ptr<void>> ChatEntryData;
//void setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
const ChatEntryData getFileMessageEntry (int id);
void removeEntry (ChatEntryData &entry);
void insertCall (const std::shared_ptr<linphone::CallLog> &callLog);
void insertMessageAtEnd (const std::shared_ptr<linphone::ChatMessage> &message);
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
void handleCallCreated(const std::shared_ptr<linphone::Call> &call);// Count an event call
//void handleIsComposingChanged (const std::shared_ptr<linphone::ChatRoom> &chatRoom);
//void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
bool mIsRemoteComposing = false;
mutable QList<ChatEntryData> mEntries;
QList<ParticipantModel*> mParticipants;
std::shared_ptr<CoreHandlers> mCoreHandlers;
std::shared_ptr<MessageHandlers> mMessageHandlers;
std::shared_ptr<linphone::ChatRoom> mChatRoom;
};
Q_DECLARE_METATYPE(std::shared_ptr<ChatRoomModel>);
#endif // CHAT_ROOM_MODEL_H_

View file

@ -23,31 +23,31 @@
#include "app/App.hpp"
#include "components/core/CoreManager.hpp"
#include "ChatProxyModel.hpp"
#include "ChatRoomProxyModel.hpp"
// =============================================================================
using namespace std;
QString ChatProxyModel::gCachedText;
QString ChatRoomProxyModel::gCachedText;
// Fetch the L last filtered chat entries.
class ChatProxyModel::ChatModelFilter : public QSortFilterProxyModel {
class ChatRoomProxyModel::ChatRoomModelFilter : public QSortFilterProxyModel {
public:
ChatModelFilter (QObject *parent) : QSortFilterProxyModel(parent) {}
ChatRoomModelFilter (QObject *parent) : QSortFilterProxyModel(parent) {}
ChatModel::EntryType getEntryTypeFilter () {
ChatRoomModel::EntryType getEntryTypeFilter () {
return mEntryTypeFilter;
}
void setEntryTypeFilter (ChatModel::EntryType type) {
void setEntryTypeFilter (ChatRoomModel::EntryType type) {
mEntryTypeFilter = type;
invalidate();
}
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &) const override {
if (mEntryTypeFilter == ChatModel::EntryType::GenericEntry)
if (mEntryTypeFilter == ChatRoomModel::EntryType::GenericEntry)
return true;
QModelIndex index = sourceModel()->index(sourceRow, 0, QModelIndex());
@ -57,13 +57,13 @@ protected:
}
private:
ChatModel::EntryType mEntryTypeFilter = ChatModel::EntryType::GenericEntry;
ChatRoomModel::EntryType mEntryTypeFilter = ChatRoomModel::EntryType::GenericEntry;
};
// =============================================================================
ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(new ChatModelFilter(this));
ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(new ChatRoomModelFilter(this));
mIsSecure = false;
App *app = App::getInstance();
@ -81,25 +81,25 @@ ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent)
// -----------------------------------------------------------------------------
#define GET_CHAT_MODEL() \
if (!mChatModel) \
if (!mChatRoomModel) \
return; \
mChatModel
mChatRoomModel
#define CREATE_PARENT_MODEL_FUNCTION(METHOD) \
void ChatProxyModel::METHOD () { \
void ChatRoomProxyModel::METHOD () { \
GET_CHAT_MODEL()->METHOD(); \
}
#define CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(METHOD, ARG_TYPE) \
void ChatProxyModel::METHOD (ARG_TYPE value) { \
void ChatRoomProxyModel::METHOD (ARG_TYPE value) { \
GET_CHAT_MODEL()->METHOD(value); \
}
#define CREATE_PARENT_MODEL_FUNCTION_WITH_ID(METHOD) \
void ChatProxyModel::METHOD (int id) { \
void ChatRoomProxyModel::METHOD (int id) { \
QModelIndex sourceIndex = mapToSource(index(id, 0)); \
GET_CHAT_MODEL()->METHOD( \
static_cast<ChatModelFilter *>(sourceModel())->mapToSource(sourceIndex).row() \
static_cast<ChatRoomModelFilter *>(sourceModel())->mapToSource(sourceIndex).row() \
); \
}
@ -120,15 +120,15 @@ CREATE_PARENT_MODEL_FUNCTION_WITH_ID(resendMessage);
#undef CREATE_PARENT_MODEL_FUNCTION_WITH_ID
void ChatProxyModel::compose (const QString& text) {
if (mChatModel)
mChatModel->compose();
void ChatRoomProxyModel::compose (const QString& text) {
if (mChatRoomModel)
mChatRoomModel->compose();
gCachedText = text;
}
// -----------------------------------------------------------------------------
void ChatProxyModel::loadMoreEntries () {
void ChatRoomProxyModel::loadMoreEntries () {
int count = rowCount();
int parentCount = sourceModel()->rowCount();
@ -146,116 +146,116 @@ void ChatProxyModel::loadMoreEntries () {
}
}
void ChatProxyModel::setEntryTypeFilter (ChatModel::EntryType type) {
ChatModelFilter *chatModelFilter = static_cast<ChatModelFilter *>(sourceModel());
void ChatRoomProxyModel::setEntryTypeFilter (ChatRoomModel::EntryType type) {
ChatRoomModelFilter *ChatRoomModelFilter = static_cast<ChatRoomProxyModel::ChatRoomModelFilter *>(sourceModel());
if (chatModelFilter->getEntryTypeFilter() != type) {
chatModelFilter->setEntryTypeFilter(type);
if (ChatRoomModelFilter->getEntryTypeFilter() != type) {
ChatRoomModelFilter->setEntryTypeFilter(type);
emit entryTypeFilterChanged(type);
}
}
// -----------------------------------------------------------------------------
bool ChatProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) const {
bool ChatRoomProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) const {
return sourceModel()->rowCount() - sourceRow <= mMaxDisplayedEntries;
}
// -----------------------------------------------------------------------------
QString ChatProxyModel::getPeerAddress () const {
return mChatModel ? mChatModel->getPeerAddress() : QString("");
QString ChatRoomProxyModel::getPeerAddress () const {
return mChatRoomModel ? mChatRoomModel->getPeerAddress() : QString("");
}
void ChatProxyModel::setPeerAddress (const QString &peerAddress) {
void ChatRoomProxyModel::setPeerAddress (const QString &peerAddress) {
mPeerAddress = peerAddress;
//reload();
}
QString ChatProxyModel::getLocalAddress () const {
return mChatModel ? mChatModel->getLocalAddress() : QString("");
QString ChatRoomProxyModel::getLocalAddress () const {
return mChatRoomModel ? mChatRoomModel->getLocalAddress() : QString("");
}
void ChatProxyModel::setLocalAddress (const QString &localAddress) {
void ChatRoomProxyModel::setLocalAddress (const QString &localAddress) {
mLocalAddress = localAddress;
//reload();
}
QString ChatProxyModel::getFullPeerAddress () const {
return mChatModel ? mChatModel->getFullPeerAddress() : QString("");
QString ChatRoomProxyModel::getFullPeerAddress () const {
return mChatRoomModel ? mChatRoomModel->getFullPeerAddress() : QString("");
}
void ChatProxyModel::setFullPeerAddress (const QString &peerAddress) {
void ChatRoomProxyModel::setFullPeerAddress (const QString &peerAddress) {
mFullPeerAddress = peerAddress;
//reload();
}
QString ChatProxyModel::getFullLocalAddress () const {
return mChatModel ? mChatModel->getFullLocalAddress() : QString("");
QString ChatRoomProxyModel::getFullLocalAddress () const {
return mChatRoomModel ? mChatRoomModel->getFullLocalAddress() : QString("");
}
void ChatProxyModel::setFullLocalAddress (const QString &localAddress) {
void ChatRoomProxyModel::setFullLocalAddress (const QString &localAddress) {
mFullLocalAddress = localAddress;
//reload();
}
int ChatProxyModel::getIsSecure () const {
return mChatModel ? mChatModel->getIsSecure() : -1;
int ChatRoomProxyModel::getIsSecure () const {
return mChatRoomModel ? mChatRoomModel->getIsSecure() : -1;
}
void ChatProxyModel::setIsSecure (const int &secure) {
void ChatRoomProxyModel::setIsSecure (const int &secure) {
mIsSecure = secure;
}
bool ChatProxyModel::getIsRemoteComposing () const {
return mChatModel ? mChatModel->getIsRemoteComposing() : false;
bool ChatRoomProxyModel::getIsRemoteComposing () const {
return mChatRoomModel ? mChatRoomModel->getIsRemoteComposing() : false;
}
QString ChatProxyModel::getCachedText() const{
QString ChatRoomProxyModel::getCachedText() const{
return gCachedText;
}
// -----------------------------------------------------------------------------
void ChatProxyModel::reload () {
void ChatRoomProxyModel::reload () {
mMaxDisplayedEntries = EntriesChunkSize;
if (mChatModel) {
ChatModel *chatModel = mChatModel.get();
QObject::disconnect(chatModel, &ChatModel::isRemoteComposingChanged, this, &ChatProxyModel::handleIsRemoteComposingChanged);
QObject::disconnect(chatModel, &ChatModel::messageReceived, this, &ChatProxyModel::handleMessageReceived);
QObject::disconnect(chatModel, &ChatModel::messageSent, this, &ChatProxyModel::handleMessageSent);
if (mChatRoomModel) {
ChatRoomModel *ChatRoomModel = mChatRoomModel.get();
QObject::disconnect(ChatRoomModel, &ChatRoomModel::isRemoteComposingChanged, this, &ChatRoomProxyModel::handleIsRemoteComposingChanged);
QObject::disconnect(ChatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
QObject::disconnect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
}
//mChatModel = CoreManager::getInstance()->getChatModel(mPeerAddress, mLocalAddress, mIsSecure);
//mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(mPeerAddress, mLocalAddress, mIsSecure);
//if(mChatRoom)
mChatModel = CoreManager::getInstance()->getChatModel(mChatRoom);
mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(mChatRoom);
if (mChatModel) {
if (mChatRoomModel) {
ChatModel *chatModel = mChatModel.get();
QObject::connect(chatModel, &ChatModel::isRemoteComposingChanged, this, &ChatProxyModel::handleIsRemoteComposingChanged);
QObject::connect(chatModel, &ChatModel::messageReceived, this, &ChatProxyModel::handleMessageReceived);
QObject::connect(chatModel, &ChatModel::messageSent, this, &ChatProxyModel::handleMessageSent);
ChatRoomModel *ChatRoomModel = mChatRoomModel.get();
QObject::connect(ChatRoomModel, &ChatRoomModel::isRemoteComposingChanged, this, &ChatRoomProxyModel::handleIsRemoteComposingChanged);
QObject::connect(ChatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
QObject::connect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
}
static_cast<ChatModelFilter *>(sourceModel())->setSourceModel(mChatModel.get());
static_cast<ChatRoomModelFilter *>(sourceModel())->setSourceModel(mChatRoomModel.get());
}
void ChatProxyModel::resetMessageCount(){
if( mChatModel){
mChatModel->resetMessageCount();
void ChatRoomProxyModel::resetMessageCount(){
if( mChatRoomModel){
mChatRoomModel->resetMessageCount();
}
}
std::shared_ptr<ChatModel> ChatProxyModel::getChatModel () const{
return mChatModel;
ChatRoomModel *ChatRoomProxyModel::getChatRoomModel () const{
return mChatRoomModel.get();
}
void ChatProxyModel::setChatModel (std::shared_ptr<ChatModel> chatModel){
mChatRoom = chatModel->getChatRoom();
void ChatRoomProxyModel::setChatRoomModel (ChatRoomModel *ChatRoomModel){
mChatRoom = ChatRoomModel->getChatRoom();
reload();
emit chatModelChanged();
emit chatRoomModelChanged();
}
// -----------------------------------------------------------------------------
@ -269,25 +269,25 @@ static inline QWindow *getParentWindow (QObject *object) {
return nullptr;
}
void ChatProxyModel::handleIsActiveChanged (QWindow *window) {
if (mChatModel && window->isActive() && getParentWindow(this) == window) {
mChatModel->resetMessageCount();
mChatModel->focused();
void ChatRoomProxyModel::handleIsActiveChanged (QWindow *window) {
if (mChatRoomModel && window->isActive() && getParentWindow(this) == window) {
mChatRoomModel->resetMessageCount();
mChatRoomModel->focused();
}
}
void ChatProxyModel::handleIsRemoteComposingChanged (bool status) {
void ChatRoomProxyModel::handleIsRemoteComposingChanged (bool status) {
emit isRemoteComposingChanged(status);
}
void ChatProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &) {
void ChatRoomProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
QWindow *window = getParentWindow(this);
if (window && window->isActive())
mChatModel->resetMessageCount();
mChatRoomModel->resetMessageCount();
}
void ChatProxyModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &) {
void ChatRoomProxyModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
}

View file

@ -18,19 +18,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_PROXY_MODEL_H_
#define CHAT_PROXY_MODEL_H_
#ifndef CHAT_ROOM_PROXY_MODEL_H_
#define CHAT_ROOM_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
#include "ChatModel.hpp"
#include "ChatRoomModel.hpp"
// =============================================================================
class QWindow;
class ChatProxyModel : public QSortFilterProxyModel {
class ChatModelFilter;
class ChatRoomProxyModel : public QSortFilterProxyModel {
class ChatRoomModelFilter;
Q_OBJECT;
@ -39,17 +39,17 @@ class ChatProxyModel : public QSortFilterProxyModel {
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress WRITE setFullPeerAddress NOTIFY fullPeerAddressChanged);
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress WRITE setFullLocalAddress NOTIFY fullLocalAddressChanged);
Q_PROPERTY(int isSecure READ getIsSecure WRITE setIsSecure NOTIFY isSecureChanged);
Q_PROPERTY(std::shared_ptr<ChatModel> chatModel READ getChatModel WRITE setChatModel NOTIFY chatModelChanged);
Q_PROPERTY(ChatRoomModel *chatRoomModel READ getChatRoomModel WRITE setChatRoomModel NOTIFY chatRoomModelChanged);
//Q_PROPERTY(bool isSecure MEMBER mIsSecure NOTIFY isSecureChanged);
Q_PROPERTY(bool isRemoteComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged);
//Q_PROPERTY(bool isSecure READ getIsSecure NOTIFY isSecureChanged);
Q_PROPERTY(QString cachedText READ getCachedText);
public:
ChatProxyModel (QObject *parent = Q_NULLPTR);
ChatRoomProxyModel (QObject *parent = Q_NULLPTR);
Q_INVOKABLE void loadMoreEntries ();
Q_INVOKABLE void setEntryTypeFilter (ChatModel::EntryType type);
Q_INVOKABLE void setEntryTypeFilter (ChatRoomModel::EntryType type);
Q_INVOKABLE void removeEntry (int id);
Q_INVOKABLE void removeAllEntries ();
@ -75,11 +75,11 @@ signals:
bool isRemoteComposingChanged (bool status);
bool isSecureChanged(bool secure);
void chatModelChanged();
void chatRoomModelChanged();
void moreEntriesLoaded (int n);
void entryTypeFilterChanged (ChatModel::EntryType type);
void entryTypeFilterChanged (ChatRoomModel::EntryType type);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
@ -100,8 +100,8 @@ private:
int getIsSecure () const;
void setIsSecure (const int &secure);
std::shared_ptr<ChatModel> getChatModel() const;
void setChatModel (std::shared_ptr<ChatModel> chatModel);
ChatRoomModel *getChatRoomModel() const;
void setChatRoomModel (ChatRoomModel *chatRoomModel);
bool getIsRemoteComposing () const;
@ -126,9 +126,9 @@ private:
std::shared_ptr<linphone::ChatRoom> mChatRoom;
std::shared_ptr<ChatModel> mChatModel;
std::shared_ptr<ChatRoomModel> mChatRoomModel;
static constexpr int EntriesChunkSize = 50;
};
#endif // CHAT_PROXY_MODEL_H_
#endif // CHAT_ROOM_PROXY_MODEL_H_

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef CHAT_MODEL_H_
#define CHAT_MODEL_H_
#include <linphone++/linphone.hh>
#include <QAbstractListModel>
// =============================================================================
// Fetch all N messages of a ChatRoom.
// =============================================================================
class CoreHandlers;
class ChatModel : public QAbstractListModel {
class MessageHandlers;
Q_OBJECT;
public:
enum Roles {
ChatEntry = Qt::DisplayRole,
SectionDate
};
enum EntryType {
GenericEntry,
MessageEntry,
CallEntry
};
Q_ENUM(EntryType);
enum CallStatus {
CallStatusDeclined = int(linphone::Call::Status::Declined),
CallStatusMissed = int(linphone::Call::Status::Missed),
CallStatusSuccess = int(linphone::Call::Status::Success),
CallStatusAborted = int(linphone::Call::Status::Aborted),
CallStatusEarlyAborted = int(linphone::Call::Status::EarlyAborted),
CallStatusAcceptedElsewhere = int(linphone::Call::Status::AcceptedElsewhere),
CallStatusDeclinedElsewhere = int(linphone::Call::Status::DeclinedElsewhere)
};
Q_ENUM(CallStatus);
enum MessageStatus {
MessageStatusDelivered = int(linphone::ChatMessage::State::Delivered),
MessageStatusDeliveredToUser = int(linphone::ChatMessage::State::DeliveredToUser),
MessageStatusDisplayed = int(linphone::ChatMessage::State::Displayed),
MessageStatusFileTransferDone = int(linphone::ChatMessage::State::FileTransferDone),
MessageStatusFileTransferError = int(linphone::ChatMessage::State::FileTransferError),
MessageStatusFileTransferInProgress = int(linphone::ChatMessage::State::FileTransferInProgress),
MessageStatusIdle = int(linphone::ChatMessage::State::Idle),
MessageStatusInProgress = int(linphone::ChatMessage::State::InProgress),
MessageStatusNotDelivered = int(linphone::ChatMessage::State::NotDelivered)
};
Q_ENUM(MessageStatus);
ChatModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
ChatModel (std::shared_ptr<linphone::ChatRoom> chatRoom);
~ChatModel ();
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role) const override;
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
QString getPeerAddress () const;
QString getLocalAddress () const;
QString getFullPeerAddress () const;
QString getFullLocalAddress () const;
bool getIsSecure() const;
bool getIsRemoteComposing () const;
void removeEntry (int id);
void removeAllEntries ();
void sendMessage (const QString &message);
void resendMessage (int id);
void sendFileMessage (const QString &path);
void downloadFile (int id);
void openFile (int id, bool showDirectory = false);
void openFileDirectory (int id) {
openFile(id, true);
}
bool fileWasDownloaded (int id);
void compose ();
void resetMessageCount ();
std::shared_ptr<linphone::ChatRoom> getChatRoom();
signals:
bool isRemoteComposingChanged (bool status);
void allEntriesRemoved ();
void lastEntryRemoved ();
void messageSent (const std::shared_ptr<linphone::ChatMessage> &message);
void messageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
void messageCountReset ();
void focused ();
private:
typedef QPair<QVariantMap, std::shared_ptr<void>> ChatEntryData;
void setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
const ChatEntryData getFileMessageEntry (int id);
void removeEntry (ChatEntryData &entry);
void insertCall (const std::shared_ptr<linphone::CallLog> &callLog);
void insertMessageAtEnd (const std::shared_ptr<linphone::ChatMessage> &message);
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
void handleIsComposingChanged (const std::shared_ptr<linphone::ChatRoom> &chatRoom);
void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
bool mIsRemoteComposing = false;
mutable QList<ChatEntryData> mEntries;
std::shared_ptr<CoreHandlers> mCoreHandlers;
std::shared_ptr<MessageHandlers> mMessageHandlers;
std::shared_ptr<linphone::ChatRoom> mChatRoom;
};
Q_DECLARE_METATYPE(std::shared_ptr<ChatModel>);
#endif // CHAT_MODEL_H_

View file

@ -51,6 +51,7 @@ public:
void mergeVcardModel (VcardModel *vcardModel);
Q_INVOKABLE VcardModel *cloneVcardModel () const;
Presence::PresenceLevel getPresenceLevel () const;
signals:
void contactUpdated ();
@ -65,7 +66,7 @@ private:
void updateSipAddresses (VcardModel *oldVcardModel);
Presence::PresenceStatus getPresenceStatus () const;
Presence::PresenceLevel getPresenceLevel () const;
VcardModel *mVcardModel = nullptr;
std::shared_ptr<linphone::Friend> mLinphoneFriend;

View file

@ -194,7 +194,7 @@ void CoreHandlers::onMessageReceived (
if (
!app->hasFocus() ||
!CoreManager::getInstance()->chatModelExists(
!CoreManager::getInstance()->chatRoomModelExists(
Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly()),
Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly()),
chatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Encrypted

View file

@ -29,7 +29,8 @@
#include "app/paths/Paths.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/chat/ChatModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/chat-room/ChatRoomListModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/contacts/ContactsImporterListModel.hpp"
@ -100,6 +101,7 @@ CoreManager::~CoreManager(){
void CoreManager::initCoreManager(){
mCallsListModel = new CallsListModel(this);
mChatRoomListModel = new ChatRoomListModel(this);
mContactsListModel = new ContactsListModel(this);
mContactsImporterListModel = new ContactsImporterListModel(this);
mAccountSettingsModel = new AccountSettingsModel(this);
@ -120,13 +122,14 @@ CoreManager *CoreManager::getInstance (){
return mInstance;
}
shared_ptr<ChatModel> CoreManager::getChatModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure) {
/*
shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure) {
if (peerAddress.isEmpty() || localAddress.isEmpty())
return nullptr;
// Create a new chat model.
QPair<bool, QPair<QString, QString>> chatModelId{isSecure,{ peerAddress, localAddress }};
if (!mChatModels.contains(chatModelId)) {
QPair<bool, QPair<QString, QString>> chatRoomModelId{isSecure,{ peerAddress, localAddress }};
if (!mChatRoomModels.contains(chatRoomModelId)) {
if (
!mCore->createAddress(peerAddress.toStdString()) ||
!mCore->createAddress(localAddress.toStdString())
@ -136,31 +139,43 @@ shared_ptr<ChatModel> CoreManager::getChatModel (const QString &peerAddress, con
return nullptr;
}
auto deleter = [this, chatModelId](ChatModel *chatModel) {
bool removed = mChatModels.remove(chatModelId);
auto deleter = [this, chatRoomModelId](ChatRoomModel *chatRoomModel) {
bool removed = mChatRoomModels.remove(chatRoomModelId);
Q_ASSERT(removed);
delete chatModel;
delete chatRoomModel;
};
shared_ptr<ChatModel> chatModel(new ChatModel(peerAddress, localAddress, isSecure), deleter);
mChatModels[chatModelId] = chatModel;
shared_ptr<ChatRoomModel> chatRoomModel(new ChatRoomModel(peerAddress, localAddress, isSecure), deleter);
mChatRoomModels[chatRoomModelId] = chatRoomModel;
emit chatModelCreated(chatModel);
emit chatRoomModelCreated(chatRoomModel);
return chatModel;
return chatRoomModel;
}
// Returns an existing chat model.
shared_ptr<ChatModel> chatModel = mChatModels[chatModelId].lock();
Q_CHECK_PTR(chatModel);
return chatModel;
shared_ptr<ChatRoomModel> chatRoomModel = mChatRoomModels[chatRoomModelId].lock();
Q_CHECK_PTR(chatRoomModel);
return chatRoomModel;
}
*/
shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (ChatRoomModel * data) {
if(data){
for(auto it = mChatRoomModels.begin() ; it != mChatRoomModels.end() ; ++it){
auto a = it->lock();
if(a.get() == data)
return a;
}
}
return nullptr;
}
shared_ptr<ChatModel> CoreManager::getChatModel (std::shared_ptr<linphone::ChatRoom> chatRoom) {
shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom) {
if (!chatRoom)
return nullptr;
auto pc = chatRoom->getCurrentParams();
for(auto it = mChatModels.begin() ; it != mChatModels.end() ; ++it) {
for(auto it = mChatRoomModels.begin() ; it != mChatRoomModels.end() ; ++it) {
auto a = it->lock();
auto pa = a->getChatRoom()->getCurrentParams();
if( a->getChatRoom()->getConferenceAddress() == chatRoom->getConferenceAddress()
@ -170,32 +185,34 @@ shared_ptr<ChatModel> CoreManager::getChatModel (std::shared_ptr<linphone::ChatR
&& pa->encryptionEnabled() == pc->encryptionEnabled()
){
// Returns an existing chat model.
shared_ptr<ChatModel> chatModel = a;
Q_CHECK_PTR(chatModel);
return chatModel;
shared_ptr<ChatRoomModel> chatRoomModel = a;
Q_CHECK_PTR(chatRoomModel);
return chatRoomModel;
}
}
QPair<bool, QPair<QString, QString>> chatModelId{pc->encryptionEnabled(),
QPair<bool, QPair<QString, QString>> chatRoomModelId{pc->encryptionEnabled(),
{ QString::fromStdString(chatRoom->getPeerAddress()->asString())
, QString::fromStdString(chatRoom->getLocalAddress()->asString()) }};
auto deleter = [this, chatModelId](ChatModel *chatModel) {
bool removed = mChatModels.remove(chatModelId);
auto deleter = [this, chatRoomModelId](ChatRoomModel *chatRoomModel) {
bool removed = mChatRoomModels.remove(chatRoomModelId);
Q_ASSERT(removed);
chatModel->deleteLater();
chatRoomModel->deleteLater();
};
shared_ptr<ChatModel> chatModel(new ChatModel(chatRoom), deleter);
mChatModels[chatModelId] = chatModel;
shared_ptr<ChatRoomModel> chatRoomModel(new ChatRoomModel(chatRoom), deleter);
chatRoom->addListener(chatRoomModel);
mChatRoomModels[chatRoomModelId] = chatRoomModel;
emit chatModelCreated(chatModel);
emit chatRoomModelCreated(chatRoomModel);
return chatModel;
return chatRoomModel;
}
bool CoreManager::chatModelExists (const QString &peerAddress, const QString &localAddress, const bool &isSecure) {
return mChatModels.contains({isSecure, { peerAddress, localAddress}});
bool CoreManager::chatRoomModelExists (const QString &peerAddress, const QString &localAddress, const bool &isSecure) {
return mChatRoomModels.contains({isSecure, { peerAddress, localAddress}});
}
HistoryModel* CoreManager::getHistoryModel(){

View file

@ -33,7 +33,8 @@ class QTimer;
class AccountSettingsModel;
class CallsListModel;
class ChatModel;
class ChatRoomModel;
class ChatRoomListModel;
class ContactsListModel;
class ContactsImporterListModel;
class CoreHandlers;
@ -67,9 +68,10 @@ public:
return mHandlers;
}
std::shared_ptr<ChatModel> getChatModel (const QString &peerAddress, const QString &localAddress, const bool &isSecure);
std::shared_ptr<ChatModel> getChatModel (std::shared_ptr<linphone::ChatRoom> chatRoom);
bool chatModelExists (const QString &sipAddress, const QString &localAddress, const bool &isSecure);
//std::shared_ptr<ChatRoomModel> getChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool &isSecure);
std::shared_ptr<ChatRoomModel> getChatRoomModel (ChatRoomModel * data);// Get the shared pointer. This can be done becuase of unicity of ChatRoomModel
std::shared_ptr<ChatRoomModel> getChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom);
bool chatRoomModelExists (const QString &sipAddress, const QString &localAddress, const bool &isSecure);
HistoryModel* getHistoryModel();
@ -93,6 +95,12 @@ public:
Q_CHECK_PTR(mCallsListModel);
return mCallsListModel;
}
ChatRoomListModel *getChatRoomListModel () const {
Q_CHECK_PTR(mChatRoomListModel);
return mChatRoomListModel;
}
ContactsListModel *getContactsListModel () const {
Q_CHECK_PTR(mContactsListModel);
@ -163,7 +171,7 @@ public slots:
signals:
void coreManagerInitialized ();
void chatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void chatRoomModelCreated (const std::shared_ptr<ChatRoomModel> &chatRoomModel);
void historyModelCreated (HistoryModel *historyModel);
void logsUploaded (const QString &url);
@ -200,6 +208,7 @@ private:
ContactsListModel *mContactsListModel = nullptr;
ContactsImporterListModel *mContactsImporterListModel = nullptr;
TimelineListModel *mTimelineListModel = nullptr;
ChatRoomListModel *mChatRoomListModel = nullptr;
SipAddressesModel *mSipAddressesModel = nullptr;
SettingsModel *mSettingsModel = nullptr;
@ -207,7 +216,7 @@ private:
EventCountNotifier *mEventCountNotifier = nullptr;
QHash<QPair<bool, QPair<QString, QString> >, std::weak_ptr<ChatModel>> mChatModels;
QHash<QPair<bool, QPair<QString, QString> >, std::weak_ptr<ChatRoomModel>> mChatRoomModels;
HistoryModel * mHistoryModel = nullptr;
LdapListModel *mLdapListModel = nullptr;

View file

@ -22,7 +22,7 @@
#include "components/call/CallModel.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/chat/ChatModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/history/HistoryModel.hpp"
@ -38,8 +38,8 @@ using namespace std;
AbstractEventCountNotifier::AbstractEventCountNotifier (QObject *parent) : QObject(parent) {
CoreManager *coreManager = CoreManager::getInstance();
QObject::connect(
coreManager, &CoreManager::chatModelCreated,
this, &AbstractEventCountNotifier::handleChatModelCreated
coreManager, &CoreManager::chatRoomModelCreated,
this, &AbstractEventCountNotifier::handleChatRoomModelCreated
);
QObject::connect(
coreManager, &CoreManager::historyModelCreated,
@ -95,19 +95,19 @@ int AbstractEventCountNotifier::getMissedCallCountFromLocal(const QString &local
}
// -----------------------------------------------------------------------------
void AbstractEventCountNotifier::handleChatModelCreated (const shared_ptr<ChatModel> &chatModel) {
ChatModel *chatModelPtr = chatModel.get();
void AbstractEventCountNotifier::handleChatRoomModelCreated (const shared_ptr<ChatRoomModel> &chatRoomModel) {
ChatRoomModel *chatRoomModelPtr = chatRoomModel.get();
QObject::connect(
chatModelPtr, &ChatModel::messageCountReset,
chatRoomModelPtr, &ChatRoomModel::messageCountReset,
this, &AbstractEventCountNotifier::updateUnreadMessageCount
);
QObject::connect(
chatModelPtr, &ChatModel::focused,
this, [this, chatModelPtr]() { handleResetMissedCalls(chatModelPtr); }
chatRoomModelPtr, &ChatRoomModel::focused,
this, [this, chatRoomModelPtr]() { handleResetMissedCalls(chatRoomModelPtr); }
);
QObject::connect(
chatModelPtr, &ChatModel::messageCountReset,
this, [this, chatModelPtr]() { handleResetMissedCalls(chatModelPtr); }
chatRoomModelPtr, &ChatRoomModel::messageCountReset,
this, [this, chatRoomModelPtr]() { handleResetMissedCalls(chatRoomModelPtr); }
);
}
@ -122,8 +122,8 @@ void AbstractEventCountNotifier::handleResetAllMissedCalls () {
}
void AbstractEventCountNotifier::handleResetMissedCalls (ChatModel *chatModel) {
auto it = mMissedCalls.find({ Utils::cleanSipAddress(chatModel->getPeerAddress()), Utils::cleanSipAddress(chatModel->getLocalAddress()) });
void AbstractEventCountNotifier::handleResetMissedCalls (ChatRoomModel *chatRoomModel) {
auto it = mMissedCalls.find({ Utils::cleanSipAddress(chatRoomModel->getPeerAddress()), Utils::cleanSipAddress(chatRoomModel->getLocalAddress()) });
if (it != mMissedCalls.cend()) {
mMissedCalls.erase(it);
internalnotifyEventCount();

View file

@ -34,7 +34,7 @@ namespace linphone {
}
class CallModel;
class ChatModel;
class ChatRoomModel;
class HistoryModel;
class AbstractEventCountNotifier : public QObject {
@ -67,12 +67,12 @@ private:
void internalnotifyEventCount ();
void handleChatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void handleChatRoomModelCreated (const std::shared_ptr<ChatRoomModel> &chatRoomModel);
void handleHistoryModelCreated (HistoryModel *historyModel);
void handleResetAllMissedCalls ();
void handleResetMissedCalls (ChatModel *chatModel);
void handleResetMissedCalls (ChatRoomModel *chatRoomModel);
void handleCallMissed (CallModel *callModel);
QHash<ConferenceId, int> mMissedCalls;

View file

@ -29,6 +29,8 @@
#include "app/App.hpp"
#include "components/call/CallModel.hpp"
#include "components/core/CoreManager.hpp"
#include "components/timeline/TimelineModel.hpp"
#include "components/timeline/TimelineListModel.hpp"
#include "utils/Utils.hpp"
#include "Notifier.hpp"
@ -267,12 +269,13 @@ void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &m
if(! message->getFileTransferInformation() ){
foreach(auto content, message->getContents()){
if(content->isText())
txt += content->getStringBuffer().c_str();
txt += content->getUtf8Text().c_str();
}
}else
txt = tr("newFileMessage");
map["message"] = txt;
shared_ptr<linphone::ChatRoom> chatRoom(message->getChatRoom());
map["timelineModel"].setValue(CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, true).get());
map["peerAddress"] = Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly());
map["localAddress"] = Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly());
map["fullPeerAddress"] = QString::fromStdString(chatRoom->getPeerAddress()->asString());

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 <QQmlApplicationEngine>
#include "app/App.hpp"
#include "ParticipantModel.hpp"
#include "utils/Utils.hpp"
// =============================================================================
using namespace std;
ParticipantModel::ParticipantModel (shared_ptr<linphone::Participant> linphoneParticipant, QObject *parent) : QObject(parent) {
mLinphoneParticipant = linphoneParticipant;
}
// -----------------------------------------------------------------------------
QString ParticipantModel::getAddress() const{
return Utils::coreStringToAppString(mLinphoneParticipant->getAddress()->asStringUriOnly());
}
QDateTime ParticipantModel::getCreationTime() const{
return QDateTime::fromSecsSinceEpoch(mLinphoneParticipant->getCreationTime());
}
//std::list<std::shared_ptr<linphone::ParticipantDevice>> ParticipantModel::getDevices() const;
bool ParticipantModel::isAdmin() const{
return mLinphoneParticipant->isAdmin();
}
bool ParticipantModel::isFocus() const{
return mLinphoneParticipant->isFocus();
}
//linphone::ChatRoomSecurityLevel ParticipantModel::getSecurityLevel() const;
//std::shared_ptr<linphone::ParticipantDevice> ParticipantModel::findDevice(const std::shared_ptr<const linphone::Address> & address) const;

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef PARTICIPANT_MODEL_H_
#define PARTICIPANT_MODEL_H_
#include <linphone++/linphone.hh>
// =============================================================================
#include <QObject>
#include <QDateTime>
#include <QString>
class ParticipantModel : public QObject {
Q_OBJECT;
Q_PROPERTY(QString address READ getAddress CONSTANT);
Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT);
Q_PROPERTY(bool admin READ isAdmin CONSTANT);
Q_PROPERTY(bool focus READ isFocus CONSTANT);
public:
ParticipantModel (std::shared_ptr<linphone::Participant> linphoneParticipant, QObject *parent = nullptr);
QString getAddress() const;
QDateTime getCreationTime() const;
//std::list<std::shared_ptr<linphone::ParticipantDevice>> getDevices() const;
bool isAdmin() const;
bool isFocus() const;
//linphone::ChatRoomSecurityLevel getSecurityLevel() const;
//std::shared_ptr<linphone::ParticipantDevice> findDevice(const std::shared_ptr<const linphone::Address> & address) const;
//signals:
// void contactUpdated ();
private:
std::shared_ptr<linphone::Participant> mLinphoneParticipant;
};
Q_DECLARE_METATYPE(ParticipantModel *);
#endif // PARTICIPANT_MODEL_H_

View file

@ -0,0 +1,293 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 <QQuickWindow>
#include "app/App.hpp"
#include "components/core/CoreManager.hpp"
#include "ChatRoomProxyModel.hpp"
// =============================================================================
using namespace std;
QString ChatRoomProxyModel::gCachedText;
// Fetch the L last filtered chat entries.
class ChatRoomProxyModel::ChatRoomModelFilter : public QSortFilterProxyModel {
public:
ChatRoomModelFilter (QObject *parent) : QSortFilterProxyModel(parent) {}
ChatRoomModel::EntryType getEntryTypeFilter () {
return mEntryTypeFilter;
}
void setEntryTypeFilter (ChatRoomModel::EntryType type) {
mEntryTypeFilter = type;
invalidate();
}
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &) const override {
if (mEntryTypeFilter == ChatRoomModel::EntryType::GenericEntry)
return true;
QModelIndex index = sourceModel()->index(sourceRow, 0, QModelIndex());
const QVariantMap data = index.data().toMap();
return data["type"].toInt() == mEntryTypeFilter;
}
private:
ChatRoomModel::EntryType mEntryTypeFilter = ChatRoomModel::EntryType::GenericEntry;
};
// =============================================================================
ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(new ChatRoomModelFilter(this));
mIsSecure = false;
App *app = App::getInstance();
QObject::connect(app->getMainWindow(), &QWindow::activeChanged, this, [this]() {
handleIsActiveChanged(App::getInstance()->getMainWindow());
});
QQuickWindow *callsWindow = app->getCallsWindow();
if (callsWindow)
QObject::connect(callsWindow, &QWindow::activeChanged, this, [this, callsWindow]() {
handleIsActiveChanged(callsWindow);
});
}
// -----------------------------------------------------------------------------
#define GET_CHAT_MODEL() \
if (!mChatRoomModel) \
return; \
mChatRoomModel
#define CREATE_PARENT_MODEL_FUNCTION(METHOD) \
void ChatRoomProxyModel::METHOD () { \
GET_CHAT_MODEL()->METHOD(); \
}
#define CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(METHOD, ARG_TYPE) \
void ChatRoomProxyModel::METHOD (ARG_TYPE value) { \
GET_CHAT_MODEL()->METHOD(value); \
}
#define CREATE_PARENT_MODEL_FUNCTION_WITH_ID(METHOD) \
void ChatRoomProxyModel::METHOD (int id) { \
QModelIndex sourceIndex = mapToSource(index(id, 0)); \
GET_CHAT_MODEL()->METHOD( \
static_cast<ChatRoomModelFilter *>(sourceModel())->mapToSource(sourceIndex).row() \
); \
}
CREATE_PARENT_MODEL_FUNCTION(removeAllEntries);
CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendFileMessage, const QString &);
CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendMessage, const QString &);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(downloadFile);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(openFile);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(openFileDirectory);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(removeEntry);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(resendMessage);
#undef GET_CHAT_MODEL
#undef CREATE_PARENT_MODEL_FUNCTION
#undef CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM
#undef CREATE_PARENT_MODEL_FUNCTION_WITH_ID
void ChatRoomProxyModel::compose (const QString& text) {
if (mChatRoomModel)
mChatRoomModel->compose();
gCachedText = text;
}
// -----------------------------------------------------------------------------
void ChatRoomProxyModel::loadMoreEntries () {
int count = rowCount();
int parentCount = sourceModel()->rowCount();
if (count < parentCount) {
// Do not increase `mMaxDisplayedEntries` if it's not necessary...
// Limit qml calls.
if (count == mMaxDisplayedEntries)
mMaxDisplayedEntries += EntriesChunkSize;
invalidateFilter();
count = rowCount() - count;
if (count > 0)
emit moreEntriesLoaded(count);
}
}
void ChatRoomProxyModel::setEntryTypeFilter (ChatRoomModel::EntryType type) {
ChatRoomModelFilter *chatRoomModelFilter = static_cast<ChatRoomModelFilter *>(sourceModel());
if (chatRoomModelFilter->getEntryTypeFilter() != type) {
chatRoomModelFilter->setEntryTypeFilter(type);
emit entryTypeFilterChanged(type);
}
}
// -----------------------------------------------------------------------------
bool ChatRoomProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) const {
return sourceModel()->rowCount() - sourceRow <= mMaxDisplayedEntries;
}
// -----------------------------------------------------------------------------
QString ChatRoomProxyModel::getPeerAddress () const {
return mChatRoomModel ? mChatRoomModel->getPeerAddress() : QString("");
}
void ChatRoomProxyModel::setPeerAddress (const QString &peerAddress) {
mPeerAddress = peerAddress;
//reload();
}
QString ChatRoomProxyModel::getLocalAddress () const {
return mChatRoomModel ? mChatRoomModel->getLocalAddress() : QString("");
}
void ChatRoomProxyModel::setLocalAddress (const QString &localAddress) {
mLocalAddress = localAddress;
//reload();
}
QString ChatRoomProxyModel::getFullPeerAddress () const {
return mChatRoomModel ? mChatRoomModel->getFullPeerAddress() : QString("");
}
void ChatRoomProxyModel::setFullPeerAddress (const QString &peerAddress) {
mFullPeerAddress = peerAddress;
//reload();
}
QString ChatRoomProxyModel::getFullLocalAddress () const {
return mChatRoomModel ? mChatRoomModel->getFullLocalAddress() : QString("");
}
void ChatRoomProxyModel::setFullLocalAddress (const QString &localAddress) {
mFullLocalAddress = localAddress;
//reload();
}
int ChatRoomProxyModel::getIsSecure () const {
return mChatRoomModel ? mChatRoomModel->getIsSecure() : -1;
}
void ChatRoomProxyModel::setIsSecure (const int &secure) {
mIsSecure = secure;
}
bool ChatRoomProxyModel::getIsRemoteComposing () const {
return mChatRoomModel ? mChatRoomModel->getIsRemoteComposing() : false;
}
QString ChatRoomProxyModel::getCachedText() const{
return gCachedText;
}
// -----------------------------------------------------------------------------
void ChatRoomProxyModel::reload () {
mMaxDisplayedEntries = EntriesChunkSize;
if (mChatRoomModel) {
ChatRoomModel *chatRoomModel = mChatRoomModel.get();
QObject::disconnect(chatRoomModel, &ChatRoomModel::isRemoteComposingChanged, this, &ChatRoomProxyModel::handleIsRemoteComposingChanged);
QObject::disconnect(chatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
QObject::disconnect(chatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
}
//mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(mPeerAddress, mLocalAddress, mIsSecure);
//if(mChatRoom)
mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(mChatRoom);
if (mChatRoomModel) {
ChatRoomModel *chatRoomModel = mChatRoomModel.get();
QObject::connect(chatRoomModel, &ChatRoomModel::isRemoteComposingChanged, this, &ChatRoomProxyModel::handleIsRemoteComposingChanged);
QObject::connect(chatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
QObject::connect(chatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
}
static_cast<ChatRoomModelFilter *>(sourceModel())->setSourceModel(mChatRoomModel.get());
}
void ChatRoomProxyModel::resetMessageCount(){
if( mChatRoomModel){
mChatRoomModel->resetMessageCount();
}
}
std::shared_ptr<ChatRoomModel> ChatRoomProxyModel::getChatRoomModel () const{
return mChatRoomModel;
}
void ChatRoomProxyModel::setChatRoomModel (std::shared_ptr<ChatRoomModel> chatRoomModel){
mChatRoom = chatRoomModel->getChatRoom();
reload();
emit chatRoomModelChanged();
}
// -----------------------------------------------------------------------------
static inline QWindow *getParentWindow (QObject *object) {
App *app = App::getInstance();
const QWindow *mainWindow = app->getMainWindow();
const QWindow *callsWindow = app->getCallsWindow();
for (QObject *parent = object->parent(); parent; parent = parent->parent())
if (parent == mainWindow || parent == callsWindow)
return static_cast<QWindow *>(parent);
return nullptr;
}
void ChatRoomProxyModel::handleIsActiveChanged (QWindow *window) {
if (mChatRoomModel && window->isActive() && getParentWindow(this) == window) {
mChatRoomModel->resetMessageCount();
mChatRoomModel->focused();
}
}
void ChatRoomProxyModel::handleIsRemoteComposingChanged (bool status) {
emit isRemoteComposingChanged(status);
}
void ChatRoomProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
QWindow *window = getParentWindow(this);
if (window && window->isActive())
mChatRoomModel->resetMessageCount();
}
void ChatRoomProxyModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &) {
mMaxDisplayedEntries++;
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef PARTICIPANT_PROXY_MODEL_H_
#define PARTICIPANT_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
#include "ParticipantModel.hpp"
// =============================================================================
class QWindow;
class ParticipantProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
ParticipantProxyModel (QObject *parent = Q_NULLPTR);
void reset();
void update();
std::shared_ptr<TimelineModel> getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
// Remove a chatroom
Q_INVOKABLE void remove (TimelineModel *importer);
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
void initTimeline ();
void updateTimelines();
QList<std::shared_ptr<ParticipantModel>> mParticipantlines;
};
#endif // PARTICIPANT_PROXY_MODEL_H_

View file

@ -137,6 +137,7 @@ QVariantMap AccountSettingsModel::getProxyConfigDescription (const shared_ptr<li
map["route"] = Utils::coreStringToAppString(proxyConfig->getRoutes().front());
else
map["route"] = "";
map["conferenceUri"] = Utils::coreStringToAppString(proxyConfig->getConferenceFactoryUri());
map["contactParams"] = Utils::coreStringToAppString(proxyConfig->getContactParameters());
map["avpfInterval"] = proxyConfig->getAvpfRrInterval();
map["registerEnabled"] = proxyConfig->registerEnabled();
@ -245,6 +246,7 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
proxyConfig->setPublishExpires(data["registrationDuration"].toInt());
proxyConfig->setRoute(Utils::appStringToCoreString(data["route"].toString()));
proxyConfig->setConferenceFactoryUri(Utils::appStringToCoreString(data["conferenceUri"].toString()));
proxyConfig->setContactParameters(Utils::appStringToCoreString(data["contactParams"].toString()));
proxyConfig->setAvpfRrInterval(uint8_t(data["avpfInterval"].toInt()));
proxyConfig->enableRegister(data["registerEnabled"].toBool());

View file

@ -24,7 +24,7 @@
#include <QtDebug>
#include "components/call/CallModel.hpp"
#include "components/chat/ChatModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"

View file

@ -24,7 +24,7 @@
#include <QtDebug>
#include "components/call/CallModel.hpp"
#include "components/chat/ChatModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
@ -59,7 +59,7 @@ SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(pare
mCoreHandlers = coreManager->getHandlers();
QObject::connect(coreManager, &CoreManager::chatModelCreated, this, &SipAddressesModel::handleChatModelCreated);
QObject::connect(coreManager, &CoreManager::chatRoomModelCreated, this, &SipAddressesModel::handleChatRoomModelCreated);
QObject::connect(coreManager, &CoreManager::historyModelCreated, this, &SipAddressesModel::handleHistoryModelCreated);
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
@ -264,20 +264,20 @@ bool SipAddressesModel::removeRows (int row, int count, const QModelIndex &paren
// -----------------------------------------------------------------------------
void SipAddressesModel::handleChatModelCreated (const shared_ptr<ChatModel> &chatModel) {
ChatModel *ptr = chatModel.get();
void SipAddressesModel::handleChatRoomModelCreated (const shared_ptr<ChatRoomModel> &chatRoomModel) {
ChatRoomModel *ptr = chatRoomModel.get();
QObject::connect(ptr, &ChatModel::allEntriesRemoved, this, [this, ptr] {
QObject::connect(ptr, &ChatRoomModel::allEntriesRemoved, this, [this, ptr] {
handleAllEntriesRemoved(ptr);
});
QObject::connect(ptr, &ChatModel::lastEntryRemoved, this, [this, ptr] {
QObject::connect(ptr, &ChatRoomModel::lastEntryRemoved, this, [this, ptr] {
handleLastEntryRemoved(ptr);
});
QObject::connect(ptr, &ChatModel::messageCountReset, this, [this, ptr] {
QObject::connect(ptr, &ChatRoomModel::messageCountReset, this, [this, ptr] {
handleMessageCountReset(ptr);
});
QObject::connect(ptr, &ChatModel::messageSent, this, &SipAddressesModel::handleMessageSent);
QObject::connect(ptr, &ChatRoomModel::messageSent, this, &SipAddressesModel::handleMessageSent);
}
void SipAddressesModel::handleHistoryModelCreated (HistoryModel *historyModel) {
@ -365,12 +365,12 @@ void SipAddressesModel::handlePresenceReceived (
updateObservers(sipAddress, status);
}
void SipAddressesModel::handleAllEntriesRemoved (ChatModel *chatModel) {
auto it = mPeerAddressToSipAddressEntry.find(chatModel->getPeerAddress());
void SipAddressesModel::handleAllEntriesRemoved (ChatRoomModel *chatRoomModel) {
auto it = mPeerAddressToSipAddressEntry.find(chatRoomModel->getPeerAddress());
if (it == mPeerAddressToSipAddressEntry.end())
return;
auto it2 = it->localAddressToConferenceEntry.find(Utils::cleanSipAddress(chatModel->getLocalAddress()));
auto it2 = it->localAddressToConferenceEntry.find(Utils::cleanSipAddress(chatRoomModel->getLocalAddress()));
if (it2 == it->localAddressToConferenceEntry.end())
return;
it->localAddressToConferenceEntry.erase(it2);
@ -387,22 +387,22 @@ void SipAddressesModel::handleAllEntriesRemoved (ChatModel *chatModel) {
emit dataChanged(index(row, 0), index(row, 0));
}
void SipAddressesModel::handleLastEntryRemoved (ChatModel *chatModel) {
auto it = mPeerAddressToSipAddressEntry.find(chatModel->getPeerAddress());
void SipAddressesModel::handleLastEntryRemoved (ChatRoomModel *chatRoomModel) {
auto it = mPeerAddressToSipAddressEntry.find(chatRoomModel->getPeerAddress());
if (it == mPeerAddressToSipAddressEntry.end())
return;
auto it2 = it->localAddressToConferenceEntry.find(Utils::cleanSipAddress(chatModel->getLocalAddress()));
auto it2 = it->localAddressToConferenceEntry.find(Utils::cleanSipAddress(chatRoomModel->getLocalAddress()));
if (it2 == it->localAddressToConferenceEntry.end())
return;
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
Q_ASSERT(chatModel->rowCount() > 0);
const QVariantMap map = chatModel->data(
chatModel->index(chatModel->rowCount() - 1, 0),
ChatModel::ChatEntry
Q_ASSERT(chatRoomModel->rowCount() > 0);
const QVariantMap map = chatRoomModel->data(
chatRoomModel->index(chatRoomModel->rowCount() - 1, 0),
ChatRoomModel::ChatEntry
).toMap();
// Update the timestamp with the new last chat message timestamp.
@ -419,13 +419,13 @@ void SipAddressesModel::handleAllCallCountReset () {
emit dataChanged(index(row, 0), index(row, 0));
}
}
void SipAddressesModel::handleMessageCountReset (ChatModel *chatModel) {
const QString &peerAddress = Utils::cleanSipAddress(chatModel->getPeerAddress());
void SipAddressesModel::handleMessageCountReset (ChatRoomModel *chatRoomModel) {
const QString &peerAddress = Utils::cleanSipAddress(chatRoomModel->getPeerAddress());
auto it = mPeerAddressToSipAddressEntry.find(peerAddress);
if (it == mPeerAddressToSipAddressEntry.end())
return;
const QString &localAddress = Utils::cleanSipAddress(chatModel->getLocalAddress());
const QString &localAddress = Utils::cleanSipAddress(chatRoomModel->getLocalAddress());
auto it2 = it->localAddressToConferenceEntry.find(localAddress);
if (it2 == it->localAddressToConferenceEntry.end())
return;

View file

@ -30,7 +30,7 @@
class QUrl;
class ChatModel;
class ChatRoomModel;
class CoreHandlers;
class HistoryModel;
@ -94,7 +94,7 @@ private:
// ---------------------------------------------------------------------------
void handleChatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void handleChatRoomModelCreated (const std::shared_ptr<ChatRoomModel> &chatRoomModel);
void handleHistoryModelCreated (HistoryModel *historyModel) ;
void handleContactAdded (ContactModel *contact);
@ -107,10 +107,10 @@ private:
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
void handlePresenceReceived (const QString &sipAddress, const std::shared_ptr<const linphone::PresenceModel> &presenceModel);
void handleAllEntriesRemoved (ChatModel *chatModel);
void handleLastEntryRemoved (ChatModel *chatModel);
void handleAllEntriesRemoved (ChatRoomModel *chatRoomModel);
void handleLastEntryRemoved (ChatRoomModel *chatRoomModel);
void handleMessageCountReset (ChatModel *chatModel);
void handleMessageCountReset (ChatRoomModel *chatRoomModel);
void handleMessageSent (const std::shared_ptr<linphone::ChatMessage> &message);

View file

@ -32,21 +32,29 @@
// =============================================================================
TimelineListModel::TimelineListModel (QObject *parent) : QAbstractListModel(parent) {
initTimeline();
//initTimeline();
mSelectedCount = 0;
updateTimelines ();
}
// -----------------------------------------------------------------------------
TimelineModel * TimelineListModel::getAt(const int& index){
return mTimelines[index];
return mTimelines[index].get();
}
void TimelineListModel::reset(){
initTimeline();
//initTimeline();
updateTimelines ();
}
void TimelineListModel::update(){
updateTimelines ();
}
void TimelineListModel::selectAll(const bool& selected){
for(auto it = mTimelines.begin() ; it != mTimelines.end() ; ++it)
(*it)->mSelected = selected;
}
int TimelineListModel::rowCount (const QModelIndex &) const {
return mTimelines.count();
@ -65,7 +73,7 @@ QVariant TimelineListModel::data (const QModelIndex &index, int role) const {
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mTimelines[row]);
return QVariant::fromValue(mTimelines[row].get());
return QVariant();
}
@ -88,8 +96,10 @@ bool TimelineListModel::removeRows (int row, int count, const QModelIndex &paren
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
delete mTimelines.takeAt(row);
for (int i = 0; i < count; ++i){
auto timeline = mTimelines.takeAt(row);
timeline->getChatRoomModel()->getChatRoom()->removeListener(timeline);
}
endRemoveRows();
@ -100,11 +110,12 @@ bool TimelineListModel::removeRows (int row, int count, const QModelIndex &paren
// -----------------------------------------------------------------------------
void TimelineListModel::initTimeline () {
/*
CoreManager *coreManager = CoreManager::getInstance();
auto currentAddress = coreManager->getAccountSettingsModel()->getUsedSipAddress();
std::list<std::shared_ptr<linphone::ChatRoom>> allChatRooms = coreManager->getCore()->getChatRooms();
QList<TimelineModel*> models;
QList<std::shared_ptr<TimelineModel>> models;
for(auto itAllChatRooms = allChatRooms.begin() ; itAllChatRooms != allChatRooms.end() ; ++itAllChatRooms){
if((*itAllChatRooms)->getMe()->getAddress()->weakEqual(currentAddress)){
models << new TimelineModel(*itAllChatRooms);
@ -115,7 +126,7 @@ void TimelineListModel::initTimeline () {
mTimelines = models;
//endInsertRows();
*/
/*
initSipAddressesFromChat();
initSipAddressesFromCalls();
@ -135,25 +146,50 @@ void TimelineListModel::initTimeline () {
*/
}
TimelineModel * TimelineListModel::getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create){
std::shared_ptr<TimelineModel> TimelineListModel::getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create){
if(chatRoom){
for(auto it = mTimelines.begin() ; it != mTimelines.end() ; ++it){
if( (*it)->getChatModel()->getChatRoom() == chatRoom){
if( (*it)->getChatRoomModel()->getChatRoom() == chatRoom){
return *it;
}
}
if(create)
return new TimelineModel(chatRoom);
if(create){
std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(chatRoom);
chatRoom->addListener(model);
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
return model;
}
}
return nullptr;
}
void TimelineListModel::setSelectedCount(int selectedCount){
if(mSelectedCount != selectedCount) {
mSelectedCount = selectedCount;
if( mSelectedCount <= 1)// Do not send signals when selection is higher than max : this is a transition state
emit selectedCountChanged(mSelectedCount);
}
}
void TimelineListModel::selectedHasChanged(bool selected){
if(selected) {
if(mSelectedCount >= 1){// We have more selection than wanted : count select first and unselect after : the final signal will be send only on limit
setSelectedCount(mSelectedCount+1);// It will not send a change signal
for(auto it = mTimelines.begin() ; it != mTimelines.end() ; ++it)
if(it->get() != sender())
(*it)->setSelected(false);
}else
setSelectedCount(mSelectedCount+1);
} else
setSelectedCount(mSelectedCount-1);
}
void TimelineListModel::updateTimelines () {
CoreManager *coreManager = CoreManager::getInstance();
auto currentAddress = coreManager->getAccountSettingsModel()->getUsedSipAddress();
std::list<std::shared_ptr<linphone::ChatRoom>> allChatRooms = coreManager->getCore()->getChatRooms();
QList<TimelineModel*> models;
QList<std::shared_ptr<TimelineModel> > models;
for(auto itAllChatRooms = allChatRooms.begin() ; itAllChatRooms != allChatRooms.end() ; ++itAllChatRooms){
if((*itAllChatRooms)->getMe()->getAddress()->weakEqual(currentAddress)){
models << getTimeline(*itAllChatRooms, true);

View file

@ -22,7 +22,7 @@
#define TIMELINE_LIST_MODEL_H_
#include <QSortFilterProxyModel>
#include "components/chat/ChatModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
class TimelineModel;
// =============================================================================
@ -30,13 +30,16 @@ class TimelineModel;
class TimelineListModel : public QAbstractListModel {
Q_OBJECT
public:
Q_PROPERTY(int selectedCount MEMBER mSelectedCount WRITE setSelectedCount NOTIFY selectedCountChanged)
TimelineListModel (QObject *parent = Q_NULLPTR);
void reset();
void update();
void selectAll(const bool& selected);
TimelineModel * getAt(const int& index);
TimelineModel * getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
std::shared_ptr<TimelineModel> getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
@ -45,6 +48,14 @@ public:
// Remove a chatroom
Q_INVOKABLE void remove (TimelineModel *importer);
int mSelectedCount;
void setSelectedCount(int selectedCount);
public slots:
void selectedHasChanged(bool selected);
signals:
void selectedCountChanged(int selectedCount);
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
@ -55,7 +66,7 @@ private:
void initTimeline ();
void updateTimelines();
QList<TimelineModel*> mTimelines;
QList<std::shared_ptr<TimelineModel>> mTimelines;
};
#endif // TIMELINE_LIST_MODEL_H_

View file

@ -21,7 +21,7 @@
#include "components/core/CoreManager.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "components/sip-addresses/SipAddressesModel.hpp"
#include "components/chat/ChatModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "utils/Utils.hpp"
#include "TimelineModel.hpp"
@ -32,29 +32,37 @@
// =============================================================================
TimelineModel::TimelineModel (std::shared_ptr<linphone::ChatRoom> chatRoom, QObject *parent) : QObject(parent) {
mChatModel = CoreManager::getInstance()->getChatModel(chatRoom);
mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(chatRoom);
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::unreadMessagesCountChanged, this, &TimelineModel::updateUnreadCount);
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::missedCallsCountChanged, this, &TimelineModel::updateUnreadCount);
//mTimestamp = QDateTime::fromMSecsSinceEpoch(mChatRoomModel->getChatRoom()->getLastUpdateTime());
mSelected = false;
}
TimelineModel::~TimelineModel(){
}
QString TimelineModel::getFullPeerAddress() const{
return mChatModel->getFullPeerAddress();
return mChatRoomModel->getFullPeerAddress();
}
QString TimelineModel::getFullLocalAddress() const{
return mChatModel->getLocalAddress();
return mChatRoomModel->getLocalAddress();
}
QString TimelineModel::getUsername() const{
std::string username = mChatModel->getChatRoom()->getSubject();
std::string username = mChatRoomModel->getChatRoom()->getSubject();
if(username != ""){
return QString::fromStdString(username);
}
username = mChatModel->getChatRoom()->getPeerAddress()->getDisplayName();
username = mChatRoomModel->getChatRoom()->getPeerAddress()->getDisplayName();
if(username != "")
return QString::fromStdString(username);
username = mChatModel->getChatRoom()->getPeerAddress()->getUsername();
username = mChatRoomModel->getChatRoom()->getPeerAddress()->getUsername();
if(username != "")
return QString::fromStdString(username);
return QString::fromStdString(mChatModel->getChatRoom()->getPeerAddress()->asStringUriOnly());
return QString::fromStdString(mChatRoomModel->getChatRoom()->getPeerAddress()->asStringUriOnly());
}
QString TimelineModel::getAvatar() const{
@ -65,6 +73,52 @@ int TimelineModel::getPresenceStatus() const{
return 0;
}
std::shared_ptr<ChatModel> TimelineModel::getChatModel() const{
return mChatModel;
ChatRoomModel *TimelineModel::getChatRoomModel() const{
return mChatRoomModel.get();
}
void TimelineModel::setSelected(const bool& selected){
if(selected != mSelected){
mSelected = selected;
emit selectedChanged(mSelected);
}
}
void TimelineModel::updateUnreadCount(){
if(mSelected){
mChatRoomModel->resetMessageCount();
}
}
//----------------------------------------------------------
//------ CHAT ROOM HANDLERS
//----------------------------------------------------------
void TimelineModel::onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & remoteAddress, bool isComposing){
}
void TimelineModel::onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){}
void TimelineModel::onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onChatMessageSent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onParticipantRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState){}
void TimelineModel::onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onSubjectChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog)
{
emit usernameChanged();
}
void TimelineModel::onUndecryptableMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){}
void TimelineModel::onParticipantDeviceAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onParticipantDeviceRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onConferenceLeft(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onEphemeralEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onConferenceAddressGeneration(const std::shared_ptr<linphone::ChatRoom> & chatRoom){}
void TimelineModel::onParticipantRegistrationSubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress){}
void TimelineModel::onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress){}
void TimelineModel::onChatMessageShouldBeStored(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){}
void TimelineModel::onChatMessageParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state){}

View file

@ -30,23 +30,25 @@
#include "../contact/ContactModel.hpp"
class ChatModel;
class ChatRoomModel;
class TimelineModel : public QObject {
class TimelineModel : public QObject, public linphone::ChatRoomListener {
Q_OBJECT
public:
TimelineModel (std::shared_ptr<linphone::ChatRoom> chatRoom, QObject *parent = Q_NULLPTR);
virtual ~TimelineModel();
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress NOTIFY fullLocalAddressChanged)
Q_PROPERTY(std::shared_ptr<ChatModel> chatModel READ getChatModel CONSTANT)
Q_PROPERTY(ChatRoomModel* chatRoomModel READ getChatRoomModel CONSTANT)
// Contact
Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged)
Q_PROPERTY(int presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged)
//Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
//Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
//Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged)
//Q_PROPERTY(int presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged)
Q_PROPERTY(bool selected MEMBER mSelected WRITE setSelected NOTIFY selectedChanged)
QString getFullPeerAddress() const;
@ -56,19 +58,53 @@ public:
QString getAvatar() const;
int getPresenceStatus() const;
void setSelected(const bool& selected);
Q_INVOKABLE std::shared_ptr<ChatModel> getChatModel() const;
//Q_INVOKABLE std::shared_ptr<ChatRoomModel> getChatRoomModel() const;
Q_INVOKABLE ChatRoomModel* getChatRoomModel() const;
QDateTime mTimestamp;
std::shared_ptr<ChatModel> mChatModel;
bool mSelected;
//QDateTime mTimestamp;
std::shared_ptr<ChatRoomModel> mChatRoomModel;
//std::shared_ptr<linphone::ChatRoom> mChatRoom;
virtual void onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & remoteAddress, bool isComposing) override;
virtual void onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessageSent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState) override;
virtual void onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onSubjectChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onUndecryptableMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onParticipantDeviceAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onParticipantDeviceRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onConferenceLeft(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onEphemeralEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onConferenceAddressGeneration(const std::shared_ptr<linphone::ChatRoom> & chatRoom) override;
virtual void onParticipantRegistrationSubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress) override;
virtual void onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress) override;
virtual void onChatMessageShouldBeStored(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onChatMessageParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state) override;
public slots:
void updateUnreadCount();
signals:
void fullPeerAddressChanged();
void fullLocalAddressChanged();
void usernameChanged();
void avatarChanged();
void presenceStatusChanged();
void selectedChanged(bool selected);
};

View file

@ -37,39 +37,50 @@
TimelineProxyModel::TimelineProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
CoreManager *coreManager = CoreManager::getInstance();
AccountSettingsModel *accountSettingsModel = coreManager->getAccountSettingsModel();
setSourceModel(CoreManager::getInstance()->getTimelineListModel());
TimelineListModel * model = CoreManager::getInstance()->getTimelineListModel();
connect(model, SIGNAL(selectedCountChanged(int)), this, SIGNAL(selectedCountChanged(int)));
setSourceModel(model);
QObject::connect(accountSettingsModel, &AccountSettingsModel::accountSettingsUpdated, this, [this]() {
dynamic_cast<TimelineListModel*>(sourceModel())->update();
invalidate();
updateCurrentSelection();
//updateCurrentSelection();
});
QObject::connect(coreManager->getSipAddressesModel(), &SipAddressesModel::sipAddressReset, this, [this]() {
dynamic_cast<TimelineListModel*>(sourceModel())->reset();
invalidate();// Invalidate and reload GUI if the model has been reset
updateCurrentSelection();
//updateCurrentSelection();
});
sort(0);
}
// -----------------------------------------------------------------------------
void TimelineProxyModel::setCurrentChatModel(std::shared_ptr<ChatModel> data){
mCurrentChatModel = data;
emit currentChatModelChanged(mCurrentChatModel);
emit currentTimelineChanged(dynamic_cast<TimelineListModel*>(sourceModel())->getTimeline(mCurrentChatModel->getChatRoom(), false));
/*
void TimelineProxyModel::setCurrentChatRoomModel(ChatRoomModel *data){
mCurrentChatRoomModel = CoreManager::getInstance()->getChatRoomModel(data);
emit currentChatRoomModelChanged(mCurrentChatRoomModel);
if(mCurrentChatRoomModel)
emit currentTimelineChanged(dynamic_cast<TimelineListModel*>(sourceModel())->getTimeline(mCurrentChatRoomModel->getChatRoom(), false).get());
else
emit currentTimelineChanged(nullptr);
}
std::shared_ptr<ChatModel> TimelineProxyModel::getCurrentChatModel()const{
return mCurrentChatModel;
ChatRoomModel *TimelineProxyModel::getCurrentChatRoomModel()const{
return mCurrentChatRoomModel.get();
}
void TimelineProxyModel::updateCurrentSelection(){
auto currentAddress = CoreManager::getInstance()->getAccountSettingsModel()->getUsedSipAddress();
if(mCurrentChatModel && !mCurrentChatModel->getChatRoom()->getMe()->getAddress()->weakEqual(currentAddress) ){
setCurrentChatModel(nullptr);
if(mCurrentChatRoomModel && !mCurrentChatRoomModel->getChatRoom()->getMe()->getAddress()->weakEqual(currentAddress) ){
setCurrentChatRoomModel(nullptr);
}
}
*/
void TimelineProxyModel::unselectAll(){
dynamic_cast<TimelineListModel*>(sourceModel())->selectAll(false);
}
// -----------------------------------------------------------------------------
bool TimelineProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
@ -81,5 +92,5 @@ bool TimelineProxyModel::lessThan (const QModelIndex &left, const QModelIndex &r
const TimelineModel* a = sourceModel()->data(left).value<TimelineModel*>();
const TimelineModel* b = sourceModel()->data(right).value<TimelineModel*>();
return a->mTimestamp <= b->mTimestamp;
return a->getChatRoomModel()->mLastUpdateTime >= b->getChatRoomModel()->mLastUpdateTime ;
}

View file

@ -24,7 +24,7 @@
#include <QSortFilterProxyModel>
// =============================================================================
#include "../chat/ChatModel.hpp"
#include "../chat-room/ChatRoomModel.hpp"
class TimelineModel;
@ -35,17 +35,19 @@ class TimelineProxyModel : public QSortFilterProxyModel {
public:
TimelineProxyModel (QObject *parent = Q_NULLPTR);
Q_PROPERTY(std::shared_ptr<ChatModel> currentChatModel WRITE setCurrentChatModel READ getCurrentChatModel NOTIFY currentChatModelChanged)
//Q_PROPERTY(ChatRoomModel *currentChatRoomModel WRITE setCurrentChatRoomModel READ getCurrentChatRoomModel NOTIFY currentChatRoomModelChanged)
void updateCurrentSelection();
//void updateCurrentSelection();
Q_INVOKABLE void setCurrentChatModel(std::shared_ptr<ChatModel> data);
std::shared_ptr<ChatModel> getCurrentChatModel() const;
//Q_INVOKABLE void setCurrentChatRoomModel(ChatRoomModel *data);
//ChatRoomModel *getCurrentChatRoomModel() const;
Q_INVOKABLE void unselectAll();
//Q_INVOKABLE TimelineModel * getTimeline();
signals:
void currentChatModelChanged(std::shared_ptr<ChatModel> currentChatModel);
void currentTimelineChanged(TimelineModel * currentTimeline);
void selectedCountChanged(int selectedCount);
// void currentChatRoomModelChanged(std::shared_ptr<ChatRoomModel> currentChatRoomModel);
// void currentTimelineChanged(TimelineModel * currentTimeline);
protected:
@ -57,7 +59,7 @@ protected:
void handleLocalAddressChanged (const QString &localAddress);
std::shared_ptr<ChatModel> mCurrentChatModel;
//std::shared_ptr<ChatRoomModel> mCurrentChatRoomModel;
};

View file

@ -47,7 +47,7 @@ function getComponentFromEntry (chatEntry) {
return 'FileMessage.qml'
}
if (chatEntry.type === Linphone.ChatModel.CallEntry) {
if (chatEntry.type === Linphone.ChatRoomModel.CallEntry) {
return 'Event.qml'
}

View file

@ -11,28 +11,28 @@ Row {
property string _type: {
var status = $chatEntry.status
if (status === ChatModel.CallStatusSuccess) {
if (status === ChatRoomModel.CallStatusSuccess) {
if (!$chatEntry.isStart) {
return 'ended_call'
}
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatModel.CallStatusDeclined) {
if (status === ChatRoomModel.CallStatusDeclined) {
return $chatEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
if (status === ChatModel.CallStatusMissed) {
if (status === ChatRoomModel.CallStatusMissed) {
return $chatEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === ChatModel.CallStatusAborted) {
if (status === ChatRoomModel.CallStatusAborted) {
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatModel.CallStatusEarlyAborted) {
if (status === ChatRoomModel.CallStatusEarlyAborted) {
return $chatEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === ChatModel.CallStatusAcceptedElsewhere) {
if (status === ChatRoomModel.CallStatusAcceptedElsewhere) {
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatModel.CallStatusDeclinedElsewhere) {
if (status === ChatRoomModel.CallStatusDeclinedElsewhere) {
return $chatEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}

View file

@ -48,12 +48,12 @@ Row {
id: rectangle
readonly property bool isError: Utils.includes([
ChatModel.MessageStatusFileTransferError,
ChatModel.MessageStatusNotDelivered,
ChatRoomModel.MessageStatusFileTransferError,
ChatRoomModel.MessageStatusNotDelivered,
], $chatEntry.status)
readonly property bool isUploaded: $chatEntry.status === ChatModel.MessageStatusDelivered
readonly property bool isDelivered: $chatEntry.status === ChatModel.MessageStatusDeliveredToUser
readonly property bool isRead: $chatEntry.status === ChatModel.MessageStatusDisplayed
readonly property bool isUploaded: $chatEntry.status === ChatRoomModel.MessageStatusDelivered
readonly property bool isDelivered: $chatEntry.status === ChatRoomModel.MessageStatusDeliveredToUser
readonly property bool isRead: $chatEntry.status === ChatRoomModel.MessageStatusDisplayed
color: $chatEntry.isOutgoing
? ChatStyle.entry.message.outgoing.backgroundColor
@ -200,7 +200,7 @@ Row {
to: $chatEntry.fileSize
value: $chatEntry.fileOffset || 0
visible: $chatEntry.status === ChatModel.MessageStatusInProgress || $chatEntry.status === ChatModel.MessageStatusFileTransferInProgress
visible: $chatEntry.status === ChatRoomModel.MessageStatusInProgress || $chatEntry.status === ChatRoomModel.MessageStatusFileTransferInProgress
background: Rectangle {
color: ChatStyle.entry.message.file.status.bar.background.color
@ -292,7 +292,7 @@ Row {
MouseArea {
anchors.fill: parent
visible: (rectangle.isError || $chatEntry.status === ChatModel.MessageStatusIdle) && $chatEntry.isOutgoing
visible: (rectangle.isError || $chatEntry.status === ChatRoomModel.MessageStatusIdle) && $chatEntry.isOutgoing
onClicked: proxyModel.resendMessage(index)
}
}
@ -319,7 +319,7 @@ Row {
sourceComponent: $chatEntry.isOutgoing
? (
$chatEntry.status === ChatModel.MessageStatusInProgress || $chatEntry.status === ChatModel.MessageStatusFileTransferInProgress
$chatEntry.status === ChatRoomModel.MessageStatusInProgress || $chatEntry.status === ChatRoomModel.MessageStatusFileTransferInProgress
? indicator
: icon
) : undefined

View file

@ -38,7 +38,7 @@ RowLayout {
// 2. Previous entry is a call event. => Visible.
// 3. I have sent a message before my contact. => Visible.
// 4. One hour between two incoming messages. => Visible.
return previousEntry.type !== ChatModel.MessageEntry ||
return previousEntry.type !== ChatRoomModel.MessageEntry ||
previousEntry.isOutgoing ||
$chatEntry.timestamp.getTime() - previousEntry.timestamp.getTime() > 3600
}

View file

@ -35,12 +35,12 @@ Item {
Icon {
id: iconId
readonly property var isError: Utils.includes([
ChatModel.MessageStatusFileTransferError,
ChatModel.MessageStatusNotDelivered,
ChatRoomModel.MessageStatusFileTransferError,
ChatRoomModel.MessageStatusNotDelivered,
], $chatEntry.status)
readonly property bool isUploaded: $chatEntry.status === ChatModel.MessageStatusDelivered
readonly property bool isDelivered: $chatEntry.status === ChatModel.MessageStatusDeliveredToUser
readonly property bool isRead: $chatEntry.status === ChatModel.MessageStatusDisplayed
readonly property bool isUploaded: $chatEntry.status === ChatRoomModel.MessageStatusDelivered
readonly property bool isDelivered: $chatEntry.status === ChatRoomModel.MessageStatusDeliveredToUser
readonly property bool isRead: $chatEntry.status === ChatRoomModel.MessageStatusDisplayed
icon: isError
? 'chat_error'
@ -50,7 +50,7 @@ Item {
MouseArea {
id:retryAction
anchors.fill: parent
visible: iconId.isError || $chatEntry.status === ChatModel.MessageStatusIdle
visible: iconId.isError || $chatEntry.status === ChatRoomModel.MessageStatusIdle
onClicked: proxyModel.resendMessage(index)
}
@ -83,7 +83,7 @@ Item {
height: ChatStyle.entry.lineHeight
width: ChatStyle.entry.message.outgoing.areaSize
sourceComponent: $chatEntry.status === ChatModel.MessageStatusInProgress || $chatEntry.status === ChatModel.MessageStatusFileTransferInProgress
sourceComponent: $chatEntry.status === ChatRoomModel.MessageStatusInProgress || $chatEntry.status === ChatRoomModel.MessageStatusFileTransferInProgress
? indicator
: iconComponent
}

View file

@ -43,14 +43,17 @@ Rectangle {
Layout.preferredWidth: ContactStyle.contentHeight
//image: _contact && _contact.vcard.avatar
image: entry.avatar
image: (entry.contactModel?entry.contactModel.vcard.avatar:entry.avatar?entry.avatar: '')
presenceLevel: entry.presenceStatus != null
? Presence.getPresenceLevel(entry.presenceStatus)
: -1
presenceLevel: (entry.contactModel ? Presence.getPresenceLevel(entry.contactModel.presenceStatus)
: entry.presenceStatus ? Presence.getPresenceLevel(entry.presenceStatus)
:-1)
//username: LinphoneUtils.getContactUsername(_contact || entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '')
username: entry.username
username: (entry.contactModel ? entry.contactModel.vcard.username
:entry.username?entry.username:
LinphoneUtils.getContactUsername(entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '')
)
}
ContactDescription {
@ -61,17 +64,18 @@ Rectangle {
Layout.leftMargin: ContactStyle.spacing
//sipAddress: entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || ''
sipAddress: entry.sipAddress
sipAddress: (entry.contactModel ? entry.contactModel.vcard.sipAddress
:entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '')
username: avatar.username
}
ContactMessageCounter {
Layout.alignment: Qt.AlignTop
count: Number(entry.unreadMessageCount) + Number(entry.missedCallCount)
count: Number(entry.unreadMessagesCount) + Number(entry.missedCallsCount)
isComposing: Boolean(entry.isComposing)
visible: item.displayUnreadMessageCount
visible: (entry.unreadMessagesCount !== null || entry.missedCallsCount !== null) && item.displayUnreadMessageCount
}
}
}

View file

@ -13,7 +13,8 @@ Notification {
icon: 'message_sign'
// ---------------------------------------------------------------------------
readonly property TimelineModel timelineModel: notificationData && notificationData.timelineModel
readonly property string peerAddress: notificationData && notificationData.peerAddress || ''
readonly property string localAddress: notificationData && notificationData.localAddress || ''
readonly property string fullPeerAddress: notificationData && notificationData.fullPeerAddress || ''
@ -22,7 +23,7 @@ Notification {
// ---------------------------------------------------------------------------
Loader {
active: Boolean(notification.peerAddress) && Boolean(notification.localAddress)
active: timelineModel//Boolean(notification.peerAddress) && Boolean(notification.localAddress)
anchors {
fill: parent
@ -37,7 +38,8 @@ Notification {
Contact {
Layout.fillWidth: true
entry: SipAddressesModel.getSipAddressObserver(notification.fullPeerAddress, notification.fullLocalAddress)
//entry: SipAddressesModel.getSipAddressObserver(notification.fullPeerAddress, notification.fullLocalAddress)
entry:notification.timelineModel.getChatRoomModel()
}
Rectangle {
@ -75,10 +77,11 @@ Notification {
onClicked: notification._close(function () {
AccountSettingsModel.setDefaultProxyConfigFromSipAddress(notification.localAddress)
notification.notificationData.window.setView('Conversation', {
chatRoomModel:notification.timelineModel.getChatRoomModel()/*,
peerAddress: notification.peerAddress,
localAddress: notification.localAddress,
fullPeerAddress: notification.fullPeerAddress,
fullLocalAddress: notification.fullLocalAddress
fullLocalAddress: notification.fullLocalAddress*/
})
})
}

View file

@ -44,8 +44,8 @@ Rectangle {
Connections {
target: model
onCurrentTimelineChanged:entrySelected(currentTimeline)
onSelectedCountChanged:if(selectedCount<=0) view.currentIndex = -1
// onCurrentTimelineChanged:entrySelected(currentTimeline)
}
/*
Connections {
@ -113,7 +113,7 @@ Rectangle {
width: parent ? parent.width : 0
Contact {
readonly property bool isSelected: view.currentIndex === index
property bool isSelected: modelData.selected //view.currentIndex === index
anchors.fill: parent
color: isSelected
@ -126,7 +126,7 @@ Rectangle {
displayUnreadMessageCount: SettingsModel.chatEnabled
//entry: $timelineEntry
//entry: SipAddressesModel.getSipAddressObserver(modelData.fullPeerAddress, modelData.fullLocalAddress)
entry: modelData
entry: modelData.chatRoomModel
sipAddressColor: isSelected
? TimelineStyle.contact.sipAddress.color.selected
: TimelineStyle.contact.sipAddress.color.normal
@ -149,15 +149,14 @@ Rectangle {
MouseArea {
anchors.fill: parent
onClicked: {
view.currentIndex = index
//timeline.model.setCurrentChatModel(modelData.getChatModel())// using member doesn't work
timeline.model.currentChatModel = modelData.chatModel
//timeline.entrySelected(modelData)
//timeline.model.unselectAll()
modelData.selected = true
view.currentIndex = index;
timeline.entrySelected(modelData)
//timeline.entrySelected($timelineEntry.sipAddress, $timelineEntry.isSecure)
}
}
}
// onCountChanged: Logic.handleCountChanged(count)
}
}

View file

@ -189,10 +189,10 @@ Window {
id: chat
Chat {
proxyModel: ChatProxyModel {
proxyModel: ChatRoomProxyModel {
Component.onCompleted: {
if (!SettingsModel.chatEnabled) {
setEntryTypeFilter(ChatModel.CallEntry)
setEntryTypeFilter(ChatRoomModel.CallEntry)
}
}
@ -205,7 +205,7 @@ Window {
Connections {
target: SettingsModel
onChatEnabledChanged: proxyModel.setEntryTypeFilter(status ? ChatModel.GenericEntry : ChatModel.CallEntry)
onChatEnabledChanged: proxyModel.setEntryTypeFilter(status ? ChatRoomModel.GenericEntry : ChatRoomModel.CallEntry)
}
}
}

View file

@ -151,7 +151,7 @@ ColumnLayout {
ActionButton {
icon: 'call_chat_unsecure'
onClicked: {console.log("A");actions.itemAt(3).open()}
onClicked: {actions.itemAt(3).open()}
}
}
@ -181,23 +181,15 @@ ColumnLayout {
peerAddress: sipAddress,
localAddress: AccountSettingsModel.sipAddress,
fullPeerAddress: sipAddress,
fullLocalAddress: AccountSettingsModel.fullSipAddress,
secure:false
fullLocalAddress: AccountSettingsModel.fullSipAddress
})
},
function (sipAddress) {
console.log("B")
if(CallsListModel.launchSecureChat(sipAddress)){
console.log("C")
window.setView('Conversation', {
peerAddress: sipAddress,
localAddress: AccountSettingsModel.sipAddress,
fullPeerAddress: sipAddress,
fullLocalAddress: AccountSettingsModel.fullSipAddress,
secure:true
//Logic.manageAccounts()
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/ManageChatRoom.qml'), {
//window.setView('Dialogs/ManageChatRoom', {
participantAddress: sipAddress
})
}else
console.log("D")
}
]

View file

@ -33,7 +33,7 @@ function removeAllEntries () {
descriptionText: qsTr('removeAllEntriesDescription'),
}, function (status) {
if (status) {
chatProxyModel.removeAllEntries()
chatRoomProxyModel.removeAllEntries()
}
})
}
@ -56,12 +56,12 @@ function getUsername () {
}
function updateChatFilter (button) {
var ChatModel = Linphone.ChatModel
var ChatRoomModel = Linphone.ChatRoomModel
if (button === 0) {
chatProxyModel.setEntryTypeFilter(ChatModel.GenericEntry)
chatRoomProxyModel.setEntryTypeFilter(ChatRoomModel.GenericEntry)
} else if (button === 1) {
chatProxyModel.setEntryTypeFilter(ChatModel.CallEntry)
chatRoomProxyModel.setEntryTypeFilter(ChatRoomModel.CallEntry)
} else {
chatProxyModel.setEntryTypeFilter(ChatModel.MessageEntry)
chatRoomProxyModel.setEntryTypeFilter(ChatRoomModel.MessageEntry)
}
}

View file

@ -12,13 +12,17 @@ import 'Conversation.js' as Logic
ColumnLayout {
id: conversation
/*
property string peerAddress
property string localAddress
property string fullPeerAddress
property string fullLocalAddress
property int isSecure
property var chatModel
property int isSecure*/
property ChatRoomModel chatRoomModel
property string peerAddress : chatRoomModel.getPeerAddress()
property string localAddress : chatRoomModel.getLocalAddress()
property string fullPeerAddress : chatRoomModel.getFullPeerAddress()
property string fullLocalAddress : chatRoomModel.getFullLocalAddress()
readonly property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver((fullPeerAddress?fullPeerAddress:peerAddress), (fullLocalAddress?fullLocalAddress:localAddress))
@ -56,7 +60,8 @@ ColumnLayout {
conversation._sipAddressObserver.presenceStatus
)
username: Logic.getUsername()
//username: Logic.getUsername()
username: chatRoomModel.username
}
ContactDescription {
@ -91,6 +96,14 @@ ColumnLayout {
onClicked: CallsListModel.launchAudioCall(conversation.peerAddress)
}
ActionButton {
icon: 'call_chat_unsecure'
onClicked: {
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/ManageChatRoom.qml'), {
//window.setView('Dialogs/ManageChatRoom', {
chatRoomModel:conversation.chatRoomModel
})}
}
}
ActionBar {
@ -163,17 +176,16 @@ ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
proxyModel: ChatProxyModel {
id: chatProxyModel
proxyModel: ChatRoomProxyModel {
id: chatRoomProxyModel
Component.onCompleted: {
if (!SettingsModel.chatEnabled) {
setEntryTypeFilter(ChatModel.CallEntry)
setEntryTypeFilter(ChatRoomModel.CallEntry)
}
resetMessageCount()
}
isSecure: conversation.isSecure
chatModel: conversation.chatModel
chatRoomModel: conversation.chatRoomModel
peerAddress: conversation.peerAddress
fullPeerAddress: conversation.fullPeerAddress
fullLocalAddress: conversation.fullLocalAddress
@ -184,7 +196,7 @@ ColumnLayout {
Connections {
target: SettingsModel
onChatEnabledChanged: chatProxyModel.setEntryTypeFilter(status ? ChatModel.GenericEntry : ChatModel.CallEntry)
onChatEnabledChanged: chatRoomProxyModel.setEntryTypeFilter(status ? ChatRoomModel.GenericEntry : ChatRoomModel.CallEntry)
}
Connections {

View file

@ -0,0 +1,142 @@
import QtQuick 2.7
import Common 1.0
import Linphone 1.0
import Utils 1.0
import App.Styles 1.0
// =============================================================================
DialogPlus {
property ChatRoomModel chatRoomModel
property var participantAddress : (chatRoomModel?chatRoomModel.getParticipants(): null)
buttons: [
TextButtonA {
text: 'cancel'
onClicked: exit(0)
},
TextButtonB {
text: 'del'
visible:chatRoomModel
onClicked: {
if(chatRoomModel){
chatRoomModel.leaveChatRoom()
exit(0)
}
}
},
TextButtonB {
text: 'ok'
onClicked: {
if(chatRoomModel && CallsListModel.createSecureChat(subject.text, participantAddress))
exit(0)
}
}
]
centeredButtons: true
height: ManageAccountsStyle.height
width: ManageAccountsStyle.width
// ---------------------------------------------------------------------------
Form {
anchors.fill: parent
orientation: Qt.Vertical
FormLine {
FormGroup {
label: 'Details'
FormLine {
FormGroup {
label: 'Subject*'
TextField {
id:subject
placeholderText :"Subject"
text:(chatRoomModel?chatRoomModel.getSubject():'')
Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()
error : text == ''
TooltipArea{
text : 'Current subject of the ChatRoom. It cannot be empty'
}
}
}
}
}
}
FormLine {
FormGroup {
label: 'Participants : '+participantAddress
/*
ScrollableListViewField {
width: parent.width
height: ManageAccountsStyle.accountSelector.height
radius: 0
ScrollableListView {
id: view
property string textRole: 'fullSipAddress' // Used by delegate.
anchors.fill: parent
model: AccountSettingsModel.accounts
onModelChanged: currentIndex = Utils.findIndex(AccountSettingsModel.accounts, function (account) {
return account.sipAddress === AccountSettingsModel.sipAddress
})
delegate: CommonItemDelegate {
id: item
container: view
flattenedModel: modelData
itemIcon: ''//Start with no error and let some time before getting status with the below timer
width: parent.width
Timer{// This timer is used to synchronize registration state by proxy, without having to deal with change signals
interval: 1000; running: item.visible; repeat: true
onTriggered:itemIcon= Logic.getItemIcon(flattenedModel)
}
ActionButton {
icon: 'options'
iconSize: 30
anchors.fill: parent
visible:false
//TODO handle click and jump to proxy config settings
}
onClicked: {
container.currentIndex = index
if(flattenedModel.proxyConfig)
AccountSettingsModel.setDefaultProxyConfig(flattenedModel.proxyConfig)
else
AccountSettingsModel.setDefaultProxyConfig()
}
MessageCounter {
anchors.fill: parent
count: flattenedModel.unreadMessageCount+flattenedModel.missedCallCount
}
}
}
}
*/
}
}
}
}

View file

@ -114,7 +114,7 @@ function updateSelectedEntry (view, props) {
timeline.resetSelectedEntry()
} else if (view === 'Contacts') {
item.contactsEntry.select()
timeline.resetSelectedEntry()
//timeline.resetSelectedEntry()
} else {
menu.resetSelectedEntry()
/*

View file

@ -264,13 +264,13 @@ ApplicationWindow {
Layout.fillWidth: true
model: TimelineProxyModel{}
onEntrySelected: (entry?setView('Conversation', {
onEntrySelected: (entry?setView('Conversation', {/*
isSecure:-1,
peerAddress: entry.fullPeerAddress,
fullPeerAddress: entry.fullPeerAddress,
fullLocalAddress: AccountSettingsModel.fullSipAddress,
localAddress: AccountSettingsModel.sipAddress,
chatModel:entry.chatModel
localAddress: AccountSettingsModel.sipAddress,*/
chatRoomModel:entry.chatRoomModel
}):
setView('HistoryView', {})

View file

@ -50,6 +50,7 @@ function initForm (account) {
)
route.text = config.route
conferenceUri.text = config.conferenceUri
contactParams.text = config.contactParams
avpfInterval.text = config.avpfInterval
registerEnabled.checked = config.registerEnabled
@ -70,7 +71,7 @@ function initForm (account) {
}
function formIsValid () {
return dialog._sipAddressOk && dialog._serverAddressOk && dialog._routeOk
return dialog._sipAddressOk && dialog._serverAddressOk && dialog._routeOk && dialog._conferenceUriOk
}
// -----------------------------------------------------------------------------
@ -82,6 +83,7 @@ function validProxyConfig () {
registrationDuration: registrationDuration.text,
transport: transport.currentText,
route: route.text,
conferenceUri: conferenceUri.text,
contactParams: contactParams.text,
avpfInterval: avpfInterval.text,
registerEnabled: registerEnabled.checked,
@ -104,6 +106,9 @@ function validProxyConfig () {
function handleRouteChanged (route) {
dialog._routeOk = route.length === 0 || Linphone.SipAddressesModel.addressIsValid(route)
}
function handleConferenceUriChanged (uri) {
dialog._conferenceUriOk = route.length === 0 || Linphone.SipAddressesModel.addressIsValid(uri)
}
function handleServerAddressChanged (address) {
if (address.length === 0) {

View file

@ -16,6 +16,7 @@ DialogPlus {
property bool _sipAddressOk: false
property bool _serverAddressOk: false
property bool _routeOk: false
property bool _conferenceUriOk: false
buttons: [
TextButtonA {
@ -123,6 +124,21 @@ DialogPlus {
}
}
}
FormLine {
FormGroup {
label: 'Conference URI'
TextField {
id: conferenceUri
error: dialog._conferenceUriOk ? '' : 'invalid conference uri'
onTextChanged: Logic.handleConferenceUriChanged(text)
Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()
}
}
}
FormLine {
FormGroup {