diff --git a/Linphone/core/chat/ChatCore.cpp b/Linphone/core/chat/ChatCore.cpp index 7bd72b4a9..a85a49b0f 100644 --- a/Linphone/core/chat/ChatCore.cpp +++ b/Linphone/core/chat/ChatCore.cpp @@ -162,6 +162,37 @@ void ChatCore::setSelf(QSharedPointer me) { mChatModelConnection->invokeToCore([this, message]() { setLastMessageInHistory(message); }); }); }); + mChatModelConnection->makeConnectToCore(&ChatCore::lSendTextMessage, [this](QString message) { + mChatModelConnection->invokeToModel([this, message]() { + auto linMessage = mChatModel->createTextMessageFromText(message); + linMessage->send(); + }); + }); + mChatModelConnection->makeConnectToModel( + &ChatModel::chatMessageSending, [this](const std::shared_ptr &chatRoom, + const std::shared_ptr &eventLog) { + auto message = eventLog->getChatMessage(); + if (message) { + auto newMessage = ChatMessageCore::create(message); + mChatModelConnection->invokeToCore([this, newMessage]() { appendMessageToMessageList(newMessage); }); + } + }); + mChatModelConnection->makeConnectToCore( + &ChatCore::lCompose, [this]() { mChatModelConnection->invokeToModel([this]() { mChatModel->compose(); }); }); + mChatModelConnection->makeConnectToModel( + &ChatModel::isComposingReceived, + [this](const std::shared_ptr &chatRoom, + const std::shared_ptr &remoteAddress, bool isComposing) { + if (mChatModel->getMonitor() != chatRoom) return; + QString name = isComposing ? ToolModel::getDisplayName(remoteAddress->clone()) : QString(); + auto remoteAddr = remoteAddress->clone(); + remoteAddr->clean(); + mChatModelConnection->invokeToCore( + [this, name, address = Utils::coreStringToAppString(remoteAddr->asStringUriOnly())]() { + setComposingName(name); + setComposingAddress(address); + }); + }); } QDateTime ChatCore::getLastUpdatedTime() const { @@ -275,6 +306,28 @@ void ChatCore::clearMessagesList() { emit messageListChanged(); } +QString ChatCore::getComposingName() const { + return mComposingName; +} + +void ChatCore::setComposingName(QString composingName) { + if (mComposingAddress != composingName) { + mComposingName = composingName; + emit composingUserChanged(); + } +} + +void ChatCore::setComposingAddress(QString composingAddress) { + if (mComposingAddress != composingAddress) { + mComposingAddress = composingAddress; + emit composingUserChanged(); + } +} + +QString ChatCore::getComposingAddress() const { + return mComposingAddress; +} + std::shared_ptr ChatCore::getModel() const { return mChatModel; } \ No newline at end of file diff --git a/Linphone/core/chat/ChatCore.hpp b/Linphone/core/chat/ChatCore.hpp index f76cd76b0..130c11d60 100644 --- a/Linphone/core/chat/ChatCore.hpp +++ b/Linphone/core/chat/ChatCore.hpp @@ -43,6 +43,8 @@ public: lastMessageInHistoryChanged) Q_PROPERTY(int unreadMessagesCount READ getUnreadMessagesCount WRITE setUnreadMessagesCount NOTIFY unreadMessagesCountChanged) + Q_PROPERTY(QString composingName READ getComposingName WRITE setComposingName NOTIFY composingUserChanged) + Q_PROPERTY(QString composingAddress READ getComposingAddress WRITE setComposingAddress NOTIFY composingUserChanged) // Q_PROPERTY(VideoStats videoStats READ getVideoStats WRITE setVideoStats NOTIFY videoStatsChanged) // Should be call from model Thread. Will be automatically in App thread after initialization @@ -78,6 +80,11 @@ public: QString getAvatarUri() const; void setAvatarUri(QString avatarUri); + QString getComposingName() const; + QString getComposingAddress() const; + void setComposingName(QString composingName); + void setComposingAddress(QString composingAddress); + std::shared_ptr getModel() const; signals: @@ -89,6 +96,7 @@ signals: void messageListChanged(); void avatarUriChanged(); void deleted(); + void composingUserChanged(); void lDeleteMessage(); void lDelete(); @@ -96,6 +104,8 @@ signals: void lMarkAsRead(); void lUpdateLastMessage(); void lUpdateUnreadCount(); + void lSendTextMessage(QString message); + void lCompose(); private: QString id; @@ -106,6 +116,8 @@ private: QString mIdentifier; QString mAvatarUri; int mUnreadMessagesCount; + QString mComposingName; + QString mComposingAddress; std::shared_ptr mChatModel; QList> mChatMessageList; QSharedPointer> mChatModelConnection; diff --git a/Linphone/core/chat/message/ChatMessageCore.cpp b/Linphone/core/chat/message/ChatMessageCore.cpp index b3c663445..07c8c75dd 100644 --- a/Linphone/core/chat/message/ChatMessageCore.cpp +++ b/Linphone/core/chat/message/ChatMessageCore.cpp @@ -45,6 +45,14 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr &c mIsRemoteMessage = !from->weakEqual(to); mPeerAddress = Utils::coreStringToAppString(chatmessage->getPeerAddress()->asStringUriOnly()); mPeerName = ToolModel::getDisplayName(chatmessage->getPeerAddress()->clone()); + auto fromAddress = chatmessage->getFromAddress()->clone(); + fromAddress->clean(); + mFromAddress = Utils::coreStringToAppString(fromAddress->asStringUriOnly()); + mFromName = ToolModel::getDisplayName(chatmessage->getFromAddress()->clone()); + + auto chatroom = chatmessage->getChatRoom(); + mIsFromChatGroup = chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) && + !chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne); } ChatMessageCore::~ChatMessageCore() { @@ -91,15 +99,24 @@ QString ChatMessageCore::getPeerName() const { return mPeerName; } +QString ChatMessageCore::getFromAddress() const { + return mFromAddress; +} + +QString ChatMessageCore::getFromName() const { + return mFromName; +} + +QString ChatMessageCore::getToAddress() const { + return mToAddress; +} + bool ChatMessageCore::isRemoteMessage() const { return mIsRemoteMessage; } -void ChatMessageCore::setIsRemoteMessage(bool isRemote) { - if (mIsRemoteMessage != isRemote) { - mIsRemoteMessage = isRemote; - emit isRemoteMessageChanged(isRemote); - } +bool ChatMessageCore::isFromChatGroup() const { + return mIsFromChatGroup; } std::shared_ptr ChatMessageCore::getModel() const { diff --git a/Linphone/core/chat/message/ChatMessageCore.hpp b/Linphone/core/chat/message/ChatMessageCore.hpp index b37679814..788a70769 100644 --- a/Linphone/core/chat/message/ChatMessageCore.hpp +++ b/Linphone/core/chat/message/ChatMessageCore.hpp @@ -36,8 +36,12 @@ class ChatMessageCore : public QObject, public AbstractObject { Q_PROPERTY(QDateTime timestamp READ getTimestamp WRITE setTimestamp NOTIFY timestampChanged) Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged) Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT) + Q_PROPERTY(QString fromAddress READ getFromAddress CONSTANT) + Q_PROPERTY(QString toAddress READ getToAddress CONSTANT) Q_PROPERTY(QString peerName READ getPeerName CONSTANT) - Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage WRITE setIsRemoteMessage NOTIFY isRemoteMessageChanged) + Q_PROPERTY(QString fromName READ getFromName CONSTANT) + Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT) + Q_PROPERTY(bool isFromChatGroup READ isFromChatGroup CONSTANT) public: static QSharedPointer create(const std::shared_ptr &chatmessage); @@ -53,9 +57,12 @@ public: QString getPeerAddress() const; QString getPeerName() const; + QString getFromAddress() const; + QString getFromName() const; + QString getToAddress() const; bool isRemoteMessage() const; - void setIsRemoteMessage(bool isRemote); + bool isFromChatGroup() const; std::shared_ptr getModel() const; @@ -70,9 +77,13 @@ signals: private: DECLARE_ABSTRACT_OBJECT QString mText; QString mPeerAddress; + QString mFromAddress; + QString mToAddress; + QString mFromName; QString mPeerName; QDateTime mTimestamp; bool mIsRemoteMessage = false; + bool mIsFromChatGroup = false; std::shared_ptr mChatMessageModel; QSharedPointer> mChatMessageModelConnection; }; diff --git a/Linphone/core/chat/message/ChatMessageProxy.cpp b/Linphone/core/chat/message/ChatMessageProxy.cpp index ef0790a87..339ceffea 100644 --- a/Linphone/core/chat/message/ChatMessageProxy.cpp +++ b/Linphone/core/chat/message/ChatMessageProxy.cpp @@ -46,19 +46,30 @@ void ChatMessageProxy::setSourceModel(QAbstractItemModel *model) { sort(0); } -ChatGui* ChatMessageProxy::getChatGui() { +ChatGui *ChatMessageProxy::getChatGui() { auto model = getListModel(); if (!mChatGui && model) mChatGui = model->getChat(); return mChatGui; } -void ChatMessageProxy::setChatGui(ChatGui* chat) { +void ChatMessageProxy::setChatGui(ChatGui *chat) { getListModel()->setChatGui(chat); } +ChatMessageGui *ChatMessageProxy::getChatMessageAtIndex(int i) { + auto model = getListModel(); + auto sourceIndex = mapToSource(index(i, 0)).row(); + if (model) { + auto chat = model->getAt(sourceIndex); + if (chat) return new ChatMessageGui(chat); + else return nullptr; + } + return nullptr; +} + bool ChatMessageProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { -// auto l = getItemAtSource(sourceRow); -// return l != nullptr; + // auto l = getItemAtSource(sourceRow); + // return l != nullptr; return true; } diff --git a/Linphone/core/chat/message/ChatMessageProxy.hpp b/Linphone/core/chat/message/ChatMessageProxy.hpp index 382fb654a..659f3cd1d 100644 --- a/Linphone/core/chat/message/ChatMessageProxy.hpp +++ b/Linphone/core/chat/message/ChatMessageProxy.hpp @@ -21,8 +21,8 @@ #ifndef CHAT_MESSAGE_PROXY_H_ #define CHAT_MESSAGE_PROXY_H_ -#include "core/proxy/LimitProxy.hpp" #include "ChatMessageList.hpp" +#include "core/proxy/LimitProxy.hpp" #include "tool/AbstractObject.hpp" // ============================================================================= @@ -31,7 +31,7 @@ class ChatGui; class ChatMessageProxy : public LimitProxy, public AbstractObject { Q_OBJECT - Q_PROPERTY(ChatGui* chatGui READ getChatGui WRITE setChatGui NOTIFY chatChanged) + Q_PROPERTY(ChatGui *chatGui READ getChatGui WRITE setChatGui NOTIFY chatChanged) public: DECLARE_SORTFILTER_CLASS() @@ -39,17 +39,19 @@ public: ChatMessageProxy(QObject *parent = Q_NULLPTR); ~ChatMessageProxy(); - ChatGui* getChatGui(); - void setChatGui(ChatGui* chat); + ChatGui *getChatGui(); + void setChatGui(ChatGui *chat); void setSourceModel(QAbstractItemModel *sourceModel) override; + Q_INVOKABLE ChatMessageGui *getChatMessageAtIndex(int index); + signals: void chatChanged(); protected: QSharedPointer mList; - ChatGui* mChatGui = nullptr; + ChatGui *mChatGui = nullptr; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/model/chat/ChatModel.cpp b/Linphone/model/chat/ChatModel.cpp index 37ddc61e7..78d155a27 100644 --- a/Linphone/model/chat/ChatModel.cpp +++ b/Linphone/model/chat/ChatModel.cpp @@ -119,6 +119,14 @@ void ChatModel::deleteChatRoom() { emit deleted(); } +std::shared_ptr ChatModel::createTextMessageFromText(QString text) { + return mMonitor->createMessageFromUtf8(Utils::appStringToCoreString(text)); +} + +void ChatModel::compose() { + mMonitor->compose(); +} + //---------------------------------------------------------------// void ChatModel::onIsComposingReceived(const std::shared_ptr &chatRoom, diff --git a/Linphone/model/chat/ChatModel.hpp b/Linphone/model/chat/ChatModel.hpp index 96b832e2d..bc3cfac18 100644 --- a/Linphone/model/chat/ChatModel.hpp +++ b/Linphone/model/chat/ChatModel.hpp @@ -47,6 +47,8 @@ public: QString getIdentifier() const; void deleteHistory(); void deleteChatRoom(); + std::shared_ptr createTextMessageFromText(QString text); + void compose(); signals: void historyDeleted(); diff --git a/Linphone/model/chat/message/ChatMessageModel.cpp b/Linphone/model/chat/message/ChatMessageModel.cpp index 3649056fb..1c0880fce 100644 --- a/Linphone/model/chat/message/ChatMessageModel.cpp +++ b/Linphone/model/chat/message/ChatMessageModel.cpp @@ -48,6 +48,14 @@ QString ChatMessageModel::getPeerAddress() const { return Utils::coreStringToAppString(mMonitor->getPeerAddress()->asStringUriOnly()); } +QString ChatMessageModel::getFromAddress() const { + return Utils::coreStringToAppString(mMonitor->getFromAddress()->asStringUriOnly()); +} + +QString ChatMessageModel::getToAddress() const { + return Utils::coreStringToAppString(mMonitor->getToAddress()->asStringUriOnly()); +} + QDateTime ChatMessageModel::getTimestamp() const { return QDateTime::fromSecsSinceEpoch(mMonitor->getTime()); } diff --git a/Linphone/model/chat/message/ChatMessageModel.hpp b/Linphone/model/chat/message/ChatMessageModel.hpp index 484eea0dc..bf7db2109 100644 --- a/Linphone/model/chat/message/ChatMessageModel.hpp +++ b/Linphone/model/chat/message/ChatMessageModel.hpp @@ -41,6 +41,8 @@ public: QDateTime getTimestamp() const; QString getPeerAddress() const; + QString getFromAddress() const; + QString getToAddress() const; void deleteMessageFromChatRoom(); diff --git a/Linphone/view/Control/Display/Chat/ChatMessage.qml b/Linphone/view/Control/Display/Chat/ChatMessage.qml index 834ce91e0..1411decf6 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessage.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessage.qml @@ -8,115 +8,136 @@ import SettingsCpp import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils -Control.Control { + +RowLayout { id: mainItem property color backgroundColor - property bool isRemoteMessage property bool isFirstMessage property string imgUrl - property string contentText + spacing: 0 + + property ChatMessageGui chatMessage + property string fromAddress: chatMessage? chatMessage.core.fromAddress : "" + property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false + property bool isFromChatGroup: chatMessage? chatMessage.core.isFromChatGroup : false - topPadding: Math.round(12 * DefaultStyle.dp) - bottomPadding: Math.round(12 * DefaultStyle.dp) - leftPadding: Math.round(18 * DefaultStyle.dp) - rightPadding: Math.round(18 * DefaultStyle.dp) - signal messageDeletionRequested() - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: (mouse) => { - console.log("message clicked") - if (mouse.button === Qt.RightButton) { - optionsMenu.x = mouse.x - optionsMenu.open() + Avatar { + id: avatar + visible: mainItem.isFromChatGroup + opacity: mainItem.isRemoteMessage && mainItem.isFirstMessage ? 1 : 0 + Layout.preferredWidth: 26 * DefaultStyle.dp + Layout.preferredHeight: 26 * DefaultStyle.dp + Layout.alignment: Qt.AlignTop + Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0 + _address: chatMessage ? chatMessage.core.fromAddress : "" + } + Control.Control { + Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0 + Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0 + Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth) + // Layout.topMargin: name.visible ? Math.round(7 * DefaultStyle.dp) : 0 + topPadding: Math.round(12 * DefaultStyle.dp) + bottomPadding: Math.round(12 * DefaultStyle.dp) + leftPadding: Math.round(18 * DefaultStyle.dp) + rightPadding: Math.round(18 * DefaultStyle.dp) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: (mouse) => { + console.log("message clicked") + if (mouse.button === Qt.RightButton) { + optionsMenu.x = mouse.x + optionsMenu.open() + } } } - } - Popup { - id: optionsMenu + Popup { + id: optionsMenu + background: Item { + anchors.fill: parent + Rectangle { + id: popupBackground + anchors.fill: parent + color: DefaultStyle.grey_0 + radius: Math.round(16 * DefaultStyle.dp) + } + MultiEffect { + source: popupBackground + anchors.fill: popupBackground + shadowEnabled: true + shadowBlur: 0.1 + shadowColor: DefaultStyle.grey_1000 + shadowOpacity: 0.4 + } + } + contentItem: ColumnLayout { + IconLabelButton { + //: "Supprimer" + text: qsTr("chat_message_delete") + icon.source: AppIcons.trashCan + spacing: Math.round(10 * DefaultStyle.dp) + Layout.fillWidth: true + onClicked: { + mainItem.messageDeletionRequested() + optionsMenu.close() + } + style: ButtonStyle.noBackgroundRed + } + } + } + background: Item { anchors.fill: parent Rectangle { - id: popupBackground anchors.fill: parent - color: DefaultStyle.grey_0 + color: mainItem.backgroundColor radius: Math.round(16 * DefaultStyle.dp) } - MultiEffect { - source: popupBackground - anchors.fill: popupBackground - shadowEnabled: true - shadowBlur: 0.1 - shadowColor: DefaultStyle.grey_1000 - shadowOpacity: 0.4 + Rectangle { + visible: mainItem.isFirstMessage && mainItem.isRemoteMessage + anchors.top: parent.top + anchors.left: parent.left + width: Math.round(parent.width / 4) + height: Math.round(parent.height / 4) + color: mainItem.backgroundColor + } + Rectangle { + visible: mainItem.isFirstMessage && !mainItem.isRemoteMessage + anchors.bottom: parent.bottom + anchors.right: parent.right + width: Math.round(parent.width / 4) + height: Math.round(parent.height / 4) + color: mainItem.backgroundColor } } contentItem: ColumnLayout { - IconLabelButton { - //: "Supprimer" - text: qsTr("chat_message_delete") - icon.source: AppIcons.trashCan - spacing: Math.round(10 * DefaultStyle.dp) + id: contentLayout + Image { + visible: mainItem.imgUrl != undefined + id: contentimage + } + Text { + visible: modelData.core.text != undefined + text: modelData.core.text Layout.fillWidth: true - onClicked: { - mainItem.messageDeletionRequested() - optionsMenu.close() + color: DefaultStyle.main2_700 + font { + pixelSize: Typography.p1.pixelSize + weight: Typography.p1.weight } - style: ButtonStyle.noBackgroundRed } - } - } - - background: Item { - anchors.fill: parent - Rectangle { - anchors.fill: parent - color: mainItem.backgroundColor - radius: Math.round(16 * DefaultStyle.dp) - } - Rectangle { - visible: mainItem.isFirstMessage && mainItem.isRemoteMessage - anchors.top: parent.top - anchors.left: parent.left - width: Math.round(parent.width / 4) - height: Math.round(parent.height / 4) - color: mainItem.backgroundColor - } - Rectangle { - visible: mainItem.isFirstMessage && !mainItem.isRemoteMessage - anchors.bottom: parent.bottom - anchors.right: parent.right - width: Math.round(parent.width / 4) - height: Math.round(parent.height / 4) - color: mainItem.backgroundColor - } - } - contentItem: ColumnLayout { - id: contentLayout - Image { - visible: mainItem.imgUrl != undefined - id: contentimage - } - Text { - visible: mainItem.contentText != undefined - text: mainItem.contentText - Layout.fillWidth: true - color: DefaultStyle.main2_700 - font { - pixelSize: Typography.p1.pixelSize - weight: Typography.p1.weight - } - } - Text { - Layout.alignment: Qt.AlignRight - text: UtilsCpp.formatDate(modelData.core.timestamp, true, false) - color: DefaultStyle.main2_500main - font { - pixelSize: Typography.p3.pixelSize - weight: Typography.p3.weight + Text { + Layout.alignment: Qt.AlignRight + text: UtilsCpp.formatDate(modelData.core.timestamp, true, false) + color: DefaultStyle.main2_500main + font { + pixelSize: Typography.p3.pixelSize + weight: Typography.p3.weight + } } } } diff --git a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml index 7118836fc..823d8e955 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml @@ -11,13 +11,15 @@ import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils ListView { id: mainItem property ChatGui chat - spacing: Math.round(20 * DefaultStyle.dp) + property color backgroundColor + spacing: Math.round(4 * DefaultStyle.dp) Component.onCompleted: positionViewAtEnd() - onCountChanged: positionViewAtEnd(); + onCountChanged: positionViewAtEnd() model: ChatMessageProxy { + id: chatMessageProxy chatGui: mainItem.chat } @@ -26,17 +28,49 @@ ListView { } delegate: ChatMessage { - id: chatMessage - width: Math.min(implicitWidth, Math.round(mainItem.width * (3/4))) + chatMessage: modelData + property real maxWidth: Math.round(mainItem.width * (3/4)) // height: childrenRect.height + // width: childrenRect.width + property var previousIndex: index - 1 + property var previousFromAddress: chatMessageProxy.getChatMessageAtIndex(index-1)?.core.fromAddress backgroundColor: isRemoteMessage ? DefaultStyle.main2_100 : DefaultStyle.main1_100 - contentText: modelData.core.text - isFirstMessage: true - isRemoteMessage: modelData.core.isRemoteMessage + isFirstMessage: !previousFromAddress || previousFromAddress !== modelData.core.fromAddress anchors.right: !isRemoteMessage && parent ? parent.right : undefined onMessageDeletionRequested: modelData.core.lDelete() } -} + + footerPositioning: ListView.OverlayFooter + footer: Control.Control { + visible: composeLayout.composingName !== "" + width: mainItem.width + z: mainItem.z + 2 + topPadding: Math.round(5 * DefaultStyle.dp) + bottomPadding: Math.round(5 * DefaultStyle.dp) + background: Rectangle { + anchors.fill: parent + color: mainItem.panelColor + } + contentItem: RowLayout { + id: composeLayout + property string composingName: mainItem.chat.core.composingName + Avatar { + Layout.preferredWidth: Math.round(20 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(20 * DefaultStyle.dp) + _address: mainItem.chat.core.composingAddress + } + Text { + Layout.fillWidth: true + font { + pixelSize: Typography.p3.pixelSize + weight: Typography.p3.weight + } + //: %1 is writing… + text: qsTr("%1 est en train d'écrire…").arg(composeLayout.composingName) + } + } + } +} \ No newline at end of file diff --git a/Linphone/view/Control/Display/Contact/Avatar.qml b/Linphone/view/Control/Display/Contact/Avatar.qml index 44895f06c..288f3b910 100644 --- a/Linphone/view/Control/Display/Contact/Avatar.qml +++ b/Linphone/view/Control/Display/Contact/Avatar.qml @@ -84,7 +84,6 @@ Loader{ Connections{ target: mainItem onHaveAvatarChanged: { - console.log("have avatar changed", mainItem.haveAvatar, mainItem._address) stackView.replace(mainItem.haveAvatar ? avatar : initials, StackView.Immediate)} } diff --git a/Linphone/view/Control/Display/Contact/ContactListItem.qml b/Linphone/view/Control/Display/Contact/ContactListItem.qml index d39af0d2c..6190a9a9d 100644 --- a/Linphone/view/Control/Display/Contact/ContactListItem.qml +++ b/Linphone/view/Control/Display/Contact/ContactListItem.qml @@ -34,8 +34,7 @@ FocusScope { property real itemsRightMargin: Math.round(39 * DefaultStyle.dp) property var displayName: searchResultItem.core.fullName - property string initial: displayName ? displayName[0].toLocaleLowerCase( - ConstantsCpp.DefaultLocale) : '' + property string initial: displayName ? displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale) : '' signal clicked(var mouse) signal contactDeletionRequested(FriendGui contact) diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index ff816a6b1..37a7eff87 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -80,6 +80,7 @@ RowLayout { ChatMessagesListView { id: chatMessagesListView height: contentHeight + backgroundColor: panelColor width: parent.width - anchors.leftMargin - anchors.rightMargin chat: mainItem.chat anchors.top: parent.top @@ -88,7 +89,6 @@ RowLayout { anchors.bottom: messageSender.top anchors.leftMargin: Math.round(18 * DefaultStyle.dp) anchors.rightMargin: Math.round(18 * DefaultStyle.dp) - anchors.bottomMargin: Math.round(18 * DefaultStyle.dp) Control.ScrollBar.vertical: scrollbar }, ScrollBar { @@ -106,13 +106,22 @@ RowLayout { anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - height: 79 * DefaultStyle.dp leftPadding: Math.round(15 * DefaultStyle.dp) rightPadding: Math.round(15 * DefaultStyle.dp) - topPadding: Math.round(16 * DefaultStyle.dp) + topPadding: Math.round(24 * DefaultStyle.dp) bottomPadding: Math.round(16 * DefaultStyle.dp) background: Rectangle { + anchors.fill: parent color: DefaultStyle.grey_100 + MediumButton { + id: expandButton + anchors.top: parent.top + anchors.topMargin: Math.round(4 * DefaultStyle.dp) + anchors.horizontalCenter: parent.horizontalCenter + style: ButtonStyle.noBackgroundOrange + icon.source: checked ? AppIcons.downArrow : AppIcons.upArrow + checkable: true + } } contentItem: RowLayout { spacing: Math.round(20 * DefaultStyle.dp) @@ -135,19 +144,62 @@ RowLayout { } Control.Control { Layout.fillWidth: true - Layout.preferredHeight: Math.round(48 * DefaultStyle.dp) + leftPadding: Math.round(15 * DefaultStyle.dp) + rightPadding: Math.round(15 * DefaultStyle.dp) + topPadding: Math.round(16 * DefaultStyle.dp) + bottomPadding: Math.round(16 * DefaultStyle.dp) background: Rectangle { id: inputBackground anchors.fill: parent - radius: Math.round(30 * DefaultStyle.dp) + radius: Math.round(35 * DefaultStyle.dp) color: DefaultStyle.grey_0 } contentItem: RowLayout { - TextArea { - id: sendingTextArea + Flickable { + id: sendingAreaFlickable Layout.fillWidth: true - Layout.fillHeight: true Layout.preferredWidth: parent.width - stackButton.width + Layout.preferredHeight: Math.min(Math.round(60 * DefaultStyle.dp), contentHeight) + Binding { + target: sendingAreaFlickable + when: expandButton.checked + property: "Layout.preferredHeight" + value: Math.round(250 * DefaultStyle.dp) + restoreMode: Binding.RestoreBindingOrValue + } + Layout.fillHeight: true + contentHeight: sendingTextArea.contentHeight + contentWidth: width + + function ensureVisible(r) { + if (contentX >= r.x) + contentX = r.x; + else if (contentX+width <= r.x+r.width) + contentX = r.x+r.width-width; + if (contentY >= r.y) + contentY = r.y; + else if (contentY+height <= r.y+r.height) + contentY = r.y+r.height-height; + } + + TextArea { + id: sendingTextArea + width: parent.width + height: sendingAreaFlickable.height + anchors.left: parent.left + anchors.right: parent.right + //: Say something… : placeholder text for sending message text area + placeholderText: qsTr("Dites quelque chose…") + placeholderTextColor: DefaultStyle.main2_400 + onCursorRectangleChanged: sendingAreaFlickable.ensureVisible(cursorRectangle) + property string previousText + Component.onCompleted: previousText = text + onTextChanged: { + if (previousText === "" && text !== "") { + mainItem.chat.core.lCompose() + } + } + } } StackLayout { id: stackButton @@ -163,7 +215,8 @@ RowLayout { style: ButtonStyle.noBackgroundOrange icon.source: AppIcons.paperPlaneRight onClicked: { - console.log("TODO : send message") + mainItem.chat.core.lSendTextMessage(sendingTextArea.text) + sendingTextArea.clear() } } } diff --git a/Linphone/view/Page/Main/Chat/ChatPage.qml b/Linphone/view/Page/Main/Chat/ChatPage.qml index d56c4264a..e19c25eb3 100644 --- a/Linphone/view/Page/Main/Chat/ChatPage.qml +++ b/Linphone/view/Page/Main/Chat/ChatPage.qml @@ -21,7 +21,7 @@ AbstractMainPage { property string remoteAddress onRemoteAddressChanged: console.log("ChatPage : remote address changed :", remoteAddress) property var remoteChatObj: UtilsCpp.getChatForAddress(remoteAddress) - property ChatGui remoteChat: remoteChatObj ? remoteChatObj.value : null + property ChatGui remoteChat: remoteChatObj && remoteChatObj.value ? remoteChatObj.value : null onRemoteChatChanged: if (remoteChat) selectedChatGui = remoteChat onSelectedChatGuiChanged: { diff --git a/Linphone/view/Style/Typography.qml b/Linphone/view/Style/Typography.qml index ad94c6dce..67a4cb96e 100644 --- a/Linphone/view/Style/Typography.qml +++ b/Linphone/view/Style/Typography.qml @@ -31,6 +31,13 @@ QtObject { weight: Math.min(Math.round(800 * DefaultStyle.dp), 1000) }) + // Text/P4 - Xsmall paragraph text + property font p4: Qt.font( { + family: DefaultStyle.defaultFont, + pixelSize: Math.round(10 * DefaultStyle.dp), + weight: Math.min(Math.round(300 * DefaultStyle.dp), 1000) + }) + // Text/P3 - Reduced paragraph text property font p3: Qt.font( { family: DefaultStyle.defaultFont,