mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
feat(chatlog): Add SystemMessages to SessionChatLog
* Rendering of system messages consolidated into single place * API added to ichatlog to insert a system message at current location * System messages are now used as type + args which will fit nicely with the work in #6221
This commit is contained in:
parent
bde6dc0df0
commit
916834fb9c
|
@ -212,6 +212,13 @@ std::vector<IChatLog::DateChatLogIdxPair> ChatHistory::getDateIdxs(const QDate&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatHistory::addSystemMessage(const SystemMessage& message)
|
||||||
|
{
|
||||||
|
// FIXME: #6221 Insert into history
|
||||||
|
sessionChatLog.addSystemMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ChatHistory::onFileUpdated(const ToxPk& sender, const ToxFile& file)
|
void ChatHistory::onFileUpdated(const ToxPk& sender, const ToxFile& file)
|
||||||
{
|
{
|
||||||
if (canUseHistory()) {
|
if (canUseHistory()) {
|
||||||
|
|
|
@ -42,12 +42,14 @@ public:
|
||||||
ChatLogIdx getFirstIdx() const override;
|
ChatLogIdx getFirstIdx() const override;
|
||||||
ChatLogIdx getNextIdx() const override;
|
ChatLogIdx getNextIdx() const override;
|
||||||
std::vector<DateChatLogIdxPair> getDateIdxs(const QDate& startDate, size_t maxDates) const override;
|
std::vector<DateChatLogIdxPair> getDateIdxs(const QDate& startDate, size_t maxDates) const override;
|
||||||
|
void addSystemMessage(const SystemMessage& message) override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onFileUpdated(const ToxPk& sender, const ToxFile& file);
|
void onFileUpdated(const ToxPk& sender, const ToxFile& file);
|
||||||
void onFileTransferRemotePausedUnpaused(const ToxPk& sender, const ToxFile& file, bool paused);
|
void onFileTransferRemotePausedUnpaused(const ToxPk& sender, const ToxFile& file, bool paused);
|
||||||
void onFileTransferBrokenUnbroken(const ToxPk& sender, const ToxFile& file, bool broken);
|
void onFileTransferBrokenUnbroken(const ToxPk& sender, const ToxFile& file, bool broken);
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onMessageReceived(const ToxPk& sender, const Message& message);
|
void onMessageReceived(const ToxPk& sender, const Message& message);
|
||||||
void onMessageSent(DispatchedMessageId id, const Message& message);
|
void onMessageSent(DispatchedMessageId id, const Message& message);
|
||||||
|
|
|
@ -50,6 +50,11 @@ ChatLogItem::ChatLogItem(ToxPk sender_, const QString& displayName, ChatLogMessa
|
||||||
ChatLogItemDeleter<ChatLogMessage>::doDelete))
|
ChatLogItemDeleter<ChatLogMessage>::doDelete))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
ChatLogItem::ChatLogItem(SystemMessage systemMessage)
|
||||||
|
: contentType(ContentType::systemMessage)
|
||||||
|
, content(new SystemMessage(std::move(systemMessage)), ChatLogItemDeleter<SystemMessage>::doDelete)
|
||||||
|
{}
|
||||||
|
|
||||||
ChatLogItem::ChatLogItem(ToxPk sender_, const QString& displayName_, ContentType contentType_, ContentPtr content_)
|
ChatLogItem::ChatLogItem(ToxPk sender_, const QString& displayName_, ContentType contentType_, ContentPtr content_)
|
||||||
: sender(std::move(sender_))
|
: sender(std::move(sender_))
|
||||||
, displayName(displayName_)
|
, displayName(displayName_)
|
||||||
|
@ -91,6 +96,19 @@ const ChatLogMessage& ChatLogItem::getContentAsMessage() const
|
||||||
return *static_cast<ChatLogMessage*>(content.get());
|
return *static_cast<ChatLogMessage*>(content.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemMessage& ChatLogItem::getContentAsSystemMessage()
|
||||||
|
{
|
||||||
|
assert(contentType == ContentType::systemMessage);
|
||||||
|
return *static_cast<SystemMessage*>(content.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const SystemMessage& ChatLogItem::getContentAsSystemMessage() const
|
||||||
|
{
|
||||||
|
assert(contentType == ContentType::systemMessage);
|
||||||
|
return *static_cast<SystemMessage*>(content.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QDateTime ChatLogItem::getTimestamp() const
|
QDateTime ChatLogItem::getTimestamp() const
|
||||||
{
|
{
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
|
@ -102,6 +120,10 @@ QDateTime ChatLogItem::getTimestamp() const
|
||||||
const auto& file = getContentAsFile();
|
const auto& file = getContentAsFile();
|
||||||
return file.timestamp;
|
return file.timestamp;
|
||||||
}
|
}
|
||||||
|
case ChatLogItem::ContentType::systemMessage: {
|
||||||
|
const auto& systemMessage = getContentAsSystemMessage();
|
||||||
|
return systemMessage.timestamp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "src/core/toxfile.h"
|
#include "src/core/toxfile.h"
|
||||||
#include "src/core/toxpk.h"
|
#include "src/core/toxpk.h"
|
||||||
#include "src/model/message.h"
|
#include "src/model/message.h"
|
||||||
|
#include "src/model/systemmessage.h"
|
||||||
#include "src/persistence/history.h"
|
#include "src/persistence/history.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -48,16 +49,20 @@ public:
|
||||||
{
|
{
|
||||||
message,
|
message,
|
||||||
fileTransfer,
|
fileTransfer,
|
||||||
|
systemMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
ChatLogItem(ToxPk sender, const QString& displayName, ChatLogFile file);
|
ChatLogItem(ToxPk sender, const QString& displayName, ChatLogFile file);
|
||||||
ChatLogItem(ToxPk sender, const QString& displayName, ChatLogMessage message);
|
ChatLogItem(ToxPk sender, const QString& displayName, ChatLogMessage message);
|
||||||
|
ChatLogItem(SystemMessage message);
|
||||||
const ToxPk& getSender() const;
|
const ToxPk& getSender() const;
|
||||||
ContentType getContentType() const;
|
ContentType getContentType() const;
|
||||||
ChatLogFile& getContentAsFile();
|
ChatLogFile& getContentAsFile();
|
||||||
const ChatLogFile& getContentAsFile() const;
|
const ChatLogFile& getContentAsFile() const;
|
||||||
ChatLogMessage& getContentAsMessage();
|
ChatLogMessage& getContentAsMessage();
|
||||||
const ChatLogMessage& getContentAsMessage() const;
|
const ChatLogMessage& getContentAsMessage() const;
|
||||||
|
SystemMessage& getContentAsSystemMessage();
|
||||||
|
const SystemMessage& getContentAsSystemMessage() const;
|
||||||
QDateTime getTimestamp() const;
|
QDateTime getTimestamp() const;
|
||||||
void setDisplayName(QString name);
|
void setDisplayName(QString name);
|
||||||
const QString& getDisplayName() const;
|
const QString& getDisplayName() const;
|
||||||
|
|
|
@ -28,9 +28,9 @@
|
||||||
#include "src/model/chatlogitem.h"
|
#include "src/model/chatlogitem.h"
|
||||||
#include "src/model/friend.h"
|
#include "src/model/friend.h"
|
||||||
#include "src/model/group.h"
|
#include "src/model/group.h"
|
||||||
#include "src/persistence/history.h"
|
#include "src/model/systemmessage.h"
|
||||||
#include "util/strongtype.h"
|
|
||||||
#include "src/widget/searchtypes.h"
|
#include "src/widget/searchtypes.h"
|
||||||
|
#include "util/strongtype.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -137,6 +137,12 @@ public:
|
||||||
virtual std::vector<DateChatLogIdxPair> getDateIdxs(const QDate& startDate,
|
virtual std::vector<DateChatLogIdxPair> getDateIdxs(const QDate& startDate,
|
||||||
size_t maxDates) const = 0;
|
size_t maxDates) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inserts a system message at the end of the chat
|
||||||
|
* @param[in] message systemMessage to insert
|
||||||
|
*/
|
||||||
|
virtual void addSystemMessage(const SystemMessage& message) = 0;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void itemUpdated(ChatLogIdx idx);
|
void itemUpdated(ChatLogIdx idx);
|
||||||
};
|
};
|
||||||
|
|
|
@ -319,6 +319,15 @@ std::vector<IChatLog::DateChatLogIdxPair> SessionChatLog::getDateIdxs(const QDat
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionChatLog::addSystemMessage(const SystemMessage& message)
|
||||||
|
{
|
||||||
|
auto messageIdx = nextIdx++;
|
||||||
|
|
||||||
|
items.emplace(messageIdx, ChatLogItem(message));
|
||||||
|
|
||||||
|
emit this->itemUpdated(messageIdx);
|
||||||
|
}
|
||||||
|
|
||||||
void SessionChatLog::insertCompleteMessageAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName,
|
void SessionChatLog::insertCompleteMessageAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName,
|
||||||
const ChatLogMessage& message)
|
const ChatLogMessage& message)
|
||||||
{
|
{
|
||||||
|
@ -358,6 +367,13 @@ void SessionChatLog::insertFileAtIdx(ChatLogIdx idx, const ToxPk& sender, QStrin
|
||||||
items.emplace(idx, std::move(item));
|
items.emplace(idx, std::move(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionChatLog::insertSystemMessageAtIdx(ChatLogIdx idx, SystemMessage message)
|
||||||
|
{
|
||||||
|
auto item = ChatLogItem(std::move(message));
|
||||||
|
|
||||||
|
items.emplace(idx, std::move(item));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inserts message data into the chatlog buffer
|
* @brief Inserts message data into the chatlog buffer
|
||||||
* @note Owner of SessionChatLog is in charge of attaching this to the appropriate IMessageDispatcher
|
* @note Owner of SessionChatLog is in charge of attaching this to the appropriate IMessageDispatcher
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
ChatLogIdx getFirstIdx() const override;
|
ChatLogIdx getFirstIdx() const override;
|
||||||
ChatLogIdx getNextIdx() const override;
|
ChatLogIdx getNextIdx() const override;
|
||||||
std::vector<DateChatLogIdxPair> getDateIdxs(const QDate& startDate, size_t maxDates) const override;
|
std::vector<DateChatLogIdxPair> getDateIdxs(const QDate& startDate, size_t maxDates) const override;
|
||||||
|
void addSystemMessage(const SystemMessage& message) override;
|
||||||
|
|
||||||
void insertCompleteMessageAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName,
|
void insertCompleteMessageAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName,
|
||||||
const ChatLogMessage& message);
|
const ChatLogMessage& message);
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
void insertBrokenMessageAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName,
|
void insertBrokenMessageAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName,
|
||||||
const ChatLogMessage& message);
|
const ChatLogMessage& message);
|
||||||
void insertFileAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName, const ChatLogFile& file);
|
void insertFileAtIdx(ChatLogIdx idx, const ToxPk& sender, QString senderName, const ChatLogFile& file);
|
||||||
|
void insertSystemMessageAtIdx(ChatLogIdx idx, SystemMessage message);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onMessageReceived(const ToxPk& sender, const Message& message);
|
void onMessageReceived(const ToxPk& sender, const Message& message);
|
||||||
|
|
114
src/model/systemmessage.h
Normal file
114
src/model/systemmessage.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2015-2021 by The qTox Project Contributors
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
enum class SystemMessageType
|
||||||
|
{
|
||||||
|
// DO NOT CHANGE ORDER
|
||||||
|
// These values are saved directly to the DB and read back, changing the
|
||||||
|
// order will break persistence!
|
||||||
|
fileSendFailed = 0,
|
||||||
|
userJoinedGroup,
|
||||||
|
userLeftGroup,
|
||||||
|
peerNameChanged,
|
||||||
|
peerStateChange,
|
||||||
|
titleChanged,
|
||||||
|
cleared,
|
||||||
|
unexpectedCallEnd,
|
||||||
|
outgoingCall,
|
||||||
|
incomingCall,
|
||||||
|
callEnd,
|
||||||
|
messageSendFailed,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SystemMessage
|
||||||
|
{
|
||||||
|
using Args = std::array<QString, 4>;
|
||||||
|
SystemMessageType messageType;
|
||||||
|
QDateTime timestamp;
|
||||||
|
Args args;
|
||||||
|
|
||||||
|
QString toString() const
|
||||||
|
{
|
||||||
|
QString translated;
|
||||||
|
size_t numArgs = 0;
|
||||||
|
|
||||||
|
switch (messageType) {
|
||||||
|
case SystemMessageType::fileSendFailed:
|
||||||
|
translated = QObject::tr("Failed to send file \"%1\"");
|
||||||
|
numArgs = 1;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::userJoinedGroup:
|
||||||
|
translated = QObject::tr("%1 has joined the group");
|
||||||
|
numArgs = 1;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::userLeftGroup:
|
||||||
|
translated = QObject::tr("%1 has left the group");
|
||||||
|
numArgs = 1;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::peerNameChanged:
|
||||||
|
translated = QObject::tr("%1 is now known as %2");
|
||||||
|
numArgs = 2;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::titleChanged:
|
||||||
|
translated = QObject::tr("%1 has set the title to %2");
|
||||||
|
numArgs = 2;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::cleared:
|
||||||
|
translated = QObject::tr("Cleared");
|
||||||
|
break;
|
||||||
|
case SystemMessageType::unexpectedCallEnd:
|
||||||
|
translated = QObject::tr("Call with %1 ended unexpectedly. %2");
|
||||||
|
numArgs = 2;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::callEnd:
|
||||||
|
translated = QObject::tr("Call with %1 ended. %2");
|
||||||
|
numArgs = 2;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::peerStateChange:
|
||||||
|
translated = QObject::tr("%1 is now %2", "e.g. \"Dubslow is now online\"");
|
||||||
|
numArgs = 2;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::outgoingCall:
|
||||||
|
translated = QObject::tr("Calling %1");
|
||||||
|
numArgs = 1;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::incomingCall:
|
||||||
|
translated = QObject::tr("%1 calling");
|
||||||
|
numArgs = 1;
|
||||||
|
break;
|
||||||
|
case SystemMessageType::messageSendFailed:
|
||||||
|
translated = QObject::tr("Message failed to send");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numArgs; ++i) {
|
||||||
|
translated = translated.arg(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return translated;
|
||||||
|
}
|
||||||
|
};
|
|
@ -289,9 +289,11 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video)
|
||||||
}
|
}
|
||||||
|
|
||||||
QString displayedName = f->getDisplayedName();
|
QString displayedName = f->getDisplayedName();
|
||||||
insertChatMessage(ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
|
|
||||||
ChatMessage::INFO,
|
SystemMessage systemMessage;
|
||||||
QDateTime::currentDateTime()));
|
systemMessage.messageType = SystemMessageType::incomingCall;
|
||||||
|
systemMessage.args = {displayedName};
|
||||||
|
chatLog.addSystemMessage(systemMessage);
|
||||||
|
|
||||||
auto testedFlag = video ? Settings::AutoAcceptCall::Video : Settings::AutoAcceptCall::Audio;
|
auto testedFlag = video ? Settings::AutoAcceptCall::Video : Settings::AutoAcceptCall::Audio;
|
||||||
// AutoAcceptCall is set for this friend
|
// AutoAcceptCall is set for this friend
|
||||||
|
@ -349,8 +351,8 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error)
|
||||||
void ChatForm::showOutgoingCall(bool video)
|
void ChatForm::showOutgoingCall(bool video)
|
||||||
{
|
{
|
||||||
headWidget->showOutgoingCall(video);
|
headWidget->showOutgoingCall(video);
|
||||||
addSystemInfoMessage(tr("Calling %1").arg(f->getDisplayedName()), ChatMessage::INFO,
|
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::outgoingCall,
|
||||||
QDateTime::currentDateTime());
|
{f->getDisplayedName()});
|
||||||
emit outgoingNotification();
|
emit outgoingNotification();
|
||||||
emit updateFriendActivity(*f);
|
emit updateFriendActivity(*f);
|
||||||
}
|
}
|
||||||
|
@ -444,10 +446,8 @@ void ChatForm::onFriendStatusChanged(const ToxPk& friendPk, Status::Status statu
|
||||||
|
|
||||||
if (Settings::getInstance().getStatusChangeNotificationEnabled()) {
|
if (Settings::getInstance().getStatusChangeNotificationEnabled()) {
|
||||||
QString fStatus = Status::getTitle(status);
|
QString fStatus = Status::getTitle(status);
|
||||||
addSystemInfoMessage(tr("%1 is now %2", "e.g. \"Dubslow is now online\"")
|
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::peerStateChange,
|
||||||
.arg(f->getDisplayedName())
|
{f->getDisplayedName(), fStatus});
|
||||||
.arg(fStatus),
|
|
||||||
ChatMessage::INFO, QDateTime::currentDateTime());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,10 +652,10 @@ void ChatForm::stopCounter(bool error)
|
||||||
}
|
}
|
||||||
QString dhms = secondsToDHMS(timeElapsed.elapsed() / 1000);
|
QString dhms = secondsToDHMS(timeElapsed.elapsed() / 1000);
|
||||||
QString name = f->getDisplayedName();
|
QString name = f->getDisplayedName();
|
||||||
QString mess = error ? tr("Call with %1 ended unexpectedly. %2") : tr("Call with %1 ended. %2");
|
auto messageType = error ? SystemMessageType::unexpectedCallEnd : SystemMessageType::callEnd;
|
||||||
// TODO: add notification once notifications are implemented
|
// TODO: add notification once notifications are implemented
|
||||||
|
|
||||||
addSystemInfoMessage(mess.arg(name, dhms), ChatMessage::INFO, QDateTime::currentDateTime());
|
addSystemInfoMessage(QDateTime::currentDateTime(), messageType, {name, dhms});
|
||||||
callDurationTimer->stop();
|
callDurationTimer->stop();
|
||||||
callDuration->setText("");
|
callDuration->setText("");
|
||||||
callDuration->hide();
|
callDuration->hide();
|
||||||
|
|
|
@ -209,6 +209,32 @@ ChatLogIdx firstItemAfterDate(QDate date, const IChatLog& chatLog)
|
||||||
return chatLog.getNextIdx();
|
return chatLog.getNextIdx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Chat message message type (info/warning) for the given system message
|
||||||
|
* @param[in] systemMessage
|
||||||
|
*/
|
||||||
|
ChatMessage::SystemMessageType getChatMessageType(const SystemMessage& systemMessage)
|
||||||
|
{
|
||||||
|
switch (systemMessage.messageType) {
|
||||||
|
case SystemMessageType::fileSendFailed:
|
||||||
|
case SystemMessageType::messageSendFailed:
|
||||||
|
case SystemMessageType::unexpectedCallEnd:
|
||||||
|
return ChatMessage::ERROR;
|
||||||
|
case SystemMessageType::userJoinedGroup:
|
||||||
|
case SystemMessageType::userLeftGroup:
|
||||||
|
case SystemMessageType::peerNameChanged:
|
||||||
|
case SystemMessageType::peerStateChange:
|
||||||
|
case SystemMessageType::titleChanged:
|
||||||
|
case SystemMessageType::cleared:
|
||||||
|
case SystemMessageType::outgoingCall:
|
||||||
|
case SystemMessageType::incomingCall:
|
||||||
|
case SystemMessageType::callEnd:
|
||||||
|
return ChatMessage::INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChatMessage::INFO;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
GenericChatForm::GenericChatForm(const Core& _core, const Contact* contact, IChatLog& chatLog,
|
GenericChatForm::GenericChatForm(const Core& _core, const Contact* contact, IChatLog& chatLog,
|
||||||
|
@ -407,7 +433,42 @@ QDateTime GenericChatForm::getLatestTime() const
|
||||||
if (chatLog.getFirstIdx() == chatLog.getNextIdx())
|
if (chatLog.getFirstIdx() == chatLog.getNextIdx())
|
||||||
return QDateTime();
|
return QDateTime();
|
||||||
|
|
||||||
return chatLog.at(chatLog.getNextIdx() - 1).getTimestamp();
|
const auto shouldUseTimestamp = [this] (ChatLogIdx idx) {
|
||||||
|
if (chatLog.at(idx).getContentType() != ChatLogItem::ContentType::systemMessage) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& message = chatLog.at(idx).getContentAsSystemMessage();
|
||||||
|
switch (message.messageType) {
|
||||||
|
case SystemMessageType::incomingCall:
|
||||||
|
case SystemMessageType::outgoingCall:
|
||||||
|
case SystemMessageType::callEnd:
|
||||||
|
case SystemMessageType::unexpectedCallEnd:
|
||||||
|
return true;
|
||||||
|
case SystemMessageType::cleared:
|
||||||
|
case SystemMessageType::titleChanged:
|
||||||
|
case SystemMessageType::peerStateChange:
|
||||||
|
case SystemMessageType::peerNameChanged:
|
||||||
|
case SystemMessageType::userLeftGroup:
|
||||||
|
case SystemMessageType::userJoinedGroup:
|
||||||
|
case SystemMessageType::fileSendFailed:
|
||||||
|
case SystemMessageType::messageSendFailed:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning("Unexpected system message type %d", static_cast<int>(message.messageType));
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChatLogIdx idx = chatLog.getNextIdx();
|
||||||
|
while (idx > chatLog.getFirstIdx()) {
|
||||||
|
idx = idx - 1;
|
||||||
|
if (shouldUseTimestamp(idx)) {
|
||||||
|
return chatLog.at(idx).getTimestamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::reloadTheme()
|
void GenericChatForm::reloadTheme()
|
||||||
|
@ -591,10 +652,14 @@ void GenericChatForm::setColorizedNames(bool enable)
|
||||||
colorizeNames = enable;
|
colorizeNames = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::addSystemInfoMessage(const QString& message, ChatMessage::SystemMessageType type,
|
void GenericChatForm::addSystemInfoMessage(const QDateTime& datetime, SystemMessageType messageType,
|
||||||
const QDateTime& datetime)
|
SystemMessage::Args messageArgs)
|
||||||
{
|
{
|
||||||
insertChatMessage(ChatMessage::createChatInfoMessage(message, type, datetime));
|
SystemMessage systemMessage;
|
||||||
|
systemMessage.messageType = static_cast<SystemMessageType>(messageType);
|
||||||
|
systemMessage.timestamp = datetime;
|
||||||
|
systemMessage.args = std::move(messageArgs);
|
||||||
|
chatLog.addSystemMessage(systemMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::addSystemDateMessage(const QDate& date)
|
void GenericChatForm::addSystemDateMessage(const QDate& date)
|
||||||
|
@ -759,7 +824,7 @@ void GenericChatForm::clearChatArea(bool confirm, bool inform)
|
||||||
chatWidget->clear();
|
chatWidget->clear();
|
||||||
|
|
||||||
if (inform)
|
if (inform)
|
||||||
addSystemInfoMessage(tr("Cleared"), ChatMessage::INFO, QDateTime::currentDateTime());
|
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::cleared, {});
|
||||||
|
|
||||||
messages.clear();
|
messages.clear();
|
||||||
}
|
}
|
||||||
|
@ -1070,6 +1135,17 @@ void GenericChatForm::renderItem(const ChatLogItem& item, bool hideName, bool co
|
||||||
renderFile(item.getDisplayName(), file.file, isSelf, item.getTimestamp(), chatMessage);
|
renderFile(item.getDisplayName(), file.file, isSelf, item.getTimestamp(), chatMessage);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ChatLogItem::ContentType::systemMessage: {
|
||||||
|
const auto& systemMessage = item.getContentAsSystemMessage();
|
||||||
|
|
||||||
|
auto chatMessageType = getChatMessageType(systemMessage);
|
||||||
|
chatMessage = ChatMessage::createChatInfoMessage(systemMessage.toString(), chatMessageType,
|
||||||
|
QDateTime::currentDateTime());
|
||||||
|
// Ignore caller's decision to hide the name. We show the icon in the
|
||||||
|
// slot of the sender's name so we always want it visible
|
||||||
|
hideName = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hideName) {
|
if (hideName) {
|
||||||
|
|
|
@ -76,8 +76,8 @@ public:
|
||||||
void setName(const QString& newName);
|
void setName(const QString& newName);
|
||||||
virtual void show(ContentLayout* contentLayout);
|
virtual void show(ContentLayout* contentLayout);
|
||||||
|
|
||||||
void addSystemInfoMessage(const QString& message, ChatMessage::SystemMessageType type,
|
void addSystemInfoMessage(const QDateTime& datetime, SystemMessageType messageType,
|
||||||
const QDateTime& datetime);
|
SystemMessage::Args messageArgs);
|
||||||
static QString resolveToxPk(const ToxPk& pk);
|
static QString resolveToxPk(const ToxPk& pk);
|
||||||
QDateTime getLatestTime() const;
|
QDateTime getLatestTime() const;
|
||||||
|
|
||||||
|
|
|
@ -148,9 +148,8 @@ void GroupChatForm::onTitleChanged(const QString& author, const QString& title)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString message = tr("%1 has set the title to %2").arg(author, title);
|
|
||||||
const QDateTime curTime = QDateTime::currentDateTime();
|
const QDateTime curTime = QDateTime::currentDateTime();
|
||||||
addSystemInfoMessage(message, ChatMessage::INFO, curTime);
|
addSystemInfoMessage(curTime, SystemMessageType::titleChanged, {author, title});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onScreenshotClicked()
|
void GroupChatForm::onScreenshotClicked()
|
||||||
|
@ -232,19 +231,20 @@ void GroupChatForm::updateUserNames()
|
||||||
|
|
||||||
void GroupChatForm::onUserJoined(const ToxPk& user, const QString& name)
|
void GroupChatForm::onUserJoined(const ToxPk& user, const QString& name)
|
||||||
{
|
{
|
||||||
addSystemInfoMessage(tr("%1 has joined the group").arg(name), ChatMessage::INFO, QDateTime::currentDateTime());
|
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::userJoinedGroup, {name});
|
||||||
updateUserNames();
|
updateUserNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onUserLeft(const ToxPk& user, const QString& name)
|
void GroupChatForm::onUserLeft(const ToxPk& user, const QString& name)
|
||||||
{
|
{
|
||||||
addSystemInfoMessage(tr("%1 has left the group").arg(name), ChatMessage::INFO, QDateTime::currentDateTime());
|
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::userLeftGroup, {name});
|
||||||
updateUserNames();
|
updateUserNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onPeerNameChanged(const ToxPk& peer, const QString& oldName, const QString& newName)
|
void GroupChatForm::onPeerNameChanged(const ToxPk& peer, const QString& oldName, const QString& newName)
|
||||||
{
|
{
|
||||||
addSystemInfoMessage(tr("%1 is now known as %2").arg(oldName, newName), ChatMessage::INFO, QDateTime::currentDateTime());
|
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::peerNameChanged,
|
||||||
|
{oldName, newName});
|
||||||
updateUserNames();
|
updateUserNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1130,8 +1130,8 @@ void Widget::dispatchFileSendFailed(uint32_t friendId, const QString& fileName)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chatForm.value()->addSystemInfoMessage(tr("Failed to send file \"%1\"").arg(fileName),
|
chatForm.value()->addSystemInfoMessage(QDateTime::currentDateTime(),
|
||||||
ChatMessage::ERROR, QDateTime::currentDateTime());
|
SystemMessageType::fileSendFailed, {fileName});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onRejectCall(uint32_t friendId)
|
void Widget::onRejectCall(uint32_t friendId)
|
||||||
|
@ -2342,10 +2342,9 @@ void Widget::onGroupSendFailed(uint32_t groupnumber)
|
||||||
const auto& groupId = GroupList::id2Key(groupnumber);
|
const auto& groupId = GroupList::id2Key(groupnumber);
|
||||||
assert(GroupList::findGroup(groupId));
|
assert(GroupList::findGroup(groupId));
|
||||||
|
|
||||||
const auto message = tr("Message failed to send");
|
|
||||||
const auto curTime = QDateTime::currentDateTime();
|
const auto curTime = QDateTime::currentDateTime();
|
||||||
auto form = groupChatForms[groupId].data();
|
auto form = groupChatForms[groupId].data();
|
||||||
form->addSystemInfoMessage(message, ChatMessage::INFO, curTime);
|
form->addSystemInfoMessage(curTime, SystemMessageType::messageSendFailed, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onFriendTypingChanged(uint32_t friendnumber, bool isTyping)
|
void Widget::onFriendTypingChanged(uint32_t friendnumber, bool isTyping)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user