open chat when clicking on message notification

select chat by clicking on notification

close all notifications when one clicked and chat is open
This commit is contained in:
Gaelle Braud 2025-05-13 15:46:36 +02:00
parent e178bd43cf
commit 4bb1e5da43
12 changed files with 90 additions and 27 deletions

View file

@ -41,11 +41,14 @@ ChatCore::ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom) : QObjec
mustBeInLinphoneThread(getClassName());
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mLastUpdatedTime = QDateTime::fromSecsSinceEpoch(chatRoom->getLastUpdateTime());
auto chatRoomAddress = chatRoom->getPeerAddress()->clone();
chatRoomAddress->clean();
mChatRoomAddress = Utils::coreStringToAppString(chatRoomAddress->asStringUriOnly());
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Basic)) {
mTitle = ToolModel::getDisplayName(chatRoom->getPeerAddress()->clone());
mAvatarUri = ToolModel::getDisplayName(chatRoom->getPeerAddress()->clone());
auto peerAddress = chatRoom->getPeerAddress();
mPeerAddress = Utils::coreStringToAppString(peerAddress->asStringUriOnly());
mTitle = ToolModel::getDisplayName(chatRoomAddress);
mAvatarUri = ToolModel::getDisplayName(chatRoomAddress);
mPeerAddress = Utils::coreStringToAppString(chatRoomAddress->asStringUriOnly());
mIsGroupChat = false;
} else {
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne)) {
auto participants = chatRoom->getParticipants();
@ -58,9 +61,11 @@ ChatCore::ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom) : QObjec
if (peerAddress) mPeerAddress = Utils::coreStringToAppString(peerAddress->asStringUriOnly());
}
}
mIsGroupChat = false;
} else if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference)) {
mTitle = Utils::coreStringToAppString(chatRoom->getSubject());
mAvatarUri = Utils::coreStringToAppString(chatRoom->getSubject());
mIsGroupChat = true;
}
}
mUnreadMessagesCount = chatRoom->getUnreadMessagesCount();
@ -101,7 +106,10 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
mChatModelConnection->makeConnectToModel(&ChatModel::historyDeleted, [this]() {
mChatModelConnection->invokeToCore([this]() {
clearMessagesList();
Utils::showInformationPopup(tr("Supprimé"), tr("L'historique des messages a été supprimé."), true);
//: Deleted
Utils::showInformationPopup(tr("info_toast_deleted_title"),
//: Message history has been deleted
tr("info_toast_deleted_message_history"), true);
});
});
mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateUnreadCount, [this]() {
@ -170,7 +178,7 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
auto lastMessageModel = mLastMessage ? mLastMessage->getModel() : nullptr;
mChatModelConnection->invokeToModel([this, lastMessageModel]() {
auto linphoneMessage = mChatModel->getLastChatMessage();
if (lastMessageModel && lastMessageModel->getMonitor() != linphoneMessage) {
if (!lastMessageModel || lastMessageModel->getMonitor() != linphoneMessage) {
auto chatMessageCore = ChatMessageCore::create(linphoneMessage);
mChatModelConnection->invokeToCore([this, chatMessageCore]() { setLastMessage(chatMessageCore); });
}
@ -232,6 +240,10 @@ void ChatCore::setTitle(QString title) {
}
}
bool ChatCore::isGroupChat() const {
return mIsGroupChat;
}
QString ChatCore::getIdentifier() const {
return mIdentifier;
}
@ -240,11 +252,8 @@ QString ChatCore::getPeerAddress() const {
return mPeerAddress;
}
void ChatCore::setPeerAddress(QString peerAddress) {
if (mPeerAddress != peerAddress) {
mPeerAddress = peerAddress;
emit peerAddressChanged(peerAddress);
}
QString ChatCore::getChatRoomAddress() const {
return mChatRoomAddress;
}
QString ChatCore::getAvatarUri() const {
@ -359,4 +368,4 @@ QString ChatCore::getComposingAddress() const {
std::shared_ptr<ChatModel> ChatCore::getModel() const {
return mChatModel;
}
}

View file

@ -36,7 +36,8 @@ class ChatCore : public QObject, public AbstractObject {
public:
Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(QString identifier READ getIdentifier CONSTANT)
Q_PROPERTY(QString peerAddress READ getPeerAddress WRITE setPeerAddress NOTIFY peerAddressChanged)
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT)
Q_PROPERTY(QString chatRoomAddress READ getChatRoomAddress CONSTANT)
Q_PROPERTY(QString avatarUri READ getAvatarUri WRITE setAvatarUri NOTIFY avatarUriChanged)
Q_PROPERTY(QDateTime lastUpdatedTime READ getLastUpdatedTime WRITE setLastUpdatedTime NOTIFY lastUpdatedTimeChanged)
Q_PROPERTY(QString lastMessageText READ getLastMessageText NOTIFY lastMessageChanged)
@ -46,7 +47,7 @@ public:
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)
Q_PROPERTY(bool isGroupChat READ isGroupChat CONSTANT)
// Should be call from model Thread. Will be automatically in App thread after initialization
static QSharedPointer<ChatCore> create(const std::shared_ptr<linphone::ChatRoom> &chatRoom);
@ -60,6 +61,8 @@ public:
QString getTitle() const;
void setTitle(QString title);
bool isGroupChat() const;
QString getIdentifier() const;
ChatMessageGui *getLastMessage() const;
@ -73,8 +76,8 @@ public:
int getUnreadMessagesCount() const;
void setUnreadMessagesCount(int count);
QString getChatRoomAddress() const;
QString getPeerAddress() const;
void setPeerAddress(QString peerAddress);
QList<QSharedPointer<ChatMessageCore>> getChatMessageList() const;
void resetChatMessageList(QList<QSharedPointer<ChatMessageCore>> list);
@ -93,11 +96,14 @@ public:
std::shared_ptr<ChatModel> getModel() const;
Q_SIGNALS:
// used to close all the notifications when one is clicked
void messageOpen();
signals:
void lastUpdatedTimeChanged(QDateTime time);
void lastMessageChanged();
void titleChanged(QString title);
void peerAddressChanged(QString address);
void unreadMessagesCountChanged(int count);
void messageListChanged();
void messagesInserted(QList<QSharedPointer<ChatMessageCore>> list);
@ -120,12 +126,14 @@ private:
QString id;
QDateTime mLastUpdatedTime;
QString mPeerAddress;
QString mChatRoomAddress;
QString mTitle;
QString mIdentifier;
QString mAvatarUri;
int mUnreadMessagesCount;
QString mComposingName;
QString mComposingAddress;
bool mIsGroupChat = false;
std::shared_ptr<ChatModel> mChatModel;
QSharedPointer<ChatMessageCore> mLastMessage;
QList<QSharedPointer<ChatMessageCore>> mChatMessageList;

View file

@ -44,7 +44,7 @@ void ChatProxy::setSourceModel(QAbstractItemModel *model) {
connect(this, &ChatProxy::filterTextChanged, newChatList,
[this, newChatList] { emit newChatList->filterChanged(getFilterText()); });
connect(newChatList, &ChatList::chatRemoved, this, &ChatProxy::chatRemoved);
// connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); });
connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); });
}
auto firstList = new SortFilterList(model, Qt::AscendingOrder);
firstList->setDynamicSortFilter(true);

View file

@ -33,7 +33,7 @@
#include "core/App.hpp"
#include "core/call/CallGui.hpp"
#include "core/chat/ChatCore.hpp"
#include "core/chat/ChatGui.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/LinphoneEnums.hpp"
#include "tool/providers/AvatarProvider.hpp"
@ -367,11 +367,12 @@ void Notifier::notifyReceivedMessages(const std::shared_ptr<linphone::ChatRoom>
mustBeInMainThread(getClassName());
QVariantMap map;
map["message"] = txt;
qDebug() << "create notif from address" << remoteAddress;
map["remoteAddress"] = remoteAddress;
map["chatRoomName"] = chatCore->getTitle();
map["chatRoomAddress"] = chatCore->getPeerAddress();
map["chatRoomAddress"] = chatCore->getChatRoomAddress();
map["avatarUri"] = chatCore->getAvatarUri();
map["isGroupChat"] = chatCore->isGroupChat();
map["chat"] = QVariant::fromValue(chatCore ? new ChatGui(chatCore) : nullptr);
CREATE_NOTIFICATION(Notifier::ReceivedMessage, map)
});
}

View file

@ -1538,6 +1538,7 @@ VariantObject *Utils::getCurrentCallChat(CallGui *call) {
//: Failed to create 1-1 conversation with %1 !
data->mConnection->invokeToCore([] {
showInformationPopup(tr("information_popup_error_title"),
//: Failed to create 1-1 conversation with %1 !
tr("information_popup_chatroom_creation_error_message"), false,
getCallsWindow());
});
@ -1583,6 +1584,15 @@ VariantObject *Utils::getChatForAddress(QString address) {
return data;
}
void Utils::openChat(ChatGui *chat) {
auto mainWindow = getMainWindow();
smartShowWindow(mainWindow);
if (mainWindow && chat) {
emit chat->mCore->messageOpen();
QMetaObject::invokeMethod(mainWindow, "openChat", Q_ARG(QVariant, QVariant::fromValue(chat)));
}
}
bool Utils::isEmptyMessage(QString message) {
return message.trimmed().isEmpty();
}

View file

@ -148,6 +148,7 @@ public:
Q_INVOKABLE static VariantObject *getCurrentCallChat(CallGui *call);
Q_INVOKABLE static VariantObject *getChatForAddress(QString address);
Q_INVOKABLE static void openChat(ChatGui *chat);
Q_INVOKABLE static bool isEmptyMessage(QString message);
Q_INVOKABLE static QString encodeTextToQmlRichFormat(const QString &text,
const QVariantMap &options = QVariantMap());

View file

@ -82,8 +82,8 @@ ListView {
// Update position only if we are moving to current item and its position is changing.
property var _currentItemY: currentItem?.y
on_CurrentItemYChanged: if (_currentItemY && moveAnimation.running) {
moveToCurrentItem()
}
moveToCurrentItem()
}
Behavior on contentY {
NumberAnimation {
id: moveAnimation

View file

@ -14,6 +14,12 @@ ListView {
property color backgroundColor
spacing: Math.round(4 * DefaultStyle.dp)
onChatChanged: {
var index = chatMessageProxy.findFirstUnreadIndex()
positionViewAtIndex(index, ListView.End)
}
Component.onCompleted: {
var index = chatMessageProxy.findFirstUnreadIndex()
positionViewAtIndex(index, ListView.End)
@ -60,6 +66,7 @@ ListView {
chatMessage: modelData
property real maxWidth: Math.round(mainItem.width * (3/4))
// height: childrenRect.height
onVisibleChanged: if (!modelData.core.isRead) modelData.core.lMarkAsRead()
width: mainItem.width
property var previousIndex: index - 1
property var previousFromAddress: chatMessageProxy.getChatMessageAtIndex(index-1)?.core.fromAddress

View file

@ -14,11 +14,22 @@ Notification {
backgroundOpacity: 0.8
overriddenWidth: Math.round(400 * DefaultStyle.dp)
overriddenHeight: content.height
property var chat: notificationData ? notificationData.chat : null
property string avatarUri: notificationData ? notificationData.avatarUri : ""
property string chatRoomName: notificationData ? notificationData.chatRoomName : ""
property string remoteAddress: notificationData ? notificationData.remoteAddress : ""
property string chatRoomAddress: notificationData ? notificationData.chatRoomAddress : ""
property bool isGroupChat: notificationData ? notificationData.isGroupChat : false
property string message: notificationData ? notificationData.message : ""
Connections {
enabled: chat
target: chat.core
function onMessageOpen() {
close()
}
}
Popup {
id: content
@ -65,14 +76,15 @@ Notification {
icon.height: Math.round(14 * DefaultStyle.dp)
contentImageColor: DefaultStyle.grey_0
onPressed: {
mainItem._close()
mainItem.close()
}
}
MouseArea {
id: mousearea
anchors.fill: parent
onClicked: {
console.log("notif clicked, open chat")
UtilsCpp.openChat(mainItem.chat)
mainItem.close()
}
}
}
@ -102,6 +114,7 @@ Notification {
}
}
Text {
visible: mainItem.isGroupChat
text: mainItem.remoteAddress
color: DefaultStyle.main2_100
Layout.fillWidth: true

View file

@ -79,6 +79,7 @@ RowLayout {
content: [
ChatMessagesListView {
id: chatMessagesListView
clip: true
height: contentHeight
backgroundColor: splitPanel.panelColor
width: parent.width - anchors.leftMargin - anchors.rightMargin
@ -86,7 +87,7 @@ RowLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: messageSender.top
anchors.bottom: messageSender.top
anchors.leftMargin: Math.round(18 * DefaultStyle.dp)
anchors.rightMargin: Math.round(18 * DefaultStyle.dp)
Control.ScrollBar.vertical: scrollbar
@ -95,7 +96,7 @@ RowLayout {
id: scrollbar
visible: chatMessagesListView.contentHeight > parent.height
active: visible
anchors.top: parent.top
anchors.top: chatMessagesListView.top
anchors.bottom: chatMessagesListView.bottom
anchors.right: parent.right
anchors.rightMargin: Math.round(5 * DefaultStyle.dp)
@ -214,7 +215,7 @@ RowLayout {
Keys.onPressed: (event) => {
event.accepted = false
if (UtilsCpp.isEmptyMessage(sendingTextArea.text)) return
if (!(event.modifiers & Qt.ControlModifier) && (event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
if (!(event.modifiers & Qt.ShiftModifier) && (event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
mainItem.chat.core.lSendTextMessage(sendingTextArea.text)
sendingTextArea.clear()
event.accepted = true

View file

@ -27,6 +27,7 @@ Item {
signal openNumPadRequest
signal displayContactRequested(string contactAddress)
signal displayChatRequested(string contactAddress)
signal openChatRequested(ChatGui chat)
signal createContactRequested(string name, string address)
signal accountRemoved
@ -46,6 +47,10 @@ Item {
tabbar.currentIndex = 2
mainItem.displayChatRequested(contactAddress)
}
function openChat(chat) {
tabbar.currentIndex = 2
mainItem.openChatRequested(chat)
}
function createContact(name, address) {
tabbar.currentIndex = 1
@ -636,6 +641,10 @@ Item {
chatPage.remoteAddress = ""
chatPage.remoteAddress = contactAddress
}
function onOpenChatRequested(chat) {
console.log("open chat requested, open", chat.core.title)
chatPage.selectedChatGui = chat
}
}
}
MeetingPage {}

View file

@ -60,6 +60,10 @@ AbstractWindow {
openMainPage()
mainWindowStackView.currentItem.displayChatPage(contactAddress)
}
function openChat(chat) {
openMainPage()
mainWindowStackView.currentItem.openChat(chat)
}
function transferCallSucceed() {
openMainPage()
//: "Appel transféré"