imdn on each chat message
imdn on chat last message change message notification ui press enter to send message
This commit is contained in:
parent
c0dbc4b0e5
commit
9b67794752
22 changed files with 427 additions and 248 deletions
|
|
@ -69,18 +69,22 @@ ChatCore::ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom) : QObjec
|
||||||
});
|
});
|
||||||
mChatModel = Utils::makeQObject_ptr<ChatModel>(chatRoom);
|
mChatModel = Utils::makeQObject_ptr<ChatModel>(chatRoom);
|
||||||
mChatModel->setSelf(mChatModel);
|
mChatModel->setSelf(mChatModel);
|
||||||
mLastMessageInHistory = mChatModel->getLastMessageInHistory();
|
auto lastMessage = chatRoom->getLastMessageInHistory();
|
||||||
|
mLastMessage = lastMessage ? ChatMessageCore::create(lastMessage) : nullptr;
|
||||||
auto history = chatRoom->getHistory(0, (int)linphone::ChatRoom::HistoryFilter::ChatMessage);
|
auto history = chatRoom->getHistory(0, (int)linphone::ChatRoom::HistoryFilter::ChatMessage);
|
||||||
std::list<std::shared_ptr<linphone::ChatMessage>> linHistory;
|
std::list<std::shared_ptr<linphone::ChatMessage>> lHistory;
|
||||||
for (auto &eventLog : history) {
|
for (auto &eventLog : history) {
|
||||||
if (eventLog->getChatMessage()) linHistory.push_back(eventLog->getChatMessage());
|
if (eventLog->getChatMessage()) lHistory.push_back(eventLog->getChatMessage());
|
||||||
}
|
}
|
||||||
for (auto &message : linHistory) {
|
for (auto &message : lHistory) {
|
||||||
if (!message) continue;
|
if (!message) continue;
|
||||||
auto chatMessage = ChatMessageCore::create(message);
|
auto chatMessage = ChatMessageCore::create(message);
|
||||||
mChatMessageList.append(chatMessage);
|
mChatMessageList.append(chatMessage);
|
||||||
}
|
}
|
||||||
mIdentifier = Utils::coreStringToAppString(chatRoom->getIdentifier());
|
mIdentifier = Utils::coreStringToAppString(chatRoom->getIdentifier());
|
||||||
|
connect(this, &ChatCore::messageListChanged, this, &ChatCore::lUpdateLastMessage);
|
||||||
|
connect(this, &ChatCore::messagesInserted, this, &ChatCore::lUpdateLastMessage);
|
||||||
|
connect(this, &ChatCore::messageRemoved, this, &ChatCore::lUpdateLastMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatCore::~ChatCore() {
|
ChatCore::~ChatCore() {
|
||||||
|
|
@ -123,16 +127,14 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
|
||||||
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||||
if (mChatModel->getMonitor() != chatRoom) return;
|
if (mChatModel->getMonitor() != chatRoom) return;
|
||||||
emit lUpdateLastMessage();
|
|
||||||
emit lUpdateUnreadCount();
|
|
||||||
emit lUpdateLastUpdatedTime();
|
|
||||||
auto message = eventLog->getChatMessage();
|
auto message = eventLog->getChatMessage();
|
||||||
qDebug() << "EVENT LOG RECEIVED IN CHATROOM" << mChatModel->getTitle();
|
qDebug() << "EVENT LOG RECEIVED IN CHATROOM" << mChatModel->getTitle();
|
||||||
if (message) {
|
if (message) {
|
||||||
auto newMessage = ChatMessageCore::create(message);
|
auto newMessage = ChatMessageCore::create(message);
|
||||||
mChatModelConnection->invokeToCore([this, newMessage]() {
|
mChatModelConnection->invokeToCore([this, newMessage]() {
|
||||||
qDebug() << log().arg("append message to chatRoom") << this;
|
|
||||||
appendMessageToMessageList(newMessage);
|
appendMessageToMessageList(newMessage);
|
||||||
|
emit lUpdateUnreadCount();
|
||||||
|
emit lUpdateLastUpdatedTime();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -140,9 +142,6 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
|
||||||
&ChatModel::chatMessagesReceived, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
&ChatModel::chatMessagesReceived, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||||
const std::list<std::shared_ptr<linphone::EventLog>> &chatMessages) {
|
const std::list<std::shared_ptr<linphone::EventLog>> &chatMessages) {
|
||||||
if (mChatModel->getMonitor() != chatRoom) return;
|
if (mChatModel->getMonitor() != chatRoom) return;
|
||||||
emit lUpdateLastMessage();
|
|
||||||
emit lUpdateUnreadCount();
|
|
||||||
emit lUpdateLastUpdatedTime();
|
|
||||||
qDebug() << "EVENT LOGS RECEIVED IN CHATROOM" << mChatModel->getTitle();
|
qDebug() << "EVENT LOGS RECEIVED IN CHATROOM" << mChatModel->getTitle();
|
||||||
QList<QSharedPointer<ChatMessageCore>> list;
|
QList<QSharedPointer<ChatMessageCore>> list;
|
||||||
for (auto &m : chatMessages) {
|
for (auto &m : chatMessages) {
|
||||||
|
|
@ -153,8 +152,9 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mChatModelConnection->invokeToCore([this, list]() {
|
mChatModelConnection->invokeToCore([this, list]() {
|
||||||
qDebug() << log().arg("append messages to chatRoom") << this;
|
|
||||||
appendMessagesToMessageList(list);
|
appendMessagesToMessageList(list);
|
||||||
|
emit lUpdateUnreadCount();
|
||||||
|
emit lUpdateLastUpdatedTime();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -167,12 +167,17 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
|
||||||
});
|
});
|
||||||
|
|
||||||
mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateLastMessage, [this]() {
|
mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateLastMessage, [this]() {
|
||||||
mChatModelConnection->invokeToModel([this]() {
|
auto lastMessageModel = mLastMessage ? mLastMessage->getModel() : nullptr;
|
||||||
auto message = mChatModel->getLastMessageInHistory();
|
mChatModelConnection->invokeToModel([this, lastMessageModel]() {
|
||||||
mChatModelConnection->invokeToCore([this, message]() { setLastMessageInHistory(message); });
|
auto linphoneMessage = mChatModel->getLastChatMessage();
|
||||||
|
if (lastMessageModel && lastMessageModel->getMonitor() != linphoneMessage) {
|
||||||
|
auto chatMessageCore = ChatMessageCore::create(linphoneMessage);
|
||||||
|
mChatModelConnection->invokeToCore([this, chatMessageCore]() { setLastMessage(chatMessageCore); });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSendTextMessage, [this](QString message) {
|
mChatModelConnection->makeConnectToCore(&ChatCore::lSendTextMessage, [this](QString message) {
|
||||||
|
if (Utils::isEmptyMessage(message)) return;
|
||||||
mChatModelConnection->invokeToModel([this, message]() {
|
mChatModelConnection->invokeToModel([this, message]() {
|
||||||
auto linMessage = mChatModel->createTextMessageFromText(message);
|
auto linMessage = mChatModel->createTextMessageFromText(message);
|
||||||
linMessage->send();
|
linMessage->send();
|
||||||
|
|
@ -253,14 +258,28 @@ void ChatCore::setAvatarUri(QString avatarUri) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChatCore::getLastMessageInHistory() const {
|
QString ChatCore::getLastMessageText() const {
|
||||||
return mLastMessageInHistory;
|
return mLastMessage ? mLastMessage->getText() : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatCore::setLastMessageInHistory(QString lastMessageInHistory) {
|
LinphoneEnums::ChatMessageState ChatCore::getLastMessageState() const {
|
||||||
if (mLastMessageInHistory != lastMessageInHistory) {
|
return mLastMessage ? mLastMessage->getMessageState() : LinphoneEnums::ChatMessageState::StateIdle;
|
||||||
mLastMessageInHistory = lastMessageInHistory;
|
}
|
||||||
emit lastMessageInHistoryChanged(lastMessageInHistory);
|
|
||||||
|
ChatMessageGui *ChatCore::getLastMessage() const {
|
||||||
|
return mLastMessage ? new ChatMessageGui(mLastMessage) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<ChatMessageCore> ChatCore::getLastMessageCore() const {
|
||||||
|
return mLastMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatCore::setLastMessage(QSharedPointer<ChatMessageCore> lastMessage) {
|
||||||
|
if (mLastMessage != lastMessage) {
|
||||||
|
disconnect(mLastMessage.get());
|
||||||
|
mLastMessage = lastMessage;
|
||||||
|
connect(mLastMessage.get(), &ChatMessageCore::messageStateChanged, this, &ChatCore::lastMessageChanged);
|
||||||
|
emit lastMessageChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#ifndef CHAT_CORE_H_
|
#ifndef CHAT_CORE_H_
|
||||||
#define CHAT_CORE_H_
|
#define CHAT_CORE_H_
|
||||||
|
|
||||||
#include "core/chat/message/ChatMessageCore.hpp"
|
#include "core/chat/message/ChatMessageGui.hpp"
|
||||||
#include "model/chat/ChatModel.hpp"
|
#include "model/chat/ChatModel.hpp"
|
||||||
#include "model/search/MagicSearchModel.hpp"
|
#include "model/search/MagicSearchModel.hpp"
|
||||||
#include "tool/LinphoneEnums.hpp"
|
#include "tool/LinphoneEnums.hpp"
|
||||||
|
|
@ -39,8 +39,9 @@ public:
|
||||||
Q_PROPERTY(QString peerAddress READ getPeerAddress WRITE setPeerAddress NOTIFY peerAddressChanged)
|
Q_PROPERTY(QString peerAddress READ getPeerAddress WRITE setPeerAddress NOTIFY peerAddressChanged)
|
||||||
Q_PROPERTY(QString avatarUri READ getAvatarUri WRITE setAvatarUri NOTIFY avatarUriChanged)
|
Q_PROPERTY(QString avatarUri READ getAvatarUri WRITE setAvatarUri NOTIFY avatarUriChanged)
|
||||||
Q_PROPERTY(QDateTime lastUpdatedTime READ getLastUpdatedTime WRITE setLastUpdatedTime NOTIFY lastUpdatedTimeChanged)
|
Q_PROPERTY(QDateTime lastUpdatedTime READ getLastUpdatedTime WRITE setLastUpdatedTime NOTIFY lastUpdatedTimeChanged)
|
||||||
Q_PROPERTY(QString lastMessageInHistory READ getLastMessageInHistory WRITE setLastMessageInHistory NOTIFY
|
Q_PROPERTY(QString lastMessageText READ getLastMessageText NOTIFY lastMessageChanged)
|
||||||
lastMessageInHistoryChanged)
|
Q_PROPERTY(ChatMessageGui *lastMessage READ getLastMessage NOTIFY lastMessageChanged)
|
||||||
|
Q_PROPERTY(LinphoneEnums::ChatMessageState lastMessageState READ getLastMessageState NOTIFY lastMessageChanged)
|
||||||
Q_PROPERTY(int unreadMessagesCount READ getUnreadMessagesCount WRITE setUnreadMessagesCount NOTIFY
|
Q_PROPERTY(int unreadMessagesCount READ getUnreadMessagesCount WRITE setUnreadMessagesCount NOTIFY
|
||||||
unreadMessagesCountChanged)
|
unreadMessagesCountChanged)
|
||||||
Q_PROPERTY(QString composingName READ getComposingName WRITE setComposingName NOTIFY composingUserChanged)
|
Q_PROPERTY(QString composingName READ getComposingName WRITE setComposingName NOTIFY composingUserChanged)
|
||||||
|
|
@ -61,8 +62,13 @@ public:
|
||||||
|
|
||||||
QString getIdentifier() const;
|
QString getIdentifier() const;
|
||||||
|
|
||||||
QString getLastMessageInHistory() const;
|
ChatMessageGui *getLastMessage() const;
|
||||||
void setLastMessageInHistory(QString message);
|
QString getLastMessageText() const;
|
||||||
|
|
||||||
|
LinphoneEnums::ChatMessageState getLastMessageState() const;
|
||||||
|
|
||||||
|
QSharedPointer<ChatMessageCore> getLastMessageCore() const;
|
||||||
|
void setLastMessage(QSharedPointer<ChatMessageCore> lastMessage);
|
||||||
|
|
||||||
int getUnreadMessagesCount() const;
|
int getUnreadMessagesCount() const;
|
||||||
void setUnreadMessagesCount(int count);
|
void setUnreadMessagesCount(int count);
|
||||||
|
|
@ -89,7 +95,7 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void lastUpdatedTimeChanged(QDateTime time);
|
void lastUpdatedTimeChanged(QDateTime time);
|
||||||
void lastMessageInHistoryChanged(QString time);
|
void lastMessageChanged();
|
||||||
void titleChanged(QString title);
|
void titleChanged(QString title);
|
||||||
void peerAddressChanged(QString address);
|
void peerAddressChanged(QString address);
|
||||||
void unreadMessagesCountChanged(int count);
|
void unreadMessagesCountChanged(int count);
|
||||||
|
|
@ -113,7 +119,6 @@ signals:
|
||||||
private:
|
private:
|
||||||
QString id;
|
QString id;
|
||||||
QDateTime mLastUpdatedTime;
|
QDateTime mLastUpdatedTime;
|
||||||
QString mLastMessageInHistory;
|
|
||||||
QString mPeerAddress;
|
QString mPeerAddress;
|
||||||
QString mTitle;
|
QString mTitle;
|
||||||
QString mIdentifier;
|
QString mIdentifier;
|
||||||
|
|
@ -122,6 +127,7 @@ private:
|
||||||
QString mComposingName;
|
QString mComposingName;
|
||||||
QString mComposingAddress;
|
QString mComposingAddress;
|
||||||
std::shared_ptr<ChatModel> mChatModel;
|
std::shared_ptr<ChatModel> mChatModel;
|
||||||
|
QSharedPointer<ChatMessageCore> mLastMessage;
|
||||||
QList<QSharedPointer<ChatMessageCore>> mChatMessageList;
|
QList<QSharedPointer<ChatMessageCore>> mChatMessageList;
|
||||||
QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection;
|
QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,25 @@ ChatList::~ChatList() {
|
||||||
mModelConnection = nullptr;
|
mModelConnection = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatList::connectItem(QSharedPointer<ChatCore> chat) {
|
||||||
|
connect(chat.get(), &ChatCore::deleted, this, [this, chat] {
|
||||||
|
remove(chat);
|
||||||
|
// We cannot use countChanged here because it is called before mList
|
||||||
|
// really has removed the item, then emit specific signal
|
||||||
|
emit chatRemoved(chat ? new ChatGui(chat) : nullptr);
|
||||||
|
});
|
||||||
|
auto dataChange = [this, chat] {
|
||||||
|
int i = -1;
|
||||||
|
get(chat.get(), &i);
|
||||||
|
if (i != -1) {
|
||||||
|
auto modelIndex = index(i);
|
||||||
|
emit dataChanged(modelIndex, modelIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
connect(chat.get(), &ChatCore::unreadMessagesCountChanged, this, dataChange);
|
||||||
|
connect(chat.get(), &ChatCore::lastUpdatedTimeChanged, this, dataChange);
|
||||||
|
}
|
||||||
|
|
||||||
void ChatList::setSelf(QSharedPointer<ChatList> me) {
|
void ChatList::setSelf(QSharedPointer<ChatList> me) {
|
||||||
mModelConnection = SafeConnection<ChatList, CoreModel>::create(me, CoreModel::getInstance());
|
mModelConnection = SafeConnection<ChatList, CoreModel>::create(me, CoreModel::getInstance());
|
||||||
|
|
||||||
|
|
@ -70,16 +89,12 @@ void ChatList::setSelf(QSharedPointer<ChatList> me) {
|
||||||
for (auto &chat : getSharedList<ChatCore>()) {
|
for (auto &chat : getSharedList<ChatCore>()) {
|
||||||
if (chat) {
|
if (chat) {
|
||||||
disconnect(chat.get(), &ChatCore::deleted, this, nullptr);
|
disconnect(chat.get(), &ChatCore::deleted, this, nullptr);
|
||||||
|
disconnect(chat.get(), &ChatCore::unreadMessagesCountChanged, this, nullptr);
|
||||||
|
disconnect(chat.get(), &ChatCore::lastUpdatedTimeChanged, this, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto &chat : *chats) {
|
for (auto &chat : *chats) {
|
||||||
connect(chat.get(), &ChatCore::deleted, this, [this, chat] {
|
connectItem(chat);
|
||||||
remove(chat);
|
|
||||||
// We cannot use countChanged here because it is called before mList
|
|
||||||
// really has removed the item, then emit specific signal
|
|
||||||
emit chatRemoved(chat ? new ChatGui(chat) : nullptr);
|
|
||||||
});
|
|
||||||
connect(chat.get(), &ChatCore::unreadMessagesCountChanged, this, [this] { emit chatUpdated(); });
|
|
||||||
}
|
}
|
||||||
mustBeInMainThread(getClassName());
|
mustBeInMainThread(getClassName());
|
||||||
resetData<ChatCore>(*chats);
|
resetData<ChatCore>(*chats);
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ public:
|
||||||
ChatList(QObject *parent = Q_NULLPTR);
|
ChatList(QObject *parent = Q_NULLPTR);
|
||||||
~ChatList();
|
~ChatList();
|
||||||
void setSelf(QSharedPointer<ChatList> me);
|
void setSelf(QSharedPointer<ChatList> me);
|
||||||
|
void connectItem(QSharedPointer<ChatCore> chat);
|
||||||
|
|
||||||
int findChatIndex(ChatGui *chat);
|
int findChatIndex(ChatGui *chat);
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@ void ChatProxy::setSourceModel(QAbstractItemModel *model) {
|
||||||
[this, newChatList] { emit newChatList->filterChanged(getFilterText()); });
|
[this, newChatList] { emit newChatList->filterChanged(getFilterText()); });
|
||||||
connect(newChatList, &ChatList::chatRemoved, this, &ChatProxy::chatRemoved);
|
connect(newChatList, &ChatList::chatRemoved, this, &ChatProxy::chatRemoved);
|
||||||
// connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); });
|
// connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); });
|
||||||
connect(newChatList, &ChatList::chatUpdated, this, [this] { invalidate(); });
|
|
||||||
}
|
}
|
||||||
auto firstList = new SortFilterList(model, Qt::AscendingOrder);
|
auto firstList = new SortFilterList(model, Qt::AscendingOrder);
|
||||||
|
firstList->setDynamicSortFilter(true);
|
||||||
setSourceModels(firstList);
|
setSourceModels(firstList);
|
||||||
sort(0);
|
sort(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
|
||||||
mIsFromChatGroup = chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) &&
|
mIsFromChatGroup = chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) &&
|
||||||
!chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne);
|
!chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne);
|
||||||
mIsRead = chatmessage->isRead();
|
mIsRead = chatmessage->isRead();
|
||||||
|
mMessageState = LinphoneEnums::fromLinphone(chatmessage->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatMessageCore::~ChatMessageCore() {
|
ChatMessageCore::~ChatMessageCore() {
|
||||||
|
|
@ -72,6 +73,14 @@ void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
|
||||||
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->markAsRead(); });
|
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->markAsRead(); });
|
||||||
});
|
});
|
||||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageRead, [this]() { setIsRead(true); });
|
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageRead, [this]() { setIsRead(true); });
|
||||||
|
|
||||||
|
mChatMessageModelConnection->makeConnectToModel(
|
||||||
|
&ChatMessageModel::msgStateChanged,
|
||||||
|
[this](const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state) {
|
||||||
|
if (mChatMessageModel->getMonitor() != message) return;
|
||||||
|
auto msgState = LinphoneEnums::fromLinphone(state);
|
||||||
|
mChatMessageModelConnection->invokeToCore([this, msgState] { setMessageState(msgState); });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime ChatMessageCore::getTimestamp() const {
|
QDateTime ChatMessageCore::getTimestamp() const {
|
||||||
|
|
@ -135,6 +144,17 @@ void ChatMessageCore::setIsRead(bool read) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LinphoneEnums::ChatMessageState ChatMessageCore::getMessageState() const {
|
||||||
|
return mMessageState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageCore::setMessageState(LinphoneEnums::ChatMessageState state) {
|
||||||
|
if (mMessageState != state) {
|
||||||
|
mMessageState = state;
|
||||||
|
emit messageStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<ChatMessageModel> ChatMessageCore::getModel() const {
|
std::shared_ptr<ChatMessageModel> ChatMessageCore::getModel() const {
|
||||||
return mChatMessageModel;
|
return mChatMessageModel;
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +40,8 @@ class ChatMessageCore : public QObject, public AbstractObject {
|
||||||
Q_PROPERTY(QString toAddress READ getToAddress CONSTANT)
|
Q_PROPERTY(QString toAddress READ getToAddress CONSTANT)
|
||||||
Q_PROPERTY(QString peerName READ getPeerName CONSTANT)
|
Q_PROPERTY(QString peerName READ getPeerName CONSTANT)
|
||||||
Q_PROPERTY(QString fromName READ getFromName CONSTANT)
|
Q_PROPERTY(QString fromName READ getFromName CONSTANT)
|
||||||
|
Q_PROPERTY(LinphoneEnums::ChatMessageState messageState READ getMessageState WRITE setMessageState NOTIFY
|
||||||
|
messageStateChanged)
|
||||||
Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT)
|
Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT)
|
||||||
Q_PROPERTY(bool isFromChatGroup READ isFromChatGroup CONSTANT)
|
Q_PROPERTY(bool isFromChatGroup READ isFromChatGroup CONSTANT)
|
||||||
Q_PROPERTY(bool isRead READ isRead WRITE setIsRead NOTIFY isReadChanged)
|
Q_PROPERTY(bool isRead READ isRead WRITE setIsRead NOTIFY isReadChanged)
|
||||||
|
|
@ -68,6 +70,9 @@ public:
|
||||||
bool isRead() const;
|
bool isRead() const;
|
||||||
void setIsRead(bool read);
|
void setIsRead(bool read);
|
||||||
|
|
||||||
|
LinphoneEnums::ChatMessageState getMessageState() const;
|
||||||
|
void setMessageState(LinphoneEnums::ChatMessageState state);
|
||||||
|
|
||||||
std::shared_ptr<ChatMessageModel> getModel() const;
|
std::shared_ptr<ChatMessageModel> getModel() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
@ -75,6 +80,7 @@ signals:
|
||||||
void textChanged(QString text);
|
void textChanged(QString text);
|
||||||
void isReadChanged(bool read);
|
void isReadChanged(bool read);
|
||||||
void isRemoteMessageChanged(bool isRemote);
|
void isRemoteMessageChanged(bool isRemote);
|
||||||
|
void messageStateChanged();
|
||||||
|
|
||||||
void lDelete();
|
void lDelete();
|
||||||
void deleted();
|
void deleted();
|
||||||
|
|
@ -92,6 +98,8 @@ private:
|
||||||
bool mIsRemoteMessage = false;
|
bool mIsRemoteMessage = false;
|
||||||
bool mIsFromChatGroup = false;
|
bool mIsFromChatGroup = false;
|
||||||
bool mIsRead = false;
|
bool mIsRead = false;
|
||||||
|
LinphoneEnums::ChatMessageState mMessageState;
|
||||||
|
|
||||||
std::shared_ptr<ChatMessageModel> mChatMessageModel;
|
std::shared_ptr<ChatMessageModel> mChatMessageModel;
|
||||||
QSharedPointer<SafeConnection<ChatMessageCore, ChatMessageModel>> mChatMessageModelConnection;
|
QSharedPointer<SafeConnection<ChatMessageCore, ChatMessageModel>> mChatMessageModelConnection;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -88,23 +88,8 @@ QString ChatModel::getPeerAddress() const {
|
||||||
return Utils::coreStringToAppString(mMonitor->getPeerAddress()->asStringUriOnly());
|
return Utils::coreStringToAppString(mMonitor->getPeerAddress()->asStringUriOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChatModel::getLastMessageInHistory(std::list<std::shared_ptr<linphone::Content>> startList) const {
|
std::shared_ptr<linphone::ChatMessage> ChatModel::getLastChatMessage() {
|
||||||
if (startList.empty()) {
|
return mMonitor->getLastMessageInHistory();
|
||||||
auto lastMessage = mMonitor->getLastMessageInHistory();
|
|
||||||
if (lastMessage) startList = lastMessage->getContents();
|
|
||||||
}
|
|
||||||
for (auto &content : startList) {
|
|
||||||
if (content->isText()) {
|
|
||||||
return Utils::coreStringToAppString(content->getUtf8Text());
|
|
||||||
} else if (content->isFile()) {
|
|
||||||
return Utils::coreStringToAppString(content->getName());
|
|
||||||
} else if (content->isIcalendar()) {
|
|
||||||
return QString("Invitation à une réunion");
|
|
||||||
} else if (content->isMultipart()) {
|
|
||||||
return getLastMessageInHistory(content->getParts());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QString("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ChatModel::getUnreadMessagesCount() const {
|
int ChatModel::getUnreadMessagesCount() const {
|
||||||
|
|
@ -137,6 +122,10 @@ void ChatModel::compose() {
|
||||||
mMonitor->compose();
|
mMonitor->compose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linphone::ChatRoom::State ChatModel::getState() const {
|
||||||
|
return mMonitor->getState();
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------//
|
//---------------------------------------------------------------//
|
||||||
|
|
||||||
void ChatModel::onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
void ChatModel::onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public:
|
||||||
QDateTime getLastUpdateTime();
|
QDateTime getLastUpdateTime();
|
||||||
QString getTitle();
|
QString getTitle();
|
||||||
QString getPeerAddress() const;
|
QString getPeerAddress() const;
|
||||||
QString getLastMessageInHistory(std::list<std::shared_ptr<linphone::Content>> startList = {}) const;
|
std::shared_ptr<linphone::ChatMessage> getLastChatMessage();
|
||||||
int getUnreadMessagesCount() const;
|
int getUnreadMessagesCount() const;
|
||||||
void markAsRead();
|
void markAsRead();
|
||||||
std::list<std::shared_ptr<linphone::ChatMessage>> getHistory() const;
|
std::list<std::shared_ptr<linphone::ChatMessage>> getHistory() const;
|
||||||
|
|
@ -49,6 +49,7 @@ public:
|
||||||
void deleteChatRoom();
|
void deleteChatRoom();
|
||||||
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
|
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
|
||||||
void compose();
|
void compose();
|
||||||
|
linphone::ChatRoom::State getState() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void historyDeleted();
|
void historyDeleted();
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,6 @@ QDateTime ChatMessageModel::getTimestamp() const {
|
||||||
return QDateTime::fromSecsSinceEpoch(mMonitor->getTime());
|
return QDateTime::fromSecsSinceEpoch(mMonitor->getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<linphone::Buffer>
|
|
||||||
ChatMessageModel::onFileTransferSend(const std::shared_ptr<linphone::ChatMessage> &message,
|
|
||||||
const std::shared_ptr<linphone::Content> &content,
|
|
||||||
size_t offset,
|
|
||||||
size_t size) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChatMessageModel::isRead() const {
|
bool ChatMessageModel::isRead() const {
|
||||||
return mMonitor->isRead();
|
return mMonitor->isRead();
|
||||||
}
|
}
|
||||||
|
|
@ -85,3 +77,88 @@ void ChatMessageModel::deleteMessageFromChatRoom() {
|
||||||
emit messageDeleted();
|
emit messageDeleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linphone::ChatMessage::State ChatMessageModel::getState() const {
|
||||||
|
return mMonitor->getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::computeDeliveryStatus() {
|
||||||
|
// Read
|
||||||
|
for (auto &participant : mMonitor->getParticipantsByImdnState(linphone::ChatMessage::State::Displayed)) {
|
||||||
|
}
|
||||||
|
// Received
|
||||||
|
for (auto &participant : mMonitor->getParticipantsByImdnState(linphone::ChatMessage::State::DeliveredToUser)) {
|
||||||
|
}
|
||||||
|
// Sent
|
||||||
|
for (auto &participant : mMonitor->getParticipantsByImdnState(linphone::ChatMessage::State::Delivered)) {
|
||||||
|
}
|
||||||
|
// Error
|
||||||
|
for (auto &participant : mMonitor->getParticipantsByImdnState(linphone::ChatMessage::State::NotDelivered)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onMsgStateChanged(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
linphone::ChatMessage::State state) {
|
||||||
|
computeDeliveryStatus();
|
||||||
|
emit msgStateChanged(message, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onNewMessageReaction(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) {
|
||||||
|
emit newMessageReaction(message, reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onReactionRemoved(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::Address> &address) {
|
||||||
|
emit reactionRemoved(message, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onFileTransferTerminated(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content) {
|
||||||
|
emit fileTransferTerminated(message, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
const std::shared_ptr<const linphone::Buffer> &buffer) {
|
||||||
|
emit fileTransferRecv(message, content, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<linphone::Buffer>
|
||||||
|
ChatMessageModel::onFileTransferSend(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t size) {
|
||||||
|
emit fileTransferSend(message, content, offset, size);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t size,
|
||||||
|
const std::shared_ptr<linphone::Buffer> &buffer) {
|
||||||
|
emit fileTransferSendChunk(message, content, offset, size, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onFileTransferProgressIndication(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t total) {
|
||||||
|
emit fileTransferProgressIndication(message, content, offset, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onParticipantImdnStateChanged(
|
||||||
|
const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::ParticipantImdnState> &state) {
|
||||||
|
computeDeliveryStatus();
|
||||||
|
emit participantImdnStateChanged(message, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||||
|
emit ephemeralMessageTimerStarted(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||||
|
emit ephemeralMessageDeleted(message);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,16 +49,74 @@ public:
|
||||||
|
|
||||||
void deleteMessageFromChatRoom();
|
void deleteMessageFromChatRoom();
|
||||||
|
|
||||||
|
void computeDeliveryStatus();
|
||||||
|
|
||||||
|
linphone::ChatMessage::State getState() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void messageDeleted();
|
void messageDeleted();
|
||||||
void messageRead();
|
void messageRead();
|
||||||
|
|
||||||
|
void msgStateChanged(const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state);
|
||||||
|
void newMessageReaction(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction);
|
||||||
|
void reactionRemoved(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::Address> &address);
|
||||||
|
void fileTransferTerminated(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content);
|
||||||
|
void fileTransferRecv(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
const std::shared_ptr<const linphone::Buffer> &buffer);
|
||||||
|
void fileTransferSend(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t size);
|
||||||
|
void fileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t size,
|
||||||
|
const std::shared_ptr<linphone::Buffer> &buffer);
|
||||||
|
void fileTransferProgressIndication(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t total);
|
||||||
|
void participantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::ParticipantImdnState> &state);
|
||||||
|
void ephemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message);
|
||||||
|
void ephemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
linphone::ChatMessage::State mMessageState;
|
||||||
|
|
||||||
DECLARE_ABSTRACT_OBJECT
|
DECLARE_ABSTRACT_OBJECT
|
||||||
virtual std::shared_ptr<linphone::Buffer> onFileTransferSend(const std::shared_ptr<linphone::ChatMessage> &message,
|
|
||||||
const std::shared_ptr<linphone::Content> &content,
|
void onMsgStateChanged(const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state);
|
||||||
size_t offset,
|
void onNewMessageReaction(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
size_t size) override;
|
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction);
|
||||||
|
void onReactionRemoved(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::Address> &address);
|
||||||
|
void onFileTransferTerminated(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content);
|
||||||
|
void onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
const std::shared_ptr<const linphone::Buffer> &buffer);
|
||||||
|
std::shared_ptr<linphone::Buffer> onFileTransferSend(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t size);
|
||||||
|
void onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t size,
|
||||||
|
const std::shared_ptr<linphone::Buffer> &buffer);
|
||||||
|
void onFileTransferProgressIndication(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<linphone::Content> &content,
|
||||||
|
size_t offset,
|
||||||
|
size_t total);
|
||||||
|
void onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> &message,
|
||||||
|
const std::shared_ptr<const linphone::ParticipantImdnState> &state);
|
||||||
|
void onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message);
|
||||||
|
void onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1582,6 +1582,10 @@ VariantObject *Utils::getChatForAddress(QString address) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Utils::isEmptyMessage(QString message) {
|
||||||
|
return message.trimmed().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
// CLI
|
// CLI
|
||||||
|
|
||||||
void Utils::runCommandLine(const QString command) {
|
void Utils::runCommandLine(const QString command) {
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE static VariantObject *getCurrentCallChat(CallGui *call);
|
Q_INVOKABLE static VariantObject *getCurrentCallChat(CallGui *call);
|
||||||
Q_INVOKABLE static VariantObject *getChatForAddress(QString address);
|
Q_INVOKABLE static VariantObject *getChatForAddress(QString address);
|
||||||
|
Q_INVOKABLE static bool isEmptyMessage(QString message);
|
||||||
// QDir findDirectoryByName(QString startPath, QString name);
|
// QDir findDirectoryByName(QString startPath, QString name);
|
||||||
|
|
||||||
static QString getApplicationProduct();
|
static QString getApplicationProduct();
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ ListView {
|
||||||
Text {
|
Text {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
text: modelData.core.lastMessageInHistory
|
text: modelData.core.lastMessageText
|
||||||
color: DefaultStyle.main2_400
|
color: DefaultStyle.main2_400
|
||||||
font {
|
font {
|
||||||
pixelSize: Typography.p1.pixelSize
|
pixelSize: Typography.p1.pixelSize
|
||||||
|
|
@ -194,25 +194,45 @@ ListView {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Text {
|
Layout.alignment: Qt.AlignRight
|
||||||
color: DefaultStyle.main2_500main
|
RowLayout {
|
||||||
text: UtilsCpp.formatDate(modelData.core.lastUpdatedTime, true, false)
|
Item{Layout.fillWidth: true}
|
||||||
font {
|
Text {
|
||||||
pixelSize: Typography.p3.pixelSize
|
color: DefaultStyle.main2_500main
|
||||||
weight: Typography.p3.weight
|
text: UtilsCpp.formatDate(modelData.core.lastUpdatedTime, true, false)
|
||||||
capitalization: Font.Capitalize
|
font {
|
||||||
|
pixelSize: Typography.p3.pixelSize
|
||||||
|
weight: Typography.p3.weight
|
||||||
|
capitalization: Font.Capitalize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
spacing: Math.round(10 * DefaultStyle.dp)
|
||||||
Item {Layout.fillWidth: true}
|
Item {Layout.fillWidth: true}
|
||||||
|
//sourdine, éphémère
|
||||||
UnreadNotification {
|
UnreadNotification {
|
||||||
id: unreadCount
|
id: unreadCount
|
||||||
unread: modelData.core.unreadMessagesCount
|
unread: modelData.core.unreadMessagesCount
|
||||||
}
|
}
|
||||||
//sourdine, éphémère, IMDN
|
EffectImage {
|
||||||
|
visible: modelData?.core.lastMessage && modelData?.core.lastMessageState !== LinphoneEnums.ChatMessageState.StateIdle
|
||||||
|
&& !modelData.core.lastMessage.core.isRemoteMessage
|
||||||
|
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
|
||||||
|
Layout.preferredHeight: 14 * DefaultStyle.dp
|
||||||
|
colorizationColor: DefaultStyle.main1_500_main
|
||||||
|
imageSource: modelData.core.lastMessageState === LinphoneEnums.ChatMessageState.StateDelivered
|
||||||
|
? AppIcons.envelope
|
||||||
|
: modelData.core.lastMessageState === LinphoneEnums.ChatMessageState.StateDeliveredToUser
|
||||||
|
? AppIcons.check
|
||||||
|
: modelData.core.lastMessageState === LinphoneEnums.ChatMessageState.StateNotDelivered
|
||||||
|
? AppIcons.warningCircle
|
||||||
|
: modelData.core.lastMessageState === LinphoneEnums.ChatMessageState.StateDisplayed
|
||||||
|
? AppIcons.checks
|
||||||
|
: ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PopupButton {
|
PopupButton {
|
||||||
|
|
@ -251,6 +271,7 @@ ListView {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
|
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
if (containsMouse)
|
if (containsMouse)
|
||||||
mainItem.lastMouseContainsIndex = index
|
mainItem.lastMouseContainsIndex = index
|
||||||
|
|
@ -265,8 +286,12 @@ ListView {
|
||||||
visible: mainItem.lastMouseContainsIndex === index || mainItem.currentIndex === index
|
visible: mainItem.lastMouseContainsIndex === index || mainItem.currentIndex === index
|
||||||
}
|
}
|
||||||
onPressed: {
|
onPressed: {
|
||||||
mainItem.currentIndex = model.index
|
if (pressedButtons & Qt.RightButton) {
|
||||||
mainItem.forceActiveFocus()
|
chatroomPopup.open()
|
||||||
|
} else {
|
||||||
|
mainItem.currentIndex = model.index
|
||||||
|
mainItem.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ Control.Control {
|
||||||
property string fromAddress: chatMessage? chatMessage.core.fromAddress : ""
|
property string fromAddress: chatMessage? chatMessage.core.fromAddress : ""
|
||||||
property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false
|
property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false
|
||||||
property bool isFromChatGroup: chatMessage? chatMessage.core.isFromChatGroup : false
|
property bool isFromChatGroup: chatMessage? chatMessage.core.isFromChatGroup : false
|
||||||
|
property var msgState: chatMessage ? chatMessage.core.messageState : LinphoneEnums.ChatMessageState.StateIdle
|
||||||
|
onMsgStateChanged: console.log("message state", msgState, chatMessage.core.text)
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
signal messageDeletionRequested()
|
signal messageDeletionRequested()
|
||||||
|
|
@ -62,9 +64,9 @@ Control.Control {
|
||||||
Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
||||||
spacing: Math.round(2 * DefaultStyle.dp)
|
spacing: Math.round(2 * DefaultStyle.dp)
|
||||||
topPadding: Math.round(12 * DefaultStyle.dp)
|
topPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
bottomPadding: Math.round(12 * DefaultStyle.dp)
|
bottomPadding: Math.round(6 * DefaultStyle.dp)
|
||||||
leftPadding: Math.round(18 * DefaultStyle.dp)
|
leftPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
rightPadding: Math.round(18 * DefaultStyle.dp)
|
rightPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -110,19 +112,38 @@ Control.Control {
|
||||||
visible: modelData.core.text != undefined
|
visible: modelData.core.text != undefined
|
||||||
text: modelData.core.text
|
text: modelData.core.text
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
horizontalAlignment: modelData.core.isRemoteMessage ? Text.AlignLeft : Text.AlignRight
|
||||||
color: DefaultStyle.main2_700
|
color: DefaultStyle.main2_700
|
||||||
font {
|
font {
|
||||||
pixelSize: Typography.p1.pixelSize
|
pixelSize: Typography.p1.pixelSize
|
||||||
weight: Typography.p1.weight
|
weight: Typography.p1.weight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text {
|
RowLayout {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: UtilsCpp.formatDate(modelData.core.timestamp, true, false)
|
Text {
|
||||||
color: DefaultStyle.main2_500main
|
text: UtilsCpp.formatDate(modelData.core.timestamp, true, false)
|
||||||
font {
|
color: DefaultStyle.main2_500main
|
||||||
pixelSize: Typography.p3.pixelSize
|
font {
|
||||||
weight: Typography.p3.weight
|
pixelSize: Typography.p3.pixelSize
|
||||||
|
weight: Typography.p3.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EffectImage {
|
||||||
|
visible: !mainItem.isRemoteMessage
|
||||||
|
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
|
||||||
|
Layout.preferredHeight: 14 * DefaultStyle.dp
|
||||||
|
colorizationColor: DefaultStyle.main1_500_main
|
||||||
|
imageSource: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDelivered
|
||||||
|
? AppIcons.envelope
|
||||||
|
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDeliveredToUser
|
||||||
|
? AppIcons.check
|
||||||
|
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateNotDelivered
|
||||||
|
? AppIcons.warningCircle
|
||||||
|
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDisplayed
|
||||||
|
? AppIcons.checks
|
||||||
|
: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,13 @@ ListView {
|
||||||
var chatMessage = chatMessageProxy.getChatMessageAtIndex(index)
|
var chatMessage = chatMessageProxy.getChatMessageAtIndex(index)
|
||||||
if (chatMessage && !chatMessage.core.isRead) chatMessage.core.lMarkAsRead()
|
if (chatMessage && !chatMessage.core.isRead) chatMessage.core.lMarkAsRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: if (atYEnd) {
|
||||||
|
var index = chatMessageProxy.findFirstUnreadIndex()
|
||||||
|
mainItem.positionViewAtIndex(index, ListView.End)
|
||||||
|
var chatMessage = chatMessageProxy.getChatMessageAtIndex(index)
|
||||||
|
if (chatMessage && !chatMessage.core.isRead) chatMessage.core.lMarkAsRead()
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
visible: !mainItem.atYEnd
|
visible: !mainItem.atYEnd
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,8 @@ import QtQuick.Controls.Basic
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Qt.labs.platform
|
import Qt.labs.platform
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
Window {
|
Window {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -17,8 +15,6 @@ Window {
|
||||||
property bool requestActivate: false
|
property bool requestActivate: false
|
||||||
//property int flags: Qt.SplashScreen
|
//property int flags: Qt.SplashScreen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default property alias _content: content.data
|
default property alias _content: content.data
|
||||||
property bool _isOpen: false
|
property bool _isOpen: false
|
||||||
signal isOpened()
|
signal isOpened()
|
||||||
|
|
@ -89,100 +85,4 @@ Window {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Item {
|
|
||||||
id: wrapper
|
|
||||||
objectName: '__internalWrapper'
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
property alias popupX: window.x
|
|
||||||
property alias popupY: window.y
|
|
||||||
property bool requestActivate: false
|
|
||||||
property int flags: Qt.SplashScreen
|
|
||||||
|
|
||||||
readonly property alias popupWidth: window.width
|
|
||||||
readonly property alias popupHeight: window.height
|
|
||||||
|
|
||||||
default property alias _content: content.data
|
|
||||||
property bool _isOpen: false
|
|
||||||
signal isOpened()
|
|
||||||
signal isClosed()
|
|
||||||
signal dataChanged()
|
|
||||||
|
|
||||||
on_ContentChanged: dataChanged(_content)
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function open () {
|
|
||||||
_isOpen = true;
|
|
||||||
isOpened();
|
|
||||||
}
|
|
||||||
|
|
||||||
function close () {
|
|
||||||
_isOpen = false
|
|
||||||
isClosed()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// No size, no position.
|
|
||||||
height: 0
|
|
||||||
width: 0
|
|
||||||
visible:true
|
|
||||||
|
|
||||||
Window {
|
|
||||||
id: window
|
|
||||||
objectName: '__internalWindow'
|
|
||||||
property bool isFrameLess : false;
|
|
||||||
property bool showAsTool : false
|
|
||||||
// Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant
|
|
||||||
flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
|
|
||||||
onXChanged: console.log(x)
|
|
||||||
opacity: 1.0
|
|
||||||
height: _content[0] != null ? _content[0].height : 0
|
|
||||||
width: _content[0] != null ? _content[0].width : 0
|
|
||||||
visible:true
|
|
||||||
Item {
|
|
||||||
id: content
|
|
||||||
anchors.fill:parent
|
|
||||||
|
|
||||||
property var $parent: wrapper
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
states: State {
|
|
||||||
name: 'opening'
|
|
||||||
when: _isOpen
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
opacity: 1.0
|
|
||||||
target: window
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transitions: [
|
|
||||||
Transition {
|
|
||||||
from: ''
|
|
||||||
to: 'opening'
|
|
||||||
ScriptAction {
|
|
||||||
script: {
|
|
||||||
if (wrapper.requestActivate) {
|
|
||||||
window.requestActivate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Transition {
|
|
||||||
from: '*'
|
|
||||||
to: ''
|
|
||||||
ScriptAction {
|
|
||||||
script: window.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -8,7 +8,7 @@ import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
|
||||||
|
|
||||||
Notification {
|
Notification {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
radius: Math.round(20 * DefaultStyle.dp)
|
radius: Math.round(10 * DefaultStyle.dp)
|
||||||
backgroundColor: DefaultStyle.grey_600
|
backgroundColor: DefaultStyle.grey_600
|
||||||
backgroundOpacity: 0.8
|
backgroundOpacity: 0.8
|
||||||
overriddenWidth: Math.round(400 * DefaultStyle.dp)
|
overriddenWidth: Math.round(400 * DefaultStyle.dp)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
|
||||||
|
|
||||||
Notification {
|
Notification {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
radius: Math.round(20 * DefaultStyle.dp)
|
radius: Math.round(10 * DefaultStyle.dp)
|
||||||
backgroundColor: DefaultStyle.grey_600
|
backgroundColor: DefaultStyle.grey_600
|
||||||
backgroundOpacity: 0.8
|
backgroundOpacity: 0.8
|
||||||
overriddenWidth: Math.round(400 * DefaultStyle.dp)
|
overriddenWidth: Math.round(400 * DefaultStyle.dp)
|
||||||
|
|
@ -26,14 +26,15 @@ Notification {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
leftPadding: Math.round(18 * DefaultStyle.dp)
|
leftPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
rightPadding: Math.round(18 * DefaultStyle.dp)
|
rightPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
topPadding: Math.round(9 * DefaultStyle.dp)
|
topPadding: Math.round(32 * DefaultStyle.dp)
|
||||||
bottomPadding: Math.round(18 * DefaultStyle.dp)
|
bottomPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
background: Item{}
|
background: Item {
|
||||||
contentItem: ColumnLayout {
|
anchors.fill: parent
|
||||||
spacing: Math.round(9 * DefaultStyle.dp)
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: Math.round(9 * DefaultStyle.dp)
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
spacing: Math.round(4 * DefaultStyle.dp)
|
spacing: Math.round(4 * DefaultStyle.dp)
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Image {
|
Image {
|
||||||
Layout.preferredWidth: Math.round(12 * DefaultStyle.dp)
|
Layout.preferredWidth: Math.round(12 * DefaultStyle.dp)
|
||||||
Layout.preferredHeight: Math.round(12 * DefaultStyle.dp)
|
Layout.preferredHeight: Math.round(12 * DefaultStyle.dp)
|
||||||
|
|
@ -49,65 +50,75 @@ Notification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
Button {
|
||||||
spacing: Math.round(14 * DefaultStyle.dp)
|
anchors.top: parent.top
|
||||||
Layout.alignment: Qt.AlignHCenter
|
anchors.right: parent.right
|
||||||
Layout.fillWidth: true
|
anchors.topMargin: Math.round(9 * DefaultStyle.dp)
|
||||||
RowLayout {
|
anchors.rightMargin: Math.round(12 * DefaultStyle.dp)
|
||||||
spacing: Math.round(10 * DefaultStyle.dp)
|
padding: 0
|
||||||
Avatar {
|
z: mousearea.z + 1
|
||||||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
background: Item{anchors.fill: parent}
|
||||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
icon.source: AppIcons.closeX
|
||||||
Layout.alignment: Qt.AlignHCenter
|
width: Math.round(14 * DefaultStyle.dp)
|
||||||
property var contactObj: UtilsCpp.findFriendByAddress(mainItem.remoteAddress)
|
height: Math.round(14 * DefaultStyle.dp)
|
||||||
contact: contactObj?.value || null
|
icon.width: Math.round(14 * DefaultStyle.dp)
|
||||||
displayNameVal: contact ? "" : mainItem.avatarUri
|
icon.height: Math.round(14 * DefaultStyle.dp)
|
||||||
}
|
contentImageColor: DefaultStyle.grey_0
|
||||||
ColumnLayout {
|
onPressed: {
|
||||||
spacing: 0
|
mainItem._close()
|
||||||
Text {
|
|
||||||
text: mainItem.chatRoomName
|
|
||||||
color: DefaultStyle.main2_200
|
|
||||||
Layout.fillWidth: true
|
|
||||||
maximumLineCount: 1
|
|
||||||
font {
|
|
||||||
pixelSize: Typography.h3.pixelSize
|
|
||||||
weight: Typography.h3.weight
|
|
||||||
capitalization: Font.Capitalize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
text: mainItem.remoteAddress
|
|
||||||
color: DefaultStyle.main2_100
|
|
||||||
Layout.fillWidth: true
|
|
||||||
maximumLineCount: 1
|
|
||||||
font {
|
|
||||||
pixelSize: Typography.p1.pixelSize
|
|
||||||
weight: Typography.p1.weight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item{Layout.fillWidth: true}
|
|
||||||
}
|
}
|
||||||
Rectangle {
|
}
|
||||||
Layout.fillWidth: true
|
MouseArea {
|
||||||
|
id: mousearea
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
console.log("notif clicked, open chat")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: Math.round(9 * DefaultStyle.dp)
|
||||||
|
RowLayout {
|
||||||
|
spacing: Math.round(14 * DefaultStyle.dp)
|
||||||
|
Avatar {
|
||||||
|
Layout.preferredWidth: Math.round(60 * DefaultStyle.dp)
|
||||||
Layout.preferredHeight: Math.round(60 * DefaultStyle.dp)
|
Layout.preferredHeight: Math.round(60 * DefaultStyle.dp)
|
||||||
color: DefaultStyle.main2_400
|
// Layout.alignment: Qt.AlignHCenter
|
||||||
radius: Math.round(5 * DefaultStyle.dp)
|
property var contactObj: UtilsCpp.findFriendByAddress(mainItem.remoteAddress)
|
||||||
|
contact: contactObj?.value || null
|
||||||
|
displayNameVal: contact ? "" : mainItem.avatarUri
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
Text {
|
||||||
|
text: mainItem.chatRoomName
|
||||||
|
color: DefaultStyle.grey_100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
maximumLineCount: 1
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.h4.pixelSize
|
||||||
|
weight: Typography.h4.weight
|
||||||
|
capitalization: Font.Capitalize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: mainItem.remoteAddress
|
||||||
|
color: DefaultStyle.main2_100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
maximumLineCount: 1
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.p4.pixelSize
|
||||||
|
weight: Typography.p4.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
Text {
|
Text {
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 8 * DefaultStyle.dp
|
|
||||||
anchors.rightMargin: 8 * DefaultStyle.dp
|
|
||||||
anchors.topMargin: 8 * DefaultStyle.dp
|
|
||||||
anchors.bottomMargin: 8 * DefaultStyle.dp
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
text: mainItem.message
|
text: mainItem.message
|
||||||
|
Layout.fillWidth: true
|
||||||
maximumLineCount: 2
|
maximumLineCount: 2
|
||||||
color: DefaultStyle.grey_1000
|
color: DefaultStyle.grey_300
|
||||||
font {
|
font {
|
||||||
pixelSize: Typography.p1s.pixelSize
|
pixelSize: Typography.p1s.pixelSize
|
||||||
weight: Typography.p1s.weight
|
weight: Typography.p1s.weight
|
||||||
italic: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,10 @@ RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: Math.round(35 * DefaultStyle.dp)
|
radius: Math.round(35 * DefaultStyle.dp)
|
||||||
color: DefaultStyle.grey_0
|
color: DefaultStyle.grey_0
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onPressed: sendingTextArea.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
Flickable {
|
Flickable {
|
||||||
|
|
@ -204,6 +208,16 @@ RowLayout {
|
||||||
if (previousText === "" && text !== "") {
|
if (previousText === "" && text !== "") {
|
||||||
mainItem.chat.core.lCompose()
|
mainItem.chat.core.lCompose()
|
||||||
}
|
}
|
||||||
|
previousText = text
|
||||||
|
}
|
||||||
|
Keys.onPressed: (event) => {
|
||||||
|
event.accepted = false
|
||||||
|
if (UtilsCpp.isEmptyMessage(sendingTextArea.text)) return
|
||||||
|
if (!(event.modifiers & Qt.ControlModifier) && (event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
|
||||||
|
mainItem.chat.core.lSendTextMessage(sendingTextArea.text)
|
||||||
|
sendingTextArea.clear()
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ AbstractMainPage {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.rightMargin: Math.round(39 * DefaultStyle.dp)
|
anchors.rightMargin: Math.round(39 * DefaultStyle.dp)
|
||||||
Text {
|
Text {
|
||||||
visible: chatListView.count === 0
|
visible: chatListView.count === 0 && chatListView.loading === false
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.topMargin: Math.round(137 * DefaultStyle.dp)
|
Layout.topMargin: Math.round(137 * DefaultStyle.dp)
|
||||||
//: "Aucun résultat…"
|
//: "Aucun résultat…"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ QtObject {
|
||||||
property string profile: "image://internal/user-circle.svg"
|
property string profile: "image://internal/user-circle.svg"
|
||||||
property string manageProfile: "image://internal/user-circle-gear.svg"
|
property string manageProfile: "image://internal/user-circle-gear.svg"
|
||||||
property string verif_page_image: "image://internal/verif_page_image.svg"
|
property string verif_page_image: "image://internal/verif_page_image.svg"
|
||||||
|
property string envelope: "image://internal/envelope-simple.svg"
|
||||||
property string check: "image://internal/check.svg"
|
property string check: "image://internal/check.svg"
|
||||||
|
property string checks: "image://internal/checks.svg"
|
||||||
property string dialer: "image://internal/numpad.svg"
|
property string dialer: "image://internal/numpad.svg"
|
||||||
property string chiffrement: "image://internal/chiffrement.svg"
|
property string chiffrement: "image://internal/chiffrement.svg"
|
||||||
property string interoperable: "image://internal/interoperable.svg"
|
property string interoperable: "image://internal/interoperable.svg"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue