ephemeral messages
This commit is contained in:
parent
430e6916bd
commit
b1ab4224ef
15 changed files with 1002 additions and 851 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
: ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue