From a5f9fcb4c46f7902ddb431197c8fddd8703ba175 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Fri, 5 Nov 2021 21:25:12 +0100 Subject: [PATCH] Feature: Reply to a message. --- .../assets/images/menu_forward_custom.svg | 49 ++++++ .../assets/images/menu_reply_custom.svg | 49 ++++++ linphone-app/assets/languages/da.ts | 26 ++++ linphone-app/assets/languages/de.ts | 26 ++++ linphone-app/assets/languages/en.ts | 26 ++++ linphone-app/assets/languages/es.ts | 26 ++++ linphone-app/assets/languages/fr_FR.ts | 34 ++++- linphone-app/assets/languages/hu.ts | 26 ++++ linphone-app/assets/languages/it.ts | 26 ++++ linphone-app/assets/languages/ja.ts | 26 ++++ linphone-app/assets/languages/lt.ts | 26 ++++ linphone-app/assets/languages/pt_BR.ts | 26 ++++ linphone-app/assets/languages/ru.ts | 26 ++++ linphone-app/assets/languages/sv.ts | 26 ++++ linphone-app/assets/languages/tr.ts | 26 ++++ linphone-app/assets/languages/uk.ts | 26 ++++ linphone-app/assets/languages/zh_CN.ts | 26 ++++ linphone-app/resources.qrc | 8 +- .../chat-events/ChatMessageModel.cpp | 21 ++- .../chat-events/ChatMessageModel.hpp | 11 ++ .../components/chat-room/ChatRoomModel.cpp | 20 ++- .../components/chat-room/ChatRoomModel.hpp | 6 + .../chat-room/ChatRoomProxyModel.cpp | 2 + .../chat-room/ChatRoomProxyModel.hpp | 3 + .../modules/Common/Form/DroppableTextArea.qml | 5 + .../Common/Styles/Menus/MenuItemStyle.qml | 8 + .../ui/modules/Linphone/Chat/Chat.qml | 93 +++++++----- .../ui/modules/Linphone/Chat/ChatMenu.qml | 25 +++- .../Linphone/Chat/ChatMessagePreview.qml | 28 ++++ .../Linphone/Chat/ChatReplyMessage.qml | 126 ++++++++++++++++ .../Linphone/Chat/ChatReplyPreview.qml | 139 ++++++++++++++++++ .../modules/Linphone/Chat/IncomingMessage.qml | 4 + .../ui/modules/Linphone/Chat/Message.qml | 133 +++++++++-------- .../modules/Linphone/Chat/OutgoingMessage.qml | 4 + .../Styles/Chat/ChatReplyMessageStyle.qml | 31 ++++ .../Linphone/Styles/Chat/ChatStyle.qml | 23 ++- .../ui/modules/Linphone/Styles/qmldir | 1 + linphone-app/ui/modules/Linphone/qmldir | 3 + linphone-sdk | 2 +- 39 files changed, 1078 insertions(+), 114 deletions(-) create mode 100644 linphone-app/assets/images/menu_forward_custom.svg create mode 100644 linphone-app/assets/images/menu_reply_custom.svg create mode 100644 linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml create mode 100644 linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml create mode 100644 linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml create mode 100644 linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml diff --git a/linphone-app/assets/images/menu_forward_custom.svg b/linphone-app/assets/images/menu_forward_custom.svg new file mode 100644 index 000000000..069924dae --- /dev/null +++ b/linphone-app/assets/images/menu_forward_custom.svg @@ -0,0 +1,49 @@ + + + + + + + + + + diff --git a/linphone-app/assets/images/menu_reply_custom.svg b/linphone-app/assets/images/menu_reply_custom.svg new file mode 100644 index 000000000..4a17c45cc --- /dev/null +++ b/linphone-app/assets/images/menu_reply_custom.svg @@ -0,0 +1,49 @@ + + + + + + + + + + diff --git a/linphone-app/assets/languages/da.ts b/linphone-app/assets/languages/da.ts index e49100424..937dc2639 100644 --- a/linphone-app/assets/languages/da.ts +++ b/linphone-app/assets/languages/da.ts @@ -533,6 +533,16 @@ Server url ikke konfigureret. 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ Server url ikke konfigureret. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/de.ts b/linphone-app/assets/languages/de.ts index 7476a7702..21ba52830 100644 --- a/linphone-app/assets/languages/de.ts +++ b/linphone-app/assets/languages/de.ts @@ -533,6 +533,16 @@ Server URL ist nicht konfiguriert. 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ Server URL ist nicht konfiguriert. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/en.ts b/linphone-app/assets/languages/en.ts index 5b4616d2a..cbd882a41 100644 --- a/linphone-app/assets/languages/en.ts +++ b/linphone-app/assets/languages/en.ts @@ -533,6 +533,16 @@ Server URL not configured. 'Hide delivery status' : Item menu that lead to IMDN of a message Hide delivery status + + menuForward + 'Forward' : Forward a message from menu + Forward + + + menuReply + 'Reply' : Reply to a message from menu + Reply + ChatNoticeModel @@ -565,6 +575,22 @@ Server URL not configured. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + Reply + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + Reply to %1 + + Cli diff --git a/linphone-app/assets/languages/es.ts b/linphone-app/assets/languages/es.ts index 980be9b5f..858ffca36 100644 --- a/linphone-app/assets/languages/es.ts +++ b/linphone-app/assets/languages/es.ts @@ -533,6 +533,16 @@ URL del servidor no configurada. 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ URL del servidor no configurada. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/fr_FR.ts b/linphone-app/assets/languages/fr_FR.ts index 176fb0a88..d933a195a 100644 --- a/linphone-app/assets/languages/fr_FR.ts +++ b/linphone-app/assets/languages/fr_FR.ts @@ -159,7 +159,7 @@ usernameStatusInvalidCharacters - Caractères invalides détectés (regex : `%1`). + Caractères invalides détectés (regex : `%1`). usernameStatusInvalid @@ -175,7 +175,7 @@ passwordStatusInvalidCharacters - Caractères invalides détectés (regex : `%1`). + Caractères invalides détectés (regex : `%1`). passwordStatusMissingCharacters @@ -533,6 +533,16 @@ URL du serveur non configurée. 'Hide delivery status' : Item menu that lead to IMDN of a message Cacher le statut du message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ URL du serveur non configurée. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli @@ -978,7 +1004,7 @@ URL du serveur non configurée. ephemeralNotInConference! 'Ephemeral message is only supported in conference based chat room!' - Les messages éphémères ne sont disponibles que pour une conversation définie en mode conférence ! + Les messages éphémères ne sont disponibles que pour une conversation définie en mode conférence ! Warning about not being in conference based chat room. @@ -1917,7 +1943,7 @@ Cliquez ici : <a href="%1">%1</a> serverTooltip - Serveur LDAP. ie : ldap:// pour un serveur local ou ldap://ldap.example.org/ + Serveur LDAP. ie : ldap:// pour un serveur local ou ldap://ldap.example.org/ bindDNLabel diff --git a/linphone-app/assets/languages/hu.ts b/linphone-app/assets/languages/hu.ts index 73e12b2cd..9f35ae17a 100644 --- a/linphone-app/assets/languages/hu.ts +++ b/linphone-app/assets/languages/hu.ts @@ -532,6 +532,16 @@ A kiszolgáló URL-je nincs konfigurálva. 'Hide delivery status' : Item menu that lead to IMDN of a message Kézbesítési állapot elrejtése + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -560,6 +570,22 @@ A kiszolgáló URL-je nincs konfigurálva. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/it.ts b/linphone-app/assets/languages/it.ts index 6b58309e2..848f35fde 100644 --- a/linphone-app/assets/languages/it.ts +++ b/linphone-app/assets/languages/it.ts @@ -533,6 +533,16 @@ URL del server non configurato. 'Hide delivery status' : Item menu that lead to IMDN of a message Nascondi lo stato del messaggio + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ URL del server non configurato. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/ja.ts b/linphone-app/assets/languages/ja.ts index 4879d776f..b94c01e8b 100644 --- a/linphone-app/assets/languages/ja.ts +++ b/linphone-app/assets/languages/ja.ts @@ -532,6 +532,16 @@ 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -560,6 +570,22 @@ + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/lt.ts b/linphone-app/assets/languages/lt.ts index e0b6f91d0..501bf3120 100644 --- a/linphone-app/assets/languages/lt.ts +++ b/linphone-app/assets/languages/lt.ts @@ -534,6 +534,16 @@ Nesukonfigūruotas serverio url. 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -570,6 +580,22 @@ Nesukonfigūruotas serverio url. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/pt_BR.ts b/linphone-app/assets/languages/pt_BR.ts index b5be19ad5..55de11580 100644 --- a/linphone-app/assets/languages/pt_BR.ts +++ b/linphone-app/assets/languages/pt_BR.ts @@ -533,6 +533,16 @@ URL do servidor não configurado. 'Hide delivery status' : Item menu that lead to IMDN of a message Ocultar status de entrega + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ URL do servidor não configurado. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/ru.ts b/linphone-app/assets/languages/ru.ts index 94cbb7e3b..3c220282b 100644 --- a/linphone-app/assets/languages/ru.ts +++ b/linphone-app/assets/languages/ru.ts @@ -534,6 +534,16 @@ 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -570,6 +580,22 @@ + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/sv.ts b/linphone-app/assets/languages/sv.ts index 3a9aed662..99861de06 100644 --- a/linphone-app/assets/languages/sv.ts +++ b/linphone-app/assets/languages/sv.ts @@ -533,6 +533,16 @@ Serverwebbadressen är inte konfigurerad. 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -565,6 +575,22 @@ Serverwebbadressen är inte konfigurerad. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/tr.ts b/linphone-app/assets/languages/tr.ts index 55979490d..687cf8285 100644 --- a/linphone-app/assets/languages/tr.ts +++ b/linphone-app/assets/languages/tr.ts @@ -532,6 +532,16 @@ Sunucu url'si yapılandırılmadı. 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -560,6 +570,22 @@ Sunucu url'si yapılandırılmadı. + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/uk.ts b/linphone-app/assets/languages/uk.ts index f12ea353b..6039d55b9 100644 --- a/linphone-app/assets/languages/uk.ts +++ b/linphone-app/assets/languages/uk.ts @@ -534,6 +534,16 @@ 'Hide delivery status' : Item menu that lead to IMDN of a message + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -570,6 +580,22 @@ + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/assets/languages/zh_CN.ts b/linphone-app/assets/languages/zh_CN.ts index cd78ba20c..b5cbca736 100644 --- a/linphone-app/assets/languages/zh_CN.ts +++ b/linphone-app/assets/languages/zh_CN.ts @@ -532,6 +532,16 @@ 'Hide delivery status' : Item menu that lead to IMDN of a message 隐藏发送状态 + + menuForward + 'Forward' : Forward a message from menu + + + + menuReply + 'Reply' : Reply to a message from menu + + ChatNoticeModel @@ -560,6 +570,22 @@ + + ChatReplyMessage + + headerReply + 'Reply' : Header on a message that contains a reply. + + + + + ChatReplyPreview + + titleReply + 'Reply to %1' : Title for a reply preview to know who said what. + + + Cli diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index 8a20f82ba..91269be15 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -82,6 +82,8 @@ assets/images/led_red.svg assets/images/led_white.svg assets/images/menu_copy_text_custom.svg + assets/images/menu_reply_custom.svg + assets/images/menu_forward_custom.svg assets/images/menu_imdn_info_custom.svg assets/images/menu_vdots_custom.svg assets/images/menu_info_custom.svg @@ -134,7 +136,7 @@ assets/images/tooltip_arrow_right_custom.svg assets/images/tooltip_arrow_top_custom.svg assets/images/transfer_custom.svg - assets/images/update_sign.svg + assets/images/update_sign.svg assets/images/video_call_accept_custom.svg assets/images/video_call_custom.svg assets/images/warning.svg @@ -268,6 +270,9 @@ ui/modules/Linphone/Chat/Chat.qml ui/modules/Linphone/Chat/ChatDeliveries.qml ui/modules/Linphone/Chat/ChatMenu.qml + ui/modules/Linphone/Chat/ChatMessagePreview.qml + ui/modules/Linphone/Chat/ChatReplyMessage.qml + ui/modules/Linphone/Chat/ChatReplyPreview.qml ui/modules/Linphone/Chat/Event.qml ui/modules/Linphone/Chat/FileMessage.qml ui/modules/Linphone/Chat/IncomingMessage.qml @@ -307,6 +312,7 @@ ui/modules/Linphone/Styles/Calls/CallStatisticsStyle.qml ui/modules/Linphone/Styles/Calls/ConferenceControlsStyle.qml ui/modules/Linphone/Styles/Chat/ChatStyle.qml + ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml ui/modules/Linphone/Styles/Codecs/CodecsViewerStyle.qml ui/modules/Linphone/Styles/Contact/AvatarStyle.qml ui/modules/Linphone/Styles/Contact/ContactDescriptionStyle.qml diff --git a/linphone-app/src/components/chat-events/ChatMessageModel.cpp b/linphone-app/src/components/chat-events/ChatMessageModel.cpp index 3661d9448..237896c7f 100644 --- a/linphone-app/src/components/chat-events/ChatMessageModel.cpp +++ b/linphone-app/src/components/chat-events/ChatMessageModel.cpp @@ -82,7 +82,6 @@ QString ContentModel::getThumbnail() const{ return mThumbnail; } - void ContentModel::setFileOffset(quint64 fileOffset){ if( mFileOffset != fileOffset) { mFileOffset = fileOffset; @@ -302,6 +301,12 @@ ChatMessageModel::ChatMessageModel ( std::shared_ptr chat mWasDownloaded = false; mChatMessage->addListener(mChatMessageListener); mTimestamp = QDateTime::fromMSecsSinceEpoch(chatMessage->getTime() * 1000); + if( mChatMessage->isReply()){ + auto replyMessage = mChatMessage->getReplyMessage(); + if( replyMessage)// Reply message could be inexistant (for example : when locally deleted) + mReplyChatMessageModel = create(replyMessage, parent); + } + connect(this, &ChatMessageModel::remove, dynamic_cast(parent), &ChatRoomModel::removeEntry); std::list> contents = chatMessage->getContents(); @@ -365,6 +370,13 @@ QString ChatMessageModel::getFromDisplayName() const{ return Utils::getDisplayName(mChatMessage->getFromAddress()); } +QString ChatMessageModel::getFromDisplayNameReplyMessage() const{ + if( isReply()) + return Utils::getDisplayName(mChatMessage->getReplyMessageSenderAddress()); + else + return ""; +} + QString ChatMessageModel::getFromSipAddress() const{ return Utils::cleanSipAddress(Utils::coreStringToAppString(mChatMessage->getFromAddress()->asStringUriOnly())); } @@ -424,6 +436,13 @@ std::shared_ptr ChatMessageModel::getParticipantI return mParticipantImdnStateListModel; } +bool ChatMessageModel::isReply() const{ + return mChatMessage->isReply(); +} + +ChatMessageModel * ChatMessageModel::getReplyChatMessageModel() const{ + return mReplyChatMessageModel.get(); +} //----------------------------------------------------------------------------------------------------------------------- diff --git a/linphone-app/src/components/chat-events/ChatMessageModel.hpp b/linphone-app/src/components/chat-events/ChatMessageModel.hpp index 66d07056a..c31741f2e 100644 --- a/linphone-app/src/components/chat-events/ChatMessageModel.hpp +++ b/linphone-app/src/components/chat-events/ChatMessageModel.hpp @@ -60,6 +60,7 @@ public: Q_PROPERTY(QString thumbnail READ getThumbnail WRITE setThumbnail NOTIFY thumbnailChanged) Q_PROPERTY(bool wasDownloaded MEMBER mWasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged) + std::shared_ptr getContent()const; quint64 getFileSize() const; @@ -135,6 +136,7 @@ public: Q_PROPERTY(QString fromDisplayName READ getFromDisplayName CONSTANT) + Q_PROPERTY(QString fromDisplayNameReplyMessage READ getFromDisplayNameReplyMessage CONSTANT) Q_PROPERTY(QString fromSipAddress READ getFromSipAddress CONSTANT) Q_PROPERTY(QString toDisplayName READ getToDisplayName CONSTANT) Q_PROPERTY(QString toSipAddress READ getToSipAddress CONSTANT) @@ -155,6 +157,9 @@ public: Q_PROPERTY(ContentModel * fileContentModel READ getFileContentModel NOTIFY fileContentChanged) //Q_PROPERTY(QList contents READ getContents CONSTANT) + Q_PROPERTY(bool isReply READ isReply CONSTANT) + Q_PROPERTY(ChatMessageModel* replyChatMessageModel READ getReplyChatMessageModel CONSTANT) + std::shared_ptr getChatMessage(); std::shared_ptr getContentModel(std::shared_ptr content); Q_INVOKABLE ContentModel * getContent(int i); @@ -162,6 +167,7 @@ public: //---------------------------------------------------------------------------- QString getFromDisplayName() const; + QString getFromDisplayNameReplyMessage() const; QString getFromSipAddress() const; QString getToDisplayName() const; QString getToSipAddress() const; @@ -176,6 +182,9 @@ public: Q_INVOKABLE ParticipantImdnStateProxyModel * getProxyImdnStates(); std::shared_ptr getParticipantImdnStates() const; + bool isReply() const; + ChatMessageModel * getReplyChatMessageModel() const; + //---------------------------------------------------------------------------- void setWasDownloaded(bool wasDownloaded); @@ -219,6 +228,8 @@ private: std::shared_ptr mChatMessage; std::shared_ptr mParticipantImdnStateListModel; std::shared_ptr mChatMessageListener; + + std::shared_ptr mReplyChatMessageModel; }; Q_DECLARE_METATYPE(ChatMessageModel*) Q_DECLARE_METATYPE(std::shared_ptr) diff --git a/linphone-app/src/components/chat-room/ChatRoomModel.cpp b/linphone-app/src/components/chat-room/ChatRoomModel.cpp index 823dfd036..26b657a6d 100644 --- a/linphone-app/src/components/chat-room/ChatRoomModel.cpp +++ b/linphone-app/src/components/chat-room/ChatRoomModel.cpp @@ -187,7 +187,7 @@ std::shared_ptr ChatRoomModel::create(std::shared_ptr chatRoom, QObject * parent) : QAbstractListModel(parent){ App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE CoreManager *coreManager = CoreManager::getInstance(); - + mReply = nullptr; mCoreHandlers = coreManager->getHandlers(); mChatRoom = chatRoom; @@ -592,6 +592,14 @@ void ChatRoomModel::setEphemeralLifetime(long lifetime){ } } +void ChatRoomModel::setReply(ChatMessageModel * model){ + if(mReply) + clearReply(); + mReply = model->getChatMessage(); +} +void ChatRoomModel::clearReply(){ + mReply = nullptr; +} //------------------------------------------------------------------------------------------------ void ChatRoomModel::deleteChatRoom(){ @@ -630,9 +638,15 @@ void ChatRoomModel::updateParticipants(const QVariantList& participants){ // ----------------------------------------------------------------------------- void ChatRoomModel::sendMessage (const QString &message) { - shared_ptr _message = mChatRoom->createMessageFromUtf8(message.toUtf8().toStdString()); - _message->send(); + shared_ptr _message; + if(mReply){ + _message = mChatRoom->createReplyMessage(mReply); + _message->addUtf8TextContent(message.toUtf8().toStdString()); + }else{ + _message= mChatRoom->createMessageFromUtf8(message.toUtf8().toStdString()); + } + _message->send(); emit messageSent(_message); } diff --git a/linphone-app/src/components/chat-room/ChatRoomModel.hpp b/linphone-app/src/components/chat-room/ChatRoomModel.hpp index c238eea79..c94ebe705 100644 --- a/linphone-app/src/components/chat-room/ChatRoomModel.hpp +++ b/linphone-app/src/components/chat-room/ChatRoomModel.hpp @@ -35,6 +35,7 @@ class ParticipantListModel; class ChatEvent; class ContactModel; class ChatRoomModel; +class ChatMessageModel; class ChatRoomModelListener : public QObject, public linphone::ChatRoomListener { Q_OBJECT @@ -207,6 +208,9 @@ public: void addMissedCallsCount(std::shared_ptr call); void setEphemeralEnabled(bool enabled); void setEphemeralLifetime(long lifetime); + + void setReply(ChatMessageModel * model); + void clearReply(); // Tools @@ -336,6 +340,8 @@ private: std::shared_ptr mChatRoom; std::shared_ptr mChatRoomModelListener; + std::shared_ptr mReply; + std::weak_ptr mSelf; }; diff --git a/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp b/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp index b6198d4db..532b1c672 100644 --- a/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp +++ b/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp @@ -120,6 +120,8 @@ CREATE_PARENT_MODEL_FUNCTION(removeAllEntries) CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendFileMessage, const QString &) CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendMessage, const QString &) +CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(setReply, ChatMessageModel*) +CREATE_PARENT_MODEL_FUNCTION(clearReply) CREATE_PARENT_MODEL_FUNCTION_WITH_ID(removeRow) diff --git a/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp b/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp index 5dd0faa01..3a003faea 100644 --- a/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp +++ b/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp @@ -70,6 +70,9 @@ public: Q_INVOKABLE void setFilterText(const QString& text); + Q_INVOKABLE void setReply(ChatMessageModel* model); + Q_INVOKABLE void clearReply(); + signals: void peerAddressChanged (const QString &peerAddress); void localAddressChanged (const QString &localAddress); diff --git a/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml b/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml index 5c98e449b..fb0d13a81 100644 --- a/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml +++ b/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml @@ -23,6 +23,9 @@ Item { property string dropDisabledReason property bool isEphemeral : false + property int textLeftMargin: (fileChooserButton.visible? fileChooserButton.totalWidth + DroppableTextAreaStyle.fileChooserButton.margins: 0) + property int textRightMargin: sendButton.visible ? sendButton.totalWidth + DroppableTextAreaStyle.fileChooserButton.margins : 0 + // --------------------------------------------------------------------------- signal dropped (var files) @@ -55,6 +58,7 @@ Item { // Handle click to select files. ActionButton { id: fileChooserButton + property int totalWidth: DroppableTextAreaStyle.fileChooserButton.margins + width Layout.leftMargin: DroppableTextAreaStyle.fileChooserButton.margins Layout.alignment: Qt.AlignVCenter @@ -189,6 +193,7 @@ Item { // Handle click to select files. ActionButton { id: sendButton + property int totalWidth: Layout.rightMargin + Layout.leftMargin + width Layout.rightMargin: DroppableTextAreaStyle.fileChooserButton.margins+15 Layout.leftMargin: 10 Layout.alignment: Qt.AlignVCenter diff --git a/linphone-app/ui/modules/Common/Styles/Menus/MenuItemStyle.qml b/linphone-app/ui/modules/Common/Styles/Menus/MenuItemStyle.qml index 531eac7b7..d9734b636 100644 --- a/linphone-app/ui/modules/Common/Styles/Menus/MenuItemStyle.qml +++ b/linphone-app/ui/modules/Common/Styles/Menus/MenuItemStyle.qml @@ -18,6 +18,14 @@ QtObject { property int iconSize: 30 property string icon : 'menu_copy_text_custom' } + property QtObject reply: QtObject { + property int iconSize: 30 + property string icon : 'menu_reply_custom' + } + property QtObject forward: QtObject { + property int iconSize: 30 + property string icon : 'menu_forward_custom' + } property QtObject imdn: QtObject { property int iconSize: 30 property string icon : 'menu_imdn_info_custom' diff --git a/linphone-app/ui/modules/Linphone/Chat/Chat.qml b/linphone-app/ui/modules/Linphone/Chat/Chat.qml index 7e9ef14a5..c4c9fc1e8 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Chat.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Chat.qml @@ -5,8 +5,11 @@ import QtQuick.Layouts 1.3 import Common 1.0 import Linphone 1.0 import Linphone.Styles 1.0 +import Utils 1.0 import UtilsCpp 1.0 +import Units 1.0 + import 'Chat.js' as Logic // ============================================================================= @@ -20,6 +23,8 @@ Rectangle { property string noticeBannerText : '' // When set, show a banner with text and hide after some time onNoticeBannerTextChanged: if(noticeBannerText!='') messageBlock.state = "showed" + property alias replyChatMessageModel: chatMessagePreview.replyChatMessageModel + // --------------------------------------------------------------------------- signal messageToSend (string text) @@ -259,31 +264,38 @@ Rectangle { source: Logic.getComponentFromEntry($chatEntry) } Connections{ - target: loader.item - ignoreUnknownSignals: true - //: "Copied to clipboard" : when a user copy a text from the menu, this message show up. - onCopyAllDone: container.noticeBannerText = qsTr("allTextCopied") - //: "Selection copied to clipboard" : when a user copy a text from the menu, this message show up. - onCopySelectionDone: container.noticeBannerText = qsTr("selectedTextCopied") + target: loader.item + ignoreUnknownSignals: true + //: "Copied to clipboard" : when a user copy a text from the menu, this message show up. + onCopyAllDone: container.noticeBannerText = qsTr("allTextCopied") + //: "Selection copied to clipboard" : when a user copy a text from the menu, this message show up. + onCopySelectionDone: container.noticeBannerText = qsTr("selectedTextCopied") + onReplyClicked: { + proxyModel.setReply($chatEntry) + container.replyChatMessageModel = $chatEntry } + } } } } } footer: Item{ - Text { - property var composers : container.proxyModel.composers - color: ChatStyle.composingText.color - font.pointSize: ChatStyle.composingText.pointSize - height: visible ? undefined : 0 - leftPadding: ChatStyle.composingText.leftPadding - visible: composers.length > 0 && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled) - wrapMode: Text.Wrap - //: '%1 is typing...' indicate that someone is composing in chat - text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers())) - } - } - + Text { + property var composers : container.proxyModel.composers + color: ChatStyle.composingText.color + font.pointSize: ChatStyle.composingText.pointSize + height: visible ? undefined : 0 + leftPadding: ChatStyle.composingText.leftPadding + visible: composers.length > 0 && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled) + wrapMode: Text.Wrap + //: '%1 is typing...' indicate that someone is composing in chat + text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers())) + } + } + + ChatMessagePreview{ + id: chatMessagePreview + } Rectangle{ id: messageBlock height: 32 @@ -315,30 +327,30 @@ Rectangle { Layout.fillWidth: true text: container.noticeBannerText font { - pointSize: ChatStyle.messageBanner.pointSize - } + pointSize: ChatStyle.messageBanner.pointSize + } color: ChatStyle.messageBanner.textColor } } states: [ - State { - name: "hidden" - PropertyChanges { target: messageBlock; opacity: 0 } - }, - State { - name: "showed" - PropertyChanges { target: messageBlock; opacity: 1 } - } - ] - transitions: [ - Transition { - from: "*"; to: "showed" - SequentialAnimation{ + State { + name: "hidden" + PropertyChanges { target: messageBlock; opacity: 0 } + }, + State { + name: "showed" + PropertyChanges { target: messageBlock; opacity: 1 } + } + ] + transitions: [ + Transition { + from: "*"; to: "showed" + SequentialAnimation{ NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 500 } - ScriptAction{ script: hideNoticeBanner.start()} + ScriptAction{ script: hideNoticeBanner.start()} } - }, - Transition { + }, + Transition { SequentialAnimation{ NumberAnimation{ properties: "opacity"; duration: 1000 } ScriptAction{ script: container.noticeBannerText = '' } @@ -360,7 +372,7 @@ Rectangle { borderColor: ChatStyle.sendArea.border.color topWidth: ChatStyle.sendArea.border.width visible: proxyModel.chatRoomModel && !proxyModel.chatRoomModel.hasBeenLeft && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled) - + DroppableTextArea { id: textArea @@ -385,9 +397,10 @@ Rectangle { onValidText: { textArea.text = '' chat.bindToEnd = true - if(proxyModel.chatRoomModel) + if(proxyModel.chatRoomModel) { proxyModel.sendMessage(text) - else{ + + }else{ console.log("Peer : " +proxyModel.peerAddress+ "/"+chat.model.peerAddress) proxyModel.chatRoomModel = CallsListModel.createChat(proxyModel.peerAddress) proxyModel.sendMessage(text) diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml b/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml index 7f136e185..a85cebd6b 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml @@ -28,6 +28,8 @@ Item { signal removeEntryRequested() signal copyAllDone() signal copySelectionDone() + signal replyClicked() + signal forwardClicked() function open(){ messageMenu.popup() @@ -68,6 +70,27 @@ Item { onTriggered: TextToSpeech.say(container.content) visible: content != '' } + MenuItem { + //: 'Forward' : Forward a message from menu + text: qsTr('menuForward') + iconMenu: MenuItemStyle.forward.icon + iconSizeMenu: MenuItemStyle.forward.iconSize + iconLayoutDirection: Qt.RightToLeft + menuItemStyle : MenuItemStyle.aux + onTriggered: container.forwardClicked() + visible: content != '' + } + MenuItem { + //: 'Reply' : Reply to a message from menu + text: qsTr('menuReply') + iconMenu: MenuItemStyle.reply.icon + iconSizeMenu: MenuItemStyle.reply.iconSize + iconLayoutDirection: Qt.RightToLeft + menuItemStyle : MenuItemStyle.aux + onTriggered: container.replyClicked() + visible: content != '' + } + MenuItem { //: 'Hide delivery status' : Item menu that lead to IMDN of a message text: (deliveryVisible ? qsTr('menuHideDeliveryStatus') @@ -97,8 +120,6 @@ Item { // Handle hovered link. MouseArea { anchors.fill: parent - //height: messageMenu.height - //width: messageMenu.width acceptedButtons: Qt.RightButton propagateComposedEvents:true diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml b/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml new file mode 100644 index 000000000..b7a15aa38 --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml @@ -0,0 +1,28 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import Common 1.0 +import Linphone 1.0 +import Linphone.Styles 1.0 +import Utils 1.0 +import UtilsCpp 1.0 + +import Units 1.0 + +import 'Chat.js' as Logic + +// ============================================================================= +ColumnLayout{ + property alias replyChatMessageModel : replyPreview.replyChatMessageModel + property int maxHeight: parent.height + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: replyPreview.height + + ChatReplyPreview{ + id: replyPreview + Layout.fillWidth: true + } +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml new file mode 100644 index 000000000..688e15a9d --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml @@ -0,0 +1,126 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +import Clipboard 1.0 +import Common 1.0 +import Linphone 1.0 + +import Common.Styles 1.0 +import Linphone.Styles 1.0 +import TextToSpeech 1.0 +import Utils 1.0 +import Units 1.0 +import UtilsCpp 1.0 +import LinphoneEnums 1.0 + +import ColorsList 1.0 + +import 'Message.js' as Logic + +// ============================================================================= + +Item { + id: mainItem + property ChatMessageModel chatMessageModel + property ChatMessageModel mainChatMessageModel + property int maxWidth : parent.width + property int contentWidth: Math.max(usernameReplied.implicitWidth + replyMessage.implicitWidth , headerArea.width) + 7 + ChatReplyMessageStyle.padding * 2 + property int contentHeight: headerArea.height + replyArea.height + property font customFont : SettingsModel.textMessageFont + + width: maxWidth > contentWidth ? contentWidth : maxWidth + + onMainChatMessageModelChanged: if( mainChatMessageModel.replyChatMessageModel) chatMessageModel = mainChatMessageModel.replyChatMessageModel + + ColumnLayout{ + anchors.fill: parent + spacing: 5 + Row{ + id: headerArea + Layout.preferredHeight: icon.height + Layout.topMargin: 5 + Icon{ + id: icon + icon: ChatReplyMessageStyle.header.replyIcon.icon + iconSize: ChatReplyMessageStyle.header.replyIcon.iconSize + height: iconSize + overwriteColor: ChatReplyMessageStyle.header.color + } + Text{ + height: icon.height + verticalAlignment: Qt.AlignVCenter + //: 'Reply' : Header on a message that contains a reply. + text: qsTr('headerReply') + + (chatMessageModel || !mainChatMessageModel? '' : ' - ' + mainChatMessageModel.fromDisplayNameReplyMessage) + font.family: mainItem.customFont.family + font.pointSize: Units.dp * (mainItem.customFont.pointSize + ChatReplyMessageStyle.header.pointSizeOffset) + color: ChatReplyMessageStyle.header.color + } + } + Rectangle{ + id: replyArea + Layout.fillWidth: true + Layout.preferredHeight: (chatMessageModel ? replyMessage.implicitHeight + usernameReplied.implicitHeight + ChatStyle.entry.message.padding : 0) + Layout.bottomMargin: ChatStyle.entry.message.padding + Layout.leftMargin: 10 + Layout.rightMargin: 10 + Rectangle{ + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: 7 + color: chatMessageModel && chatMessageModel.isOutgoing ? ChatReplyMessageStyle.replyArea.outgoingMarkColor : ChatReplyMessageStyle.replyArea.incomingMarkColor + } + + radius: 5 + color: ChatReplyMessageStyle.replyArea.backgroundColor + visible: chatMessageModel != undefined + Text{ + id: usernameReplied + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 3 + + + leftPadding: 2 * ChatStyle.entry.message.padding + + text: mainChatMessageModel && mainChatMessageModel.fromDisplayNameReplyMessage + font.family: mainItem.customFont.family + font.pointSize: Units.dp * (mainItem.customFont.pointSize + ChatReplyMessageStyle.replyArea.usernamePointSizeOffset) + font.weight: Font.Bold + + color: ChatReplyMessageStyle.replyArea.foregroundColor + } + TextEdit { + id: replyMessage + property string lastTextSelected : '' + property font customFont : SettingsModel.textMessageFont + + anchors.top: usernameReplied.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 3 + + clip: true + leftPadding: 2*ChatStyle.entry.message.padding + rightPadding: ChatStyle.entry.message.padding + bottomPadding: ChatStyle.entry.message.padding + readOnly: true + selectByMouse: true + font.family: customFont.family + font.pointSize: Units.dp * (customFont.pointSize + ChatReplyMessageStyle.replyArea.pointSizeOffset) + font.weight: Font.Light + color: ChatReplyMessageStyle.replyArea.foregroundColor + text: (visible ? Utils.encodeTextToQmlRichFormat(chatMessageModel.content, { + imagesHeight: ChatStyle.entry.message.images.height, + imagesWidth: ChatStyle.entry.message.images.width + }) + : '') + + textFormat: Text.RichText // To supports links and imgs. + wrapMode: TextEdit.Wrap + } + } + } +} diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml b/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml new file mode 100644 index 000000000..01df0ddcd --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml @@ -0,0 +1,139 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import Common 1.0 +import Linphone 1.0 +import Linphone.Styles 1.0 +import Utils 1.0 +import UtilsCpp 1.0 + +import Units 1.0 + +import 'Chat.js' as Logic + +// ============================================================================= + +Rectangle{ + id: replyPreviewBlock + property ChatMessageModel replyChatMessageModel + onReplyChatMessageModelChanged: if(replyChatMessageModel) replyPreviewBlock.state = "showed" + + Layout.preferredHeight: Math.min(replayPreviewText.implicitHeight + replyPreviewHeaderArea.implicitHeight + 10, parent.maxHeight) + + property int leftMargin: textArea.textLeftMargin + property int rightMargin: textArea.textRightMargin + + color: ChatStyle.replyPreview.backgroundColor + radius: 10 + state: "hidden" + visible: container.replyChatMessageModel +// Remove bottom corners + clip: false + Rectangle{ + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: parent.radius + color: parent.color + } +//------------------------- + ColumnLayout{ + anchors.fill: parent + anchors.leftMargin: replyPreviewBlock.leftMargin + anchors.rightMargin: replyPreviewBlock.rightMargin + spacing: 0 + RowLayout{ + id: replyPreviewHeaderArea + Layout.fillWidth: true + Layout.preferredHeight: replyPreviewTitleText.implicitHeight + Layout.topMargin: 10 + spacing: 5 + Icon{ + icon: ChatStyle.replyPreview.icon + overwriteColor: ChatStyle.replyPreview.iconColor + iconSize: 20 + } + Text{ + id: replyPreviewTitleText + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + //: 'Reply to %1' : Title for a reply preview to know who said what. + text: container.replyChatMessageModel ? qsTr('titleReply').arg(container.replyChatMessageModel.fromDisplayName) : '' + font.pointSize: ChatStyle.replyPreview.headerPointSize + font.weight: Font.Bold + color: ChatStyle.replyPreview.headerTextColor + } + } + Flickable { + id: replayPreviewTextArea + ScrollBar.vertical: ForceScrollBar {visible: replayPreviewTextArea.height < replayPreviewText.implicitHeight} + boundsBehavior: Flickable.StopAtBounds + clip: true + contentHeight: replayPreviewText.implicitHeight + contentWidth: width - ScrollBar.vertical.width + flickableDirection: Flickable.VerticalFlick + + Layout.fillHeight: true + Layout.fillWidth: true + + TextEdit { + id: replayPreviewText + property font customFont : SettingsModel.textMessageFont + + anchors.left: parent.left + anchors.right: parent.right + clip: true + padding: ChatStyle.entry.message.padding + readOnly: true + selectByMouse: true + font.family: customFont.family + font.pointSize: Units.dp * (customFont.pointSize - 2) + text: replyChatMessageModel ? Utils.encodeTextToQmlRichFormat(replyChatMessageModel.content, { + imagesHeight: ChatStyle.entry.message.images.height, + imagesWidth: ChatStyle.entry.message.images.width + }) + : '' + textFormat: Text.RichText // To supports links and imgs. + wrapMode: TextEdit.Wrap + + onLinkActivated: Qt.openUrlExternally(link) + } + } + } + ActionButton{ + anchors.right:parent.right + anchors.rightMargin: 14 + anchors.verticalCenter: parent.verticalCenter + height: ChatStyle.replyPreview.closeButton.iconSize + isCustom: true + backgroundRadius: 90 + colorSet: ChatStyle.replyPreview.closeButton + + onClicked: parent.state = 'hidden' + } + states: [ + State { + name: "hidden" + PropertyChanges { target: replyPreviewBlock; opacity: 0 } + }, + State { + name: "showed" + PropertyChanges { target: replyPreviewBlock; opacity: 1 } + } + ] + transitions: [ + Transition { + from: "*"; to: "showed" + SequentialAnimation{ + NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 500 } + } + }, + Transition { + SequentialAnimation{ + NumberAnimation{ properties: "opacity"; duration: 250 } + ScriptAction{ script: container.replyChatMessageModel = null } + } + } + ] +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml b/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml index 2be7dc21f..da6175024 100644 --- a/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml @@ -13,6 +13,8 @@ RowLayout { signal copyAllDone() signal copySelectionDone() + signal replyClicked() + signal forwardClicked() implicitHeight: message.height spacing: 0 @@ -61,6 +63,8 @@ RowLayout { onCopyAllDone: parent.copyAllDone() onCopySelectionDone: parent.copySelectionDone() + onReplyClicked: parent.replyClicked() + onForwardClicked: parent.forwardClicked() Layout.fillWidth: true diff --git a/linphone-app/ui/modules/Linphone/Chat/Message.qml b/linphone-app/ui/modules/Linphone/Chat/Message.qml index e850e5d05..af0a0f0f8 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Message.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Message.qml @@ -34,26 +34,28 @@ Item { signal copyAllDone() signal copySelectionDone() + signal replyClicked() + signal forwardClicked() // --------------------------------------------------------------------------- - implicitHeight: message.contentHeight + implicitHeight: message.contentHeight + + + (replyMessage.visible ? replyMessage.contentHeight + 5 : 0) + (ephemeralTimerRow.visible? message.padding * 4 : message.padding * 2) + (deliveryLayout.visible? deliveryLayout.height : 0) Rectangle { id: rectangle - + property int maxWidth: parent.width + property int dataWidth: Math.max(message.implicitWidth + 2*ChatStyle.entry.message.padding + 10, replyMessage.contentWidth) height: parent.height - (deliveryLayout.visible? deliveryLayout.height : 0) radius: ChatStyle.entry.message.radius width: ( - ephemeralTimerRow.visible && message.contentWidth < ephemeralTimerRow.width + ephemeralTimerRow.visible && dataWidth < ephemeralTimerRow.width ? ephemeralTimerRow.width - : message.contentWidth < parent.width - ? message.contentWidth - : parent.width - ) + message.padding * 2 + : Math.min(dataWidth, maxWidth) + ) Row{ id:ephemeralTimerRow anchors.right:parent.right @@ -78,64 +80,73 @@ Item { overwriteColor: ChatStyle.ephemeralTimer.timerColor iconSize: ChatStyle.ephemeralTimer.iconSize } - } - } - - + } // --------------------------------------------------------------------------- // Message. // --------------------------------------------------------------------------- - - TextEdit { - id: message - property string lastTextSelected : '' - property font customFont : SettingsModel.textMessageFont - - anchors { - left: container.left - right: container.right - } - - clip: true - padding: ChatStyle.entry.message.padding - readOnly: true - selectByMouse: true - font.family: customFont.family - font.pointSize: Units.dp * customFont.pointSize - text: Utils.encodeTextToQmlRichFormat($chatEntry.content, { - imagesHeight: ChatStyle.entry.message.images.height, - imagesWidth: ChatStyle.entry.message.images.width - }) - - // See http://doc.qt.io/qt-5/qml-qtquick-text.html#textFormat-prop - // and http://doc.qt.io/qt-5/richtext-html-subset.html - textFormat: Text.RichText // To supports links and imgs. - wrapMode: TextEdit.Wrap - - onCursorRectangleChanged: Logic.ensureVisible(cursorRectangle) - onLinkActivated: Qt.openUrlExternally(link) - onSelectedTextChanged:if(selectedText != '') lastTextSelected = selectedText - onActiveFocusChanged: { - if(activeFocus) - lastTextSelected = '' - deselect() - } - - ChatMenu{ - id:chatMenu - height: parent.height - width: rectangle.width - - lastTextSelected: message.lastTextSelected - content: $chatEntry.content - deliveryCount: deliveryLayout.model.count - onDeliveryStatusClicked: deliveryLayout.visible = !deliveryLayout.visible - onRemoveEntryRequested: removeEntry() - deliveryVisible: deliveryLayout.visible - - onCopyAllDone: container.copyAllDone() - onCopySelectionDone: container.copySelectionDone() + Column{ + anchors.left: parent.left + anchors.right: parent.right + spacing: 5 + ChatReplyMessage{ + id: replyMessage + mainChatMessageModel: $chatEntry + visible: $chatEntry.isReply + maxWidth: container.width + height: contentHeight + } + TextEdit { + id: message + property string lastTextSelected : '' + property font customFont : SettingsModel.textMessageFont + + anchors.left: parent.left + anchors.right: parent.right + + clip: true + padding: ChatStyle.entry.message.padding + readOnly: true + selectByMouse: true + font.family: customFont.family + font.pointSize: Units.dp * customFont.pointSize + text: Utils.encodeTextToQmlRichFormat($chatEntry.content, { + imagesHeight: ChatStyle.entry.message.images.height, + imagesWidth: ChatStyle.entry.message.images.width + }) + + // See http://doc.qt.io/qt-5/qml-qtquick-text.html#textFormat-prop + // and http://doc.qt.io/qt-5/richtext-html-subset.html + textFormat: Text.RichText // To supports links and imgs. + wrapMode: TextEdit.Wrap + + onCursorRectangleChanged: Logic.ensureVisible(cursorRectangle) + onLinkActivated: Qt.openUrlExternally(link) + onSelectedTextChanged:if(selectedText != '') lastTextSelected = selectedText + onActiveFocusChanged: { + if(activeFocus) + lastTextSelected = '' + deselect() + } + + ChatMenu{ + id:chatMenu + height: parent.height + width: rectangle.width + + lastTextSelected: message.lastTextSelected + content: $chatEntry.content + deliveryCount: deliveryLayout.model.count + onDeliveryStatusClicked: deliveryLayout.visible = !deliveryLayout.visible + onRemoveEntryRequested: removeEntry() + deliveryVisible: deliveryLayout.visible + + onCopyAllDone: container.copyAllDone() + onCopySelectionDone: container.copySelectionDone() + onReplyClicked: container.replyClicked() + onForwardClicked: container.forwardClicked() + } + } } } diff --git a/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml b/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml index 5b37d6909..8ff3e7ed0 100644 --- a/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml @@ -16,12 +16,16 @@ Item { signal copyAllDone() signal copySelectionDone() + signal replyClicked() + signal forwardClicked() Message { id: message onCopyAllDone: parent.copyAllDone() onCopySelectionDone: parent.copySelectionDone() + onReplyClicked: parent.replyClicked() + onForwardClicked: parent.forwardClicked() anchors { left: parent.left diff --git a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml new file mode 100644 index 000000000..5a5b64bb5 --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml @@ -0,0 +1,31 @@ +pragma Singleton +import QtQml 2.2 + +import Units 1.0 +import ColorsList 1.0 + +// ============================================================================= + +QtObject { + property string sectionName : 'ChatReplyMessage' + property color color: ColorsList.add(sectionName, 'q').color + property QtObject header: QtObject{ + property color color: ColorsList.add(sectionName+'_header', 'h').color + property int pointSizeOffset: -3 + property QtObject replyIcon: QtObject{ + property string icon : 'menu_reply_custom' + property int iconSize: 22 + } + } + property QtObject replyArea: QtObject{ + property color outgoingMarkColor: ColorsList.add(sectionName+'_reply_outgoing_mark', 'm').color + property color incomingMarkColor: ColorsList.add(sectionName+'_reply_incoming_mark', 'r').color + property color backgroundColor: ColorsList.add(sectionName+'_reply_bg', 'q').color + property color foregroundColor: ColorsList.add(sectionName+'_reply_fg', 'h').color + property int usernamePointSizeOffset: -2 + property int pointSizeOffset: -2 + } + + property int padding: 8 + +} diff --git a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml index 96f3958b2..c0a53d115 100644 --- a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml +++ b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml @@ -41,7 +41,28 @@ QtObject { property int leftPadding: 20 property int pointSize: Units.dp * 9 } - + property QtObject replyPreview: QtObject { + id: replyPreviewObject + property string name: 'replyPreview' + property string icon: 'menu_reply_custom' + property color backgroundColor: ColorsList.add(sectionName+'_'+name+'_bg', 'e').color + property color headerTextColor: ColorsList.add(sectionName+'_'+name+'_header_fg', 'i').color + property color iconColor: ColorsList.add(sectionName+'_'+name+'_header_fg', 'i').color + property color textColor: ColorsList.add(sectionName+'_'+name+'_fg', 'd').color + property int pointSize: Units.dp * 9 + property int headerPointSize: Units.dp * 9 + property QtObject closeButton: QtObject{ + property int iconSize: 30 + property string name : 'close' + property string icon : 'close_custom' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_b_n', icon, 'l_n_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_b_h', icon, 'l_h_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_b_p', icon, 'l_p_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_f_n', icon, 'l_n_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_f_h', icon, 'l_h_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_f_p', icon, 'l_p_b_fg').color + } + } property QtObject messageBanner: QtObject { property color color: ColorsList.add(sectionName+'_message_banner', '', 'Background of message banner', '#9ecd1d').color property color textColor: ColorsList.add(sectionName+'_message_banner_text', 'q', 'Text of message banner').color diff --git a/linphone-app/ui/modules/Linphone/Styles/qmldir b/linphone-app/ui/modules/Linphone/Styles/qmldir index 2eccc00c5..2a2445dc4 100644 --- a/linphone-app/ui/modules/Linphone/Styles/qmldir +++ b/linphone-app/ui/modules/Linphone/Styles/qmldir @@ -10,6 +10,7 @@ singleton CardBlockStyle 1.0 Blocks/CardBlockStyle.qml singleton RequestBlockStyle 1.0 Blocks/RequestBlockStyle.qml singleton ChatStyle 1.0 Chat/ChatStyle.qml +singleton ChatReplyMessageStyle 1.0 Chat/ChatReplyMessageStyle.qml singleton CallControlsStyle 1.0 Calls/CallControlsStyle.qml singleton CallsStyle 1.0 Calls/CallsStyle.qml diff --git a/linphone-app/ui/modules/Linphone/qmldir b/linphone-app/ui/modules/Linphone/qmldir index 096c3b498..5eae08a7e 100644 --- a/linphone-app/ui/modules/Linphone/qmldir +++ b/linphone-app/ui/modules/Linphone/qmldir @@ -15,6 +15,9 @@ Calls 1.0 Calls/Calls.qml CallStatistics 1.0 Calls/CallStatistics.qml Chat 1.0 Chat/Chat.qml +ChatMessagePreview 1.0 Chat/ChatMessagePreview.qml +ChatReplyMessage 1.0 Chat/ChatReplyMessage.qml +ChatReplyPreview 1.0 Chat/ChatReplyPreview.qml History 1.0 History/History.qml diff --git a/linphone-sdk b/linphone-sdk index 6f1485a2d..ec7245a7a 160000 --- a/linphone-sdk +++ b/linphone-sdk @@ -1 +1 @@ -Subproject commit 6f1485a2de0507a51087c81d6f457df8e6a496cd +Subproject commit ec7245a7a8a64d6f8e7f077e48e046907f524399