ephemeral messages

This commit is contained in:
Gaelle Braud 2025-07-03 17:58:27 +02:00
parent 430e6916bd
commit b1ab4224ef
15 changed files with 1002 additions and 851 deletions

View file

@ -71,10 +71,12 @@ QQuickFramebufferObject::Renderer *PreviewManager::subscribe(const CameraGui *ca
App::postModelBlock([&renderer, isFirst = (itCandidate == mCandidates.begin()), App::postModelBlock([&renderer, isFirst = (itCandidate == mCandidates.begin()),
name = itCandidate->first->getQmlName()]() { name = itCandidate->first->getQmlName()]() {
renderer = renderer =
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId(); (QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId(
nullptr);
if (!renderer) { // TODO debug if (!renderer) { // TODO debug
renderer = renderer =
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId(); (QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId(
nullptr);
} }
if (isFirst) { if (isFirst) {
lDebug() << "[PreviewManager] " << name << " Set Native Preview Id with " << renderer; lDebug() << "[PreviewManager] " << name << " Set Native Preview Id with " << renderer;

View file

@ -120,6 +120,13 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
!chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne); !chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne);
mIsRead = chatmessage->isRead(); mIsRead = chatmessage->isRead();
mMessageState = LinphoneEnums::fromLinphone(chatmessage->getState()); mMessageState = LinphoneEnums::fromLinphone(chatmessage->getState());
mIsEphemeral = chatmessage->isEphemeral();
if (mIsEphemeral) {
auto now = QDateTime::currentDateTime();
mEphemeralDuration = chatmessage->getEphemeralExpireTime() == 0
? chatmessage->getEphemeralLifetime()
: now.secsTo(QDateTime::fromSecsSinceEpoch(chatmessage->getEphemeralExpireTime()));
}
mMessageId = Utils::coreStringToAppString(chatmessage->getMessageId()); mMessageId = Utils::coreStringToAppString(chatmessage->getMessageId());
for (auto content : chatmessage->getContents()) { for (auto content : chatmessage->getContents()) {
auto contentCore = ChatMessageContentCore::create(content, mChatMessageModel); auto contentCore = ChatMessageContentCore::create(content, mChatMessageModel);
@ -182,14 +189,17 @@ ChatMessageCore::~ChatMessageCore() {
void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) { void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
mChatMessageModelConnection = SafeConnection<ChatMessageCore, ChatMessageModel>::create(me, mChatMessageModel); mChatMessageModelConnection = SafeConnection<ChatMessageCore, ChatMessageModel>::create(me, mChatMessageModel);
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lDelete, [this] { mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lDelete, [this] {
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->deleteMessageFromChatRoom(); }); mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->deleteMessageFromChatRoom(true); });
}); });
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageDeleted, [this]() { mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageDeleted, [this](bool deletedByUser) {
//: Deleted mChatMessageModelConnection->invokeToCore([this, deletedByUser] {
Utils::showInformationPopup(tr("info_toast_deleted_title"), //: Deleted
//: The message has been deleted if (deletedByUser)
tr("info_toast_deleted_message"), true); Utils::showInformationPopup(tr("info_toast_deleted_title"),
emit deleted(); //: The message has been deleted
tr("info_toast_deleted_message"), true);
emit deleted();
});
}); });
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lMarkAsRead, [this] { mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lMarkAsRead, [this] {
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->markAsRead(); }); mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->markAsRead(); });
@ -308,10 +318,13 @@ void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
auto imdnStatusList = computeDeliveryStatus(message); auto imdnStatusList = computeDeliveryStatus(message);
mChatMessageModelConnection->invokeToCore([this, imdnStatusList] { setImdnStatusList(imdnStatusList); }); mChatMessageModelConnection->invokeToCore([this, imdnStatusList] { setImdnStatusList(imdnStatusList); });
}); });
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::ephemeralMessageTimerStarted, mChatMessageModelConnection->makeConnectToModel(
[this](const std::shared_ptr<linphone::ChatMessage> &message) {}); &ChatMessageModel::ephemeralMessageTimeUpdated,
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::ephemeralMessageDeleted, [this](const std::shared_ptr<linphone::ChatMessage> &message, int expireTime) {
[this](const std::shared_ptr<linphone::ChatMessage> &message) {}); auto now = QDateTime::currentDateTime();
int duration = now.secsTo(QDateTime::fromSecsSinceEpoch(expireTime));
mChatMessageModelConnection->invokeToCore([this, duration] { setEphemeralDuration(duration); });
});
} }
QList<ImdnStatus> ChatMessageCore::computeDeliveryStatus(const std::shared_ptr<linphone::ChatMessage> &message) { QList<ImdnStatus> ChatMessageCore::computeDeliveryStatus(const std::shared_ptr<linphone::ChatMessage> &message) {
@ -405,6 +418,21 @@ bool ChatMessageCore::isFromChatGroup() const {
return mIsFromChatGroup; return mIsFromChatGroup;
} }
bool ChatMessageCore::isEphemeral() const {
return mIsEphemeral;
}
int ChatMessageCore::getEphemeralDuration() const {
return mEphemeralDuration;
}
void ChatMessageCore::setEphemeralDuration(int duration) {
if (mEphemeralDuration != duration) {
mEphemeralDuration = duration;
emit ephemeralDurationChanged(duration);
}
}
bool ChatMessageCore::hasFileContent() const { bool ChatMessageCore::hasFileContent() const {
return mHasFileContent; return mHasFileContent;
} }

View file

@ -89,6 +89,9 @@ class ChatMessageCore : public QObject, public AbstractObject {
messageStateChanged) messageStateChanged)
Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT) Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT)
Q_PROPERTY(bool isFromChatGroup READ isFromChatGroup CONSTANT) Q_PROPERTY(bool isFromChatGroup READ isFromChatGroup CONSTANT)
Q_PROPERTY(bool isEphemeral READ isEphemeral CONSTANT)
Q_PROPERTY(
int ephemeralDuration READ getEphemeralDuration WRITE setEphemeralDuration NOTIFY ephemeralDurationChanged)
Q_PROPERTY(bool isRead READ isRead WRITE setIsRead NOTIFY isReadChanged) Q_PROPERTY(bool isRead READ isRead WRITE setIsRead NOTIFY isReadChanged)
Q_PROPERTY(QString ownReaction READ getOwnReaction WRITE setOwnReaction NOTIFY messageReactionChanged) Q_PROPERTY(QString ownReaction READ getOwnReaction WRITE setOwnReaction NOTIFY messageReactionChanged)
Q_PROPERTY(QStringList imdnStatusListAsString READ getImdnStatusListLabels NOTIFY imdnStatusListChanged) Q_PROPERTY(QStringList imdnStatusListAsString READ getImdnStatusListLabels NOTIFY imdnStatusListChanged)
@ -130,6 +133,9 @@ public:
bool isRemoteMessage() const; bool isRemoteMessage() const;
bool isFromChatGroup() const; bool isFromChatGroup() const;
bool isEphemeral() const;
int getEphemeralDuration() const;
void setEphemeralDuration(int duration);
bool hasFileContent() const; bool hasFileContent() const;
@ -169,6 +175,7 @@ signals:
void imdnStatusListChanged(); void imdnStatusListChanged();
void messageReactionChanged(); void messageReactionChanged();
void singletonReactionMapChanged(); void singletonReactionMapChanged();
void ephemeralDurationChanged(int duration);
void lDelete(); void lDelete();
void deleted(); void deleted();
@ -205,6 +212,8 @@ private:
bool mHasFileContent = false; bool mHasFileContent = false;
bool mIsCalendarInvite = false; bool mIsCalendarInvite = false;
bool mIsVoiceRecording = false; bool mIsVoiceRecording = false;
bool mIsEphemeral = false;
int mEphemeralDuration = 0;
bool mIsOutgoing = false; bool mIsOutgoing = false;
QString mTotalReactionsLabel; QString mTotalReactionsLabel;

