Send message, composing notification

This commit is contained in:
Gaelle Braud 2025-05-06 14:39:57 +02:00
parent bdff2bddcd
commit ecd9373df9
17 changed files with 363 additions and 124 deletions

View file

@ -162,6 +162,37 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> 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<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<const linphone::EventLog> &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<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<const linphone::Address> &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<ChatModel> ChatCore::getModel() const {
return mChatModel;
}

View file

@ -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<ChatModel> 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<ChatModel> mChatModel;
QList<QSharedPointer<ChatMessageCore>> mChatMessageList;
QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection;

View file

@ -45,6 +45,14 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &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<ChatMessageModel> ChatMessageCore::getModel() const {

View file

@ -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<ChatMessageCore> create(const std::shared_ptr<linphone::ChatMessage> &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<ChatMessageModel> 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<ChatMessageModel> mChatMessageModel;
QSharedPointer<SafeConnection<ChatMessageCore, ChatMessageModel>> mChatMessageModelConnection;
};

View file

@ -46,19 +46,30 @@ void ChatMessageProxy::setSourceModel(QAbstractItemModel *model) {
sort(0);
}
ChatGui* ChatMessageProxy::getChatGui() {
ChatGui *ChatMessageProxy::getChatGui() {
auto model = getListModel<ChatMessageList>();
if (!mChatGui && model) mChatGui = model->getChat();
return mChatGui;
}
void ChatMessageProxy::setChatGui(ChatGui* chat) {
void ChatMessageProxy::setChatGui(ChatGui *chat) {
getListModel<ChatMessageList>()->setChatGui(chat);
}
ChatMessageGui *ChatMessageProxy::getChatMessageAtIndex(int i) {
auto model = getListModel<ChatMessageList>();
auto sourceIndex = mapToSource(index(i, 0)).row();
if (model) {
auto chat = model->getAt<ChatMessageCore>(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<ChatMessageList, ChatMessageCore>(sourceRow);
// return l != nullptr;
// auto l = getItemAtSource<ChatMessageList, ChatMessageCore>(sourceRow);
// return l != nullptr;
return true;
}

View file

@ -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<ChatMessageList> mList;
ChatGui* mChatGui = nullptr;
ChatGui *mChatGui = nullptr;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -119,6 +119,14 @@ void ChatModel::deleteChatRoom() {
emit deleted();
}
std::shared_ptr<linphone::ChatMessage> ChatModel::createTextMessageFromText(QString text) {
return mMonitor->createMessageFromUtf8(Utils::appStringToCoreString(text));
}
void ChatModel::compose() {
mMonitor->compose();
}
//---------------------------------------------------------------//
void ChatModel::onIsComposingReceived(const std::shared_ptr<linphone::ChatRoom> &chatRoom,

View file

@ -47,6 +47,8 @@ public:
QString getIdentifier() const;
void deleteHistory();
void deleteChatRoom();
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
void compose();
signals:
void historyDeleted();

View file

@ -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());
}

View file

@ -41,6 +41,8 @@ public:
QDateTime getTimestamp() const;
QString getPeerAddress() const;
QString getFromAddress() const;
QString getToAddress() const;
void deleteMessageFromChatRoom();

View file

@ -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
}
}
}
}

View file

@ -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)
}
}
}
}

View file

@ -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)}
}

View file

@ -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)

View file

@ -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()
}
}
}

View file

@ -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: {

View file

@ -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,