forked from blue/squawk
now it's possible to fix your messages
This commit is contained in:
parent
bf4a27f35d
commit
788c6ca556
@ -4,6 +4,7 @@
|
|||||||
### Bug fixes
|
### Bug fixes
|
||||||
- build in release mode now no longer spams warnings
|
- build in release mode now no longer spams warnings
|
||||||
- build now correctly installs all build plugin libs
|
- build now correctly installs all build plugin libs
|
||||||
|
- a bug where the correction message was received, the indication was on but the text didn't actually change
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- reduced amount of places where platform specific path separator is used
|
- reduced amount of places where platform specific path separator is used
|
||||||
@ -13,6 +14,7 @@
|
|||||||
- now it's possible to set up different qt styles from settings
|
- now it's possible to set up different qt styles from settings
|
||||||
- if you have KConfig nad KConfigWidgets packages installed - you can chose from global color schemes
|
- if you have KConfig nad KConfigWidgets packages installed - you can chose from global color schemes
|
||||||
- it's possible now to chose a folder where squawk is going to store downloaded files
|
- it's possible now to chose a folder where squawk is going to store downloaded files
|
||||||
|
- now you can correct your message
|
||||||
|
|
||||||
## Squawk 0.2.0 (Jan 10, 2022)
|
## Squawk 0.2.0 (Jan 10, 2022)
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
@ -935,3 +935,7 @@ void Core::Account::requestChangeMessage(const QString& jid, const QString& mess
|
|||||||
|
|
||||||
void Core::Account::resendMessage(const QString& jid, const QString& id) {
|
void Core::Account::resendMessage(const QString& jid, const QString& id) {
|
||||||
mh->resendMessage(jid, id);}
|
mh->resendMessage(jid, id);}
|
||||||
|
|
||||||
|
void Core::Account::replaceMessage(const QString& originalId, const Shared::Message& data) {
|
||||||
|
mh->sendMessage(data, false, originalId);}
|
||||||
|
|
||||||
|
@ -104,6 +104,7 @@ public:
|
|||||||
void addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin);
|
void addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin);
|
||||||
void uploadVCard(const Shared::VCard& card);
|
void uploadVCard(const Shared::VCard& card);
|
||||||
void resendMessage(const QString& jid, const QString& id);
|
void resendMessage(const QString& jid, const QString& id);
|
||||||
|
void replaceMessage(const QString& originalId, const Shared::Message& data);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void connect();
|
void connect();
|
||||||
|
@ -41,10 +41,10 @@ void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg)
|
|||||||
handled = handleGroupMessage(msg);
|
handled = handleGroupMessage(msg);
|
||||||
break;
|
break;
|
||||||
case QXmppMessage::Error: {
|
case QXmppMessage::Error: {
|
||||||
QString id = msg.id();
|
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(msg.id());
|
||||||
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
|
if (std::get<0>(ids)) {
|
||||||
if (itr != pendingStateMessages.end()) {
|
QString id = std::get<1>(ids);
|
||||||
QString jid = itr->second;
|
QString jid = std::get<2>(ids);
|
||||||
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
||||||
QMap<QString, QVariant> cData = {
|
QMap<QString, QVariant> cData = {
|
||||||
{"state", static_cast<uint>(Shared::Message::State::error)},
|
{"state", static_cast<uint>(Shared::Message::State::error)},
|
||||||
@ -53,9 +53,7 @@ void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg)
|
|||||||
if (cnt != 0) {
|
if (cnt != 0) {
|
||||||
cnt->changeMessage(id, cData);
|
cnt->changeMessage(id, cData);
|
||||||
}
|
}
|
||||||
;
|
|
||||||
emit acc->changeMessage(jid, id, cData);
|
emit acc->changeMessage(jid, id, cData);
|
||||||
pendingStateMessages.erase(itr);
|
|
||||||
handled = true;
|
handled = true;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "received a message with type \"Error\", not sure what to do with it now, skipping";
|
qDebug() << "received a message with type \"Error\", not sure what to do with it now, skipping";
|
||||||
@ -111,7 +109,6 @@ bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outg
|
|||||||
{
|
{
|
||||||
const QString& body(msg.body());
|
const QString& body(msg.body());
|
||||||
if (body.size() != 0) {
|
if (body.size() != 0) {
|
||||||
QString id = msg.id();
|
|
||||||
|
|
||||||
Shared::Message sMsg(Shared::Message::groupChat);
|
Shared::Message sMsg(Shared::Message::groupChat);
|
||||||
initializeMessage(sMsg, msg, outgoing, forwarded, guessing);
|
initializeMessage(sMsg, msg, outgoing, forwarded, guessing);
|
||||||
@ -121,12 +118,11 @@ bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outg
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, QString>::const_iterator pItr = pendingStateMessages.find(id);
|
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(msg.id());
|
||||||
if (pItr != pendingStateMessages.end()) {
|
if (std::get<0>(ids)) {
|
||||||
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
||||||
cnt->changeMessage(id, cData);
|
cnt->changeMessage(std::get<1>(ids), cData);
|
||||||
pendingStateMessages.erase(pItr);
|
emit acc->changeMessage(std::get<2>(ids), std::get<1>(ids), cData);
|
||||||
emit acc->changeMessage(jid, id, cData);
|
|
||||||
} else {
|
} else {
|
||||||
QString oId = msg.replaceId();
|
QString oId = msg.replaceId();
|
||||||
if (oId.size() > 0) {
|
if (oId.size() > 0) {
|
||||||
@ -227,53 +223,70 @@ void Core::MessageHandler::onCarbonMessageSent(const QXmppMessage& msg)
|
|||||||
handleChatMessage(msg, true, true);
|
handleChatMessage(msg, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString& id)
|
std::tuple<bool, QString, QString> Core::MessageHandler::getOriginalPendingMessageId(const QString& id)
|
||||||
{
|
{
|
||||||
|
std::tuple<bool, QString, QString> result({false, "", ""});
|
||||||
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
|
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
|
||||||
if (itr != pendingStateMessages.end()) {
|
if (itr != pendingStateMessages.end()) {
|
||||||
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
std::get<0>(result) = true;
|
||||||
RosterItem* ri = acc->rh->getRosterItem(itr->second);
|
std::get<2>(result) = itr->second;
|
||||||
if (ri != 0) {
|
|
||||||
ri->changeMessage(id, cData);
|
std::map<QString, QString>::const_iterator itrC = pendingCorrectionMessages.find(id);
|
||||||
|
if (itrC != pendingCorrectionMessages.end()) {
|
||||||
|
std::get<1>(result) = itrC->second;
|
||||||
|
pendingCorrectionMessages.erase(itrC);
|
||||||
|
} else {
|
||||||
|
std::get<1>(result) = itr->first;
|
||||||
}
|
}
|
||||||
emit acc->changeMessage(itr->second, id, cData);
|
|
||||||
pendingStateMessages.erase(itr);
|
pendingStateMessages.erase(itr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::sendMessage(const Shared::Message& data, bool newMessage)
|
void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString& id)
|
||||||
|
{
|
||||||
|
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(id);
|
||||||
|
if (std::get<0>(ids)) {
|
||||||
|
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
||||||
|
RosterItem* ri = acc->rh->getRosterItem(std::get<2>(ids));
|
||||||
|
|
||||||
|
if (ri != 0) {
|
||||||
|
ri->changeMessage(std::get<1>(ids), cData);
|
||||||
|
}
|
||||||
|
emit acc->changeMessage(std::get<2>(ids), std::get<1>(ids), cData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::MessageHandler::sendMessage(const Shared::Message& data, bool newMessage, QString originalId)
|
||||||
{
|
{
|
||||||
if (data.getOutOfBandUrl().size() == 0 && data.getAttachPath().size() > 0) {
|
if (data.getOutOfBandUrl().size() == 0 && data.getAttachPath().size() > 0) {
|
||||||
|
pendingCorrectionMessages.insert(std::make_pair(data.getId(), originalId));
|
||||||
prepareUpload(data, newMessage);
|
prepareUpload(data, newMessage);
|
||||||
} else {
|
} else {
|
||||||
performSending(data, newMessage);
|
performSending(data, originalId, newMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::performSending(Shared::Message data, bool newMessage)
|
void Core::MessageHandler::performSending(Shared::Message data, const QString& originalId, bool newMessage)
|
||||||
{
|
{
|
||||||
QString jid = data.getPenPalJid();
|
QString jid = data.getPenPalJid();
|
||||||
QString id = data.getId();
|
QString id = data.getId();
|
||||||
QString oob = data.getOutOfBandUrl();
|
qDebug() << "Sending message with id:" << id;
|
||||||
|
if (originalId.size() > 0) {
|
||||||
|
qDebug() << "To replace one with id:" << originalId;
|
||||||
|
}
|
||||||
RosterItem* ri = acc->rh->getRosterItem(jid);
|
RosterItem* ri = acc->rh->getRosterItem(jid);
|
||||||
bool sent = false;
|
bool sent = false;
|
||||||
QMap<QString, QVariant> changes;
|
if (newMessage && originalId.size() > 0) {
|
||||||
|
newMessage = false;
|
||||||
|
}
|
||||||
QDateTime sendTime = QDateTime::currentDateTimeUtc();
|
QDateTime sendTime = QDateTime::currentDateTimeUtc();
|
||||||
if (acc->state == Shared::ConnectionState::connected) {
|
if (acc->state == Shared::ConnectionState::connected) {
|
||||||
QXmppMessage msg(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread());
|
QXmppMessage msg(createPacket(data, sendTime, originalId));
|
||||||
|
|
||||||
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
|
||||||
msg.setOriginId(id);
|
|
||||||
#endif
|
|
||||||
msg.setId(id);
|
|
||||||
msg.setType(static_cast<QXmppMessage::Type>(data.getType())); //it is safe here, my type is compatible
|
|
||||||
msg.setOutOfBandUrl(oob);
|
|
||||||
msg.setReceiptRequested(true);
|
|
||||||
msg.setStamp(sendTime);
|
|
||||||
|
|
||||||
sent = acc->client.sendPacket(msg);
|
sent = acc->client.sendPacket(msg);
|
||||||
//sent = false;
|
|
||||||
|
|
||||||
if (sent) {
|
if (sent) {
|
||||||
data.setState(Shared::Message::State::sent);
|
data.setState(Shared::Message::State::sent);
|
||||||
} else {
|
} else {
|
||||||
@ -286,6 +299,39 @@ void Core::MessageHandler::performSending(Shared::Message data, bool newMessage)
|
|||||||
data.setErrorText("You are is offline or reconnecting");
|
data.setErrorText("You are is offline or reconnecting");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> changes(getChanges(data, sendTime, newMessage, originalId));
|
||||||
|
|
||||||
|
QString realId;
|
||||||
|
if (originalId.size() > 0) {
|
||||||
|
realId = originalId;
|
||||||
|
} else {
|
||||||
|
realId = id;
|
||||||
|
}
|
||||||
|
if (ri != 0) {
|
||||||
|
if (newMessage) {
|
||||||
|
ri->appendMessageToArchive(data);
|
||||||
|
} else {
|
||||||
|
ri->changeMessage(realId, changes);
|
||||||
|
}
|
||||||
|
if (sent) {
|
||||||
|
pendingStateMessages.insert(std::make_pair(id, jid));
|
||||||
|
if (originalId.size() > 0) {
|
||||||
|
pendingCorrectionMessages.insert(std::make_pair(id, originalId));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pendingStateMessages.erase(id);
|
||||||
|
pendingCorrectionMessages.erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit acc->changeMessage(jid, realId, changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> Core::MessageHandler::getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const
|
||||||
|
{
|
||||||
|
QMap<QString, QVariant> changes;
|
||||||
|
|
||||||
|
QString oob = data.getOutOfBandUrl();
|
||||||
Shared::Message::State mstate = data.getState();
|
Shared::Message::State mstate = data.getState();
|
||||||
changes.insert("state", static_cast<uint>(mstate));
|
changes.insert("state", static_cast<uint>(mstate));
|
||||||
if (mstate == Shared::Message::State::error) {
|
if (mstate == Shared::Message::State::error) {
|
||||||
@ -295,9 +341,12 @@ void Core::MessageHandler::performSending(Shared::Message data, bool newMessage)
|
|||||||
changes.insert("outOfBandUrl", oob);
|
changes.insert("outOfBandUrl", oob);
|
||||||
}
|
}
|
||||||
if (newMessage) {
|
if (newMessage) {
|
||||||
data.setTime(sendTime);
|
data.setTime(time);
|
||||||
}
|
}
|
||||||
changes.insert("stamp", sendTime);
|
if (originalId.size() > 0) {
|
||||||
|
changes.insert("body", data.getBody());
|
||||||
|
}
|
||||||
|
changes.insert("stamp", time);
|
||||||
|
|
||||||
//sometimes (when the image is pasted with ctrl+v)
|
//sometimes (when the image is pasted with ctrl+v)
|
||||||
//I start sending message with one path, then copy it to downloads directory
|
//I start sending message with one path, then copy it to downloads directory
|
||||||
@ -311,20 +360,28 @@ void Core::MessageHandler::performSending(Shared::Message data, bool newMessage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ri != 0) {
|
return changes;
|
||||||
if (newMessage) {
|
|
||||||
ri->appendMessageToArchive(data);
|
|
||||||
} else {
|
|
||||||
ri->changeMessage(id, changes);
|
|
||||||
}
|
|
||||||
if (sent) {
|
|
||||||
pendingStateMessages.insert(std::make_pair(id, jid));
|
|
||||||
} else {
|
|
||||||
pendingStateMessages.erase(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit acc->changeMessage(jid, id, changes);
|
QXmppMessage Core::MessageHandler::createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const
|
||||||
|
{
|
||||||
|
QXmppMessage msg(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread());
|
||||||
|
QString id(data.getId());
|
||||||
|
|
||||||
|
if (originalId.size() > 0) {
|
||||||
|
msg.setReplaceId(originalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
||||||
|
msg.setOriginId(id);
|
||||||
|
#endif
|
||||||
|
msg.setId(id);
|
||||||
|
msg.setType(static_cast<QXmppMessage::Type>(data.getType())); //it is safe here, my type is compatible
|
||||||
|
msg.setOutOfBandUrl(data.getOutOfBandUrl());
|
||||||
|
msg.setReceiptRequested(true);
|
||||||
|
msg.setStamp(time);
|
||||||
|
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::prepareUpload(const Shared::Message& data, bool newMessage)
|
void Core::MessageHandler::prepareUpload(const Shared::Message& data, bool newMessage)
|
||||||
@ -444,7 +501,8 @@ void Core::MessageHandler::onLoadFileError(const std::list<Shared::MessageInfo>&
|
|||||||
void Core::MessageHandler::handleUploadError(const QString& jid, const QString& messageId, const QString& errorText)
|
void Core::MessageHandler::handleUploadError(const QString& jid, const QString& messageId, const QString& errorText)
|
||||||
{
|
{
|
||||||
emit acc->uploadFileError(jid, messageId, "Error requesting slot to upload file: " + errorText);
|
emit acc->uploadFileError(jid, messageId, "Error requesting slot to upload file: " + errorText);
|
||||||
pendingStateMessages.erase(jid);
|
pendingStateMessages.erase(messageId);
|
||||||
|
pendingCorrectionMessages.erase(messageId);
|
||||||
requestChangeMessage(jid, messageId, {
|
requestChangeMessage(jid, messageId, {
|
||||||
{"state", static_cast<uint>(Shared::Message::State::error)},
|
{"state", static_cast<uint>(Shared::Message::State::error)},
|
||||||
{"errorText", errorText}
|
{"errorText", errorText}
|
||||||
@ -473,11 +531,11 @@ void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg,
|
|||||||
if (msg.getBody().size() == 0) { //not sure why, but most messages do that
|
if (msg.getBody().size() == 0) { //not sure why, but most messages do that
|
||||||
msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that
|
msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that
|
||||||
}
|
}
|
||||||
performSending(msg, newMessage);
|
performSending(msg, pendingCorrectionMessages.at(msg.getId()), newMessage);
|
||||||
//TODO removal/progress update
|
//TODO removal/progress update
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::set<QString> allowerToChangeKeys({
|
static const std::set<QString> allowedToChangeKeys({
|
||||||
"attachPath",
|
"attachPath",
|
||||||
"outOfBandUrl",
|
"outOfBandUrl",
|
||||||
"state",
|
"state",
|
||||||
@ -491,11 +549,11 @@ void Core::MessageHandler::requestChangeMessage(const QString& jid, const QStrin
|
|||||||
bool allSupported = true;
|
bool allSupported = true;
|
||||||
QString unsupportedString;
|
QString unsupportedString;
|
||||||
for (QMap<QString, QVariant>::const_iterator itr = data.begin(); itr != data.end(); ++itr) { //I need all this madness
|
for (QMap<QString, QVariant>::const_iterator itr = data.begin(); itr != data.end(); ++itr) { //I need all this madness
|
||||||
if (allowerToChangeKeys.count(itr.key()) != 1) { //to not allow this method
|
if (allowedToChangeKeys.count(itr.key()) != 1) { //to not allow this method
|
||||||
allSupported = false; //to make a message to look like if it was edited
|
allSupported = false; //to make a message to look like if it was edited
|
||||||
unsupportedString = itr.key(); //basically I needed to control who exaclty calls this method
|
unsupportedString = itr.key(); //basically I needed to control who exaclty calls this method
|
||||||
break; //because the underlying tech assumes that the change is initiated by user
|
break; //because the underlying tech assumes that
|
||||||
} //not by system
|
} //the change is initiated by user, not by system
|
||||||
}
|
}
|
||||||
if (allSupported) {
|
if (allSupported) {
|
||||||
cnt->changeMessage(messageId, data);
|
cnt->changeMessage(messageId, data);
|
||||||
@ -514,7 +572,13 @@ void Core::MessageHandler::resendMessage(const QString& jid, const QString& id)
|
|||||||
try {
|
try {
|
||||||
Shared::Message msg = cnt->getMessage(id);
|
Shared::Message msg = cnt->getMessage(id);
|
||||||
if (msg.getState() == Shared::Message::State::error) {
|
if (msg.getState() == Shared::Message::State::error) {
|
||||||
|
if (msg.getEdited()){
|
||||||
|
QString originalId = msg.getId();
|
||||||
|
msg.generateRandomId();
|
||||||
|
sendMessage(msg, false, originalId);
|
||||||
|
} else {
|
||||||
sendMessage(msg, false);
|
sendMessage(msg, false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message seems to have been normally sent, this method was made to retry sending failed to be sent messages, skipping";
|
qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message seems to have been normally sent, this method was made to retry sending failed to be sent messages, skipping";
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public:
|
|||||||
MessageHandler(Account* account);
|
MessageHandler(Account* account);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void sendMessage(const Shared::Message& data, bool newMessage = true);
|
void sendMessage(const Shared::Message& data, bool newMessage = true, QString originalId = "");
|
||||||
void initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing = false, bool forwarded = false, bool guessing = false) const;
|
void initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing = false, bool forwarded = false, bool guessing = false) const;
|
||||||
void resendMessage(const QString& jid, const QString& id);
|
void resendMessage(const QString& jid, const QString& id);
|
||||||
|
|
||||||
@ -67,13 +67,17 @@ private:
|
|||||||
bool handleGroupMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false);
|
bool handleGroupMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false);
|
||||||
void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: ");
|
void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: ");
|
||||||
void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage = true);
|
void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage = true);
|
||||||
void performSending(Shared::Message data, bool newMessage = true);
|
void performSending(Shared::Message data, const QString& originalId, bool newMessage = true);
|
||||||
void prepareUpload(const Shared::Message& data, bool newMessage = true);
|
void prepareUpload(const Shared::Message& data, bool newMessage = true);
|
||||||
void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText);
|
void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText);
|
||||||
|
QXmppMessage createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const;
|
||||||
|
QMap<QString, QVariant> getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const;
|
||||||
|
std::tuple<bool, QString, QString> getOriginalPendingMessageId(const QString& id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Account* acc;
|
Account* acc;
|
||||||
std::map<QString, QString> pendingStateMessages; //key is message id, value is JID
|
std::map<QString, QString> pendingStateMessages; //key is message id, value is JID
|
||||||
|
std::map<QString, QString> pendingCorrectionMessages; //key is new mesage, value is originalOne
|
||||||
std::deque<std::pair<QString, QString>> uploadingSlotsQueue;
|
std::deque<std::pair<QString, QString>> uploadingSlotsQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -142,6 +142,7 @@ int main(int argc, char *argv[])
|
|||||||
QObject::connect(&w, &Squawk::disconnectAccount, squawk, &Core::Squawk::disconnectAccount);
|
QObject::connect(&w, &Squawk::disconnectAccount, squawk, &Core::Squawk::disconnectAccount);
|
||||||
QObject::connect(&w, &Squawk::changeState, squawk, &Core::Squawk::changeState);
|
QObject::connect(&w, &Squawk::changeState, squawk, &Core::Squawk::changeState);
|
||||||
QObject::connect(&w, &Squawk::sendMessage, squawk,&Core::Squawk::sendMessage);
|
QObject::connect(&w, &Squawk::sendMessage, squawk,&Core::Squawk::sendMessage);
|
||||||
|
QObject::connect(&w, &Squawk::replaceMessage, squawk,&Core::Squawk::replaceMessage);
|
||||||
QObject::connect(&w, &Squawk::resendMessage, squawk,&Core::Squawk::resendMessage);
|
QObject::connect(&w, &Squawk::resendMessage, squawk,&Core::Squawk::resendMessage);
|
||||||
QObject::connect(&w, &Squawk::requestArchive, squawk, &Core::Squawk::requestArchive);
|
QObject::connect(&w, &Squawk::requestArchive, squawk, &Core::Squawk::requestArchive);
|
||||||
QObject::connect(&w, &Squawk::subscribeContact, squawk, &Core::Squawk::subscribeContact);
|
QObject::connect(&w, &Squawk::subscribeContact, squawk, &Core::Squawk::subscribeContact);
|
||||||
|
@ -341,6 +341,17 @@ void Core::Squawk::sendMessage(const QString& account, const Shared::Message& da
|
|||||||
itr->second->sendMessage(data);
|
itr->second->sendMessage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Squawk::replaceMessage(const QString& account, const QString& originalId, const Shared::Message& data)
|
||||||
|
{
|
||||||
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
|
if (itr == amap.end()) {
|
||||||
|
qDebug() << "An attempt to replace a message with non existing account" << account << ", skipping";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
itr->second->replaceMessage(originalId, data);
|
||||||
|
}
|
||||||
|
|
||||||
void Core::Squawk::resendMessage(const QString& account, const QString& jid, const QString& id)
|
void Core::Squawk::resendMessage(const QString& account, const QString& jid, const QString& id)
|
||||||
{
|
{
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
|
@ -101,6 +101,7 @@ public slots:
|
|||||||
void changeState(Shared::Availability state);
|
void changeState(Shared::Availability state);
|
||||||
|
|
||||||
void sendMessage(const QString& account, const Shared::Message& data);
|
void sendMessage(const QString& account, const Shared::Message& data);
|
||||||
|
void replaceMessage(const QString& account, const QString& originalId, const Shared::Message& data);
|
||||||
void resendMessage(const QString& account, const QString& jid, const QString& id);
|
void resendMessage(const QString& account, const QString& jid, const QString& id);
|
||||||
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
||||||
|
|
||||||
|
@ -404,7 +404,9 @@ bool Shared::Message::change(const QMap<QString, QVariant>& data)
|
|||||||
correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied
|
correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied
|
||||||
}
|
}
|
||||||
if (!edited || lastModified < correctionDate) {
|
if (!edited || lastModified < correctionDate) {
|
||||||
|
if (!edited) {
|
||||||
originalMessage = body;
|
originalMessage = body;
|
||||||
|
}
|
||||||
lastModified = correctionDate;
|
lastModified = correctionDate;
|
||||||
setBody(b);
|
setBody(b);
|
||||||
setEdited(true);
|
setEdited(true);
|
||||||
|
@ -497,6 +497,17 @@ void Squawk::onConversationMessage(const Shared::Message& msg)
|
|||||||
emit sendMessage(acc, msg);
|
emit sendMessage(acc, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Squawk::onConversationReplaceMessage(const QString& originalId, const Shared::Message& msg)
|
||||||
|
{
|
||||||
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
|
QString acc = conv->getAccount();
|
||||||
|
|
||||||
|
rosterModel.changeMessage(acc, msg.getPenPalJid(), originalId, {
|
||||||
|
{"state", static_cast<uint>(Shared::Message::State::pending)}
|
||||||
|
});
|
||||||
|
emit replaceMessage(acc, originalId, msg);
|
||||||
|
}
|
||||||
|
|
||||||
void Squawk::onConversationResend(const QString& id)
|
void Squawk::onConversationResend(const QString& id)
|
||||||
{
|
{
|
||||||
Conversation* conv = static_cast<Conversation*>(sender());
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
@ -958,6 +969,7 @@ void Squawk::subscribeConversation(Conversation* conv)
|
|||||||
{
|
{
|
||||||
connect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
connect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
||||||
connect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage);
|
connect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage);
|
||||||
|
connect(conv, &Conversation::replaceMessage, this, &Squawk::onConversationReplaceMessage);
|
||||||
connect(conv, &Conversation::resendMessage, this, &Squawk::onConversationResend);
|
connect(conv, &Conversation::resendMessage, this, &Squawk::onConversationResend);
|
||||||
connect(conv, &Conversation::notifyableMessage, this, &Squawk::notify);
|
connect(conv, &Conversation::notifyableMessage, this, &Squawk::notify);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ signals:
|
|||||||
void disconnectAccount(const QString&);
|
void disconnectAccount(const QString&);
|
||||||
void changeState(Shared::Availability state);
|
void changeState(Shared::Availability state);
|
||||||
void sendMessage(const QString& account, const Shared::Message& data);
|
void sendMessage(const QString& account, const Shared::Message& data);
|
||||||
|
void replaceMessage(const QString& account, const QString& originalId, const Shared::Message& data);
|
||||||
void resendMessage(const QString& account, const QString& jid, const QString& id);
|
void resendMessage(const QString& account, const QString& jid, const QString& id);
|
||||||
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
||||||
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||||
@ -153,6 +154,7 @@ private slots:
|
|||||||
void onComboboxActivated(int index);
|
void onComboboxActivated(int index);
|
||||||
void onRosterItemDoubleClicked(const QModelIndex& item);
|
void onRosterItemDoubleClicked(const QModelIndex& item);
|
||||||
void onConversationMessage(const Shared::Message& msg);
|
void onConversationMessage(const Shared::Message& msg);
|
||||||
|
void onConversationReplaceMessage(const QString& originalId, const Shared::Message& msg);
|
||||||
void onConversationResend(const QString& id);
|
void onConversationResend(const QString& id);
|
||||||
void onRequestArchive(const QString& account, const QString& jid, const QString& before);
|
void onRequestArchive(const QString& account, const QString& jid, const QString& before);
|
||||||
void onRosterContextMenu(const QPoint& point);
|
void onRosterContextMenu(const QPoint& point);
|
||||||
|
@ -58,7 +58,8 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
|||||||
pasteImageAction(new QAction(tr("Paste Image"), this)),
|
pasteImageAction(new QAction(tr("Paste Image"), this)),
|
||||||
shadow(10, 1, Qt::black, this),
|
shadow(10, 1, Qt::black, this),
|
||||||
contextMenu(new QMenu()),
|
contextMenu(new QMenu()),
|
||||||
currentAction(CurrentAction::none)
|
currentAction(CurrentAction::none),
|
||||||
|
currentMessageId()
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
@ -84,11 +85,11 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
|||||||
statusIcon = m_ui->statusIcon;
|
statusIcon = m_ui->statusIcon;
|
||||||
statusLabel = m_ui->statusLabel;
|
statusLabel = m_ui->statusLabel;
|
||||||
|
|
||||||
connect(&ker, &KeyEnterReceiver::enterPressed, this, &Conversation::onEnterPressed);
|
connect(&ker, &KeyEnterReceiver::enterPressed, this, qOverload<>(&Conversation::initiateMessageSending));
|
||||||
connect(&ker, &KeyEnterReceiver::imagePasted, this, &Conversation::onImagePasted);
|
connect(&ker, &KeyEnterReceiver::imagePasted, this, &Conversation::onImagePasted);
|
||||||
connect(m_ui->sendButton, &QPushButton::clicked, this, &Conversation::onEnterPressed);
|
connect(m_ui->sendButton, &QPushButton::clicked, this, qOverload<>(&Conversation::initiateMessageSending));
|
||||||
connect(m_ui->attachButton, &QPushButton::clicked, this, &Conversation::onAttach);
|
connect(m_ui->attachButton, &QPushButton::clicked, this, &Conversation::onAttach);
|
||||||
connect(m_ui->clearButton, &QPushButton::clicked, this, &Conversation::onClearButton);
|
connect(m_ui->clearButton, &QPushButton::clicked, this, &Conversation::clear);
|
||||||
connect(m_ui->messageEditor->document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
|
connect(m_ui->messageEditor->document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
|
||||||
this, &Conversation::onTextEditDocSizeChanged);
|
this, &Conversation::onTextEditDocSizeChanged);
|
||||||
|
|
||||||
@ -98,6 +99,9 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
|||||||
connect(m_ui->messageEditor, &QTextEdit::customContextMenuRequested, this, &Conversation::onMessageEditorContext);
|
connect(m_ui->messageEditor, &QTextEdit::customContextMenuRequested, this, &Conversation::onMessageEditorContext);
|
||||||
connect(pasteImageAction, &QAction::triggered, this, &Conversation::onImagePasted);
|
connect(pasteImageAction, &QAction::triggered, this, &Conversation::onImagePasted);
|
||||||
|
|
||||||
|
connect(m_ui->currentActionBadge, &Badge::close, this, &Conversation::clear);
|
||||||
|
m_ui->currentActionBadge->setVisible(false);
|
||||||
|
|
||||||
//line->setAutoFillBackground(false);
|
//line->setAutoFillBackground(false);
|
||||||
//if (testAttribute(Qt::WA_TranslucentBackground)) {
|
//if (testAttribute(Qt::WA_TranslucentBackground)) {
|
||||||
//m_ui->scrollArea->setAutoFillBackground(false);
|
//m_ui->scrollArea->setAutoFillBackground(false);
|
||||||
@ -109,9 +113,6 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
|||||||
//line->setMyName(acc->getName());
|
//line->setMyName(acc->getName());
|
||||||
|
|
||||||
initializeOverlay();
|
initializeOverlay();
|
||||||
|
|
||||||
m_ui->currentActionBadge->setVisible(false);
|
|
||||||
// m_ui->currentActionBadge->setText(tr("Editing message..."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Conversation::~Conversation()
|
Conversation::~Conversation()
|
||||||
@ -224,24 +225,33 @@ void Conversation::setPalResource(const QString& res)
|
|||||||
activePalResource = res;
|
activePalResource = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Conversation::onEnterPressed()
|
void Conversation::initiateMessageSending()
|
||||||
{
|
{
|
||||||
QString body(m_ui->messageEditor->toPlainText());
|
QString body(m_ui->messageEditor->toPlainText());
|
||||||
|
|
||||||
if (body.size() > 0) {
|
if (body.size() > 0) {
|
||||||
m_ui->messageEditor->clear();
|
|
||||||
Shared::Message msg = createMessage();
|
Shared::Message msg = createMessage();
|
||||||
msg.setBody(body);
|
msg.setBody(body);
|
||||||
emit sendMessage(msg);
|
initiateMessageSending(msg);
|
||||||
}
|
}
|
||||||
if (filesToAttach.size() > 0) {
|
if (filesToAttach.size() > 0) {
|
||||||
for (Badge* badge : filesToAttach) {
|
for (Badge* badge : filesToAttach) {
|
||||||
Shared::Message msg = createMessage();
|
Shared::Message msg = createMessage();
|
||||||
msg.setAttachPath(badge->id);
|
msg.setAttachPath(badge->id);
|
||||||
element->feed->registerUpload(msg.getId());
|
element->feed->registerUpload(msg.getId());
|
||||||
emit sendMessage(msg);
|
initiateMessageSending(msg);
|
||||||
}
|
}
|
||||||
clearAttachedFiles();
|
}
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Conversation::initiateMessageSending(const Shared::Message& msg)
|
||||||
|
{
|
||||||
|
if (currentAction == CurrentAction::edit) {
|
||||||
|
emit replaceMessage(currentMessageId, msg);
|
||||||
|
currentAction = CurrentAction::none;
|
||||||
|
} else {
|
||||||
|
emit sendMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,8 +358,11 @@ void Conversation::clearAttachedFiles()
|
|||||||
filesLayout->setContentsMargins(0, 0, 0, 0);
|
filesLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Conversation::onClearButton()
|
void Conversation::clear()
|
||||||
{
|
{
|
||||||
|
currentMessageId.clear();
|
||||||
|
currentAction = CurrentAction::none;
|
||||||
|
m_ui->currentActionBadge->setVisible(false);
|
||||||
clearAttachedFiles();
|
clearAttachedFiles();
|
||||||
m_ui->messageEditor->clear();
|
m_ui->messageEditor->clear();
|
||||||
}
|
}
|
||||||
@ -526,13 +539,12 @@ void Conversation::onMessageEditorContext(const QPoint& pos)
|
|||||||
|
|
||||||
void Conversation::onMessageEditRequested(const QString& id)
|
void Conversation::onMessageEditRequested(const QString& id)
|
||||||
{
|
{
|
||||||
if (currentAction == CurrentAction::edit) {
|
clear();
|
||||||
//todo;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Shared::Message msg = element->feed->getMessage(id);
|
Shared::Message msg = element->feed->getMessage(id);
|
||||||
|
|
||||||
|
currentMessageId = id;
|
||||||
m_ui->currentActionBadge->setVisible(true);
|
m_ui->currentActionBadge->setVisible(true);
|
||||||
m_ui->currentActionBadge->setText(tr("Editing message..."));
|
m_ui->currentActionBadge->setText(tr("Editing message..."));
|
||||||
currentAction = CurrentAction::edit;
|
currentAction = CurrentAction::edit;
|
||||||
|
@ -83,6 +83,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sendMessage(const Shared::Message& message);
|
void sendMessage(const Shared::Message& message);
|
||||||
|
void replaceMessage(const QString& originalId, const Shared::Message& message);
|
||||||
void resendMessage(const QString& id);
|
void resendMessage(const QString& id);
|
||||||
void requestArchive(const QString& before);
|
void requestArchive(const QString& before);
|
||||||
void shown();
|
void shown();
|
||||||
@ -104,12 +105,13 @@ protected:
|
|||||||
virtual void onMessage(const Shared::Message& msg);
|
virtual void onMessage(const Shared::Message& msg);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void onEnterPressed();
|
void initiateMessageSending();
|
||||||
|
void initiateMessageSending(const Shared::Message& msg);
|
||||||
void onImagePasted();
|
void onImagePasted();
|
||||||
void onAttach();
|
void onAttach();
|
||||||
void onFileSelected();
|
void onFileSelected();
|
||||||
void onBadgeClose();
|
void onBadgeClose();
|
||||||
void onClearButton();
|
void clear();
|
||||||
void onTextEditDocSizeChanged(const QSizeF& size);
|
void onTextEditDocSizeChanged(const QSizeF& size);
|
||||||
void onAccountChanged(Models::Item* item, int row, int col);
|
void onAccountChanged(Models::Item* item, int row, int col);
|
||||||
void onFeedMessage(const Shared::Message& msg);
|
void onFeedMessage(const Shared::Message& msg);
|
||||||
@ -149,6 +151,7 @@ protected:
|
|||||||
ShadowOverlay shadow;
|
ShadowOverlay shadow;
|
||||||
QMenu* contextMenu;
|
QMenu* contextMenu;
|
||||||
CurrentAction currentAction;
|
CurrentAction currentAction;
|
||||||
|
QString currentMessageId;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool painterInitialized;
|
static bool painterInitialized;
|
||||||
|
Loading…
Reference in New Issue
Block a user