View file

@ -58,6 +58,21 @@ QSharedPointer<ChatCore> EventLogList::getChatCore() const {
return mChatCore; return mChatCore;
} }
void EventLogList::connectItem(const QSharedPointer<EventLogCore> item) {
auto message = item->getChatMessageCore();
if (message) {
connect(message.get(), &ChatMessageCore::deleted, this, [this, item] {
emit mChatCore->lUpdateLastMessage();
remove(item);
});
connect(message.get(), &ChatMessageCore::ephemeralDurationChanged, this, [this, item](int duration) {
int i;
get(item.get(), &i);
emit dataChanged(index(i), index(i));
});
}
}
void EventLogList::setChatCore(QSharedPointer<ChatCore> core) { void EventLogList::setChatCore(QSharedPointer<ChatCore> core) {
if (mChatCore != core) { if (mChatCore != core) {
if (mChatCore) disconnect(mChatCore.get(), &ChatCore::eventListChanged, this, nullptr); if (mChatCore) disconnect(mChatCore.get(), &ChatCore::eventListChanged, this, nullptr);
@ -104,12 +119,7 @@ void EventLogList::setSelf(QSharedPointer<EventLogList> me) {
if (!mChatCore) return; if (!mChatCore) return;
auto events = mChatCore->getEventLogList(); auto events = mChatCore->getEventLogList();
for (auto &event : events) { for (auto &event : events) {
auto message = event->getChatMessageCore(); connectItem(event);
if (message)
connect(message.get(), &ChatMessageCore::deleted, this, [this, message, event] {
emit mChatCore->lUpdateLastMessage();
remove(event);
});
} }
resetData<EventLogCore>(events); resetData<EventLogCore>(events);
}); });

View file

@ -27,6 +27,7 @@
#include <QLocale> #include <QLocale>
class EventLogGui; class EventLogGui;
class EventLogCore;
class ChatCore; class ChatCore;
class ChatGui; class ChatGui;
// ============================================================================= // =============================================================================
@ -43,6 +44,8 @@ public:
void setChatCore(QSharedPointer<ChatCore> core); void setChatCore(QSharedPointer<ChatCore> core);
void setChatGui(ChatGui *chat); void setChatGui(ChatGui *chat);
void connectItem(const QSharedPointer<EventLogCore> item);
int findFirstUnreadIndex(); int findFirstUnreadIndex();
void setSelf(QSharedPointer<EventLogList> me); void setSelf(QSharedPointer<EventLogList> me);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -323,7 +323,7 @@ void ChatModel::onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::C
void ChatModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatRoom> &chatRoom, void ChatModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<const linphone::EventLog> &eventLog) { const std::shared_ptr<const linphone::EventLog> &eventLog) {
emit onEphemeralMessageDeleted(chatRoom, eventLog); emit ephemeralMessageDeleted(chatRoom, eventLog);
} }
void ChatModel::onConferenceAddressGeneration(const std::shared_ptr<linphone::ChatRoom> &chatRoom) { void ChatModel::onConferenceAddressGeneration(const std::shared_ptr<linphone::ChatRoom> &chatRoom) {

View file

@ -34,6 +34,16 @@ ChatMessageModel::ChatMessageModel(const std::shared_ptr<linphone::ChatMessage>
: ::Listener<linphone::ChatMessage, linphone::ChatMessageListener>(chatMessage, parent) { : ::Listener<linphone::ChatMessage, linphone::ChatMessageListener>(chatMessage, parent) {
// lDebug() << "[ChatMessageModel] new" << this << " / SDKModel=" << chatMessage.get(); // lDebug() << "[ChatMessageModel] new" << this << " / SDKModel=" << chatMessage.get();
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
mEphemeralTimer.setInterval(60);
mEphemeralTimer.setSingleShot(false);
if (mMonitor->getEphemeralExpireTime() != 0) mEphemeralTimer.start();
connect(&mEphemeralTimer, &QTimer::timeout, this,
[this] { emit ephemeralMessageTimeUpdated(mMonitor, mMonitor->getEphemeralExpireTime()); });
connect(this, &ChatMessageModel::ephemeralMessageTimerStarted, this, [this] { mEphemeralTimer.start(); });
connect(this, &ChatMessageModel::ephemeralMessageDeleted, this, [this] {
mEphemeralTimer.stop();
deleteMessageFromChatRoom(false);
});
} }
ChatMessageModel::~ChatMessageModel() { ChatMessageModel::~ChatMessageModel() {
@ -85,11 +95,11 @@ void ChatMessageModel::markAsRead() {
emit CoreModel::getInstance()->messageReadInChatRoom(mMonitor->getChatRoom()); emit CoreModel::getInstance()->messageReadInChatRoom(mMonitor->getChatRoom());
} }
void ChatMessageModel::deleteMessageFromChatRoom() { void ChatMessageModel::deleteMessageFromChatRoom(bool deletedByUser) {
auto chatRoom = mMonitor->getChatRoom(); auto chatRoom = mMonitor->getChatRoom();
if (chatRoom) { if (chatRoom) {
chatRoom->deleteMessage(mMonitor); chatRoom->deleteMessage(mMonitor);
emit messageDeleted(); emit messageDeleted(deletedByUser);
} }
} }

View file

@ -51,7 +51,7 @@ public:
bool isRead() const; bool isRead() const;
void markAsRead(); void markAsRead();
void deleteMessageFromChatRoom(); void deleteMessageFromChatRoom(bool deletedByUser);
void sendReaction(const QString &reaction); void sendReaction(const QString &reaction);
@ -64,7 +64,7 @@ public:
QString getOwnReaction() const; QString getOwnReaction() const;
signals: signals:
void messageDeleted(); void messageDeleted(bool deletedByUser);
void messageRead(); void messageRead();
void msgStateChanged(const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state); void msgStateChanged(const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state);
@ -94,9 +94,11 @@ signals:
const std::shared_ptr<const linphone::ParticipantImdnState> &state); const std::shared_ptr<const linphone::ParticipantImdnState> &state);
void ephemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message); void ephemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message);
void ephemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message); void ephemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message);
void ephemeralMessageTimeUpdated(const std::shared_ptr<linphone::ChatMessage> &message, int expireTime);
private: private:
linphone::ChatMessage::State mMessageState; linphone::ChatMessage::State mMessageState;
QTimer mEphemeralTimer;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -74,7 +74,7 @@ signals:
private: private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
void onEofReached(const std::shared_ptr<linphone::Player> &player); void onEofReached(const std::shared_ptr<linphone::Player> &player) override;
}; };
#endif // SOUND_PLAYER_H_ #endif // SOUND_PLAYER_H_

