message reply
This commit is contained in:
parent
f82a4db826
commit
4a1f1a895b
16 changed files with 1691 additions and 1389 deletions
|
|
@ -76,9 +76,7 @@ void AccountDeviceList::setAccount(const QSharedPointer<AccountCore> &accountCor
|
||||||
|
|
||||||
void AccountDeviceList::refreshDevices() {
|
void AccountDeviceList::refreshDevices() {
|
||||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||||
beginResetModel();
|
resetData();
|
||||||
clearData();
|
|
||||||
endResetModel();
|
|
||||||
if (mAccountCore) {
|
if (mAccountCore) {
|
||||||
auto requestDeviceList = [this] {
|
auto requestDeviceList = [this] {
|
||||||
if (!mAccountManagerServicesModelConnection) return;
|
if (!mAccountManagerServicesModelConnection) return;
|
||||||
|
|
@ -150,14 +148,14 @@ void AccountDeviceList::setSelf(QSharedPointer<AccountDeviceList> me) {
|
||||||
&AccountManagerServicesModel::requestError,
|
&AccountManagerServicesModel::requestError,
|
||||||
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
|
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
|
||||||
const std::string &errorMessage,
|
const std::string &errorMessage,
|
||||||
const std::shared_ptr<const linphone::Dictionary> ¶meterErrors) {
|
const std::shared_ptr<const linphone::Dictionary> ¶meterErrors) {
|
||||||
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
|
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
|
||||||
QString message = QString::fromStdString(errorMessage);
|
QString message = QString::fromStdString(errorMessage);
|
||||||
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
|
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
|
||||||
//: "Erreur lors de la récupération des appareils"
|
//: "Erreur lors de la récupération des appareils"
|
||||||
message = tr("manage_account_no_device_found_error_message");
|
message = tr("manage_account_no_device_found_error_message");
|
||||||
}
|
}
|
||||||
emit requestError(message);
|
emit requestError(message);
|
||||||
});
|
});
|
||||||
mAccountManagerServicesModelConnection->makeConnectToModel(
|
mAccountManagerServicesModelConnection->makeConnectToModel(
|
||||||
&AccountManagerServicesModel::devicesListFetched,
|
&AccountManagerServicesModel::devicesListFetched,
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
|
||||||
fromAddress->clean();
|
fromAddress->clean();
|
||||||
mFromAddress = Utils::coreStringToAppString(fromAddress->asStringUriOnly());
|
mFromAddress = Utils::coreStringToAppString(fromAddress->asStringUriOnly());
|
||||||
mFromName = ToolModel::getDisplayName(chatmessage->getFromAddress()->clone());
|
mFromName = ToolModel::getDisplayName(chatmessage->getFromAddress()->clone());
|
||||||
|
mToName = ToolModel::getDisplayName(chatmessage->getToAddress()->clone());
|
||||||
|
|
||||||
auto chatroom = chatmessage->getChatRoom();
|
auto chatroom = chatmessage->getChatRoom();
|
||||||
mIsFromChatGroup = chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) &&
|
mIsFromChatGroup = chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) &&
|
||||||
|
|
@ -166,6 +167,13 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
|
||||||
|
|
||||||
mIsForward = chatmessage->isForward();
|
mIsForward = chatmessage->isForward();
|
||||||
mIsReply = chatmessage->isReply();
|
mIsReply = chatmessage->isReply();
|
||||||
|
if (mIsReply) {
|
||||||
|
auto replymessage = chatmessage->getReplyMessage();
|
||||||
|
if (replymessage) {
|
||||||
|
mReplyText = ToolModel::getMessageFromContent(replymessage->getContents());
|
||||||
|
if (mIsFromChatGroup) mRepliedToName = ToolModel::getDisplayName(replymessage->getToAddress()->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
mImdnStatusList = computeDeliveryStatus(chatmessage);
|
mImdnStatusList = computeDeliveryStatus(chatmessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,6 +388,10 @@ QString ChatMessageCore::getToAddress() const {
|
||||||
return mToAddress;
|
return mToAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ChatMessageCore::getToName() const {
|
||||||
|
return mToName;
|
||||||
|
}
|
||||||
|
|
||||||
QString ChatMessageCore::getMessageId() const {
|
QString ChatMessageCore::getMessageId() const {
|
||||||
return mMessageId;
|
return mMessageId;
|
||||||
}
|
}
|
||||||
|
|
@ -575,4 +587,4 @@ std::shared_ptr<ChatMessageModel> ChatMessageCore::getModel() const {
|
||||||
|
|
||||||
ChatMessageContentGui *ChatMessageCore::getVoiceRecordingContent() const {
|
ChatMessageContentGui *ChatMessageCore::getVoiceRecordingContent() const {
|
||||||
return new ChatMessageContentGui(mVoiceRecordingContent);
|
return new ChatMessageContentGui(mVoiceRecordingContent);
|
||||||
}
|
}
|
||||||
|
|
@ -100,6 +100,8 @@ class ChatMessageCore : public QObject, public AbstractObject {
|
||||||
QStringList reactionsSingletonAsStrings READ getReactionsSingletonAsStrings NOTIFY singletonReactionMapChanged)
|
QStringList reactionsSingletonAsStrings READ getReactionsSingletonAsStrings NOTIFY singletonReactionMapChanged)
|
||||||
Q_PROPERTY(bool isForward MEMBER mIsForward CONSTANT)
|
Q_PROPERTY(bool isForward MEMBER mIsForward CONSTANT)
|
||||||
Q_PROPERTY(bool isReply MEMBER mIsReply CONSTANT)
|
Q_PROPERTY(bool isReply MEMBER mIsReply CONSTANT)
|
||||||
|
Q_PROPERTY(QString replyText MEMBER mReplyText CONSTANT)
|
||||||
|
Q_PROPERTY(QString repliedToName MEMBER mRepliedToName CONSTANT)
|
||||||
Q_PROPERTY(bool hasFileContent MEMBER mHasFileContent CONSTANT)
|
Q_PROPERTY(bool hasFileContent MEMBER mHasFileContent CONSTANT)
|
||||||
Q_PROPERTY(bool isVoiceRecording MEMBER mIsVoiceRecording CONSTANT)
|
Q_PROPERTY(bool isVoiceRecording MEMBER mIsVoiceRecording CONSTANT)
|
||||||
Q_PROPERTY(bool isCalendarInvite MEMBER mIsCalendarInvite CONSTANT)
|
Q_PROPERTY(bool isCalendarInvite MEMBER mIsCalendarInvite CONSTANT)
|
||||||
|
|
@ -123,6 +125,7 @@ public:
|
||||||
QString getFromAddress() const;
|
QString getFromAddress() const;
|
||||||
QString getFromName() const;
|
QString getFromName() const;
|
||||||
QString getToAddress() const;
|
QString getToAddress() const;
|
||||||
|
QString getToName() const;
|
||||||
QString getMessageId() const;
|
QString getMessageId() const;
|
||||||
|
|
||||||
bool isRemoteMessage() const;
|
bool isRemoteMessage() const;
|
||||||
|
|
@ -182,6 +185,7 @@ private:
|
||||||
QString mFromAddress;
|
QString mFromAddress;
|
||||||
QString mToAddress;
|
QString mToAddress;
|
||||||
QString mFromName;
|
QString mFromName;
|
||||||
|
QString mToName;
|
||||||
QString mPeerName;
|
QString mPeerName;
|
||||||
QString mMessageId;
|
QString mMessageId;
|
||||||
QString mOwnReaction;
|
QString mOwnReaction;
|
||||||
|
|
@ -194,6 +198,8 @@ private:
|
||||||
bool mIsRead = false;
|
bool mIsRead = false;
|
||||||
bool mIsForward = false;
|
bool mIsForward = false;
|
||||||
bool mIsReply = false;
|
bool mIsReply = false;
|
||||||
|
QString mReplyText;
|
||||||
|
QString mRepliedToName;
|
||||||
bool mHasFileContent = false;
|
bool mHasFileContent = false;
|
||||||
bool mIsCalendarInvite = false;
|
bool mIsCalendarInvite = false;
|
||||||
bool mIsVoiceRecording = false;
|
bool mIsVoiceRecording = false;
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,11 @@ EventLogCore::EventLogCore(const std::shared_ptr<const linphone::EventLog> &even
|
||||||
} else if (eventLog->getCallLog()) {
|
} else if (eventLog->getCallLog()) {
|
||||||
mCallHistoryCore = CallHistoryCore::create(eventLog->getCallLog());
|
mCallHistoryCore = CallHistoryCore::create(eventLog->getCallLog());
|
||||||
mEventId = Utils::coreStringToAppString(eventLog->getCallLog()->getCallId());
|
mEventId = Utils::coreStringToAppString(eventLog->getCallLog()->getCallId());
|
||||||
} else { // getNotifyId
|
}
|
||||||
|
if (mEventId.isEmpty()) { // getNotifyId
|
||||||
QString type = QString::fromLatin1(
|
QString type = QString::fromLatin1(
|
||||||
QMetaEnum::fromType<LinphoneEnums::EventLogType>().valueToKey(static_cast<int>(mEventLogType)));
|
QMetaEnum::fromType<LinphoneEnums::EventLogType>().valueToKey(static_cast<int>(mEventLogType)));
|
||||||
mEventId = type + QString::number(static_cast<qint64>(eventLog->getCreationTime()));
|
mEventId = type + QString::number(static_cast<qint64>(eventLog->getCreationTime()));
|
||||||
;
|
|
||||||
computeEvent(eventLog);
|
computeEvent(eventLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -137,6 +137,11 @@ ChatModel::createVoiceRecordingMessage(const std::shared_ptr<linphone::Recorder>
|
||||||
return mMonitor->createVoiceRecordingMessage(recorder);
|
return mMonitor->createVoiceRecordingMessage(recorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<linphone::ChatMessage>
|
||||||
|
ChatModel::createReplyMessage(const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||||
|
return mMonitor->createReplyMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<linphone::ChatMessage> ChatModel::createTextMessageFromText(QString text) {
|
std::shared_ptr<linphone::ChatMessage> ChatModel::createTextMessageFromText(QString text) {
|
||||||
return mMonitor->createMessageFromUtf8(Utils::appStringToCoreString(text));
|
return mMonitor->createMessageFromUtf8(Utils::appStringToCoreString(text));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ public:
|
||||||
void leave();
|
void leave();
|
||||||
std::shared_ptr<linphone::ChatMessage>
|
std::shared_ptr<linphone::ChatMessage>
|
||||||
createVoiceRecordingMessage(const std::shared_ptr<linphone::Recorder> &recorder);
|
createVoiceRecordingMessage(const std::shared_ptr<linphone::Recorder> &recorder);
|
||||||
|
|
||||||
|
std::shared_ptr<linphone::ChatMessage> createReplyMessage(const std::shared_ptr<linphone::ChatMessage> &message);
|
||||||
|
|
||||||
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
|
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
|
||||||
std::shared_ptr<linphone::ChatMessage> createMessage(QString text,
|
std::shared_ptr<linphone::ChatMessage> createMessage(QString text,
|
||||||
QList<std::shared_ptr<ChatMessageContentModel>> filesContent);
|
QList<std::shared_ptr<ChatMessageContentModel>> filesContent);
|
||||||
|
|
|
||||||
|
|
@ -388,11 +388,13 @@ bool ToolModel::friendIsInFriendList(const std::shared_ptr<linphone::FriendList>
|
||||||
|
|
||||||
QString ToolModel::getMessageFromContent(std::list<std::shared_ptr<linphone::Content>> contents) {
|
QString ToolModel::getMessageFromContent(std::list<std::shared_ptr<linphone::Content>> contents) {
|
||||||
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
|
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
|
||||||
|
QString res;
|
||||||
for (auto &content : contents) {
|
for (auto &content : contents) {
|
||||||
if (content->isText()) {
|
if (content->isText()) {
|
||||||
return Utils::coreStringToAppString(content->getUtf8Text());
|
return Utils::coreStringToAppString(content->getUtf8Text());
|
||||||
} else if (content->isFile()) {
|
} else if (content->isFile()) {
|
||||||
return Utils::coreStringToAppString(content->getName());
|
if (res.isEmpty()) res.append(Utils::coreStringToAppString(content->getName()));
|
||||||
|
else res.append(", " + Utils::coreStringToAppString(content->getName()));
|
||||||
} else if (content->isIcalendar()) {
|
} else if (content->isIcalendar()) {
|
||||||
auto conferenceInfo = linphone::Factory::get()->createConferenceInfoFromIcalendarContent(content);
|
auto conferenceInfo = linphone::Factory::get()->createConferenceInfoFromIcalendarContent(content);
|
||||||
auto conferenceInfoCore = ConferenceInfoCore::create(conferenceInfo);
|
auto conferenceInfoCore = ConferenceInfoCore::create(conferenceInfo);
|
||||||
|
|
@ -406,7 +408,7 @@ QString ToolModel::getMessageFromContent(std::list<std::shared_ptr<linphone::Con
|
||||||
return getMessageFromContent(content->getParts());
|
return getMessageFromContent(content->getParts());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QString("");
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as
|
// Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "core/call/CallGui.hpp"
|
#include "core/call/CallGui.hpp"
|
||||||
#include "core/chat/ChatCore.hpp"
|
#include "core/chat/ChatCore.hpp"
|
||||||
#include "core/chat/ChatGui.hpp"
|
#include "core/chat/ChatGui.hpp"
|
||||||
|
#include "core/chat/message/ChatMessageGui.hpp"
|
||||||
#include "core/conference/ConferenceCore.hpp"
|
#include "core/conference/ConferenceCore.hpp"
|
||||||
#include "core/conference/ConferenceInfoCore.hpp"
|
#include "core/conference/ConferenceInfoCore.hpp"
|
||||||
#include "core/conference/ConferenceInfoGui.hpp"
|
#include "core/conference/ConferenceInfoGui.hpp"
|
||||||
|
|
@ -1950,6 +1951,50 @@ QString Utils::getSafeFilePath(const QString &filePath, bool *soFarSoGood) {
|
||||||
return QString("");
|
return QString("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Utils::sendReplyMessage(ChatMessageGui *message, ChatGui *chatGui, QString text, QVariantList files) {
|
||||||
|
auto chatModel = chatGui && chatGui->mCore ? chatGui->mCore->getModel() : nullptr;
|
||||||
|
auto chatMessageModel = message && message->mCore ? message->mCore->getModel() : nullptr;
|
||||||
|
if (!chatModel || !chatMessageModel) {
|
||||||
|
//: Cannot reply to invalid message
|
||||||
|
QString error = !chatMessageModel ? tr("chatMessage_error")
|
||||||
|
//: Error in the chat
|
||||||
|
: tr("chat_error");
|
||||||
|
//: Error
|
||||||
|
showInformationPopup(tr("info_popup_error_title"),
|
||||||
|
//: Could not send voice message : %1
|
||||||
|
tr("info_popup_send_voice_message_error_message").arg(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QList<std::shared_ptr<ChatMessageContentModel>> filesContent;
|
||||||
|
for (auto &file : files) {
|
||||||
|
auto contentGui = qvariant_cast<ChatMessageContentGui *>(file);
|
||||||
|
if (contentGui) {
|
||||||
|
auto contentCore = contentGui->mCore;
|
||||||
|
filesContent.append(contentCore->getContentModel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
App::postModelAsync([chatModel, chatMessageModel, text, filesContent] {
|
||||||
|
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
|
||||||
|
auto chat = chatModel->getMonitor();
|
||||||
|
auto messageToReplyTo = chatMessageModel->getMonitor();
|
||||||
|
auto linMessage = chatModel->createReplyMessage(messageToReplyTo);
|
||||||
|
if (linMessage) {
|
||||||
|
linMessage->addUtf8TextContent(Utils::appStringToCoreString(text));
|
||||||
|
for (auto &content : filesContent) {
|
||||||
|
linMessage->addFileContent(content->getContent());
|
||||||
|
}
|
||||||
|
linMessage->send();
|
||||||
|
} else {
|
||||||
|
App::postCoreAsync([] {
|
||||||
|
//: Error
|
||||||
|
showInformationPopup(tr("info_popup_error_title"),
|
||||||
|
//: Failed to create message from record
|
||||||
|
tr("info_popup_send_voice_message_sending_error_message"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
VariantObject *Utils::createVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui) {
|
VariantObject *Utils::createVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui) {
|
||||||
VariantObject *data = new VariantObject("createVoiceRecordingMessage");
|
VariantObject *data = new VariantObject("createVoiceRecordingMessage");
|
||||||
if (!data) return nullptr;
|
if (!data) return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class ConferenceCore;
|
||||||
class ParticipantDeviceCore;
|
class ParticipantDeviceCore;
|
||||||
class DownloadablePayloadTypeCore;
|
class DownloadablePayloadTypeCore;
|
||||||
class ChatGui;
|
class ChatGui;
|
||||||
|
class ChatMessageGui;
|
||||||
class RecorderGui;
|
class RecorderGui;
|
||||||
|
|
||||||
class Utils : public QObject, public AbstractObject {
|
class Utils : public QObject, public AbstractObject {
|
||||||
|
|
@ -176,6 +177,8 @@ public:
|
||||||
Q_INVOKABLE static QString toTimeString(QDateTime date, const QString &format = "hh:mm:ss");
|
Q_INVOKABLE static QString toTimeString(QDateTime date, const QString &format = "hh:mm:ss");
|
||||||
|
|
||||||
Q_INVOKABLE static VariantObject *createVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui);
|
Q_INVOKABLE static VariantObject *createVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui);
|
||||||
|
Q_INVOKABLE static void
|
||||||
|
sendReplyMessage(ChatMessageGui *message, ChatGui *chatGui, QString text, QVariantList files);
|
||||||
Q_INVOKABLE static void sendVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui);
|
Q_INVOKABLE static void sendVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui);
|
||||||
|
|
||||||
// QDir findDirectoryByName(QString startPath, QString name);
|
// QDir findDirectoryByName(QString startPath, QString name);
|
||||||
|
|
|
||||||
|
|
@ -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 bool isReply: chatMessage? chatMessage.core.isReply : false
|
||||||
|
property string replyText: chatMessage? chatMessage.core.replyText : false
|
||||||
property var msgState: chatMessage ? chatMessage.core.messageState : LinphoneEnums.ChatMessageState.StateIdle
|
property var msgState: chatMessage ? chatMessage.core.messageState : LinphoneEnums.ChatMessageState.StateIdle
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
property bool linkHovered: false
|
property bool linkHovered: false
|
||||||
|
|
@ -30,6 +32,7 @@ Control.Control {
|
||||||
signal isFileHoveringChanged(bool isFileHovering)
|
signal isFileHoveringChanged(bool isFileHovering)
|
||||||
signal showReactionsForMessageRequested()
|
signal showReactionsForMessageRequested()
|
||||||
signal showImdnStatusForMessageRequested()
|
signal showImdnStatusForMessageRequested()
|
||||||
|
signal replyToMessageRequested()
|
||||||
|
|
||||||
background: Item {
|
background: Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -41,52 +44,119 @@ Control.Control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: ColumnLayout {
|
||||||
spacing: 0
|
spacing: Math.round(5 * DefaultStyle.dp)
|
||||||
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
Text {
|
||||||
|
id: fromNameText
|
||||||
Avatar {
|
|
||||||
id: avatar
|
|
||||||
visible: mainItem.isFromChatGroup && mainItem.isRemoteMessage
|
|
||||||
Layout.preferredWidth: mainItem.isRemoteMessage ? 26 * DefaultStyle.dp : 0
|
|
||||||
Layout.preferredHeight: 26 * DefaultStyle.dp
|
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0
|
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) + avatar.width : 0
|
||||||
_address: chatMessage ? chatMessage.core.fromAddress : ""
|
visible: mainItem.isFromChatGroup && mainItem.isRemoteMessage && mainItem.isFirstMessage && !replyLayout.visible
|
||||||
|
maximumLineCount: 1
|
||||||
|
width: implicitWidth
|
||||||
|
x: mapToItem(this, chatBubble.x, chatBubble.y).x
|
||||||
|
text: mainItem.chatMessage.core.fromName
|
||||||
|
color: DefaultStyle.main2_500main
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.p4.pixelSize
|
||||||
|
weight: Typography.p4.weight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
RowLayout {
|
||||||
Layout.alignment: Qt.AlignTop
|
id: replyLayout
|
||||||
spacing: 0
|
visible: mainItem.isReply
|
||||||
Text {
|
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) + avatar.width : 0
|
||||||
id: fromNameText
|
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
||||||
Layout.alignment: Qt.AlignTop
|
ColumnLayout {
|
||||||
visible: mainItem.isFromChatGroup && mainItem.isRemoteMessage && mainItem.isFirstMessage
|
spacing: Math.round(5 * DefaultStyle.dp)
|
||||||
// anchors.top: parent.top
|
RowLayout {
|
||||||
// anchors.left: parent.left
|
id: replyLabel
|
||||||
// anchors.leftMargin: avatar.width// mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0
|
spacing: Math.round(8 * DefaultStyle.dp)
|
||||||
maximumLineCount: 1
|
Layout.fillWidth: false
|
||||||
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0
|
Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft : Qt.AlignRight
|
||||||
width: implicitWidth
|
EffectImage {
|
||||||
x: mapToItem(this, chatBubble.x, chatBubble.y).x
|
imageSource: AppIcons.reply
|
||||||
text: mainItem.chatMessage.core.fromName
|
colorizationColor: DefaultStyle.main2_500main
|
||||||
color: DefaultStyle.main2_500main
|
Layout.preferredWidth: Math.round(12 * DefaultStyle.dp)
|
||||||
font {
|
Layout.preferredHeight: Math.round(12 * DefaultStyle.dp)
|
||||||
pixelSize: Typography.p4.pixelSize
|
}
|
||||||
weight: Typography.p4.weight
|
Text {
|
||||||
|
Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft: Qt.AlignRight
|
||||||
|
text: mainItem.isRemoteMessage
|
||||||
|
? mainItem.chatMessage.core.repliedToName !== ""
|
||||||
|
//: %1 replied to %2
|
||||||
|
? qsTr("chat_message_remote_replied_to").arg(mainItem.chatMessage.core.fromName).arg(mainItem.chatMessage.core.repliedToName)
|
||||||
|
//: %1 replied
|
||||||
|
: qsTr("chat_message_remote_replied").arg(mainItem.chatMessage.core.fromName)
|
||||||
|
: mainItem.chatMessage.core.repliedToName !== ""
|
||||||
|
//: You replied to %1
|
||||||
|
? qsTr("chat_message_user_replied_to").arg(mainItem.chatMessage.core.repliedToName)
|
||||||
|
//: You replied
|
||||||
|
: qsTr("chat_message_user_replied")
|
||||||
|
color: DefaultStyle.main2_600
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.p4.pixelSize
|
||||||
|
weight: Typography.p4.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Control.Control {
|
||||||
|
id: replyMessage
|
||||||
|
visible: mainItem.replyText !== ""
|
||||||
|
Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft : Qt.AlignRight
|
||||||
|
spacing: Math.round(5 * DefaultStyle.dp)
|
||||||
|
topPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
|
bottomPadding: Math.round(19 * DefaultStyle.dp)
|
||||||
|
leftPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
|
rightPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
|
width: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
||||||
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: DefaultStyle.grey_200
|
||||||
|
radius: Math.round(16 * DefaultStyle.dp)
|
||||||
|
}
|
||||||
|
contentItem: Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: mainItem.replyText
|
||||||
|
color: DefaultStyle.main2_800
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.p1.pixelSize
|
||||||
|
weight: Typography.p1.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Item{Layout.fillWidth: true}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
id: bubbleLayout
|
||||||
|
z: replyLayout.z + 1
|
||||||
|
spacing: 0
|
||||||
|
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
||||||
|
Layout.topMargin: replyMessage.visible ? Math.round(-20 * DefaultStyle.dp) : 0
|
||||||
|
|
||||||
|
Avatar {
|
||||||
|
id: avatar
|
||||||
|
visible: mainItem.isFromChatGroup && mainItem.isRemoteMessage
|
||||||
|
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 {
|
Item {
|
||||||
|
id: bubbleContainer
|
||||||
// Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0
|
// Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0
|
||||||
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0
|
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0
|
||||||
Layout.preferredHeight: childrenRect.height
|
Layout.preferredHeight: childrenRect.height
|
||||||
Layout.preferredWidth: childrenRect.width
|
Layout.preferredWidth: childrenRect.width
|
||||||
|
|
||||||
Control.Control {
|
Control.Control {
|
||||||
id: chatBubble
|
id: chatBubble
|
||||||
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(6 * DefaultStyle.dp)
|
bottomPadding: Math.round(6 * DefaultStyle.dp)
|
||||||
leftPadding: Math.round(12 * DefaultStyle.dp)
|
leftPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
rightPadding: Math.round(12 * DefaultStyle.dp)
|
rightPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
width: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
width: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
||||||
|
|
||||||
MouseArea { // Default mouse area. Each sub bubble can control the mouse and pass on to the main mouse handler. Child bubble mouse area must cover the entire bubble.
|
MouseArea { // Default mouse area. Each sub bubble can control the mouse and pass on to the main mouse handler. Child bubble mouse area must cover the entire bubble.
|
||||||
|
|
@ -133,6 +203,7 @@ Control.Control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
Layout.fillWidth: false
|
||||||
Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft : Qt.AlignRight
|
Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft : Qt.AlignRight
|
||||||
Text {
|
Text {
|
||||||
text: UtilsCpp.formatDate(mainItem.chatMessage.core.timestamp, true, false, "dd/MM")
|
text: UtilsCpp.formatDate(mainItem.chatMessage.core.timestamp, true, false, "dd/MM")
|
||||||
|
|
@ -217,118 +288,130 @@ Control.Control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
RowLayout {
|
||||||
RowLayout {
|
id: actionsLayout
|
||||||
id: actionsLayout
|
visible: mainItem.hovered || optionsMenu.hovered || optionsMenu.popup.opened || emojiButton.hovered || emojiButton.popup.opened
|
||||||
visible: mainItem.hovered || optionsMenu.hovered || optionsMenu.popup.opened || emojiButton.hovered || emojiButton.popup.opened
|
Layout.leftMargin: Math.round(8 * DefaultStyle.dp)
|
||||||
Layout.leftMargin: Math.round(8 * DefaultStyle.dp)
|
Layout.rightMargin: Math.round(8 * DefaultStyle.dp)
|
||||||
Layout.rightMargin: Math.round(8 * DefaultStyle.dp)
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.alignment: Qt.AlignVCenter
|
// Layout.fillWidth: true
|
||||||
// Layout.fillWidth: true
|
spacing: Math.round(7 * DefaultStyle.dp)
|
||||||
spacing: Math.round(7 * DefaultStyle.dp)
|
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
||||||
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
PopupButton {
|
||||||
PopupButton {
|
id: optionsMenu
|
||||||
id: optionsMenu
|
popup.padding: 0
|
||||||
popup.padding: 0
|
popup.contentItem: ColumnLayout {
|
||||||
popup.contentItem: ColumnLayout {
|
spacing: 0
|
||||||
spacing: 0
|
IconLabelButton {
|
||||||
IconLabelButton {
|
inverseLayout: true
|
||||||
inverseLayout: true
|
//: "Reception info"
|
||||||
text: chatBubbleContent.selectedText != ""
|
text: qsTr("chat_message_reception_info")
|
||||||
//: "Copy selection"
|
icon.source: AppIcons.chatTeardropText
|
||||||
? qsTr("chat_message_copy_selection")
|
Layout.fillWidth: true
|
||||||
//: "Copy"
|
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||||
: qsTr("chat_message_copy")
|
|
||||||
icon.source: AppIcons.copy
|
|
||||||
// spacing: Math.round(10 * DefaultStyle.dp)
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
|
||||||
onClicked: {
|
|
||||||
var success = UtilsCpp.copyToClipboard(chatBubbleContent.selectedText != "" ? chatBubbleContent.selectedText : mainItem.chatMessage.core.text)
|
|
||||||
//: Copied
|
|
||||||
if (success) UtilsCpp.showInformationPopup(qsTr("chat_message_copied_to_clipboard_title"),
|
|
||||||
//: "to clipboard"
|
|
||||||
qsTr("chat_message_copied_to_clipboard_toast"))
|
|
||||||
optionsMenu.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IconLabelButton {
|
|
||||||
inverseLayout: true
|
|
||||||
//: "See message status"
|
|
||||||
text: qsTr("chat_message_see_status")
|
|
||||||
icon.source: AppIcons.chatTeardropText
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
|
||||||
onClicked: {
|
|
||||||
mainItem.showImdnStatusForMessageRequested()
|
|
||||||
optionsMenu.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: Math.min(1, Math.round(1 * DefaultStyle.dp))
|
|
||||||
color: DefaultStyle.main2_400
|
|
||||||
}
|
|
||||||
IconLabelButton {
|
|
||||||
inverseLayout: true
|
|
||||||
//: "Delete"
|
|
||||||
text: qsTr("chat_message_delete")
|
|
||||||
icon.source: AppIcons.trashCan
|
|
||||||
// spacing: Math.round(10 * DefaultStyle.dp)
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
|
||||||
onClicked: {
|
|
||||||
mainItem.messageDeletionRequested()
|
|
||||||
optionsMenu.close()
|
|
||||||
}
|
|
||||||
style: ButtonStyle.hoveredBackgroundRed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PopupButton {
|
|
||||||
id: emojiButton
|
|
||||||
style: ButtonStyle.noBackground
|
|
||||||
icon.source: AppIcons.smiley
|
|
||||||
popup.contentItem: RowLayout {
|
|
||||||
Repeater {
|
|
||||||
model: ConstantsCpp.reactionsList
|
|
||||||
delegate: Button {
|
|
||||||
text: UtilsCpp.encodeEmojiToQmlRichFormat(modelData)
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
color: DefaultStyle.grey_200
|
|
||||||
radius: parent.width * 4
|
|
||||||
visible: mainItem.ownReaction === modelData
|
|
||||||
}
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if(modelData) {
|
mainItem.showImdnStatusForMessageRequested()
|
||||||
if (mainItem.ownReaction === modelData) mainItem.chatMessage.core.lRemoveReaction()
|
optionsMenu.close()
|
||||||
else mainItem.chatMessage.core.lSendReaction(modelData)
|
|
||||||
}
|
|
||||||
emojiButton.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
IconLabelButton {
|
||||||
|
inverseLayout: true
|
||||||
|
//: Reply
|
||||||
|
text: qsTr("chat_message_reply")
|
||||||
|
icon.source: AppIcons.reply
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||||
|
onClicked: {
|
||||||
|
mainItem.replyToMessageRequested()
|
||||||
|
optionsMenu.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IconLabelButton {
|
||||||
|
inverseLayout: true
|
||||||
|
text: chatBubbleContent.selectedText != ""
|
||||||
|
//: "Copy selection"
|
||||||
|
? qsTr("chat_message_copy_selection")
|
||||||
|
//: "Copy"
|
||||||
|
: qsTr("chat_message_copy")
|
||||||
|
icon.source: AppIcons.copy
|
||||||
|
// spacing: Math.round(10 * DefaultStyle.dp)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||||
|
onClicked: {
|
||||||
|
var success = UtilsCpp.copyToClipboard(chatBubbleContent.selectedText != "" ? chatBubbleContent.selectedText : mainItem.chatMessage.core.text)
|
||||||
|
//: Copied
|
||||||
|
if (success) UtilsCpp.showInformationPopup(qsTr("chat_message_copied_to_clipboard_title"),
|
||||||
|
//: "to clipboard"
|
||||||
|
qsTr("chat_message_copied_to_clipboard_toast"))
|
||||||
|
optionsMenu.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Math.min(1, Math.round(1 * DefaultStyle.dp))
|
||||||
|
color: DefaultStyle.main2_400
|
||||||
|
}
|
||||||
|
IconLabelButton {
|
||||||
|
inverseLayout: true
|
||||||
|
//: "Delete"
|
||||||
|
text: qsTr("chat_message_delete")
|
||||||
|
icon.source: AppIcons.trashCan
|
||||||
|
// spacing: Math.round(10 * DefaultStyle.dp)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||||
|
onClicked: {
|
||||||
|
mainItem.messageDeletionRequested()
|
||||||
|
optionsMenu.close()
|
||||||
|
}
|
||||||
|
style: ButtonStyle.hoveredBackgroundRed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PopupButton {
|
}
|
||||||
id: emojiPickerButton
|
PopupButton {
|
||||||
icon.source: AppIcons.plusCircle
|
id: emojiButton
|
||||||
popup.width: Math.round(393 * DefaultStyle.dp)
|
style: ButtonStyle.noBackground
|
||||||
popup.height: Math.round(291 * DefaultStyle.dp)
|
icon.source: AppIcons.smiley
|
||||||
popup.contentItem: EmojiPicker {
|
popup.contentItem: RowLayout {
|
||||||
id: emojiPicker
|
Repeater {
|
||||||
onEmojiClicked: (emoji) => {
|
model: ConstantsCpp.reactionsList
|
||||||
if (mainItem.chatMessage) {
|
delegate: Button {
|
||||||
if (mainItem.ownReaction === emoji) mainItem.chatMessage.core.lRemoveReaction()
|
text: UtilsCpp.encodeEmojiToQmlRichFormat(modelData)
|
||||||
else mainItem.chatMessage.core.lSendReaction(emoji)
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: DefaultStyle.grey_200
|
||||||
|
radius: parent.width * 4
|
||||||
|
visible: mainItem.ownReaction === modelData
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
if(modelData) {
|
||||||
|
if (mainItem.ownReaction === modelData) mainItem.chatMessage.core.lRemoveReaction()
|
||||||
|
else mainItem.chatMessage.core.lSendReaction(modelData)
|
||||||
|
}
|
||||||
|
emojiButton.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopupButton {
|
||||||
|
id: emojiPickerButton
|
||||||
|
icon.source: AppIcons.plusCircle
|
||||||
|
popup.width: Math.round(393 * DefaultStyle.dp)
|
||||||
|
popup.height: Math.round(291 * DefaultStyle.dp)
|
||||||
|
popup.contentItem: EmojiPicker {
|
||||||
|
id: emojiPicker
|
||||||
|
onEmojiClicked: (emoji) => {
|
||||||
|
if (mainItem.chatMessage) {
|
||||||
|
if (mainItem.ownReaction === emoji) mainItem.chatMessage.core.lRemoveReaction()
|
||||||
|
else mainItem.chatMessage.core.lSendReaction(emoji)
|
||||||
|
}
|
||||||
|
emojiPickerButton.close()
|
||||||
|
emojiButton.close()
|
||||||
}
|
}
|
||||||
emojiPickerButton.close()
|
|
||||||
emojiButton.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Item{Layout.fillWidth: true}
|
||||||
}
|
}
|
||||||
Item{Layout.fillWidth: true}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ ListView {
|
||||||
property color backgroundColor
|
property color backgroundColor
|
||||||
signal showReactionsForMessageRequested(ChatMessageGui chatMessage)
|
signal showReactionsForMessageRequested(ChatMessageGui chatMessage)
|
||||||
signal showImdnStatusForMessageRequested(ChatMessageGui chatMessage)
|
signal showImdnStatusForMessageRequested(ChatMessageGui chatMessage)
|
||||||
|
signal replyToMessageRequested(ChatMessageGui chatMessage)
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var index = eventLogProxy.findFirstUnreadIndex()
|
var index = eventLogProxy.findFirstUnreadIndex()
|
||||||
|
|
@ -137,6 +138,7 @@ ListView {
|
||||||
onMessageDeletionRequested: modelData.core.lDelete()
|
onMessageDeletionRequested: modelData.core.lDelete()
|
||||||
onShowReactionsForMessageRequested: mainItem.showReactionsForMessageRequested(modelData)
|
onShowReactionsForMessageRequested: mainItem.showReactionsForMessageRequested(modelData)
|
||||||
onShowImdnStatusForMessageRequested: mainItem.showImdnStatusForMessageRequested(modelData)
|
onShowImdnStatusForMessageRequested: mainItem.showImdnStatusForMessageRequested(modelData)
|
||||||
|
onReplyToMessageRequested: mainItem.replyToMessageRequested(modelData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ Control.Control {
|
||||||
function _emitFiles (files) {
|
function _emitFiles (files) {
|
||||||
// Filtering files, other urls are forbidden.
|
// Filtering files, other urls are forbidden.
|
||||||
files = files.reduce(function (files, file) {
|
files = files.reduce(function (files, file) {
|
||||||
console.log("dropping", file.toString())
|
|
||||||
if (file.toString().startsWith("file:")) {
|
if (file.toString().startsWith("file:")) {
|
||||||
files.push(Utils.getSystemPathFromUri(file))
|
files.push(Utils.getSystemPathFromUri(file))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ RowLayout {
|
||||||
property var contact: contactObj?.value || null
|
property var contact: contactObj?.value || null
|
||||||
property CallGui call
|
property CallGui call
|
||||||
property alias callHeaderContent: splitPanel.headerContent
|
property alias callHeaderContent: splitPanel.headerContent
|
||||||
|
property bool replyingToMessage: false
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
signal oneOneCall(bool video)
|
signal oneOneCall(bool video)
|
||||||
|
|
@ -161,6 +162,10 @@ RowLayout {
|
||||||
contentLoader.showingImdnStatus = true
|
contentLoader.showingImdnStatus = true
|
||||||
detailsPanel.visible = true
|
detailsPanel.visible = true
|
||||||
}
|
}
|
||||||
|
onReplyToMessageRequested: (chatMessage) => {
|
||||||
|
mainItem.chatMessage = chatMessage
|
||||||
|
mainItem.replyingToMessage = true
|
||||||
|
}
|
||||||
|
|
||||||
Popup {
|
Popup {
|
||||||
id: emojiPickerPopup
|
id: emojiPickerPopup
|
||||||
|
|
@ -208,9 +213,9 @@ RowLayout {
|
||||||
}
|
}
|
||||||
Control.Control {
|
Control.Control {
|
||||||
id: selectedFilesArea
|
id: selectedFilesArea
|
||||||
visible: selectedFiles.count > 0
|
visible: selectedFiles.count > 0 || mainItem.replyingToMessage
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: Math.round(104 * DefaultStyle.dp)
|
Layout.preferredHeight: implicitHeight
|
||||||
topPadding: Math.round(12 * DefaultStyle.dp)
|
topPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
bottomPadding: Math.round(12 * DefaultStyle.dp)
|
bottomPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
leftPadding: Math.round(19 * DefaultStyle.dp)
|
leftPadding: Math.round(19 * DefaultStyle.dp)
|
||||||
|
|
@ -225,6 +230,7 @@ RowLayout {
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
onClicked: {
|
onClicked: {
|
||||||
contents.clear()
|
contents.clear()
|
||||||
|
mainItem.replyingToMessage = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
background: Item{
|
background: Item{
|
||||||
|
|
@ -233,7 +239,6 @@ RowLayout {
|
||||||
color: DefaultStyle.grey_0
|
color: DefaultStyle.grey_0
|
||||||
border.color: DefaultStyle.main2_100
|
border.color: DefaultStyle.main2_100
|
||||||
border.width: Math.round(2 * DefaultStyle.dp)
|
border.width: Math.round(2 * DefaultStyle.dp)
|
||||||
radius: Math.round(20 * DefaultStyle.dp)
|
|
||||||
height: parent.height / 2
|
height: parent.height / 2
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
@ -246,37 +251,73 @@ RowLayout {
|
||||||
height: 2 * parent.height / 3
|
height: 2 * parent.height / 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentItem: ListView {
|
contentItem: ColumnLayout {
|
||||||
id: selectedFiles
|
spacing: Math.round(5 * DefaultStyle.dp)
|
||||||
orientation: ListView.Horizontal
|
ColumnLayout {
|
||||||
spacing: Math.round(16 * DefaultStyle.dp)
|
id: replyLayout
|
||||||
model: ChatMessageContentProxy {
|
spacing: 0
|
||||||
id: contents
|
visible: mainItem.chatMessage && mainItem.replyingToMessage
|
||||||
filterType: ChatMessageContentProxy.FilterContentType.File
|
Text {
|
||||||
}
|
Layout.fillWidth: true
|
||||||
delegate: Item {
|
//: Reply to %1
|
||||||
width: Math.round(80 * DefaultStyle.dp)
|
text: mainItem.chatMessage ? qsTr("reply_to_label").arg(UtilsCpp.boldTextPart(mainItem.chatMessage.core.fromName, mainItem.chatMessage.core.fromName)) : ""
|
||||||
height: Math.round(80 * DefaultStyle.dp)
|
color: DefaultStyle.main2_500main
|
||||||
FileView {
|
font {
|
||||||
contentGui: modelData
|
pixelSize: Typography.p3.pixelSize
|
||||||
anchors.left: parent.left
|
weight: Typography.p3.weight
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
width: Math.round(69 * DefaultStyle.dp)
|
|
||||||
height: Math.round(69 * DefaultStyle.dp)
|
|
||||||
}
|
}
|
||||||
RoundButton {
|
Text {
|
||||||
icon.source: AppIcons.closeX
|
Layout.fillWidth: true
|
||||||
icon.width: Math.round(12 * DefaultStyle.dp)
|
text: mainItem.chatMessage ? mainItem.chatMessage.core.text : ""
|
||||||
icon.height: Math.round(12 * DefaultStyle.dp)
|
color: DefaultStyle.main2_400
|
||||||
anchors.top: parent.top
|
font {
|
||||||
anchors.right: parent.right
|
pixelSize: Typography.p3.pixelSize
|
||||||
style: ButtonStyle.numericPad
|
weight: Typography.p3.weight
|
||||||
shadowEnabled: true
|
}
|
||||||
padding: Math.round(3 * DefaultStyle.dp)
|
|
||||||
onClicked: contents.removeContent(modelData)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Control.ScrollBar.horizontal: selectedFilesScrollbar
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
visible: replyLayout.visible && selectedFiles.visible
|
||||||
|
color: DefaultStyle.main2_300
|
||||||
|
Layout.preferredHeight: Math.max(1, Math.round(1 * DefaultStyle.dp))
|
||||||
|
}
|
||||||
|
ListView {
|
||||||
|
id: selectedFiles
|
||||||
|
orientation: ListView.Horizontal
|
||||||
|
visible: count > 0
|
||||||
|
spacing: Math.round(16 * DefaultStyle.dp)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Math.round(104 * DefaultStyle.dp)
|
||||||
|
model: ChatMessageContentProxy {
|
||||||
|
id: contents
|
||||||
|
filterType: ChatMessageContentProxy.FilterContentType.File
|
||||||
|
}
|
||||||
|
delegate: Item {
|
||||||
|
width: Math.round(80 * DefaultStyle.dp)
|
||||||
|
height: Math.round(80 * DefaultStyle.dp)
|
||||||
|
FileView {
|
||||||
|
contentGui: modelData
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: Math.round(69 * DefaultStyle.dp)
|
||||||
|
height: Math.round(69 * DefaultStyle.dp)
|
||||||
|
}
|
||||||
|
RoundButton {
|
||||||
|
icon.source: AppIcons.closeX
|
||||||
|
icon.width: Math.round(12 * DefaultStyle.dp)
|
||||||
|
icon.height: Math.round(12 * DefaultStyle.dp)
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
style: ButtonStyle.numericPad
|
||||||
|
shadowEnabled: true
|
||||||
|
padding: Math.round(3 * DefaultStyle.dp)
|
||||||
|
onClicked: contents.removeContent(modelData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Control.ScrollBar.horizontal: selectedFilesScrollbar
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ScrollBar {
|
ScrollBar {
|
||||||
id: selectedFilesScrollbar
|
id: selectedFilesScrollbar
|
||||||
|
|
@ -304,7 +345,11 @@ RowLayout {
|
||||||
}
|
}
|
||||||
onSendMessage: {
|
onSendMessage: {
|
||||||
var filesContents = contents.getAll()
|
var filesContents = contents.getAll()
|
||||||
if (filesContents.length === 0)
|
if (mainItem.replyingToMessage) {
|
||||||
|
mainItem.replyingToMessage = false
|
||||||
|
UtilsCpp.sendReplyMessage(mainItem.chatMessage, mainItem.chat, text, filesContents)
|
||||||
|
}
|
||||||
|
else if (filesContents.length === 0)
|
||||||
mainItem.chat.core.lSendTextMessage(text)
|
mainItem.chat.core.lSendTextMessage(text)
|
||||||
else mainItem.chat.core.lSendMessage(text, filesContents)
|
else mainItem.chat.core.lSendMessage(text, filesContents)
|
||||||
contents.clear()
|
contents.clear()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue