2020-09-02 23:49:15 +03:00
|
|
|
/*
|
2020-10-19 20:34:47 +03:00
|
|
|
Copyright (C) 2020 Sebastian J. Wolf and other contributors
|
2020-09-02 23:49:15 +03:00
|
|
|
|
|
|
|
This file is part of Fernschreiber.
|
|
|
|
|
|
|
|
Fernschreiber is free 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.
|
|
|
|
|
|
|
|
Fernschreiber 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 Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2020-08-22 18:30:02 +03:00
|
|
|
#include "chatmodel.h"
|
|
|
|
|
2020-08-22 22:43:20 +03:00
|
|
|
#include <QListIterator>
|
2020-08-28 11:41:18 +03:00
|
|
|
#include <QByteArray>
|
|
|
|
#include <QBitArray>
|
2020-08-22 22:43:20 +03:00
|
|
|
|
2020-11-22 06:58:47 +03:00
|
|
|
#define DEBUG_MODULE ChatModel
|
|
|
|
#include "debuglog.h"
|
2020-11-15 06:38:43 +03:00
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
namespace {
|
|
|
|
const QString ID("id");
|
|
|
|
const QString CHAT_ID("chat_id");
|
|
|
|
const QString PHOTO("photo");
|
|
|
|
const QString SMALL("small");
|
2020-11-16 16:22:32 +03:00
|
|
|
const QString UNREAD_COUNT("unread_count");
|
2020-11-16 01:05:22 +03:00
|
|
|
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
|
2020-11-16 02:08:55 +03:00
|
|
|
const QString SENDER_USER_ID("sender_user_id");
|
2020-11-17 14:18:46 +03:00
|
|
|
const QString PINNED_MESSAGE_ID("pinned_message_id");
|
2020-11-15 07:11:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) :
|
|
|
|
chatId(0),
|
|
|
|
inReload(false),
|
|
|
|
inIncrementalUpdate(false)
|
2020-08-22 18:30:02 +03:00
|
|
|
{
|
|
|
|
this->tdLibWrapper = tdLibWrapper;
|
2020-10-19 13:20:02 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int)));
|
2020-08-23 00:49:02 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap)));
|
2020-08-31 22:51:52 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int)));
|
2020-08-30 20:04:16 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
|
2020-08-31 00:52:22 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, QVariantMap)));
|
2020-09-16 21:43:36 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SLOT(handleChatNotificationSettingsUpdated(QString, QVariantMap)));
|
2020-11-15 07:11:10 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SLOT(handleChatPhotoUpdated(qlonglong, QVariantMap)));
|
2020-11-17 14:18:46 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SLOT(handleChatPinnedMessageUpdated(qlonglong, qlonglong)));
|
2020-09-19 21:33:51 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)), this, SLOT(handleMessageContentUpdated(QString, QString, QVariantMap)));
|
2020-09-20 01:13:42 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(messagesDeleted(QString, QVariantList)), this, SLOT(handleMessagesDeleted(QString, QVariantList)));
|
2020-08-22 18:30:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ChatModel::~ChatModel()
|
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Destroying myself...");
|
2020-08-22 18:30:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int ChatModel::rowCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return messages.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant ChatModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
if(index.isValid() && role == Qt::DisplayRole) {
|
|
|
|
return QVariant(messages.value(index.row()));
|
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ChatModel::insertRows(int row, int count, const QModelIndex &parent)
|
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Inserting at" << row << ", row count:" << count);
|
2020-08-22 18:30:02 +03:00
|
|
|
beginInsertRows(parent, row, row + count - 1);
|
2020-08-22 22:43:20 +03:00
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
this->messages.insert(row + i, this->messagesToBeAdded.at(i));
|
|
|
|
}
|
2020-08-30 20:04:16 +03:00
|
|
|
this->calculateMessageIndexMap();
|
2020-08-22 18:30:02 +03:00
|
|
|
endInsertRows();
|
|
|
|
return true;
|
|
|
|
}
|
2020-08-22 22:43:20 +03:00
|
|
|
|
2020-11-20 22:39:23 +03:00
|
|
|
void ChatModel::clear()
|
|
|
|
{
|
|
|
|
LOG("Clearing chat model");
|
|
|
|
chatId = 0;
|
|
|
|
inReload = false;
|
|
|
|
inIncrementalUpdate = false;
|
|
|
|
if (!messages.isEmpty()) {
|
|
|
|
beginResetModel();
|
|
|
|
messages.clear();
|
|
|
|
endResetModel();
|
|
|
|
}
|
|
|
|
if (!chatInformation.isEmpty()) {
|
|
|
|
chatInformation.clear();
|
|
|
|
emit smallPhotoChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-29 22:39:57 +03:00
|
|
|
void ChatModel::initialize(const QVariantMap &chatInformation)
|
2020-08-22 22:43:20 +03:00
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Initializing chat model...");
|
2020-10-19 13:20:02 +03:00
|
|
|
beginResetModel();
|
2020-11-15 07:11:10 +03:00
|
|
|
this->chatInformation = chatInformation;
|
|
|
|
this->chatId = chatInformation.value(ID).toLongLong();
|
2020-08-22 22:43:20 +03:00
|
|
|
this->messages.clear();
|
|
|
|
this->messageIndexMap.clear();
|
|
|
|
this->messagesToBeAdded.clear();
|
2020-10-19 13:20:02 +03:00
|
|
|
endResetModel();
|
2020-11-15 07:11:10 +03:00
|
|
|
emit smallPhotoChanged();
|
2020-11-16 01:05:22 +03:00
|
|
|
tdLibWrapper->getChatHistory(chatId, this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong());
|
2020-08-22 22:43:20 +03:00
|
|
|
}
|
|
|
|
|
2020-08-26 23:52:06 +03:00
|
|
|
void ChatModel::triggerLoadMoreHistory()
|
|
|
|
{
|
2020-11-01 05:57:37 +03:00
|
|
|
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Trigger loading older history...");
|
2020-08-26 23:52:06 +03:00
|
|
|
this->inIncrementalUpdate = true;
|
2020-11-15 07:11:10 +03:00
|
|
|
this->tdLibWrapper->getChatHistory(chatId, messages.first().toMap().value(ID).toLongLong());
|
2020-08-26 23:52:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-16 01:05:22 +03:00
|
|
|
void ChatModel::triggerLoadMoreFuture()
|
|
|
|
{
|
|
|
|
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
|
|
|
|
LOG("Trigger loading newer future...");
|
|
|
|
this->inIncrementalUpdate = true;
|
|
|
|
this->tdLibWrapper->getChatHistory(chatId, messages.last().toMap().value(ID).toLongLong(), -49);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 21:43:36 +03:00
|
|
|
QVariantMap ChatModel::getChatInformation()
|
|
|
|
{
|
|
|
|
return this->chatInformation;
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
QVariantMap ChatModel::getMessage(int index)
|
2020-09-16 22:12:39 +03:00
|
|
|
{
|
|
|
|
if (index < this->messages.size()) {
|
|
|
|
return this->messages.at(index).toMap();
|
|
|
|
} else {
|
|
|
|
return QVariantMap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-16 01:05:22 +03:00
|
|
|
int ChatModel::getLastReadMessageIndex()
|
|
|
|
{
|
2020-11-16 16:22:32 +03:00
|
|
|
LOG("Obtaining last read message index");
|
2020-11-16 02:08:55 +03:00
|
|
|
if (this->messages.isEmpty()) {
|
2020-11-16 16:22:32 +03:00
|
|
|
LOG("Messages are empty, nothing to do...");
|
2020-11-16 02:08:55 +03:00
|
|
|
return 0;
|
2020-11-16 16:22:32 +03:00
|
|
|
} else if (this->messages.last().toMap().value(SENDER_USER_ID).toString() == tdLibWrapper->getUserInformation().value(ID).toString()) {
|
|
|
|
LOG("Last message is an own one, then simply set the last read to the last one...");
|
|
|
|
return this->messages.size() - 1;
|
2020-11-16 02:08:55 +03:00
|
|
|
} else {
|
2020-11-16 16:22:32 +03:00
|
|
|
int lastReadMessageIndex = this->messageIndexMap.value(this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toString()).toInt();
|
|
|
|
if (lastReadMessageIndex == 0) {
|
|
|
|
LOG("Last read message not found in the list of messages. That shouldn't happen, therefore setting the unread indicator to the end of the list.");
|
|
|
|
return this->messages.size() - 1;
|
|
|
|
} else {
|
|
|
|
LOG("Found last read message in the already loaded messages. Index: " << lastReadMessageIndex);
|
|
|
|
return lastReadMessageIndex;
|
|
|
|
}
|
2020-11-16 02:08:55 +03:00
|
|
|
}
|
2020-11-16 01:05:22 +03:00
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
QVariantMap ChatModel::smallPhoto() const
|
2020-08-22 22:43:20 +03:00
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
return chatInformation.value(PHOTO).toMap().value(SMALL).toMap();
|
2020-08-22 22:43:20 +03:00
|
|
|
}
|
|
|
|
|
2020-11-20 22:39:23 +03:00
|
|
|
qlonglong ChatModel::getChatId() const
|
|
|
|
{
|
|
|
|
return chatId;
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
static bool compareMessages(const QVariant &message1, const QVariant &message2)
|
|
|
|
{
|
|
|
|
const QVariantMap messageMap1 = message1.toMap();
|
|
|
|
const QVariantMap messageMap2 = message2.toMap();
|
|
|
|
return messageMap1.value(ID).toLongLong() < messageMap2.value(ID).toLongLong();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCount)
|
2020-08-22 22:43:20 +03:00
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Receiving new messages :)" << messages.size());
|
2020-08-23 18:24:05 +03:00
|
|
|
|
|
|
|
if (messages.size() == 0) {
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("No additional messages loaded, notifying chat UI...");
|
2020-08-23 00:49:02 +03:00
|
|
|
this->inReload = false;
|
2020-08-30 20:04:16 +03:00
|
|
|
int listInboxPosition = this->calculateLastKnownMessageId();
|
|
|
|
int listOutboxPosition = this->calculateLastReadSentMessageId();
|
2020-08-26 23:52:06 +03:00
|
|
|
if (this->inIncrementalUpdate) {
|
|
|
|
this->inIncrementalUpdate = false;
|
2020-08-30 20:04:16 +03:00
|
|
|
emit messagesIncrementalUpdate(listInboxPosition, listOutboxPosition);
|
2020-08-26 23:52:06 +03:00
|
|
|
} else {
|
2020-10-19 13:20:02 +03:00
|
|
|
emit messagesReceived(listInboxPosition, listOutboxPosition, totalCount);
|
2020-08-26 23:52:06 +03:00
|
|
|
}
|
2020-08-29 19:28:57 +03:00
|
|
|
} else {
|
2020-11-16 16:22:32 +03:00
|
|
|
if (this->isMostRecentMessageLoaded() || this->inIncrementalUpdate) {
|
|
|
|
this->messagesToBeAdded.clear();
|
|
|
|
QListIterator<QVariant> messagesIterator(messages);
|
|
|
|
while (messagesIterator.hasNext()) {
|
|
|
|
QVariantMap currentMessage = messagesIterator.next().toMap();
|
|
|
|
if (currentMessage.value(CHAT_ID).toLongLong() == chatId && !this->messageIndexMap.contains(currentMessage.value(ID).toString())) {
|
|
|
|
LOG("New message will be added: " + currentMessage.value(ID).toString());
|
|
|
|
this->messagesToBeAdded.append(currentMessage);
|
|
|
|
}
|
2020-08-29 19:28:57 +03:00
|
|
|
}
|
2020-11-16 01:05:22 +03:00
|
|
|
|
2020-11-16 16:22:32 +03:00
|
|
|
std::sort(this->messagesToBeAdded.begin(), this->messagesToBeAdded.end(), compareMessages);
|
2020-08-29 19:28:57 +03:00
|
|
|
|
2020-11-16 16:22:32 +03:00
|
|
|
if (!this->messagesToBeAdded.isEmpty()) {
|
|
|
|
this->insertMessages();
|
|
|
|
}
|
2020-08-29 19:28:57 +03:00
|
|
|
|
2020-11-16 16:22:32 +03:00
|
|
|
// First call only returns a few messages, we need to get a little more than that...
|
2020-11-16 18:52:48 +03:00
|
|
|
if (!this->messagesToBeAdded.isEmpty() && (this->messagesToBeAdded.size() + this->messages.size()) < 10 && !this->inReload) {
|
2020-11-16 16:22:32 +03:00
|
|
|
LOG("Only a few messages received in first call, loading more...");
|
|
|
|
this->inReload = true;
|
|
|
|
this->tdLibWrapper->getChatHistory(this->chatId, this->messagesToBeAdded.first().toMap().value(ID).toLongLong());
|
2020-08-29 19:28:57 +03:00
|
|
|
} else {
|
2020-11-16 16:22:32 +03:00
|
|
|
LOG("Messages loaded, notifying chat UI...");
|
|
|
|
this->inReload = false;
|
|
|
|
int listInboxPosition = this->calculateLastKnownMessageId();
|
|
|
|
int listOutboxPosition = this->calculateLastReadSentMessageId();
|
|
|
|
if (this->inIncrementalUpdate) {
|
|
|
|
this->inIncrementalUpdate = false;
|
|
|
|
emit messagesIncrementalUpdate(listInboxPosition, listOutboxPosition);
|
|
|
|
} else {
|
|
|
|
emit messagesReceived(listInboxPosition, listOutboxPosition, totalCount);
|
|
|
|
}
|
2020-08-29 19:28:57 +03:00
|
|
|
}
|
2020-11-16 16:22:32 +03:00
|
|
|
} else {
|
|
|
|
// Cleanup... Is that really needed? Well, let's see...
|
|
|
|
this->inReload = false;
|
|
|
|
this->inIncrementalUpdate = false;
|
|
|
|
LOG("New messages in this chat, but not relevant as less recent messages need to be loaded first!");
|
2020-08-29 19:28:57 +03:00
|
|
|
}
|
2020-08-23 00:49:02 +03:00
|
|
|
}
|
2020-08-29 19:28:57 +03:00
|
|
|
|
2020-08-23 00:49:02 +03:00
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleNewMessageReceived(const QString &id, const QVariantMap &message)
|
2020-08-23 00:49:02 +03:00
|
|
|
{
|
2020-11-16 01:05:22 +03:00
|
|
|
if (id.toLongLong() == chatId && !this->messageIndexMap.contains(id)) {
|
2020-11-16 16:22:32 +03:00
|
|
|
if (this->isMostRecentMessageLoaded()) {
|
|
|
|
LOG("New message received for this chat");
|
2020-08-23 00:49:02 +03:00
|
|
|
|
2020-11-16 16:22:32 +03:00
|
|
|
this->messagesToBeAdded.clear();
|
|
|
|
this->messagesToBeAdded.append(message);
|
2020-08-23 00:49:02 +03:00
|
|
|
|
2020-11-16 16:22:32 +03:00
|
|
|
this->insertMessages();
|
|
|
|
emit newMessageReceived(message);
|
|
|
|
} else {
|
|
|
|
LOG("New message in this chat, but not relevant as less recent messages need to be loaded first!");
|
|
|
|
}
|
2020-08-23 00:49:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleChatReadInboxUpdated(const QString &id, const QString &lastReadInboxMessageId, int unreadCount)
|
2020-08-29 22:39:57 +03:00
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
if (id.toLongLong() == chatId) {
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Updating chat unread count, unread messages" << unreadCount << ", last read message ID:" << lastReadInboxMessageId);
|
2020-08-29 22:39:57 +03:00
|
|
|
this->chatInformation.insert("unread_count", unreadCount);
|
2020-11-16 01:05:22 +03:00
|
|
|
this->chatInformation.insert(LAST_READ_INBOX_MESSAGE_ID, lastReadInboxMessageId);
|
2020-08-31 22:51:52 +03:00
|
|
|
emit unreadCountUpdated(unreadCount, lastReadInboxMessageId);
|
2020-08-29 22:39:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleChatReadOutboxUpdated(const QString &id, const QString &lastReadOutboxMessageId)
|
2020-08-30 20:04:16 +03:00
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
if (id.toLongLong() == chatId) {
|
2020-08-30 20:04:16 +03:00
|
|
|
this->chatInformation.insert("last_read_outbox_message_id", lastReadOutboxMessageId);
|
|
|
|
int sentIndex = calculateLastReadSentMessageId();
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Updating sent message ID, new index" << sentIndex);
|
2020-08-30 20:04:16 +03:00
|
|
|
emit lastReadSentMessageUpdated(sentIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 00:52:22 +03:00
|
|
|
void ChatModel::handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message)
|
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
LOG("Message send succeeded, new message ID" << messageId << "old message ID" << oldMessageId << ", chat ID" << message.value(CHAT_ID).toString());
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("index map:" << messageIndexMap.contains(oldMessageId) << ", index count:" << messageIndexMap.size() << ", message count:" << messages.size());
|
2020-08-31 00:52:22 +03:00
|
|
|
if (this->messageIndexMap.contains(oldMessageId)) {
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Message was successfully sent" << oldMessageId);
|
2020-08-31 00:52:22 +03:00
|
|
|
int messageIndex = this->messageIndexMap.value(oldMessageId).toInt();
|
|
|
|
this->messages.replace(messageIndex, message);
|
|
|
|
this->calculateMessageIndexMap();
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Message was replaced at index" << messageIndex);
|
2020-08-31 00:52:22 +03:00
|
|
|
emit dataChanged(index(messageIndex), index(messageIndex));
|
2020-11-14 01:39:27 +03:00
|
|
|
emit lastReadSentMessageUpdated(calculateLastReadSentMessageId());
|
2020-08-31 00:52:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleChatNotificationSettingsUpdated(const QString &id, const QVariantMap &chatNotificationSettings)
|
2020-09-16 21:43:36 +03:00
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
if (id.toLongLong() == chatId) {
|
2020-09-16 21:43:36 +03:00
|
|
|
this->chatInformation.insert("notification_settings", chatNotificationSettings);
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Notification settings updated");
|
2020-09-16 21:43:36 +03:00
|
|
|
emit notificationSettingsUpdated();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleChatPhotoUpdated(qlonglong id, const QVariantMap &photo)
|
|
|
|
{
|
|
|
|
if (id == chatId) {
|
|
|
|
LOG("Chat photo updated" << chatId);
|
|
|
|
chatInformation.insert(PHOTO, photo);
|
|
|
|
emit smallPhotoChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-17 14:18:46 +03:00
|
|
|
void ChatModel::handleChatPinnedMessageUpdated(qlonglong id, qlonglong pinnedMessageId)
|
|
|
|
{
|
|
|
|
if (id == chatId) {
|
|
|
|
LOG("Pinned message updated" << chatId);
|
|
|
|
chatInformation.insert(PINNED_MESSAGE_ID, pinnedMessageId);
|
|
|
|
emit pinnedMessageChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleMessageContentUpdated(const QString &id, const QString &messageId, const QVariantMap &newContent)
|
2020-09-19 21:33:51 +03:00
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
LOG("Message content updated" << id << messageId);
|
|
|
|
if (id.toLongLong() == chatId && messageIndexMap.contains(messageId)) {
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("We know the message that was updated " << messageId);
|
2020-09-19 21:33:51 +03:00
|
|
|
int messageIndex = this->messageIndexMap.value(messageId).toInt();
|
|
|
|
QVariantMap messageToBeUpdated = this->messages.at(messageIndex).toMap();
|
|
|
|
messageToBeUpdated.insert("content", newContent);
|
|
|
|
this->messages.replace(messageIndex, messageToBeUpdated);
|
|
|
|
this->calculateMessageIndexMap();
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Message was replaced at index" << messageIndex);
|
2020-09-19 21:33:51 +03:00
|
|
|
emit messageUpdated(messageIndex);
|
|
|
|
emit dataChanged(index(messageIndex), index(messageIndex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:11:10 +03:00
|
|
|
void ChatModel::handleMessagesDeleted(const QString &id, const QVariantList &messageIds)
|
2020-09-20 01:13:42 +03:00
|
|
|
{
|
2020-11-15 07:11:10 +03:00
|
|
|
LOG("Messages were deleted in a chat" << id);
|
|
|
|
if (id.toLongLong() == chatId) {
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Messages in this chat were deleted...");
|
2020-09-20 01:13:42 +03:00
|
|
|
QListIterator<QVariant> messageIdIterator(messageIds);
|
|
|
|
while (messageIdIterator.hasNext()) {
|
|
|
|
QString messageId = messageIdIterator.next().toString();
|
|
|
|
if (this->messageIndexMap.contains(messageId)) {
|
|
|
|
int messageIndex = this->messageIndexMap.value(messageId).toInt();
|
|
|
|
beginRemoveRows(QModelIndex(), messageIndex, messageIndex);
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("...and we even know this message!" << messageId << messageIndex);
|
2020-09-20 01:13:42 +03:00
|
|
|
this->messages.removeAt(messageIndex);
|
|
|
|
this->calculateMessageIndexMap();
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emit messagesDeleted();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-23 00:49:02 +03:00
|
|
|
void ChatModel::insertMessages()
|
|
|
|
{
|
2020-08-22 22:43:20 +03:00
|
|
|
if (this->messages.isEmpty()) {
|
|
|
|
beginResetModel();
|
|
|
|
this->messages.append(this->messagesToBeAdded);
|
2020-08-30 20:04:16 +03:00
|
|
|
this->calculateMessageIndexMap();
|
2020-08-22 22:43:20 +03:00
|
|
|
endResetModel();
|
|
|
|
} else {
|
|
|
|
// There is only an append or a prepend, tertium non datur! (probably ;))
|
2020-11-16 01:05:22 +03:00
|
|
|
qlonglong lastKnownId = this->messages.last().toMap().value(ID).toLongLong();
|
|
|
|
qlonglong firstNewId = this->messagesToBeAdded.first().toMap().value(ID).toLongLong();
|
|
|
|
LOG("Inserting messages, last known ID: " + QString::number(lastKnownId) + ", first new ID: " + QString::number(firstNewId));
|
|
|
|
if (lastKnownId < firstNewId) {
|
2020-08-22 22:43:20 +03:00
|
|
|
// Append
|
2020-11-16 01:05:22 +03:00
|
|
|
LOG("Appending new messages...");
|
2020-08-22 22:43:20 +03:00
|
|
|
this->insertRows(rowCount(QModelIndex()), this->messagesToBeAdded.size());
|
|
|
|
} else {
|
|
|
|
// Prepend
|
2020-11-16 01:05:22 +03:00
|
|
|
LOG("Prepending new messages...");
|
2020-08-22 22:43:20 +03:00
|
|
|
this->insertRows(0, this->messagesToBeAdded.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-28 11:41:18 +03:00
|
|
|
|
|
|
|
QVariantMap ChatModel::enhanceMessage(const QVariantMap &message)
|
|
|
|
{
|
|
|
|
QVariantMap enhancedMessage = message;
|
|
|
|
if (enhancedMessage.value("content").toMap().value("@type").toString() == "messageVoiceNote" ) {
|
|
|
|
QVariantMap contentMap = enhancedMessage.value("content").toMap();
|
|
|
|
QVariantMap voiceNoteMap = contentMap.value("voice_note").toMap();
|
|
|
|
QByteArray waveBytes = QByteArray::fromBase64(voiceNoteMap.value("waveform").toByteArray());
|
|
|
|
QBitArray waveBits(waveBytes.count() * 8);
|
|
|
|
|
|
|
|
for (int i = 0; i < waveBytes.count(); i++) {
|
|
|
|
for (int b = 0; b < 8; b++) {
|
|
|
|
waveBits.setBit( i * 8 + b, waveBytes.at(i) & (1 << (7 - b)) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int waveSize = 10;
|
|
|
|
int waveformSets = waveBits.size() / waveSize;
|
|
|
|
QVariantList decodedWaveform;
|
|
|
|
for (int i = 0; i < waveformSets; i++) {
|
|
|
|
int waveformHeight = 0;
|
|
|
|
for (int j = 0; j < waveSize; j++) {
|
|
|
|
waveformHeight = waveformHeight + ( waveBits.at(i * waveSize + j) * (2 ^ (j)) );
|
|
|
|
}
|
|
|
|
decodedWaveform.append(waveformHeight);
|
|
|
|
}
|
|
|
|
voiceNoteMap.insert("decoded_voice_note", decodedWaveform);
|
|
|
|
contentMap.insert("voice_note", voiceNoteMap);
|
|
|
|
enhancedMessage.insert("content", contentMap);
|
|
|
|
}
|
|
|
|
return enhancedMessage;
|
|
|
|
}
|
2020-08-30 20:04:16 +03:00
|
|
|
|
|
|
|
int ChatModel::calculateLastKnownMessageId()
|
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("calculateLastKnownMessageId");
|
2020-11-16 01:05:22 +03:00
|
|
|
QString lastKnownMessageId = this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toString();
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("lastKnownMessageId" << lastKnownMessageId);
|
|
|
|
LOG("size messageIndexMap" << messageIndexMap.size());
|
|
|
|
LOG("contains ID?" << messageIndexMap.contains(lastKnownMessageId));
|
2020-09-14 00:25:48 +03:00
|
|
|
int listInboxPosition = this->messageIndexMap.value(lastKnownMessageId, this->messages.size() - 1).toInt();
|
|
|
|
if (listInboxPosition > this->messages.size() - 1 ) {
|
|
|
|
listInboxPosition = this->messages.size() - 1;
|
2020-09-01 00:50:39 +03:00
|
|
|
}
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Last known message is at position" << listInboxPosition);
|
2020-08-30 20:04:16 +03:00
|
|
|
return listInboxPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ChatModel::calculateLastReadSentMessageId()
|
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("calculateLastReadSentMessageId");
|
2020-08-30 20:04:16 +03:00
|
|
|
QString lastReadSentMessageId = this->chatInformation.value("last_read_outbox_message_id").toString();
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("lastReadSentMessageId" << lastReadSentMessageId);
|
|
|
|
LOG("size messageIndexMap" << messageIndexMap.size());
|
|
|
|
LOG("contains ID?" << messageIndexMap.contains(lastReadSentMessageId));
|
2020-08-30 20:04:16 +03:00
|
|
|
int listOutboxPosition = this->messageIndexMap.value(lastReadSentMessageId, this->messages.size() - 1).toInt();
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("Last read sent message is at position" << listOutboxPosition);
|
2020-08-30 20:04:16 +03:00
|
|
|
return listOutboxPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatModel::calculateMessageIndexMap()
|
|
|
|
{
|
2020-11-15 06:38:43 +03:00
|
|
|
LOG("calculateMessageIndexMap");
|
2020-08-30 20:04:16 +03:00
|
|
|
this->messageIndexMap.clear();
|
|
|
|
for (int i = 0; i < this->messages.size(); i++) {
|
2020-11-15 07:11:10 +03:00
|
|
|
this->messageIndexMap.insert(this->messages.at(i).toMap().value(ID).toString(), i);
|
2020-08-30 20:04:16 +03:00
|
|
|
}
|
|
|
|
}
|
2020-11-16 16:22:32 +03:00
|
|
|
|
|
|
|
bool ChatModel::isMostRecentMessageLoaded()
|
|
|
|
{
|
|
|
|
// Need to check if we can actually add messages (only possible if the previously latest messages are loaded)
|
|
|
|
// Trying with half of the size of an initial list to ensure that everything is there...
|
|
|
|
return this->getLastReadMessageIndex() >= this->messages.size() - 25;
|
|
|
|
}
|