View file

@ -1011,7 +1011,7 @@ template <typename T>
quint32 QExifImageHeader::calculateSize(const QMap<T, QExifValue> &values) const { quint32 QExifImageHeader::calculateSize(const QMap<T, QExifValue> &values) const {
quint32 size = sizeof(quint16); quint32 size = sizeof(quint16);
foreach (const QExifValue &value, values) for (const QExifValue &value : values)
size += sizeOf(value); size += sizeOf(value);
return size; return size;
@ -1387,7 +1387,7 @@ QExifImageHeader::readIfdValues(QDataStream &stream, int startPos, const QList<E
// This needs to be non-const so it works with gcc3 // This needs to be non-const so it works with gcc3
QList<ExifIfdHeader> headers_ = headers; QList<ExifIfdHeader> headers_ = headers;
foreach (const ExifIfdHeader &header, headers_) for (const ExifIfdHeader &header : headers_)
values[T(header.tag)] = readIfdValue(stream, startPos, header); values[T(header.tag)] = readIfdValue(stream, startPos, header);
return values; return values;
@ -1491,7 +1491,7 @@ QExifImageHeader::writeExifHeader(QDataStream &stream, quint16 tag, const QExifV
switch (value.type()) { switch (value.type()) {
case QExifValue::Byte: case QExifValue::Byte:
if (value.count() <= 4) { if (value.count() <= 4) {
foreach (quint8 byte, value.toByteVector()) for (quint8 byte : value.toByteVector())
stream << byte; stream << byte;
for (int j = value.count(); j < 4; j++) for (int j = value.count(); j < 4; j++)
stream << quint8(0); stream << quint8(0);
@ -1526,7 +1526,7 @@ QExifImageHeader::writeExifHeader(QDataStream &stream, quint16 tag, const QExifV
break; break;
case QExifValue::Short: case QExifValue::Short:
if (value.count() <= 2) { if (value.count() <= 2) {
foreach (quint16 shrt, value.toShortVector()) for (quint16 shrt : value.toShortVector())
stream << shrt; stream << shrt;
for (int j = value.count(); j < 2; j++) for (int j = value.count(); j < 2; j++)
stream << quint16(0); stream << quint16(0);
@ -1588,7 +1588,7 @@ void QExifImageHeader::writeExifValue(QDataStream &stream, const QExifValue &val
switch (value.type()) { switch (value.type()) {
case QExifValue::Byte: case QExifValue::Byte:
if (value.count() > 4) if (value.count() > 4)
foreach (quint8 byte, value.toByteVector()) for (quint8 byte : value.toByteVector())
stream << byte; stream << byte;
break; break;
case QExifValue::Undefined: case QExifValue::Undefined:
@ -1603,27 +1603,27 @@ void QExifImageHeader::writeExifValue(QDataStream &stream, const QExifValue &val
break; break;
case QExifValue::Short: case QExifValue::Short:
if (value.count() > 2) if (value.count() > 2)
foreach (quint16 shrt, value.toShortVector()) for (quint16 shrt : value.toShortVector())
stream << shrt; stream << shrt;
break; break;
case QExifValue::Long: case QExifValue::Long:
if (value.count() > 1) if (value.count() > 1)
foreach (quint32 lng, value.toLongVector()) for (quint32 lng : value.toLongVector())
stream << lng; stream << lng;
break; break;
case QExifValue::SignedLong: case QExifValue::SignedLong:
if (value.count() > 1) if (value.count() > 1)
foreach (qint32 lng, value.toSignedLongVector()) for (qint32 lng : value.toSignedLongVector())
stream << lng; stream << lng;
break; break;
case QExifValue::Rational: case QExifValue::Rational:
if (value.count() > 0) if (value.count() > 0)
foreach (QExifURational rational, value.toRationalVector()) for (QExifURational rational : value.toRationalVector())
stream << rational; stream << rational;
break; break;
case QExifValue::SignedRational: case QExifValue::SignedRational:
if (value.count() > 0) if (value.count() > 0)
foreach (QExifSRational rational, value.toSignedRationalVector()) for (QExifSRational rational : value.toSignedRationalVector())
stream << rational; stream << rational;
break; break;
default: default:

View file

@ -356,9 +356,21 @@ QString Utils::formatTime(const QDateTime &date) {
} }
QString Utils::formatDuration(int durationMs) { QString Utils::formatDuration(int durationMs) {
QTime duration(0, 0); auto now = QDateTime::currentDateTime();
duration = duration.addMSecs(durationMs); auto end = now.addMSecs(durationMs);
return duration.hour() > 0 ? duration.toString("hh:mm:ss") : duration.toString("mm:ss"); auto daysTo = now.daysTo(end);
if (daysTo > 0) {
//: Tomorrow
if (daysTo == 1) return tr("duration_tomorrow");
else {
//: %1 jour(s)
return tr("duration_number_of_days", "", daysTo);
}
} else {
QTime duration(0, 0);
duration = duration.addMSecs(durationMs);
return duration.hour() > 0 ? duration.toString("hh:mm:ss") : duration.toString("mm:ss");
}
} }
QString Utils::formatDateElapsedTime(const QDateTime &date) { QString Utils::formatDateElapsedTime(const QDateTime &date) {

View file

@ -204,30 +204,60 @@ Control.Control {
} }
} }
RowLayout { RowLayout {
Layout.fillWidth: false Layout.preferredHeight: childrenRect.height
Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft : Qt.AlignRight Layout.alignment: mainItem.isRemoteMessage ? Qt.AlignLeft : Qt.AlignRight
Text { layoutDirection: mainItem.isRemoteMessage ? Qt.RightToLeft : Qt.LeftToRight
text: UtilsCpp.formatDate(mainItem.chatMessage.core.timestamp, true, false, "dd/MM") spacing: Math.round(7 * DefaultStyle.dp)
color: DefaultStyle.main2_500main RowLayout {
font { spacing: Math.round(3 * DefaultStyle.dp)
pixelSize: Typography.p3.pixelSize Layout.preferredHeight: childrenRect.height
weight: Typography.p3.weight Text {
id: ephemeralTime
visible: mainItem.chatMessage.core.isEphemeral
color: DefaultStyle.main2_500main
text: UtilsCpp.formatDuration(mainItem.chatMessage.core.ephemeralDuration * 1000)
font {
pixelSize: Typography.p3.pixelSize
weight: Typography.p3.weight
}
}
EffectImage {
visible: mainItem.chatMessage.core.isEphemeral
imageSource: AppIcons.clockCountDown
colorizationColor: DefaultStyle.main2_500main
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
Layout.preferredHeight: visible ? 14 * DefaultStyle.dp : 0
} }
} }
EffectImage { RowLayout {
visible: !mainItem.isRemoteMessage spacing: mainItem.isRemoteMessage ? 0 : Math.round(5 * DefaultStyle.dp)
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0 Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 14 * DefaultStyle.dp Layout.preferredHeight: childrenRect.height
colorizationColor: DefaultStyle.main1_500_main Text {
imageSource: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDelivered Layout.alignment: Qt.AlignVCenter
? AppIcons.envelope text: UtilsCpp.formatDate(mainItem.chatMessage.core.timestamp, true, false, "dd/MM")
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDeliveredToUser color: DefaultStyle.main2_500main
? AppIcons.check font {
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateNotDelivered pixelSize: Typography.p3.pixelSize
? AppIcons.warningCircle weight: Typography.p3.weight
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDisplayed }
? AppIcons.checks }
: "" EffectImage {
visible: !mainItem.isRemoteMessage
Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
Layout.preferredHeight: visible ? 14 * DefaultStyle.dp : 0
Layout.alignment: Qt.AlignVCenter
colorizationColor: DefaultStyle.main1_500_main
imageSource: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDelivered
? AppIcons.envelope
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDeliveredToUser
? AppIcons.check
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateNotDelivered
? AppIcons.warningCircle
: mainItem.msgState === LinphoneEnums.ChatMessageState.StateDisplayed
? AppIcons.checks
: ""
}
} }
} }
} }