mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-02-01 19:59:24 +00:00
mentions
This commit is contained in:
parent
a7e39ab276
commit
de6d62021a
33 changed files with 566 additions and 98 deletions
|
|
@ -73,6 +73,7 @@
|
|||
#include "core/notifier/Notifier.hpp"
|
||||
#include "core/participant/ParticipantDeviceProxy.hpp"
|
||||
#include "core/participant/ParticipantGui.hpp"
|
||||
#include "core/participant/ParticipantInfoProxy.hpp"
|
||||
#include "core/participant/ParticipantProxy.hpp"
|
||||
#include "core/payload-type/PayloadTypeCore.hpp"
|
||||
#include "core/payload-type/PayloadTypeGui.hpp"
|
||||
|
|
@ -652,6 +653,7 @@ void App::initCppInterfaces() {
|
|||
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
|
||||
qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList");
|
||||
|
||||
qmlRegisterType<ParticipantInfoProxy>(Constants::MainQmlUri, 1, 0, "ParticipantInfoProxy");
|
||||
qmlRegisterType<ParticipantProxy>(Constants::MainQmlUri, 1, 0, "ParticipantProxy");
|
||||
qmlRegisterType<ParticipantGui>(Constants::MainQmlUri, 1, 0, "ParticipantGui");
|
||||
qmlRegisterType<ConferenceInfoProxy>(Constants::MainQmlUri, 1, 0, "ConferenceInfoProxy");
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/participant/ParticipantDeviceProxy.cpp
|
||||
core/participant/ParticipantList.cpp
|
||||
core/participant/ParticipantProxy.cpp
|
||||
core/participant/ParticipantInfoList.cpp
|
||||
core/participant/ParticipantInfoProxy.cpp
|
||||
|
||||
core/screen/ScreenList.cpp
|
||||
core/screen/ScreenProxy.cpp
|
||||
|
|
|
|||
|
|
@ -593,3 +593,7 @@ ChatCore::buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom)
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ParticipantCore>> ChatCore::getParticipants() const {
|
||||
return mParticipants;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ public:
|
|||
std::shared_ptr<ChatModel> getModel() const;
|
||||
|
||||
QList<QSharedPointer<ParticipantCore>> buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const;
|
||||
QList<QSharedPointer<ParticipantCore>> getParticipants() const;
|
||||
QVariantList getParticipantsGui() const;
|
||||
QStringList getParticipantsAddresses() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
|
|||
auto replymessage = chatmessage->getReplyMessage();
|
||||
if (replymessage) {
|
||||
mReplyText = ToolModel::getMessageFromContent(replymessage->getContents());
|
||||
if (mIsFromChatGroup) mRepliedToName = ToolModel::getDisplayName(replymessage->getToAddress()->clone());
|
||||
if (mIsFromChatGroup) mRepliedToName = ToolModel::getDisplayName(replymessage->getFromAddress()->clone());
|
||||
}
|
||||
}
|
||||
mImdnStatusList = computeDeliveryStatus(chatmessage);
|
||||
|
|
@ -305,7 +305,10 @@ void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
|
|||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::participantImdnStateChanged,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<const linphone::ParticipantImdnState> &state) {});
|
||||
const std::shared_ptr<const linphone::ParticipantImdnState> &state) {
|
||||
auto imdnStatusList = computeDeliveryStatus(message);
|
||||
mChatMessageModelConnection->invokeToCore([this, imdnStatusList] { setImdnStatusList(imdnStatusList); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::ephemeralMessageTimerStarted,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message) {});
|
||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::ephemeralMessageDeleted,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ ImdnStatusList::ImdnStatusList(QObject *parent) : AbstractListProxy<ImdnStatus>(
|
|||
|
||||
ImdnStatusList::~ImdnStatusList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
QList<ImdnStatus> ImdnStatusList::getImdnStatusList() {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ signals:
|
|||
void imdnStatusListChanged();
|
||||
|
||||
private:
|
||||
QList<ImdnStatus> mImdnStatuss;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -551,6 +551,10 @@ void ConferenceInfoCore::writeIntoModel(std::shared_ptr<ConferenceInfoModel> mod
|
|||
model->setParticipantInfos(participantInfos);
|
||||
}
|
||||
|
||||
std::shared_ptr<ConferenceInfoModel> ConferenceInfoCore::getModel() const {
|
||||
return mConferenceInfoModel;
|
||||
}
|
||||
|
||||
void ConferenceInfoCore::save() {
|
||||
mustBeInMainThread(getClassName() + "::save()");
|
||||
ConferenceInfoCore *thisCopy = new ConferenceInfoCore(*this); // Pointer to avoid multiple copies in lambdas
|
||||
|
|
@ -571,8 +575,8 @@ void ConferenceInfoCore::save() {
|
|||
linphone::RegistrationState::Ok) {
|
||||
//: "Erreur"
|
||||
Utils::showInformationPopup(tr("information_popup_error_title"),
|
||||
//: "Votre compte est déconnecté"
|
||||
tr("information_popup_disconnected_account_message"), false);
|
||||
//: "Votre compte est déconnecté"
|
||||
tr("information_popup_disconnected_account_message"), false);
|
||||
emit saveFailed();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ public:
|
|||
void writeFromModel(const std::shared_ptr<ConferenceInfoModel> &model);
|
||||
void writeIntoModel(std::shared_ptr<ConferenceInfoModel> model);
|
||||
|
||||
std::shared_ptr<ConferenceInfoModel> getModel() const;
|
||||
|
||||
Q_INVOKABLE void save();
|
||||
Q_INVOKABLE void undo();
|
||||
Q_INVOKABLE void cancelCreation();
|
||||
|
|
|
|||
|
|
@ -46,11 +46,13 @@ ParticipantCore::ParticipantCore(const std::shared_ptr<linphone::Participant> &p
|
|||
mParticipantModel->moveToThread(CoreModel::getInstance()->thread());
|
||||
if (participant) {
|
||||
mAdminStatus = participant->isAdmin();
|
||||
mSipAddress = Utils::coreStringToAppString(participant->getAddress()->asStringUriOnly());
|
||||
auto participantAddress = participant->getAddress();
|
||||
mUsername = Utils::coreStringToAppString(participantAddress->getUsername());
|
||||
mSipAddress = Utils::coreStringToAppString(participantAddress->asStringUriOnly());
|
||||
mIsMe = ToolModel::isMe(mSipAddress);
|
||||
mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime());
|
||||
mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getDisplayName());
|
||||
if (mDisplayName.isEmpty()) mDisplayName = ToolModel::getDisplayName(participant->getAddress()->clone());
|
||||
mDisplayName = Utils::coreStringToAppString(participantAddress->getDisplayName());
|
||||
if (mDisplayName.isEmpty()) mDisplayName = ToolModel::getDisplayName(participantAddress->clone());
|
||||
for (auto &device : participant->getDevices()) {
|
||||
auto name = Utils::coreStringToAppString(device->getName());
|
||||
auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly());
|
||||
|
|
@ -120,6 +122,17 @@ QString ParticipantCore::getDisplayName() const {
|
|||
return mDisplayName;
|
||||
}
|
||||
|
||||
void ParticipantCore::setUsername(const QString &name) {
|
||||
if (mUsername != name) {
|
||||
mUsername = name;
|
||||
emit usernameChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ParticipantCore::getUsername() const {
|
||||
return mUsername;
|
||||
}
|
||||
|
||||
QDateTime ParticipantCore::getCreationTime() const {
|
||||
return mCreationTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ParticipantCore : public QObject, public AbstractObject {
|
|||
|
||||
Q_PROPERTY(QString sipAddress READ getSipAddress WRITE setSipAddress NOTIFY sipAddressChanged)
|
||||
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QString username READ getUsername WRITE setUsername NOTIFY usernameChanged)
|
||||
Q_PROPERTY(bool isAdmin READ isAdmin WRITE setIsAdmin NOTIFY isAdminChanged)
|
||||
Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged)
|
||||
Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT)
|
||||
|
|
@ -56,6 +57,7 @@ public:
|
|||
void setSelf(QSharedPointer<ParticipantCore> me);
|
||||
|
||||
QString getDisplayName() const;
|
||||
QString getUsername() const;
|
||||
QString getSipAddress() const;
|
||||
QDateTime getCreationTime() const;
|
||||
bool isAdmin() const;
|
||||
|
|
@ -69,6 +71,7 @@ public:
|
|||
|
||||
void setSipAddress(const QString &address);
|
||||
void setDisplayName(const QString &name);
|
||||
void setUsername(const QString &name);
|
||||
void setCreationTime(const QDateTime &date);
|
||||
void setIsAdmin(const bool &status);
|
||||
void setIsFocus(const bool &focus);
|
||||
|
|
@ -92,6 +95,7 @@ signals:
|
|||
void invitingChanged();
|
||||
void creationTimeChanged();
|
||||
void displayNameChanged();
|
||||
void usernameChanged();
|
||||
|
||||
void lStartInvitation(const int &secs = 30);
|
||||
void lSetIsAdmin(bool status);
|
||||
|
|
@ -107,6 +111,7 @@ private:
|
|||
QList<QVariant> mParticipantDevices;
|
||||
|
||||
QString mDisplayName;
|
||||
QString mUsername;
|
||||
QString mSipAddress;
|
||||
QDateTime mCreationTime;
|
||||
bool mAdminStatus;
|
||||
|
|
|
|||
74
Linphone/core/participant/ParticipantInfoList.cpp
Normal file
74
Linphone/core/participant/ParticipantInfoList.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 "ParticipantInfoList.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "core/participant/ParticipantGui.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ParticipantInfoList)
|
||||
|
||||
QSharedPointer<ParticipantInfoList> ParticipantInfoList::create() {
|
||||
auto model = QSharedPointer<ParticipantInfoList>(new ParticipantInfoList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
return model;
|
||||
}
|
||||
|
||||
QSharedPointer<ParticipantInfoList> ParticipantInfoList::create(const QSharedPointer<ChatCore> &chatCore) {
|
||||
auto model = create();
|
||||
model->setChatCore(chatCore);
|
||||
return model;
|
||||
}
|
||||
|
||||
ParticipantInfoList::ParticipantInfoList(QObject *parent) : ListProxy(parent) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
ParticipantInfoList::~ParticipantInfoList() {
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
void ParticipantInfoList::setChatCore(const QSharedPointer<ChatCore> &chatCore) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mChatCore) disconnect(mChatCore.get());
|
||||
mChatCore = chatCore;
|
||||
lDebug() << "[ParticipantInfoList] : set Chat " << mChatCore.get();
|
||||
clearData();
|
||||
if (mChatCore) {
|
||||
auto buildList = [this] {
|
||||
QStringList participantAddresses;
|
||||
QList<QSharedPointer<ParticipantGui>> participantList;
|
||||
auto participants = mChatCore->getParticipants();
|
||||
resetData<ParticipantCore>(participants);
|
||||
};
|
||||
connect(mChatCore.get(), &ChatCore::participantsChanged, this, buildList);
|
||||
buildList();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant ParticipantInfoList::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(new ParticipantGui(mList[row].objectCast<ParticipantCore>()));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
51
Linphone/core/participant/ParticipantInfoList.hpp
Normal file
51
Linphone/core/participant/ParticipantInfoList.hpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 PARTICIPANT_INFO_LIST_H_
|
||||
#define PARTICIPANT_INFO_LIST_H_
|
||||
|
||||
#include "../proxy/ListProxy.hpp"
|
||||
#include "model/chat/ChatModel.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
class ChatCore;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ParticipantInfoList : public ListProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QSharedPointer<ParticipantInfoList> create();
|
||||
static QSharedPointer<ParticipantInfoList> create(const QSharedPointer<ChatCore> &chatCore);
|
||||
|
||||
ParticipantInfoList(QObject *parent = Q_NULLPTR);
|
||||
virtual ~ParticipantInfoList();
|
||||
|
||||
void setChatCore(const QSharedPointer<ChatCore> &chatCore);
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void lUpdateParticipants();
|
||||
|
||||
private:
|
||||
QSharedPointer<ChatCore> mChatCore;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
#endif // PARTICIPANT_INFO_LIST_H_
|
||||
63
Linphone/core/participant/ParticipantInfoProxy.cpp
Normal file
63
Linphone/core/participant/ParticipantInfoProxy.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 "ParticipantInfoProxy.hpp"
|
||||
#include "ParticipantInfoList.hpp"
|
||||
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ParticipantInfoProxy)
|
||||
|
||||
ParticipantInfoProxy::ParticipantInfoProxy(QObject *parent) : LimitProxy(parent) {
|
||||
mParticipants = ParticipantInfoList::create();
|
||||
setSourceModels(new SortFilterList(mParticipants.get(), Qt::AscendingOrder));
|
||||
}
|
||||
|
||||
ParticipantInfoProxy::~ParticipantInfoProxy() {
|
||||
}
|
||||
|
||||
ChatGui *ParticipantInfoProxy::getChat() const {
|
||||
return mChat;
|
||||
}
|
||||
|
||||
void ParticipantInfoProxy::setChat(ChatGui *chat) {
|
||||
lDebug() << "[ParticipantInfoProxy] set current chat " << this << " => " << chat;
|
||||
if (mChat != chat) {
|
||||
mChat = chat;
|
||||
mParticipants->setChatCore(chat ? chat->mCore : nullptr);
|
||||
emit chatChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool ParticipantInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParticipantInfoProxy::SortFilterList::lessThan(const QModelIndex &left, const QModelIndex &right) const {
|
||||
return true;
|
||||
}
|
||||
59
Linphone/core/participant/ParticipantInfoProxy.hpp
Normal file
59
Linphone/core/participant/ParticipantInfoProxy.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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_INFO_PROXY_H_
|
||||
#define PARTICIPANT_INFO_PROXY_H_
|
||||
|
||||
#include "../proxy/LimitProxy.hpp"
|
||||
#include "core/chat/ChatGui.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class ParticipantInfoList;
|
||||
class ChatModel;
|
||||
// =============================================================================
|
||||
|
||||
class QWindow;
|
||||
|
||||
class ParticipantInfoProxy : public LimitProxy, public AbstractObject {
|
||||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ChatGui *chat READ getChat WRITE setChat NOTIFY chatChanged)
|
||||
|
||||
public:
|
||||
DECLARE_SORTFILTER_CLASS(bool mShowMe;)
|
||||
|
||||
ParticipantInfoProxy(QObject *parent = Q_NULLPTR);
|
||||
~ParticipantInfoProxy();
|
||||
|
||||
ChatGui *getChat() const;
|
||||
void setChat(ChatGui *chatGui);
|
||||
|
||||
signals:
|
||||
void chatChanged();
|
||||
|
||||
private:
|
||||
ChatGui *mChat = nullptr;
|
||||
QSharedPointer<ParticipantInfoList> mParticipants;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif // PARTICIPANT_INFO_PROXY_H_
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include "ParticipantList.hpp"
|
||||
#include "core/participant/ParticipantCore.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
|
|
|||
|
|
@ -115,24 +115,8 @@ 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);
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +168,6 @@ void ChatMessageModel::onFileTransferProgressIndication(const std::shared_ptr<li
|
|||
void ChatMessageModel::onParticipantImdnStateChanged(
|
||||
const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<const linphone::ParticipantImdnState> &state) {
|
||||
computeDeliveryStatus();
|
||||
emit participantImdnStateChanged(message, state);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ public:
|
|||
|
||||
void deleteMessageFromChatRoom();
|
||||
|
||||
void computeDeliveryStatus();
|
||||
|
||||
void sendReaction(const QString &reaction);
|
||||
|
||||
void removeReaction();
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ QVector<QPair<bool, QString>> UriTools::parseUri(const QString &text) {
|
|||
return parse(text, gUriTools.mUriRegularExpression);
|
||||
}
|
||||
|
||||
QVector<QPair<bool, QString>> UriTools::parseMention(const QString &text) {
|
||||
return parse(text, gUriTools.mMentionRegularExpression);
|
||||
}
|
||||
|
||||
// Parse a text and return all lines where regex is matched or not
|
||||
QVector<QPair<bool, QString>> UriTools::parse(const QString &text, const QRegularExpression regex) {
|
||||
QVector<QPair<bool, QString>> results;
|
||||
|
|
@ -200,4 +204,6 @@ void UriTools::initRegularExpressions() {
|
|||
QRegularExpression::UseUnicodePropertiesOption);
|
||||
mUriRegularExpression = QRegularExpression(URI, QRegularExpression::CaseInsensitiveOption |
|
||||
QRegularExpression::UseUnicodePropertiesOption);
|
||||
}
|
||||
mMentionRegularExpression = QRegularExpression(
|
||||
"@[A-Za-z0-9.-_]+", QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption);
|
||||
}
|
||||
|
|
@ -41,14 +41,16 @@ public:
|
|||
|
||||
static QVector<QPair<bool, QString>> parseIri(const QString &text);
|
||||
static QVector<QPair<bool, QString>> parseUri(const QString &text);
|
||||
static QVector<QPair<bool, QString>> parseMention(const QString &text);
|
||||
static QRegularExpression getRegularExpression();
|
||||
|
||||
private:
|
||||
void initRegularExpressions();
|
||||
static QVector<QPair<bool, QString>> parse(const QString &text, const QRegularExpression regex);
|
||||
|
||||
QRegularExpression mIriRegularExpression; // https://tools.ietf.org/html/rfc3987
|
||||
QRegularExpression mUriRegularExpression; // https://tools.ietf.org/html/rfc3986
|
||||
QRegularExpression mIriRegularExpression; // https://tools.ietf.org/html/rfc3987
|
||||
QRegularExpression mUriRegularExpression; // https://tools.ietf.org/html/rfc3986
|
||||
QRegularExpression mMentionRegularExpression; // https://tools.ietf.org/html/rfc3986
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1798,64 +1798,111 @@ QString Utils::getPresenceStatus(LinphoneEnums::Presence presence) {
|
|||
return presenceStatus;
|
||||
}
|
||||
|
||||
QString Utils::encodeTextToQmlRichFormat(const QString &text, const QVariantMap &options) {
|
||||
VariantObject *Utils::encodeTextToQmlRichFormat(const QString &text, const QVariantMap &options, ChatGui *chat) {
|
||||
/*QString images;
|
||||
QStringList imageFormat;
|
||||
for(auto format : QImageReader::supportedImageFormats())
|
||||
imageFormat.append(QString::fromLatin1(format).toUpper());
|
||||
*/
|
||||
QStringList formattedText;
|
||||
bool lastWasUrl = false;
|
||||
*/
|
||||
VariantObject *data = new VariantObject("encodeTextToQmlRichFormat");
|
||||
if (!data) return nullptr;
|
||||
auto primaryColor = getDefaultStyleColor("info_500_main");
|
||||
data->makeRequest([text, options, chat, primaryColor] {
|
||||
QStringList formattedText;
|
||||
bool lastWasUrl = false;
|
||||
|
||||
if (options.contains("noLink") && options["noLink"].toBool()) {
|
||||
formattedText.append(encodeEmojiToQmlRichFormat(text));
|
||||
} else {
|
||||
auto primaryColor = getDefaultStyleColor("info_500_main");
|
||||
auto iriParsed = UriTools::parseIri(text);
|
||||
if (options.contains("noLink") && options["noLink"].toBool()) {
|
||||
formattedText.append(encodeEmojiToQmlRichFormat(text));
|
||||
} else {
|
||||
|
||||
for (int i = 0; i < iriParsed.size(); ++i) {
|
||||
QString iri = iriParsed[i]
|
||||
.second.replace('&', "&")
|
||||
.replace('<', "\u2063<")
|
||||
.replace('>', "\u2063>")
|
||||
.replace('"', """)
|
||||
.replace('\'', "'");
|
||||
if (!iriParsed[i].first) {
|
||||
if (lastWasUrl) {
|
||||
lastWasUrl = false;
|
||||
if (iri.front() != ' ') iri.push_front(' ');
|
||||
auto iriParsed = UriTools::parseIri(text);
|
||||
|
||||
for (int i = 0; i < iriParsed.size(); ++i) {
|
||||
QString iri = iriParsed[i]
|
||||
.second.replace('&', "&")
|
||||
.replace('<', "\u2063<")
|
||||
.replace('>', "\u2063>")
|
||||
.replace('"', """)
|
||||
.replace('\'', "'");
|
||||
if (!iriParsed[i].first) {
|
||||
if (lastWasUrl) {
|
||||
lastWasUrl = false;
|
||||
if (iri.front() != ' ') iri.push_front(' ');
|
||||
}
|
||||
formattedText.append(encodeEmojiToQmlRichFormat(iri));
|
||||
} else {
|
||||
QString uri =
|
||||
iriParsed[i].second.left(3) == "www" ? "http://" + iriParsed[i].second : iriParsed[i].second;
|
||||
/* TODO : preview from link
|
||||
int extIndex = iriParsed[i].second.lastIndexOf('.');
|
||||
QString ext;
|
||||
if( extIndex >= 0)
|
||||
ext = iriParsed[i].second.mid(extIndex+1).toUpper();
|
||||
if(imageFormat.contains(ext.toLatin1())){// imagesHeight is not used because of bugs on display
|
||||
(blank image if set without width) images += "<a href=\"" + uri + "\"><img" + (
|
||||
options.contains("imagesWidth") ? QString(" width='") + options["imagesWidth"].toString() + "'" : ""
|
||||
) + (
|
||||
options.contains("imagesWidth")
|
||||
? QString(" height='auto'")
|
||||
: ""
|
||||
) + " src=\"" + iriParsed[i].second + "\" />"+uri+"</a>";
|
||||
}else{
|
||||
*/
|
||||
formattedText.append("<a style=\"color:" + primaryColor.name() + ";\" href=\"" + uri + "\">" + iri +
|
||||
"</a>");
|
||||
lastWasUrl = true;
|
||||
/*}*/
|
||||
}
|
||||
formattedText.append(encodeEmojiToQmlRichFormat(iri));
|
||||
} else {
|
||||
QString uri =
|
||||
iriParsed[i].second.left(3) == "www" ? "http://" + iriParsed[i].second : iriParsed[i].second;
|
||||
/* TODO : preview from link
|
||||
int extIndex = iriParsed[i].second.lastIndexOf('.');
|
||||
QString ext;
|
||||
if( extIndex >= 0)
|
||||
ext = iriParsed[i].second.mid(extIndex+1).toUpper();
|
||||
if(imageFormat.contains(ext.toLatin1())){// imagesHeight is not used because of bugs on display (blank
|
||||
image if set without width) images += "<a href=\"" + uri + "\"><img" + ( options.contains("imagesWidth")
|
||||
? QString(" width='") + options["imagesWidth"].toString() + "'"
|
||||
: ""
|
||||
) + (
|
||||
options.contains("imagesWidth")
|
||||
? QString(" height='auto'")
|
||||
: ""
|
||||
) + " src=\"" + iriParsed[i].second + "\" />"+uri+"</a>";
|
||||
}else{
|
||||
*/
|
||||
formattedText.append("<a style=\"color:" + primaryColor.name() + ";\" href=\"" + uri + "\">" + iri +
|
||||
"</a>");
|
||||
lastWasUrl = true;
|
||||
/*}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastWasUrl && formattedText.last().back() != ' ') {
|
||||
formattedText.push_back(" ");
|
||||
}
|
||||
return "<p style=\"white-space:pre-wrap;\">" + formattedText.join("");
|
||||
if (lastWasUrl && formattedText.last().back() != ' ') {
|
||||
formattedText.push_back(" ");
|
||||
}
|
||||
if (chat && chat->mCore) {
|
||||
auto participants = chat->mCore->getParticipants();
|
||||
auto mentionsParsed = UriTools::parseMention(formattedText.join(""));
|
||||
formattedText.clear();
|
||||
|
||||
for (int i = 0; i < mentionsParsed.size(); ++i) {
|
||||
QString mention = mentionsParsed[i].second;
|
||||
|
||||
if (mentionsParsed[i].first) {
|
||||
QString mentions = mentionsParsed[i].second;
|
||||
QStringList finalMentions;
|
||||
QStringList parts = mentions.split(" ");
|
||||
for (auto part : parts) {
|
||||
if (part.startsWith("@")) { // mention
|
||||
QString username = part;
|
||||
username.removeFirst();
|
||||
auto it = std::find_if(
|
||||
participants.begin(), participants.end(),
|
||||
[username](QSharedPointer<ParticipantCore> p) { return username == p->getUsername(); });
|
||||
if (it != participants.end()) {
|
||||
auto foundParticipant = participants.at(std::distance(participants.begin(), it));
|
||||
auto address = foundParticipant->getSipAddress();
|
||||
auto isFriend = ToolModel::findFriendByAddress(address);
|
||||
if (isFriend)
|
||||
part = "@" + Utils::coreStringToAppString(isFriend->getAddress()->getDisplayName());
|
||||
QString participantLink = "<a style=\"color:" + primaryColor.name() +
|
||||
";\" href=\"mention:" + address + "\">" + part + "</a>";
|
||||
finalMentions.append(participantLink);
|
||||
} else {
|
||||
finalMentions.append(part);
|
||||
}
|
||||
} else {
|
||||
finalMentions.append(part);
|
||||
}
|
||||
}
|
||||
formattedText.push_back(finalMentions.join(" "));
|
||||
} else {
|
||||
formattedText.push_back(mentionsParsed[i].second);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "<p style=\"white-space:pre-wrap;\">" + formattedText.join("");
|
||||
});
|
||||
data->requestValue();
|
||||
return data;
|
||||
}
|
||||
|
||||
QString Utils::encodeEmojiToQmlRichFormat(const QString &body) {
|
||||
|
|
@ -1896,6 +1943,24 @@ bool Utils::isOnlyEmojis(const QString &text) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Utils::openContactAtAddress(const QString &address) {
|
||||
App::postModelAsync([address] {
|
||||
auto isFriend = ToolModel::findFriendByAddress(address);
|
||||
if (isFriend) {
|
||||
App::postCoreAsync([address] {
|
||||
auto window = getMainWindow();
|
||||
QMetaObject::invokeMethod(window, "displayContactPage", Q_ARG(QVariant, address));
|
||||
});
|
||||
} else {
|
||||
App::postCoreAsync([address] {
|
||||
auto window = getMainWindow();
|
||||
QMetaObject::invokeMethod(window, "displayCreateContactPage", Q_ARG(QVariant, ""),
|
||||
Q_ARG(QVariant, address));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString Utils::getFilename(QUrl url) {
|
||||
return url.fileName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,10 +154,11 @@ public:
|
|||
Q_INVOKABLE static VariantObject *createGroupChat(QString subject, QStringList participantAddresses);
|
||||
Q_INVOKABLE static void openChat(ChatGui *chat);
|
||||
Q_INVOKABLE static bool isEmptyMessage(QString message);
|
||||
Q_INVOKABLE static QString encodeTextToQmlRichFormat(const QString &text,
|
||||
const QVariantMap &options = QVariantMap());
|
||||
Q_INVOKABLE static VariantObject *
|
||||
encodeTextToQmlRichFormat(const QString &text, const QVariantMap &options = QVariantMap(), ChatGui *chat = nullptr);
|
||||
Q_INVOKABLE static QString encodeEmojiToQmlRichFormat(const QString &body);
|
||||
Q_INVOKABLE static bool isOnlyEmojis(const QString &text);
|
||||
Q_INVOKABLE static void openContactAtAddress(const QString &address);
|
||||
|
||||
Q_INVOKABLE static QString getFilename(QUrl url);
|
||||
static bool codepointIsEmoji(uint code);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Control/Display/Contact/Voicemail.qml
|
||||
view/Control/Display/Meeting/MeetingListView.qml
|
||||
view/Control/Display/Participant/ParticipantDeviceListView.qml
|
||||
view/Control/Display/Participant/ParticipantInfoListView.qml
|
||||
view/Control/Display/Participant/ParticipantListView.qml
|
||||
view/Control/Display/Settings/SettingsMenuItem.qml
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Control.Control {
|
|||
property bool isFirstMessage
|
||||
|
||||
property ChatMessageGui chatMessage
|
||||
property ChatGui chat
|
||||
property string ownReaction: chatMessage? chatMessage.core.ownReaction : ""
|
||||
property string fromAddress: chatMessage? chatMessage.core.fromAddress : ""
|
||||
property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false
|
||||
|
|
@ -140,7 +141,6 @@ Control.Control {
|
|||
Layout.preferredWidth: mainItem.isRemoteMessage ? 26 * DefaultStyle.dp : 0
|
||||
Layout.preferredHeight: 26 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0
|
||||
_address: chatMessage ? chatMessage.core.fromAddress : ""
|
||||
}
|
||||
Item {
|
||||
|
|
@ -197,6 +197,7 @@ Control.Control {
|
|||
id: chatBubbleContent
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
chatGui: mainItem.chat
|
||||
chatMessageGui: mainItem.chatMessage
|
||||
onMouseEvent: (event) => {
|
||||
mainItem.handleDefaultMouseEvent(event)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import Linphone
|
|||
ColumnLayout {
|
||||
id: mainItem
|
||||
property ChatMessageGui chatMessageGui: null
|
||||
property ChatGui chatGui: null
|
||||
|
||||
signal isFileHoveringChanged(bool isFileHovering)
|
||||
signal lastSelectedTextChanged(string selectedText)
|
||||
|
|
@ -88,6 +89,7 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
// height: implicitHeight
|
||||
contentGui: modelData
|
||||
chatGui: mainItem.chatGui
|
||||
onLastTextSelectedChanged: mainItem.selectedText = selectedText
|
||||
// onRightClicked: mainItem.rightClicked()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,13 +202,14 @@ Rectangle {
|
|||
}
|
||||
|
||||
Text {
|
||||
text: UtilsCpp.encodeTextToQmlRichFormat(conferenceInfo.description)
|
||||
property var encodeTextObj: UtilsCpp.encodeTextToQmlRichFormat(conferenceInfo.description)
|
||||
text: encodeTextObj? encodeTextObj.value : ""
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.RichText
|
||||
font: Typography.p4
|
||||
color: DefaultStyle.main2_500main
|
||||
visible: conferenceInfo.description.length > 0
|
||||
onLinkActivated: {
|
||||
onLinkActivated: (link) => {
|
||||
if (link.startsWith('sip'))
|
||||
UtilsCpp.createCall(link)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ ListView {
|
|||
delegate:
|
||||
ChatMessage {
|
||||
chatMessage: modelData
|
||||
chat: mainItem.chat
|
||||
maxWidth: Math.round(mainItem.width * (3/4))
|
||||
onVisibleChanged: {
|
||||
if (visible && !modelData.core.isRead) modelData.core.lMarkAsRead()
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ import UtilsCpp
|
|||
// TODO : into Loader
|
||||
// =============================================================================
|
||||
TextEdit {
|
||||
id: message
|
||||
id: mainItem
|
||||
property ChatMessageContentGui contentGui
|
||||
property ChatGui chatGui: null
|
||||
property string lastTextSelected : ''
|
||||
color: DefaultStyle.main2_700
|
||||
font {
|
||||
|
|
@ -24,15 +25,19 @@ TextEdit {
|
|||
readOnly: true
|
||||
selectByMouse: true
|
||||
|
||||
text: visible ? UtilsCpp.encodeTextToQmlRichFormat(contentGui.core.utf8Text)
|
||||
property var encodeTextObj: visible ? UtilsCpp.encodeTextToQmlRichFormat(contentGui.core.utf8Text, {}, mainItem.chatGui)
|
||||
: ''
|
||||
|
||||
text: encodeTextObj ? encodeTextObj.value : ""
|
||||
textFormat: Text.RichText // To supports links and imgs.
|
||||
wrapMode: TextEdit.Wrap
|
||||
|
||||
onLinkActivated: (link) => {
|
||||
if (link.startsWith('sip'))
|
||||
UtilsCpp.createCall(link)
|
||||
else if (link.startsWith('mention:')) {
|
||||
var mentionAddress = link.substring(8) // remove "mention:"
|
||||
UtilsCpp.openContactAtAddress(mentionAddress);
|
||||
}
|
||||
else
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Linphone
|
||||
import UtilsCpp
|
||||
|
||||
ListView {
|
||||
id: mainItem
|
||||
clip: true
|
||||
spacing: Math.round(5 * DefaultStyle.dp)
|
||||
|
||||
property bool hoverEnabled: true
|
||||
property bool displayNameCapitalization: true
|
||||
|
||||
property ChatGui chatGui
|
||||
height: contentHeight
|
||||
|
||||
signal participantClicked(string username)
|
||||
|
||||
currentIndex: -1
|
||||
|
||||
model: ParticipantInfoProxy {
|
||||
id: participantModel
|
||||
chat: mainItem.chatGui
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: participantDelegate
|
||||
height: Math.round(56 * DefaultStyle.dp)
|
||||
width: mainItem.width//mainItem.width
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Math.round(18 * DefaultStyle.dp)
|
||||
anchors.rightMargin: Math.round(18 * DefaultStyle.dp)
|
||||
spacing: Math.round(10 * DefaultStyle.dp)
|
||||
Avatar {
|
||||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData.core.sipAddress
|
||||
shadowEnabled: false
|
||||
}
|
||||
Text {
|
||||
text: modelData.core.displayName
|
||||
font.pixelSize: Math.round(14 * DefaultStyle.dp)
|
||||
font.capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Item{Layout.fillWidth: true}
|
||||
}
|
||||
MouseArea {
|
||||
id: mousearea
|
||||
anchors.fill: parent
|
||||
onClicked: mainItem.participantClicked(modelData.core.username)
|
||||
hoverEnabled: true
|
||||
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: mousearea.containsMouse
|
||||
color: DefaultStyle.main2_200
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,8 +138,13 @@ Control.Control {
|
|||
width: sendingAreaFlickable.width
|
||||
height: sendingAreaFlickable.height
|
||||
textFormat: TextEdit.AutoText
|
||||
onTextChanged: mainItem.text = text
|
||||
Component.onCompleted: mainItem.textArea = sendingTextArea
|
||||
onTextChanged: {
|
||||
mainItem.text = text
|
||||
}
|
||||
Component.onCompleted: {
|
||||
mainItem.textArea = sendingTextArea
|
||||
sendingTextArea.text = mainItem.text
|
||||
}
|
||||
//: Say something… : placeholder text for sending message text area
|
||||
placeholderText: qsTr("chat_view_send_area_placeholder_text")
|
||||
placeholderTextColor: DefaultStyle.main2_400
|
||||
|
|
@ -160,7 +165,7 @@ Control.Control {
|
|||
Connections {
|
||||
target: mainItem
|
||||
function onTextChanged() {
|
||||
if (mainItem.text !== text) text = mainItem.text
|
||||
sendingTextArea.text = mainItem.text
|
||||
}
|
||||
function onSendMessage() {
|
||||
sendingTextArea.clear()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ TextEdit {
|
|||
activeFocusOnTab: true
|
||||
|
||||
property bool displayAsRichText: false
|
||||
property string richFormatText: UtilsCpp.encodeTextToQmlRichFormat(text)
|
||||
property var encodeTextObj: UtilsCpp.encodeTextToQmlRichFormat(text)
|
||||
property string richFormatText: encodeTextObj && encodeTextObj.value || ""
|
||||
property color textAreaColor
|
||||
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ TextEdit {
|
|||
}
|
||||
|
||||
onTextChanged: {
|
||||
richFormatText = UtilsCpp.encodeTextToQmlRichFormat(text)
|
||||
encodeTextObj = UtilsCpp.encodeTextToQmlRichFormat(text)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
|
|
|||
|
|
@ -210,6 +210,54 @@ RowLayout {
|
|||
anchors.rightMargin: Math.round(5 * DefaultStyle.dp)
|
||||
policy: Control.ScrollBar.AsNeeded
|
||||
}
|
||||
Control.Control {
|
||||
id: participantListPopup
|
||||
width: parent.width
|
||||
height: Math.min(contentItem.height, Math.round(200 * DefaultStyle.dp))
|
||||
visible: false
|
||||
anchors.bottom: chatMessagesListView.bottom
|
||||
anchors.left: chatMessagesListView.left
|
||||
anchors.right: chatMessagesListView.right
|
||||
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: participantBg
|
||||
color: DefaultStyle.grey_0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
radius: Math.round(20 * DefaultStyle.dp)
|
||||
height: parent.height
|
||||
}
|
||||
MultiEffect {
|
||||
anchors.fill: participantBg
|
||||
source: participantBg
|
||||
shadowEnabled: true
|
||||
shadowBlur: 0.5
|
||||
shadowColor: DefaultStyle.grey_1000
|
||||
shadowOpacity: 0.3
|
||||
}
|
||||
Rectangle {
|
||||
id: bg
|
||||
color: DefaultStyle.grey_0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: parent.height/2
|
||||
}
|
||||
}
|
||||
contentItem: ParticipantInfoListView {
|
||||
id: participantInfoList
|
||||
height: contentHeight
|
||||
width: participantListPopup.width
|
||||
chatGui: mainItem.chat
|
||||
onParticipantClicked: (username) => {
|
||||
messageSender.text = messageSender.text + username + " "
|
||||
messageSender.textArea.cursorPosition = messageSender.text.length
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Control.Control {
|
||||
id: selectedFilesArea
|
||||
|
|
@ -333,14 +381,16 @@ RowLayout {
|
|||
Control.SplitView.preferredHeight: mainItem.chat.core.isReadOnly ? 0 : Math.round(79 * DefaultStyle.dp)
|
||||
Control.SplitView.minimumHeight: mainItem.chat.core.isReadOnly ? 0 : Math.round(79 * DefaultStyle.dp)
|
||||
chat: mainItem.chat
|
||||
Component.onCompleted: {
|
||||
|
||||
if (mainItem.chat) text = mainItem.chat.core.sendingText
|
||||
onChatChanged: {
|
||||
if (chat) messageSender.text = mainItem.chat.core.sendingText
|
||||
}
|
||||
onTextChanged: {
|
||||
if (text !== "" && mainItem.chat.core.composingName !== "") {
|
||||
mainItem.chat.core.lCompose()
|
||||
}
|
||||
var lastChar = text.slice(-1)
|
||||
if (lastChar == "@") participantListPopup.visible = true
|
||||
else participantListPopup.visible = false
|
||||
mainItem.chat.core.sendingText = text
|
||||
}
|
||||
onSendMessage: {
|
||||
|
|
@ -359,7 +409,6 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Rectangle {
|
||||
visible: detailsPanel.visible
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ AbstractMainPage {
|
|||
FocusScope {
|
||||
SelectedChatView {
|
||||
anchors.fill: parent
|
||||
chat: mainItem.selectedChatGui
|
||||
chat: mainItem.selectedChatGui || null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue