diff --git a/assets/images/chat_is_composing_0.svg b/assets/images/chat_is_composing_0.svg new file mode 100644 index 000000000..7376ef009 --- /dev/null +++ b/assets/images/chat_is_composing_0.svg @@ -0,0 +1,15 @@ + + + + chat_in_writing_0 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/chat_is_composing_1.svg b/assets/images/chat_is_composing_1.svg new file mode 100644 index 000000000..e4f5348a9 --- /dev/null +++ b/assets/images/chat_is_composing_1.svg @@ -0,0 +1,15 @@ + + + + chat_in_writing_1 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/chat_is_composing_2.svg b/assets/images/chat_is_composing_2.svg new file mode 100644 index 000000000..c3194052c --- /dev/null +++ b/assets/images/chat_is_composing_2.svg @@ -0,0 +1,15 @@ + + + + chat_in_writing_2 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/chat_is_composing_3.svg b/assets/images/chat_is_composing_3.svg new file mode 100644 index 000000000..ea8b790e8 --- /dev/null +++ b/assets/images/chat_is_composing_3.svg @@ -0,0 +1,15 @@ + + + + chat_in_writing_3 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/resources.qrc b/resources.qrc index 921027113..c06c6dc99 100644 --- a/resources.qrc +++ b/resources.qrc @@ -60,6 +60,10 @@ assets/images/chat_delivered.svg assets/images/chat_error.svg assets/images/chat_hovered.svg + assets/images/chat_is_composing_0.svg + assets/images/chat_is_composing_1.svg + assets/images/chat_is_composing_2.svg + assets/images/chat_is_composing_3.svg assets/images/chat_normal.svg assets/images/chat_pressed.svg assets/images/chat_read.svg diff --git a/src/components/sip-addresses/SipAddressesModel.cpp b/src/components/sip-addresses/SipAddressesModel.cpp index 23d11e441..6166872cd 100644 --- a/src/components/sip-addresses/SipAddressesModel.cpp +++ b/src/components/sip-addresses/SipAddressesModel.cpp @@ -48,10 +48,11 @@ SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(pare QObject::connect(contacts, &ContactsListModel::sipAddressAdded, this, &SipAddressesModel::handleSipAddressAdded); QObject::connect(contacts, &ContactsListModel::sipAddressRemoved, this, &SipAddressesModel::handleSipAddressRemoved); - CoreHandlers *intHandlers = mCoreHandlers.get(); - QObject::connect(intHandlers, &CoreHandlers::messageReceived, this, &SipAddressesModel::handleMessageReceived); - QObject::connect(intHandlers, &CoreHandlers::callStateChanged, this, &SipAddressesModel::handleCallStateChanged); - QObject::connect(intHandlers, &CoreHandlers::presenceReceived, this, &SipAddressesModel::handlePresenceReceived); + CoreHandlers *coreHandlers = mCoreHandlers.get(); + QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &SipAddressesModel::handleMessageReceived); + QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &SipAddressesModel::handleCallStateChanged); + QObject::connect(coreHandlers, &CoreHandlers::presenceReceived, this, &SipAddressesModel::handlePresenceReceived); + QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &SipAddressesModel::handlerIsComposingChanged); } // ----------------------------------------------------------------------------- @@ -348,6 +349,17 @@ void SipAddressesModel::handleMessagesCountReset (const QString &sipAddress) { updateObservers(sipAddress, 0); } +void SipAddressesModel::handlerIsComposingChanged (const shared_ptr &chatRoom) { + auto it = mSipAddresses.find(::Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly())); + if (it != mSipAddresses.end()) { + (*it)["isComposing"] = chatRoom->isRemoteComposing(); + + int row = mRefs.indexOf(&(*it)); + Q_ASSERT(row != -1); + emit dataChanged(index(row, 0), index(row, 0)); + } +} + // ----------------------------------------------------------------------------- void SipAddressesModel::addOrUpdateSipAddress (QVariantMap &map, ContactModel *contact) { diff --git a/src/components/sip-addresses/SipAddressesModel.hpp b/src/components/sip-addresses/SipAddressesModel.hpp index c306e2d29..77fd80cdb 100644 --- a/src/components/sip-addresses/SipAddressesModel.hpp +++ b/src/components/sip-addresses/SipAddressesModel.hpp @@ -86,6 +86,8 @@ private: void handleMessageSent (const std::shared_ptr &message); void handleMessagesCountReset (const QString &sipAddress); + void handlerIsComposingChanged (const std::shared_ptr &chatRoom); + // --------------------------------------------------------------------------- // A sip address exists in this list if a contact is linked to it, or a call, or a message. diff --git a/ui/modules/Linphone/Contact/Contact.qml b/ui/modules/Linphone/Contact/Contact.qml index c11dadb3d..48c3e459b 100644 --- a/ui/modules/Linphone/Contact/Contact.qml +++ b/ui/modules/Linphone/Contact/Contact.qml @@ -65,7 +65,9 @@ Rectangle { Layout.alignment: Qt.AlignTop count: Number(entry.unreadMessagesCount) - visible: displayUnreadMessagesCount && entry.unreadMessagesCount > 0 + isComposing: Boolean(entry.isComposing) + + visible: item.displayUnreadMessagesCount } } } diff --git a/ui/modules/Linphone/Contact/MessagesCounter.qml b/ui/modules/Linphone/Contact/MessagesCounter.qml index 7463ae990..5d7c11da6 100644 --- a/ui/modules/Linphone/Contact/MessagesCounter.qml +++ b/ui/modules/Linphone/Contact/MessagesCounter.qml @@ -10,6 +10,7 @@ Item { id: messagesCounter property int count + property bool isComposing implicitHeight: counterIcon.height + MessagesCounterStyle.verticalMargins * 2 implicitWidth: counterIcon.width + MessagesCounterStyle.horizontalMargins * 2 @@ -17,10 +18,15 @@ Item { Icon { id: counterIcon + property int composingIndex: 0 + anchors.centerIn: parent - icon: 'chat_count' + icon: messagesCounter.isComposing + ? ('chat_is_composing_' + counterIcon.composingIndex) + : 'chat_count' iconSize: MessagesCounterStyle.iconSize.message + visible: messagesCounter.count > 0 || messagesCounter.isComposing Icon { anchors { @@ -30,6 +36,7 @@ Item { icon: 'chat_amount' iconSize: MessagesCounterStyle.iconSize.amount + visible: messagesCounter.count > 0 Text { anchors.centerIn: parent @@ -38,5 +45,19 @@ Item { text: messagesCounter.count } } + + Timer { + interval: 500 + repeat: true + running: messagesCounter.isComposing + + onRunningChanged: { + if (running) { + counterIcon.composingIndex = 0 + } + } + + onTriggered: counterIcon.composingIndex = (counterIcon.composingIndex + 1) % 4 + } } }