Chatroom infos in Chatroom lists - composing/muted/ephemeral/imdn ...

This commit is contained in:
Christophe Deschamps 2025-06-03 17:18:37 +02:00
parent 460c0334c4
commit 7617996dc4
10 changed files with 189 additions and 34 deletions

View file

@ -99,6 +99,8 @@ ChatCore::ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom) : QObjec
connect(this, &ChatCore::eventListChanged, this, &ChatCore::lUpdateLastMessage);
connect(this, &ChatCore::eventsInserted, this, &ChatCore::lUpdateLastMessage);
connect(this, &ChatCore::eventRemoved, this, &ChatCore::lUpdateLastMessage);
mEphemeralEnabled = chatRoom->ephemeralEnabled();
mIsMuted = chatRoom->getMuted();
}
ChatCore::~ChatCore() {
@ -228,6 +230,29 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
setComposingAddress(address);
});
});
mChatModelConnection->makeConnectToCore(&ChatCore::lSetMuted, [this](bool muted) {
mChatModelConnection->invokeToModel([this, muted]() { mChatModel->setMuted(muted); });
});
mChatModelConnection->makeConnectToModel(&ChatModel::mutedChanged, [this](bool muted) {
mChatModelConnection->invokeToCore([this, muted]() {
if (mIsMuted != muted) {
mIsMuted = muted;
emit mutedChanged();
}
});
});
mChatModelConnection->makeConnectToCore(&ChatCore::lEnableEphemeral, [this](bool enable) {
mChatModelConnection->invokeToModel([this, enable]() { mChatModel->enableEphemeral(enable); });
});
mChatModelConnection->makeConnectToModel(&ChatModel::ephemeralEnableChanged, [this](bool enable) {
mChatModelConnection->invokeToCore([this, enable]() {
if (mEphemeralEnabled != enable) {
mEphemeralEnabled = enable;
emit ephemeralEnabledChanged();
}
});
});
}
QDateTime ChatCore::getLastUpdatedTime() const {
@ -414,3 +439,11 @@ QString ChatCore::getComposingAddress() const {
std::shared_ptr<ChatModel> ChatCore::getModel() const {
return mChatModel;
}
bool ChatCore::isMuted() const {
return mIsMuted;
}
bool ChatCore::isEphemeralEnabled() const {
return mEphemeralEnabled;
}

View file

@ -55,6 +55,8 @@ public:
Q_PROPERTY(bool isEncrypted READ isEncrypted CONSTANT)
Q_PROPERTY(bool isReadOnly READ getIsReadOnly WRITE setIsReadOnly NOTIFY readOnlyChanged)
Q_PROPERTY(QString sendingText READ getSendingText WRITE setSendingText NOTIFY sendingTextChanged)
Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE lEnableEphemeral NOTIFY ephemeralEnabledChanged)
Q_PROPERTY(bool muted READ isMuted WRITE lSetMuted NOTIFY mutedChanged)
// 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);
@ -72,6 +74,10 @@ public:
bool isEncrypted() const;
bool isMuted() const;
bool isEphemeralEnabled() const;
QString getIdentifier() const;
QString getSendingText() const;
@ -130,6 +136,8 @@ signals:
void chatRoomStateChanged();
void readOnlyChanged();
void sendingTextChanged(QString text);
void mutedChanged();
void ephemeralEnabledChanged();
void lDeleteMessage();
void lDelete();
@ -141,6 +149,8 @@ signals:
void lSendTextMessage(QString message);
void lCompose();
void lLeave();
void lSetMuted(bool muted);
void lEnableEphemeral(bool enable);
private:
QString id;
@ -157,6 +167,8 @@ private:
bool mIsGroupChat = false;
bool mIsEncrypted = false;
bool mIsReadOnly = false;
bool mEphemeralEnabled = false;
bool mIsMuted = false;
LinphoneEnums::ChatRoomState mChatRoomState;
std::shared_ptr<ChatModel> mChatModel;
QSharedPointer<ChatMessageCore> mLastMessage;

View file

@ -72,9 +72,7 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
mUtf8Text = mChatMessageModel->getUtf8Text();
mHasTextContent = mChatMessageModel->getHasTextContent();
mTimestamp = QDateTime::fromSecsSinceEpoch(chatmessage->getTime());
auto from = chatmessage->getFromAddress();
auto to = chatmessage->getLocalAddress();
mIsRemoteMessage = !from->weakEqual(to);
mIsRemoteMessage = !chatmessage->isOutgoing();
mPeerAddress = Utils::coreStringToAppString(chatmessage->getPeerAddress()->asStringUriOnly());
mPeerName = ToolModel::getDisplayName(chatmessage->getPeerAddress()->clone());
auto fromAddress = chatmessage->getFromAddress()->clone();
@ -122,6 +120,14 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
}
}
connect(this, &ChatMessageCore::messageReactionChanged, this, &ChatMessageCore::resetReactionsSingleton);
mIsForward = chatmessage->isForward();
mIsReply = chatmessage->isReply();
for (auto &content : chatmessage->getContents()) {
if (content->isFile() && !content->isVoiceRecording()) mHasFileContent = true;
if (content->isIcalendar()) mIsCalendarInvite = true;
if (content->isVoiceRecording()) mIsVoiceRecording = true;
}
}
ChatMessageCore::~ChatMessageCore() {

View file

@ -71,6 +71,11 @@ class ChatMessageCore : public QObject, public AbstractObject {
Q_PROPERTY(QString ownReaction READ getOwnReaction WRITE setOwnReaction NOTIFY messageReactionChanged)
Q_PROPERTY(QList<Reaction> reactions READ getReactions WRITE setReactions NOTIFY messageReactionChanged)
Q_PROPERTY(QList<QVariant> reactionsSingleton READ getReactionsSingleton NOTIFY singletonReactionMapChanged)
Q_PROPERTY(bool isForward MEMBER mIsForward CONSTANT)
Q_PROPERTY(bool isReply MEMBER mIsReply CONSTANT)
Q_PROPERTY(bool hasFileContent MEMBER mHasFileContent CONSTANT)
Q_PROPERTY(bool isVoiceRecording MEMBER mIsVoiceRecording CONSTANT)
Q_PROPERTY(bool isCalendarInvite MEMBER mIsCalendarInvite CONSTANT)
public:
static QSharedPointer<ChatMessageCore> create(const std::shared_ptr<linphone::ChatMessage> &chatmessage);
@ -147,6 +152,12 @@ private:
bool mIsRemoteMessage = false;
bool mIsFromChatGroup = false;
bool mIsRead = false;
bool mIsForward = false;
bool mIsReply = false;
bool mHasFileContent = false;
bool mIsCalendarInvite = false;
bool mIsVoiceRecording = false;
LinphoneEnums::ChatMessageState mMessageState;
QSharedPointer<ConferenceInfoCore> mConferenceInfo = nullptr;

View file

@ -0,0 +1,4 @@
<svg width="22" height="19" viewBox="0 0 22 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.7696 9.19914L13.9126 17.0561C13.8027 17.1661 13.6627 17.241 13.5102 17.2714C13.3577 17.3018 13.1996 17.2862 13.056 17.2267C12.9123 17.1672 12.7896 17.0664 12.7033 16.937C12.6169 16.8077 12.5709 16.6557 12.571 16.5002V12.5943C6.96316 12.9125 3.11816 16.5493 2.03882 17.7013C1.86933 17.8823 1.64708 18.0053 1.40368 18.0526C1.16029 18.1 0.908151 18.0694 0.683157 17.9652C0.458164 17.8609 0.271777 17.6884 0.150522 17.4721C0.0292678 17.2558 -0.0206766 17.0068 0.00779724 16.7605C0.372163 13.5922 2.10757 10.5446 4.89482 8.1797C7.20967 6.21546 10.0234 4.96915 12.571 4.75112V0.786313C12.5709 0.630828 12.6169 0.478802 12.7033 0.349481C12.7896 0.220161 12.9123 0.119361 13.056 0.0598424C13.1996 0.000324097 13.3577 -0.0152363 13.5102 0.0151311C13.6627 0.0454985 13.8027 0.120428 13.9126 0.230434L21.7696 8.08738C21.8426 8.16035 21.9006 8.247 21.9401 8.34238C21.9796 8.43777 22 8.54001 22 8.64326C22 8.74651 21.9796 8.84875 21.9401 8.94413C21.9006 9.03951 21.8426 9.12617 21.7696 9.19914Z" fill="#6C7A87"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,4 @@
<svg width="28" height="22" viewBox="0 0 28 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.94614 11.2169L10.4697 20.7404C10.6029 20.8738 10.7727 20.9646 10.9575 21.0014C11.1423 21.0382 11.3339 21.0194 11.5081 20.9472C11.6822 20.8751 11.831 20.7529 11.9356 20.5961C12.0402 20.4394 12.096 20.2551 12.0959 20.0667V15.3322C18.8933 15.7179 23.5539 20.1262 24.8622 21.5226C25.0676 21.742 25.337 21.891 25.6321 21.9484C25.9271 22.0058 26.2327 21.9687 26.5054 21.8424C26.7781 21.716 27.0041 21.5069 27.151 21.2447C27.298 20.9825 27.3586 20.6807 27.324 20.3821C26.8824 16.5417 24.7789 12.8478 21.4004 9.98119C18.5945 7.6003 15.1839 6.08962 12.0959 5.82534V1.01951C12.096 0.831046 12.0402 0.646772 11.9356 0.49002C11.831 0.333268 11.6822 0.211086 11.5081 0.138942C11.3339 0.0667991 11.1423 0.047938 10.9575 0.084747C10.7727 0.121556 10.6029 0.21238 10.4697 0.345721L0.94614 9.86929C0.857594 9.95774 0.787348 10.0628 0.739422 10.1784C0.691494 10.294 0.666828 10.4179 0.666828 10.5431C0.666828 10.6682 0.691494 10.7922 0.739422 10.9078C0.787348 11.0234 0.857594 11.1284 0.94614 11.2169Z" fill="#6C7A87"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -104,6 +104,16 @@ void ChatModel::markAsRead() {
emit messagesRead();
}
void ChatModel::setMuted(bool muted) {
mMonitor->setMuted(muted);
emit mutedChanged(muted);
}
void ChatModel::enableEphemeral(bool enable) {
mMonitor->enableEphemeral(enable);
emit ephemeralEnableChanged(enable);
}
void ChatModel::deleteHistory() {
mMonitor->deleteHistory();
emit historyDeleted();

View file

@ -51,11 +51,16 @@ public:
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
void compose();
linphone::ChatRoom::State getState() const;
void setMuted(bool muted);
void enableEphemeral(bool enable);
signals:
void historyDeleted();
void messagesRead();
void deleted();
void mutedChanged(bool muted);
void ephemeralEnableChanged(bool enable);
private:
DECLARE_ABSTRACT_OBJECT

View file

@ -171,7 +171,7 @@ ListView {
property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.peerAddress)
contact: contactObj?.value || null
displayNameVal: contact ? "" : modelData.core.avatarUri
// secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
secured: modelData.core.isEncrypted
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
// isConference: modelData.core.isConference
@ -194,32 +194,84 @@ ListView {
capitalization: Font.Capitalize
}
}
Text {
Layout.fillWidth: true
maximumLineCount: 1
visible: !remoteComposingInfo.visible
text: modelData.core.lastMessageText
color: DefaultStyle.main2_400
font {
pixelSize: Typography.p1.pixelSize
weight: unreadCount.unread > 0 ? Typography.p2.weight : Typography.p1.weight
}
}
Text {
id: remoteComposingInfo
visible: mainItem.currentIndex !== model.index && (modelData.core.composingName !== "" || modelData.core.sendingText !== "")
Layout.fillWidth: true
maximumLineCount: 1
font {
pixelSize: Typography.p3.pixelSize
weight: Typography.p3.weight
}
//: %1 is writing
text: modelData.core.composingName !== ""
? qsTr("chat_message_is_writing_info").arg(modelData.core.composingName)
: modelData.core.sendingText !== ""
? qsTr("chat_message_draft_sending_text").arg(modelData.core.sendingText)
: ""
RowLayout {
spacing: Math.round(5 * DefaultStyle.dp)
Layout.fillWidth: true
EffectImage {
visible: modelData != undefined && modelData.core.lastMessage && modelData.core.lastMessage.core.isReply && !remoteComposingInfo.visible
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.reply
colorizationColor: DefaultStyle.main2_500
Layout.preferredHeight: Math.round(14 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(14 * DefaultStyle.dp)
}
EffectImage {
visible: modelData != undefined && modelData.core.lastMessage && modelData.core.lastMessage.core.isForward && !remoteComposingInfo.visible
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.forward
colorizationColor: DefaultStyle.main2_500
Layout.preferredHeight: Math.round(14 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(14 * DefaultStyle.dp)
}
EffectImage {
visible: modelData != undefined && modelData.core.lastMessage && modelData.core.lastMessage.core.hasFileContent && !remoteComposingInfo.visible
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.paperclip
colorizationColor: DefaultStyle.main2_500
Layout.preferredHeight: Math.round(14 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(14 * DefaultStyle.dp)
}
EffectImage {
visible: modelData != undefined && modelData.core.lastMessage && modelData.core.lastMessage.core.isVoiceRecording && !remoteComposingInfo.visible
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.waveform
colorizationColor: DefaultStyle.main2_500
Layout.preferredHeight: Math.round(14 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(14 * DefaultStyle.dp)
}
EffectImage {
visible: modelData != undefined && modelData.core.lastMessage && modelData.core.lastMessage.core.isCalendarInvite && !remoteComposingInfo.visible
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.calendar
colorizationColor: DefaultStyle.main2_500
Layout.preferredHeight: Math.round(14 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(14 * DefaultStyle.dp)
}
Text {
id: lastMessageText
Layout.fillWidth: true
maximumLineCount: 1
visible: !remoteComposingInfo.visible
text: modelData.core.lastMessageText
color: DefaultStyle.main2_400
font {
pixelSize: Typography.p1.pixelSize
weight: unreadCount.unread > 0 ? Typography.p2.weight : Typography.p1.weight
}
}
Text {
id: remoteComposingInfo
visible: (modelData.core.composingName !== "" || modelData.core.sendingText !== "")
Layout.fillWidth: true
maximumLineCount: 1
font {
pixelSize: Typography.p3.pixelSize
weight: Typography.p3.weight
}
//: %1 is writing
text: modelData.core.composingName !== ""
? qsTr("chat_message_is_writing_info").arg(modelData.core.composingName)
: modelData.core.sendingText !== ""
? qsTr("chat_message_draft_sending_text").arg(modelData.core.sendingText)
: ""
}
}
}
ColumnLayout {
@ -240,14 +292,27 @@ ListView {
RowLayout {
spacing: Math.round(10 * DefaultStyle.dp)
Item {Layout.fillWidth: true}
//sourdine, éphémère
UnreadNotification {
EffectImage {
visible: modelData?.core.ephemeralEnabled
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
Layout.preferredHeight: 14 * DefaultStyle.dp
colorizationColor: DefaultStyle.main2_400
imageSource: AppIcons.clockCountDown
}
EffectImage {
visible: modelData != undefined && modelData?.core.muted
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
Layout.preferredHeight: 14 * DefaultStyle.dp
colorizationColor: DefaultStyle.main2_400
imageSource: AppIcons.bellSlash
}
UnreadNotification {
id: unreadCount
unread: modelData.core.unreadMessagesCount
}
EffectImage {
visible: modelData?.core.lastEvent && modelData?.core.lastMessageState !== LinphoneEnums.ChatMessageState.StateIdle
&& !modelData.core.lastMessage.core.isRemoteMessage
visible: modelData != undefined && lastMessageText.visible && modelData?.core.lastMessage && modelData?.core.lastMessageState !== LinphoneEnums.ChatMessageState.StateIdle
&& !modelData?.core.lastMessage.core.isRemoteMessage
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
Layout.preferredHeight: 14 * DefaultStyle.dp
colorizationColor: DefaultStyle.main1_500_main

View file

@ -139,4 +139,9 @@ QtObject {
property string presenceDoNotDisturb: "image://internal/presence_do_not_disturb.svg"
property string presenceOffline: "image://internal/presence_offline.svg"
property string presenceNote: "image://internal/presence-note.svg"
property string clockCountDown: "image://internal/clock-countdown.svg"
property string reply: "image://internal/reply.svg"
property string forward: "image://internal/forward.svg"
}