Optimized chat model a bit
1. Store and handle message ids as numbers rather than variants/strings 2. Incrementally update message id map 3. Expose additional roles and properties to avoid unnecessary lookups
This commit is contained in:
parent
0064b80bb9
commit
b6c97c7f93
10 changed files with 277 additions and 172 deletions
|
@ -25,19 +25,19 @@ import "../js/debug.js" as Debug
|
||||||
ListItem {
|
ListItem {
|
||||||
id: messageListItem
|
id: messageListItem
|
||||||
contentHeight: messageBackground.height + Theme.paddingMedium
|
contentHeight: messageBackground.height + Theme.paddingMedium
|
||||||
readonly property var myMessage: display
|
property var chatId
|
||||||
|
property var messageId
|
||||||
|
property var myMessage
|
||||||
readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender_user_id)
|
readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender_user_id)
|
||||||
property QtObject precalculatedValues: ListView.view.precalculatedValues
|
property QtObject precalculatedValues: ListView.view.precalculatedValues
|
||||||
readonly property color textColor: isOwnMessage ? Theme.highlightColor : Theme.primaryColor
|
readonly property color textColor: isOwnMessage ? Theme.highlightColor : Theme.primaryColor
|
||||||
readonly property int textAlign: isOwnMessage ? Text.AlignRight : Text.AlignLeft
|
readonly property int textAlign: isOwnMessage ? Text.AlignRight : Text.AlignLeft
|
||||||
readonly property Page page: precalculatedValues.page
|
readonly property Page page: precalculatedValues.page
|
||||||
readonly property bool isSelected: messageListItem.precalculatedValues.pageIsSelecting && page.selectedMessages.some(function(existingMessage) {
|
readonly property bool isSelected: messageListItem.precalculatedValues.pageIsSelecting && page.selectedMessages.some(function(existingMessage) {
|
||||||
return existingMessage.id === myMessage.id;
|
return existingMessage.id === messageId
|
||||||
});
|
});
|
||||||
readonly property bool isOwnMessage: page.myUserId === myMessage.sender_user_id
|
readonly property bool isOwnMessage: page.myUserId === myMessage.sender_user_id
|
||||||
readonly property string extraContentComponentName: typeof myMessage.content !== "undefined"
|
property string extraContentComponentName
|
||||||
&& typeof chatView.contentComponentNames[myMessage.content['@type']] !== "undefined" ?
|
|
||||||
chatView.contentComponentNames[myMessage.content['@type']] : ""
|
|
||||||
|
|
||||||
highlighted: (down || isSelected) && !menuOpen
|
highlighted: (down || isSelected) && !menuOpen
|
||||||
openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting
|
openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting
|
||||||
|
@ -96,7 +96,7 @@ ListItem {
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
newMessageColumn.editMessageId = myMessage.id;
|
newMessageColumn.editMessageId = messageId;
|
||||||
newMessageTextField.text = Functions.getMessageText(myMessage, false, false, true);
|
newMessageTextField.text = Functions.getMessageText(myMessage, false, false, true);
|
||||||
newMessageTextField.focus = true;
|
newMessageTextField.focus = true;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ ListItem {
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tdLibWrapper.pinMessage(page.chatInformation.id, myMessage.id);
|
tdLibWrapper.pinMessage(page.chatInformation.id, messageId)
|
||||||
}
|
}
|
||||||
text: qsTr("Pin Message")
|
text: qsTr("Pin Message")
|
||||||
visible: canPinMessages()
|
visible: canPinMessages()
|
||||||
|
@ -125,7 +125,7 @@ ListItem {
|
||||||
MenuItem {
|
MenuItem {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var chatId = page.chatInformation.id;
|
var chatId = page.chatInformation.id;
|
||||||
var messageId = myMessage.id;
|
var messageId = messageListItem.messageId;
|
||||||
Remorse.itemAction(messageListItem, qsTr("Message deleted"), function() { tdLibWrapper.deleteMessages(chatId, [ messageId]); })
|
Remorse.itemAction(messageListItem, qsTr("Message deleted"), function() { tdLibWrapper.deleteMessages(chatId, [ messageId]); })
|
||||||
}
|
}
|
||||||
text: qsTr("Delete Message")
|
text: qsTr("Delete Message")
|
||||||
|
|
|
@ -919,13 +919,17 @@ Page {
|
||||||
id: messageListViewItemComponent
|
id: messageListViewItemComponent
|
||||||
MessageListViewItem {
|
MessageListViewItem {
|
||||||
precalculatedValues: chatView.precalculatedValues
|
precalculatedValues: chatView.precalculatedValues
|
||||||
|
chatId: chatModel.chatId
|
||||||
|
myMessage: model.display
|
||||||
|
messageId: model.message_id
|
||||||
|
extraContentComponentName: chatView.contentComponentNames[model.content_type]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component {
|
Component {
|
||||||
id: messageListViewItemSimpleComponent
|
id: messageListViewItemSimpleComponent
|
||||||
MessageListViewItemSimple {}
|
MessageListViewItemSimple {}
|
||||||
}
|
}
|
||||||
sourceComponent: chatView.simpleDelegateMessages.indexOf(display.content['@type']) > -1 ? messageListViewItemSimpleComponent : messageListViewItemComponent
|
sourceComponent: chatView.simpleDelegateMessages.indexOf(model.content_type) > -1 ? messageListViewItemSimpleComponent : messageListViewItemComponent
|
||||||
}
|
}
|
||||||
VerticalScrollDecorator {}
|
VerticalScrollDecorator {}
|
||||||
|
|
||||||
|
|
|
@ -330,7 +330,7 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper) : showHiddenChats(false
|
||||||
connect(tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
|
connect(tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
|
||||||
connect(tdLibWrapper, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SLOT(handleChatPhotoUpdated(qlonglong, QVariantMap)));
|
connect(tdLibWrapper, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SLOT(handleChatPhotoUpdated(qlonglong, QVariantMap)));
|
||||||
connect(tdLibWrapper, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SLOT(handleChatPinnedMessageUpdated(qlonglong, qlonglong)));
|
connect(tdLibWrapper, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SLOT(handleChatPinnedMessageUpdated(qlonglong, qlonglong)));
|
||||||
connect(tdLibWrapper, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, QVariantMap)));
|
connect(tdLibWrapper, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageSendSucceeded(qlonglong, qlonglong, QVariantMap)));
|
||||||
connect(tdLibWrapper, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SLOT(handleChatNotificationSettingsUpdated(QString, QVariantMap)));
|
connect(tdLibWrapper, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SLOT(handleChatNotificationSettingsUpdated(QString, QVariantMap)));
|
||||||
connect(tdLibWrapper, SIGNAL(superGroupUpdated(qlonglong)), this, SLOT(handleGroupUpdated(qlonglong)));
|
connect(tdLibWrapper, SIGNAL(superGroupUpdated(qlonglong)), this, SLOT(handleGroupUpdated(qlonglong)));
|
||||||
connect(tdLibWrapper, SIGNAL(basicGroupUpdated(qlonglong)), this, SLOT(handleGroupUpdated(qlonglong)));
|
connect(tdLibWrapper, SIGNAL(basicGroupUpdated(qlonglong)), this, SLOT(handleGroupUpdated(qlonglong)));
|
||||||
|
@ -741,7 +741,7 @@ void ChatListModel::handleChatPinnedMessageUpdated(qlonglong chatId, qlonglong p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatListModel::handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message)
|
void ChatListModel::handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message)
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
const qlonglong chatId(message.value(CHAT_ID).toLongLong(&ok));
|
const qlonglong chatId(message.value(CHAT_ID).toLongLong(&ok));
|
||||||
|
|
|
@ -51,7 +51,7 @@ private slots:
|
||||||
void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
|
void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
|
||||||
void handleChatPhotoUpdated(qlonglong chatId, const QVariantMap &photo);
|
void handleChatPhotoUpdated(qlonglong chatId, const QVariantMap &photo);
|
||||||
void handleChatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId);
|
void handleChatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId);
|
||||||
void handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message);
|
void handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message);
|
||||||
void handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings);
|
void handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings);
|
||||||
void handleGroupUpdated(qlonglong groupId);
|
void handleGroupUpdated(qlonglong groupId);
|
||||||
void handleSecretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat);
|
void handleSecretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat);
|
||||||
|
|
|
@ -28,13 +28,59 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const QString ID("id");
|
const QString ID("id");
|
||||||
|
const QString CONTENT("content");
|
||||||
const QString CHAT_ID("chat_id");
|
const QString CHAT_ID("chat_id");
|
||||||
const QString PHOTO("photo");
|
const QString PHOTO("photo");
|
||||||
const QString SMALL("small");
|
const QString SMALL("small");
|
||||||
const QString UNREAD_COUNT("unread_count");
|
const QString UNREAD_COUNT("unread_count");
|
||||||
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
|
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
|
||||||
|
const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id");
|
||||||
const QString SENDER_USER_ID("sender_user_id");
|
const QString SENDER_USER_ID("sender_user_id");
|
||||||
const QString PINNED_MESSAGE_ID("pinned_message_id");
|
const QString PINNED_MESSAGE_ID("pinned_message_id");
|
||||||
|
const QString _TYPE("@type");
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatModel::MessageData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Role {
|
||||||
|
RoleDisplay = Qt::DisplayRole,
|
||||||
|
RoleMessageId,
|
||||||
|
RoleMessageContentType
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageData(const QVariantMap &data, qlonglong msgid);
|
||||||
|
|
||||||
|
static bool lessThan(const MessageData *message1, const MessageData *message2);
|
||||||
|
void setContent(const QVariantMap &content);
|
||||||
|
int senderUserId() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QVariantMap messageData;
|
||||||
|
const qlonglong messageId;
|
||||||
|
const QString messageContentType;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChatModel::MessageData::MessageData(const QVariantMap &data, qlonglong msgid) :
|
||||||
|
messageData(data),
|
||||||
|
messageId(msgid),
|
||||||
|
messageContentType(data.value(CONTENT).toMap().value(_TYPE).toString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatModel::MessageData::senderUserId() const
|
||||||
|
{
|
||||||
|
return messageData.value(SENDER_USER_ID).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatModel::MessageData::setContent(const QVariantMap &content)
|
||||||
|
{
|
||||||
|
messageData.insert(CONTENT, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatModel::MessageData::lessThan(const MessageData *message1, const MessageData *message2)
|
||||||
|
{
|
||||||
|
return message1->messageId < message2->messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) :
|
ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) :
|
||||||
|
@ -44,20 +90,30 @@ ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) :
|
||||||
{
|
{
|
||||||
this->tdLibWrapper = tdLibWrapper;
|
this->tdLibWrapper = tdLibWrapper;
|
||||||
connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int)));
|
connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap)));
|
connect(this->tdLibWrapper, SIGNAL(newMessageReceived(qlonglong, QVariantMap)), this, SLOT(handleNewMessageReceived(qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int)));
|
connect(this->tdLibWrapper, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
|
connect(this->tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, QVariantMap)));
|
connect(this->tdLibWrapper, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageSendSucceeded(qlonglong, qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SLOT(handleChatNotificationSettingsUpdated(QString, QVariantMap)));
|
connect(this->tdLibWrapper, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SLOT(handleChatNotificationSettingsUpdated(QString, QVariantMap)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SLOT(handleChatPhotoUpdated(qlonglong, QVariantMap)));
|
connect(this->tdLibWrapper, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SLOT(handleChatPhotoUpdated(qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SLOT(handleChatPinnedMessageUpdated(qlonglong, qlonglong)));
|
connect(this->tdLibWrapper, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SLOT(handleChatPinnedMessageUpdated(qlonglong, qlonglong)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)), this, SLOT(handleMessageContentUpdated(QString, QString, QVariantMap)));
|
connect(this->tdLibWrapper, SIGNAL(messageContentUpdated(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageContentUpdated(qlonglong, qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibWrapper, SIGNAL(messagesDeleted(QString, QVariantList)), this, SLOT(handleMessagesDeleted(QString, QVariantList)));
|
connect(this->tdLibWrapper, SIGNAL(messagesDeleted(qlonglong, QList<qlonglong>)), this, SLOT(handleMessagesDeleted(qlonglong, QList<qlonglong>)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatModel::~ChatModel()
|
ChatModel::~ChatModel()
|
||||||
{
|
{
|
||||||
LOG("Destroying myself...");
|
LOG("Destroying myself...");
|
||||||
|
qDeleteAll(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int,QByteArray> ChatModel::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int,QByteArray> roles;
|
||||||
|
roles.insert(MessageData::RoleDisplay, "display");
|
||||||
|
roles.insert(MessageData::RoleMessageId, "message_id");
|
||||||
|
roles.insert(MessageData::RoleMessageContentType, "content_type");
|
||||||
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ChatModel::rowCount(const QModelIndex &) const
|
int ChatModel::rowCount(const QModelIndex &) const
|
||||||
|
@ -67,51 +123,52 @@ int ChatModel::rowCount(const QModelIndex &) const
|
||||||
|
|
||||||
QVariant ChatModel::data(const QModelIndex &index, int role) const
|
QVariant ChatModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if(index.isValid() && role == Qt::DisplayRole) {
|
const int row = index.row();
|
||||||
return QVariant(messages.value(index.row()));
|
if (row >= 0 && row < messages.size()) {
|
||||||
|
const MessageData *message = messages.at(row);
|
||||||
|
switch ((MessageData::Role)role) {
|
||||||
|
case MessageData::RoleDisplay: return message->messageData;
|
||||||
|
case MessageData::RoleMessageId: return message->messageId;
|
||||||
|
case MessageData::RoleMessageContentType: return message->messageContentType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatModel::insertRows(int row, int count, const QModelIndex &parent)
|
|
||||||
{
|
|
||||||
LOG("Inserting at" << row << ", row count:" << count);
|
|
||||||
beginInsertRows(parent, row, row + count - 1);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
this->messages.insert(row + i, this->messagesToBeAdded.at(i));
|
|
||||||
}
|
|
||||||
this->calculateMessageIndexMap();
|
|
||||||
endInsertRows();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatModel::clear()
|
void ChatModel::clear()
|
||||||
{
|
{
|
||||||
LOG("Clearing chat model");
|
LOG("Clearing chat model");
|
||||||
chatId = 0;
|
|
||||||
inReload = false;
|
inReload = false;
|
||||||
inIncrementalUpdate = false;
|
inIncrementalUpdate = false;
|
||||||
if (!messages.isEmpty()) {
|
if (!messages.isEmpty()) {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
qDeleteAll(messages);
|
||||||
messages.clear();
|
messages.clear();
|
||||||
|
messageIndexMap.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
if (!chatInformation.isEmpty()) {
|
if (!chatInformation.isEmpty()) {
|
||||||
chatInformation.clear();
|
chatInformation.clear();
|
||||||
emit smallPhotoChanged();
|
emit smallPhotoChanged();
|
||||||
}
|
}
|
||||||
|
if (chatId) {
|
||||||
|
chatId = 0;
|
||||||
|
emit chatIdChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::initialize(const QVariantMap &chatInformation)
|
void ChatModel::initialize(const QVariantMap &chatInformation)
|
||||||
{
|
{
|
||||||
LOG("Initializing chat model...");
|
const qlonglong chatId = chatInformation.value(ID).toLongLong();
|
||||||
|
LOG("Initializing chat model..." << chatId);
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
qDeleteAll(messages);
|
||||||
this->chatInformation = chatInformation;
|
this->chatInformation = chatInformation;
|
||||||
this->chatId = chatInformation.value(ID).toLongLong();
|
this->chatId = chatId;
|
||||||
this->messages.clear();
|
this->messages.clear();
|
||||||
this->messageIndexMap.clear();
|
this->messageIndexMap.clear();
|
||||||
this->messagesToBeAdded.clear();
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
emit chatIdChanged();
|
||||||
emit smallPhotoChanged();
|
emit smallPhotoChanged();
|
||||||
tdLibWrapper->getChatHistory(chatId, this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong());
|
tdLibWrapper->getChatHistory(chatId, this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong());
|
||||||
}
|
}
|
||||||
|
@ -121,7 +178,7 @@ void ChatModel::triggerLoadMoreHistory()
|
||||||
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
|
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
|
||||||
LOG("Trigger loading older history...");
|
LOG("Trigger loading older history...");
|
||||||
this->inIncrementalUpdate = true;
|
this->inIncrementalUpdate = true;
|
||||||
this->tdLibWrapper->getChatHistory(chatId, messages.first().toMap().value(ID).toLongLong());
|
this->tdLibWrapper->getChatHistory(chatId, messages.first()->messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +187,7 @@ void ChatModel::triggerLoadMoreFuture()
|
||||||
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
|
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
|
||||||
LOG("Trigger loading newer future...");
|
LOG("Trigger loading newer future...");
|
||||||
this->inIncrementalUpdate = true;
|
this->inIncrementalUpdate = true;
|
||||||
this->tdLibWrapper->getChatHistory(chatId, messages.last().toMap().value(ID).toLongLong(), -49);
|
this->tdLibWrapper->getChatHistory(chatId, messages.last()->messageId, -49);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,8 +198,8 @@ QVariantMap ChatModel::getChatInformation()
|
||||||
|
|
||||||
QVariantMap ChatModel::getMessage(int index)
|
QVariantMap ChatModel::getMessage(int index)
|
||||||
{
|
{
|
||||||
if (index < this->messages.size()) {
|
if (index >= 0 && index < messages.size()) {
|
||||||
return this->messages.at(index).toMap();
|
return messages.at(index)->messageData;
|
||||||
} else {
|
} else {
|
||||||
return QVariantMap();
|
return QVariantMap();
|
||||||
}
|
}
|
||||||
|
@ -154,16 +211,16 @@ int ChatModel::getLastReadMessageIndex()
|
||||||
if (this->messages.isEmpty()) {
|
if (this->messages.isEmpty()) {
|
||||||
LOG("Messages are empty, nothing to do...");
|
LOG("Messages are empty, nothing to do...");
|
||||||
return 0;
|
return 0;
|
||||||
} else if (this->messages.last().toMap().value(SENDER_USER_ID).toString() == tdLibWrapper->getUserInformation().value(ID).toString()) {
|
} else if (messages.last()->senderUserId() == tdLibWrapper->getUserInformation().value(ID).toInt()) {
|
||||||
LOG("Last message is an own one, then simply set the last read to the last one...");
|
LOG("Last message is an own one, then simply set the last read to the last one...");
|
||||||
return this->messages.size() - 1;
|
return this->messages.size() - 1;
|
||||||
} else {
|
} else {
|
||||||
int lastReadMessageIndex = this->messageIndexMap.value(this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toString()).toInt();
|
const int lastReadMessageIndex = messageIndexMap.value(chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong(), -1);
|
||||||
if (lastReadMessageIndex == 0) {
|
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.");
|
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;
|
return this->messages.size() - 1;
|
||||||
} else {
|
} else {
|
||||||
LOG("Found last read message in the already loaded messages. Index: " << lastReadMessageIndex);
|
LOG("Found last read message in the already loaded messages. Index:" << lastReadMessageIndex);
|
||||||
return lastReadMessageIndex;
|
return lastReadMessageIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,13 +236,6 @@ qlonglong ChatModel::getChatId() const
|
||||||
return chatId;
|
return chatId;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCount)
|
||||||
{
|
{
|
||||||
LOG("Receiving new messages :)" << messages.size());
|
LOG("Receiving new messages :)" << messages.size());
|
||||||
|
@ -203,27 +253,28 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCo
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this->isMostRecentMessageLoaded() || this->inIncrementalUpdate) {
|
if (this->isMostRecentMessageLoaded() || this->inIncrementalUpdate) {
|
||||||
this->messagesToBeAdded.clear();
|
QList<MessageData*> messagesToBeAdded;
|
||||||
QListIterator<QVariant> messagesIterator(messages);
|
QListIterator<QVariant> messagesIterator(messages);
|
||||||
while (messagesIterator.hasNext()) {
|
while (messagesIterator.hasNext()) {
|
||||||
QVariantMap currentMessage = messagesIterator.next().toMap();
|
const QVariantMap messageData = messagesIterator.next().toMap();
|
||||||
if (currentMessage.value(CHAT_ID).toLongLong() == chatId && !this->messageIndexMap.contains(currentMessage.value(ID).toString())) {
|
const qlonglong messageId = messageData.value(ID).toLongLong();
|
||||||
LOG("New message will be added: " + currentMessage.value(ID).toString());
|
if (messageId && messageData.value(CHAT_ID).toLongLong() == chatId && !messageIndexMap.contains(messageId)) {
|
||||||
this->messagesToBeAdded.append(currentMessage);
|
LOG("New message will be added:" << messageId);
|
||||||
|
messagesToBeAdded.append(new MessageData(messageData, messageId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(this->messagesToBeAdded.begin(), this->messagesToBeAdded.end(), compareMessages);
|
std::sort(messagesToBeAdded.begin(), messagesToBeAdded.end(), MessageData::lessThan);
|
||||||
|
|
||||||
if (!this->messagesToBeAdded.isEmpty()) {
|
if (!messagesToBeAdded.isEmpty()) {
|
||||||
this->insertMessages();
|
insertMessages(messagesToBeAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
// First call only returns a few messages, we need to get a little more than that...
|
// First call only returns a few messages, we need to get a little more than that...
|
||||||
if (!this->messagesToBeAdded.isEmpty() && (this->messagesToBeAdded.size() + this->messages.size()) < 10 && !this->inReload) {
|
if (!messagesToBeAdded.isEmpty() && (messagesToBeAdded.size() + messages.size()) < 10 && !inReload) {
|
||||||
LOG("Only a few messages received in first call, loading more...");
|
LOG("Only a few messages received in first call, loading more...");
|
||||||
this->inReload = true;
|
this->inReload = true;
|
||||||
this->tdLibWrapper->getChatHistory(this->chatId, this->messagesToBeAdded.first().toMap().value(ID).toLongLong(), 0);
|
this->tdLibWrapper->getChatHistory(chatId, messagesToBeAdded.first()->messageId, 0);
|
||||||
} else {
|
} else {
|
||||||
LOG("Messages loaded, notifying chat UI...");
|
LOG("Messages loaded, notifying chat UI...");
|
||||||
this->inReload = false;
|
this->inReload = false;
|
||||||
|
@ -246,16 +297,15 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCo
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::handleNewMessageReceived(const QString &id, const QVariantMap &message)
|
void ChatModel::handleNewMessageReceived(qlonglong chatId, const QVariantMap &message)
|
||||||
{
|
{
|
||||||
if (id.toLongLong() == chatId && !this->messageIndexMap.contains(id)) {
|
const qlonglong messageId = message.value(ID).toLongLong();
|
||||||
|
if (chatId == this->chatId && !messageIndexMap.contains(messageId)) {
|
||||||
if (this->isMostRecentMessageLoaded()) {
|
if (this->isMostRecentMessageLoaded()) {
|
||||||
LOG("New message received for this chat");
|
LOG("New message received for this chat");
|
||||||
|
QList<MessageData*> messagesToBeAdded;
|
||||||
this->messagesToBeAdded.clear();
|
messagesToBeAdded.append(new MessageData(message, messageId));
|
||||||
this->messagesToBeAdded.append(message);
|
insertMessages(messagesToBeAdded);
|
||||||
|
|
||||||
this->insertMessages();
|
|
||||||
emit newMessageReceived(message);
|
emit newMessageReceived(message);
|
||||||
} else {
|
} else {
|
||||||
LOG("New message in this chat, but not relevant as less recent messages need to be loaded first!");
|
LOG("New message in this chat, but not relevant as less recent messages need to be loaded first!");
|
||||||
|
@ -276,24 +326,25 @@ void ChatModel::handleChatReadInboxUpdated(const QString &id, const QString &las
|
||||||
void ChatModel::handleChatReadOutboxUpdated(const QString &id, const QString &lastReadOutboxMessageId)
|
void ChatModel::handleChatReadOutboxUpdated(const QString &id, const QString &lastReadOutboxMessageId)
|
||||||
{
|
{
|
||||||
if (id.toLongLong() == chatId) {
|
if (id.toLongLong() == chatId) {
|
||||||
this->chatInformation.insert("last_read_outbox_message_id", lastReadOutboxMessageId);
|
this->chatInformation.insert(LAST_READ_OUTBOX_MESSAGE_ID, lastReadOutboxMessageId);
|
||||||
int sentIndex = calculateLastReadSentMessageId();
|
int sentIndex = calculateLastReadSentMessageId();
|
||||||
LOG("Updating sent message ID, new index" << sentIndex);
|
LOG("Updating sent message ID, new index" << sentIndex);
|
||||||
emit lastReadSentMessageUpdated(sentIndex);
|
emit lastReadSentMessageUpdated(sentIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message)
|
void ChatModel::handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message)
|
||||||
{
|
{
|
||||||
LOG("Message send succeeded, new message ID" << messageId << "old message ID" << oldMessageId << ", chat ID" << message.value(CHAT_ID).toString());
|
LOG("Message send succeeded, new message ID" << messageId << "old message ID" << oldMessageId << ", chat ID" << message.value(CHAT_ID).toString());
|
||||||
LOG("index map:" << messageIndexMap.contains(oldMessageId) << ", index count:" << messageIndexMap.size() << ", message count:" << messages.size());
|
LOG("index map:" << messageIndexMap.contains(oldMessageId) << ", index count:" << messageIndexMap.size() << ", message count:" << messages.size());
|
||||||
if (this->messageIndexMap.contains(oldMessageId)) {
|
if (this->messageIndexMap.contains(oldMessageId)) {
|
||||||
LOG("Message was successfully sent" << oldMessageId);
|
LOG("Message was successfully sent" << oldMessageId);
|
||||||
int messageIndex = this->messageIndexMap.value(oldMessageId).toInt();
|
const int pos = messageIndexMap.take(oldMessageId);
|
||||||
this->messages.replace(messageIndex, message);
|
delete messages.at(pos);
|
||||||
this->calculateMessageIndexMap();
|
messages.replace(pos, new MessageData(message, messageId));
|
||||||
LOG("Message was replaced at index" << messageIndex);
|
LOG("Message was replaced at index" << pos);
|
||||||
emit dataChanged(index(messageIndex), index(messageIndex));
|
const QModelIndex messageIndex(index(pos));
|
||||||
|
emit dataChanged(messageIndex, messageIndex);
|
||||||
emit lastReadSentMessageUpdated(calculateLastReadSentMessageId());
|
emit lastReadSentMessageUpdated(calculateLastReadSentMessageId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,72 +376,120 @@ void ChatModel::handleChatPinnedMessageUpdated(qlonglong id, qlonglong pinnedMes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::handleMessageContentUpdated(const QString &id, const QString &messageId, const QVariantMap &newContent)
|
void ChatModel::handleMessageContentUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &newContent)
|
||||||
{
|
{
|
||||||
LOG("Message content updated" << id << messageId);
|
LOG("Message content updated" << chatId << messageId);
|
||||||
if (id.toLongLong() == chatId && messageIndexMap.contains(messageId)) {
|
if (chatId == this->chatId && messageIndexMap.contains(messageId)) {
|
||||||
LOG("We know the message that was updated " << messageId);
|
LOG("We know the message that was updated" << messageId);
|
||||||
int messageIndex = this->messageIndexMap.value(messageId).toInt();
|
const int pos = messageIndexMap.value(messageId, -1);
|
||||||
QVariantMap messageToBeUpdated = this->messages.at(messageIndex).toMap();
|
if (pos >= 0) {
|
||||||
messageToBeUpdated.insert("content", newContent);
|
messages.at(pos)->setContent(newContent);
|
||||||
this->messages.replace(messageIndex, messageToBeUpdated);
|
LOG("Message was replaced at index" << pos);
|
||||||
this->calculateMessageIndexMap();
|
const QModelIndex messageIndex(index(pos));
|
||||||
LOG("Message was replaced at index" << messageIndex);
|
emit dataChanged(messageIndex, messageIndex);
|
||||||
emit dataChanged(index(messageIndex), index(messageIndex));
|
emit messageUpdated(pos);
|
||||||
emit messageUpdated(messageIndex);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::handleMessagesDeleted(const QString &id, const QVariantList &messageIds)
|
void ChatModel::handleMessagesDeleted(qlonglong chatId, const QList<qlonglong> &messageIds)
|
||||||
{
|
{
|
||||||
LOG("Messages were deleted in a chat" << id);
|
LOG("Messages were deleted in a chat" << chatId);
|
||||||
if (id.toLongLong() == chatId) {
|
if (chatId == this->chatId) {
|
||||||
LOG("Messages in this chat were deleted...");
|
const int count = messageIds.size();
|
||||||
QListIterator<QVariant> messageIdIterator(messageIds);
|
LOG(count << "messages in this chat were deleted...");
|
||||||
while (messageIdIterator.hasNext()) {
|
int firstDeleted = -1, lastDeleted = -2;
|
||||||
QString messageId = messageIdIterator.next().toString();
|
for (int i = 0; i < count; i++) {
|
||||||
if (this->messageIndexMap.contains(messageId)) {
|
const int pos = messageIndexMap.value(messageIds.at(i), -1);
|
||||||
int messageIndex = this->messageIndexMap.value(messageId).toInt();
|
if (pos >= 0) {
|
||||||
beginRemoveRows(QModelIndex(), messageIndex, messageIndex);
|
if (pos == lastDeleted + 1) {
|
||||||
LOG("...and we even know this message!" << messageId << messageIndex);
|
lastDeleted = pos; // Extend the current range
|
||||||
this->messages.removeAt(messageIndex);
|
} else {
|
||||||
this->calculateMessageIndexMap();
|
removeRange(firstDeleted, lastDeleted);
|
||||||
endRemoveRows();
|
firstDeleted = lastDeleted = pos; // Start new range
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit messagesDeleted();
|
// Handle the last (and likely the only) range
|
||||||
|
removeRange(firstDeleted, lastDeleted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::insertMessages()
|
void ChatModel::removeRange(int firstDeleted, int lastDeleted)
|
||||||
{
|
{
|
||||||
if (this->messages.isEmpty()) {
|
if (firstDeleted >= 0 && firstDeleted <= lastDeleted) {
|
||||||
beginResetModel();
|
LOG("Removing range" << firstDeleted << "..." << lastDeleted);
|
||||||
this->messages.append(this->messagesToBeAdded);
|
beginRemoveRows(QModelIndex(), firstDeleted, lastDeleted);
|
||||||
this->calculateMessageIndexMap();
|
for (int i = firstDeleted; i <= lastDeleted; i++) {
|
||||||
endResetModel();
|
MessageData *message = messages.at(i);
|
||||||
} else {
|
messageIndexMap.remove(message->messageId);
|
||||||
|
delete message;
|
||||||
|
}
|
||||||
|
messages.erase(messages.begin() + firstDeleted, messages.begin() + (lastDeleted + 1));
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatModel::insertMessages(const QList<MessageData*> newMessages)
|
||||||
|
{
|
||||||
|
// Caller ensures that newMessages is not empty
|
||||||
|
if (messages.isEmpty()) {
|
||||||
|
appendMessages(newMessages);
|
||||||
|
} else if (!newMessages.isEmpty()) {
|
||||||
// There is only an append or a prepend, tertium non datur! (probably ;))
|
// There is only an append or a prepend, tertium non datur! (probably ;))
|
||||||
qlonglong lastKnownId = this->messages.last().toMap().value(ID).toLongLong();
|
const qlonglong lastKnownId = messages.last()->messageId;
|
||||||
qlonglong firstNewId = this->messagesToBeAdded.first().toMap().value(ID).toLongLong();
|
const qlonglong firstNewId = newMessages.first()->messageId;
|
||||||
LOG("Inserting messages, last known ID: " + QString::number(lastKnownId) + ", first new ID: " + QString::number(firstNewId));
|
LOG("Inserting messages, last known ID:" << lastKnownId << ", first new ID:" << firstNewId);
|
||||||
if (lastKnownId < firstNewId) {
|
if (lastKnownId < firstNewId) {
|
||||||
// Append
|
appendMessages(newMessages);
|
||||||
LOG("Appending new messages...");
|
|
||||||
this->insertRows(rowCount(QModelIndex()), this->messagesToBeAdded.size());
|
|
||||||
} else {
|
} else {
|
||||||
// Prepend
|
prependMessages(newMessages);
|
||||||
LOG("Prepending new messages...");
|
|
||||||
this->insertRows(0, this->messagesToBeAdded.size());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatModel::appendMessages(const QList<MessageData*> newMessages)
|
||||||
|
{
|
||||||
|
const int oldSize = messages.size();
|
||||||
|
const int count = newMessages.size();
|
||||||
|
LOG("Appending" << count << "new messages...");
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), oldSize, oldSize + count - 1);
|
||||||
|
messages.append(newMessages);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
// Appens new indeces to the map
|
||||||
|
messageIndexMap.insert(newMessages.at(i)->messageId, oldSize + i);
|
||||||
|
}
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatModel::prependMessages(const QList<MessageData*> newMessages)
|
||||||
|
{
|
||||||
|
const int insertCount = newMessages.size();
|
||||||
|
const int totalCount = messages.size() + insertCount;
|
||||||
|
LOG("Prepending" << insertCount << "messages...");
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), 0, insertCount - 1);
|
||||||
|
// Too bad there's no bulk insert
|
||||||
|
messages.reserve(totalCount);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < insertCount; i++) {
|
||||||
|
MessageData* message = newMessages.at(i);
|
||||||
|
messages.insert(i, message);
|
||||||
|
messageIndexMap.insert(message->messageId, i);
|
||||||
|
}
|
||||||
|
// The rest of the map has been damaged too
|
||||||
|
for (; i < totalCount; i++) {
|
||||||
|
messageIndexMap.insert(messages.at(i)->messageId, i);
|
||||||
|
}
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap ChatModel::enhanceMessage(const QVariantMap &message)
|
QVariantMap ChatModel::enhanceMessage(const QVariantMap &message)
|
||||||
{
|
{
|
||||||
QVariantMap enhancedMessage = message;
|
QVariantMap enhancedMessage = message;
|
||||||
if (enhancedMessage.value("content").toMap().value("@type").toString() == "messageVoiceNote" ) {
|
if (enhancedMessage.value(CONTENT).toMap().value(_TYPE).toString() == "messageVoiceNote" ) {
|
||||||
QVariantMap contentMap = enhancedMessage.value("content").toMap();
|
QVariantMap contentMap = enhancedMessage.value(CONTENT).toMap();
|
||||||
QVariantMap voiceNoteMap = contentMap.value("voice_note").toMap();
|
QVariantMap voiceNoteMap = contentMap.value("voice_note").toMap();
|
||||||
QByteArray waveBytes = QByteArray::fromBase64(voiceNoteMap.value("waveform").toByteArray());
|
QByteArray waveBytes = QByteArray::fromBase64(voiceNoteMap.value("waveform").toByteArray());
|
||||||
QBitArray waveBits(waveBytes.count() * 8);
|
QBitArray waveBits(waveBytes.count() * 8);
|
||||||
|
@ -412,7 +511,7 @@ QVariantMap ChatModel::enhanceMessage(const QVariantMap &message)
|
||||||
}
|
}
|
||||||
voiceNoteMap.insert("decoded_voice_note", decodedWaveform);
|
voiceNoteMap.insert("decoded_voice_note", decodedWaveform);
|
||||||
contentMap.insert("voice_note", voiceNoteMap);
|
contentMap.insert("voice_note", voiceNoteMap);
|
||||||
enhancedMessage.insert("content", contentMap);
|
enhancedMessage.insert(CONTENT, contentMap);
|
||||||
}
|
}
|
||||||
return enhancedMessage;
|
return enhancedMessage;
|
||||||
}
|
}
|
||||||
|
@ -420,11 +519,11 @@ QVariantMap ChatModel::enhanceMessage(const QVariantMap &message)
|
||||||
int ChatModel::calculateLastKnownMessageId()
|
int ChatModel::calculateLastKnownMessageId()
|
||||||
{
|
{
|
||||||
LOG("calculateLastKnownMessageId");
|
LOG("calculateLastKnownMessageId");
|
||||||
QString lastKnownMessageId = this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toString();
|
const qlonglong lastKnownMessageId = this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong();
|
||||||
LOG("lastKnownMessageId" << lastKnownMessageId);
|
LOG("lastKnownMessageId" << lastKnownMessageId);
|
||||||
LOG("size messageIndexMap" << messageIndexMap.size());
|
LOG("size messageIndexMap" << messageIndexMap.size());
|
||||||
LOG("contains ID?" << messageIndexMap.contains(lastKnownMessageId));
|
LOG("contains ID?" << messageIndexMap.contains(lastKnownMessageId));
|
||||||
int listInboxPosition = this->messageIndexMap.value(lastKnownMessageId, this->messages.size() - 1).toInt();
|
int listInboxPosition = messageIndexMap.value(lastKnownMessageId, messages.size() - 1);
|
||||||
if (listInboxPosition > this->messages.size() - 1 ) {
|
if (listInboxPosition > this->messages.size() - 1 ) {
|
||||||
listInboxPosition = this->messages.size() - 1;
|
listInboxPosition = this->messages.size() - 1;
|
||||||
}
|
}
|
||||||
|
@ -435,24 +534,15 @@ int ChatModel::calculateLastKnownMessageId()
|
||||||
int ChatModel::calculateLastReadSentMessageId()
|
int ChatModel::calculateLastReadSentMessageId()
|
||||||
{
|
{
|
||||||
LOG("calculateLastReadSentMessageId");
|
LOG("calculateLastReadSentMessageId");
|
||||||
QString lastReadSentMessageId = this->chatInformation.value("last_read_outbox_message_id").toString();
|
const qlonglong lastReadSentMessageId = this->chatInformation.value(LAST_READ_OUTBOX_MESSAGE_ID).toLongLong();
|
||||||
LOG("lastReadSentMessageId" << lastReadSentMessageId);
|
LOG("lastReadSentMessageId" << lastReadSentMessageId);
|
||||||
LOG("size messageIndexMap" << messageIndexMap.size());
|
LOG("size messageIndexMap" << messageIndexMap.size());
|
||||||
LOG("contains ID?" << messageIndexMap.contains(lastReadSentMessageId));
|
LOG("contains ID?" << messageIndexMap.contains(lastReadSentMessageId));
|
||||||
int listOutboxPosition = this->messageIndexMap.value(lastReadSentMessageId, this->messages.size() - 1).toInt();
|
const int listOutboxPosition = messageIndexMap.value(lastReadSentMessageId, messages.size() - 1);
|
||||||
LOG("Last read sent message is at position" << listOutboxPosition);
|
LOG("Last read sent message is at position" << listOutboxPosition);
|
||||||
return listOutboxPosition;
|
return listOutboxPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatModel::calculateMessageIndexMap()
|
|
||||||
{
|
|
||||||
LOG("calculateMessageIndexMap");
|
|
||||||
this->messageIndexMap.clear();
|
|
||||||
for (int i = 0; i < this->messages.size(); i++) {
|
|
||||||
this->messageIndexMap.insert(this->messages.at(i).toMap().value(ID).toString(), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChatModel::isMostRecentMessageLoaded()
|
bool ChatModel::isMostRecentMessageLoaded()
|
||||||
{
|
{
|
||||||
// Need to check if we can actually add messages (only possible if the previously latest messages are loaded)
|
// Need to check if we can actually add messages (only possible if the previously latest messages are loaded)
|
||||||
|
|
|
@ -26,15 +26,16 @@
|
||||||
class ChatModel : public QAbstractListModel
|
class ChatModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(qlonglong chatId READ getChatId NOTIFY chatIdChanged)
|
||||||
Q_PROPERTY(QVariantMap smallPhoto READ smallPhoto NOTIFY smallPhotoChanged)
|
Q_PROPERTY(QVariantMap smallPhoto READ smallPhoto NOTIFY smallPhotoChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChatModel(TDLibWrapper *tdLibWrapper);
|
ChatModel(TDLibWrapper *tdLibWrapper);
|
||||||
~ChatModel() override;
|
~ChatModel() override;
|
||||||
|
|
||||||
|
virtual QHash<int,QByteArray> roleNames() const override;
|
||||||
virtual int rowCount(const QModelIndex&) const override;
|
virtual int rowCount(const QModelIndex&) const override;
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
virtual QVariant data(const QModelIndex &index, int role) const override;
|
||||||
virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
|
|
||||||
|
|
||||||
Q_INVOKABLE void clear();
|
Q_INVOKABLE void clear();
|
||||||
Q_INVOKABLE void initialize(const QVariantMap &chatInformation);
|
Q_INVOKABLE void initialize(const QVariantMap &chatInformation);
|
||||||
|
@ -55,38 +56,41 @@ signals:
|
||||||
void lastReadSentMessageUpdated(int lastReadSentIndex);
|
void lastReadSentMessageUpdated(int lastReadSentIndex);
|
||||||
void notificationSettingsUpdated();
|
void notificationSettingsUpdated();
|
||||||
void messageUpdated(int modelIndex);
|
void messageUpdated(int modelIndex);
|
||||||
void messagesDeleted();
|
|
||||||
void smallPhotoChanged();
|
void smallPhotoChanged();
|
||||||
|
void chatIdChanged();
|
||||||
void pinnedMessageChanged();
|
void pinnedMessageChanged();
|
||||||
|
|
||||||
public slots:
|
private slots:
|
||||||
void handleMessagesReceived(const QVariantList &messages, int totalCount);
|
void handleMessagesReceived(const QVariantList &messages, int totalCount);
|
||||||
void handleNewMessageReceived(const QString &chatId, const QVariantMap &message);
|
void handleNewMessageReceived(qlonglong chatId, const QVariantMap &message);
|
||||||
void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount);
|
void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount);
|
||||||
void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
|
void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
|
||||||
void handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message);
|
void handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message);
|
||||||
void handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings);
|
void handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings);
|
||||||
void handleChatPhotoUpdated(qlonglong chatId, const QVariantMap &photo);
|
void handleChatPhotoUpdated(qlonglong chatId, const QVariantMap &photo);
|
||||||
void handleChatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId);
|
void handleChatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId);
|
||||||
void handleMessageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent);
|
void handleMessageContentUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &newContent);
|
||||||
void handleMessagesDeleted(const QString &chatId, const QVariantList &messageIds);
|
void handleMessagesDeleted(qlonglong chatId, const QList<qlonglong> &messageIds);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class MessageData;
|
||||||
|
void removeRange(int firstDeleted, int lastDeleted);
|
||||||
|
void insertMessages(const QList<MessageData*> newMessages);
|
||||||
|
void appendMessages(const QList<MessageData*> newMessages);
|
||||||
|
void prependMessages(const QList<MessageData*> newMessages);
|
||||||
|
QVariantMap enhanceMessage(const QVariantMap &message);
|
||||||
|
int calculateLastKnownMessageId();
|
||||||
|
int calculateLastReadSentMessageId();
|
||||||
|
bool isMostRecentMessageLoaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TDLibWrapper *tdLibWrapper;
|
TDLibWrapper *tdLibWrapper;
|
||||||
QVariantList messages;
|
QList<MessageData*> messages;
|
||||||
QVariantList messagesToBeAdded;
|
QHash<qlonglong,int> messageIndexMap;
|
||||||
QVariantMap messageIndexMap;
|
|
||||||
QVariantMap chatInformation;
|
QVariantMap chatInformation;
|
||||||
qlonglong chatId;
|
qlonglong chatId;
|
||||||
bool inReload;
|
bool inReload;
|
||||||
bool inIncrementalUpdate;
|
bool inIncrementalUpdate;
|
||||||
|
|
||||||
void insertMessages();
|
|
||||||
QVariantMap enhanceMessage(const QVariantMap &message);
|
|
||||||
int calculateLastKnownMessageId();
|
|
||||||
int calculateLastReadSentMessageId();
|
|
||||||
void calculateMessageIndexMap();
|
|
||||||
bool isMostRecentMessageLoaded();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CHATMODEL_H
|
#endif // CHATMODEL_H
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace {
|
||||||
const QString LIST("list");
|
const QString LIST("list");
|
||||||
const QString CHAT_ID("chat_id");
|
const QString CHAT_ID("chat_id");
|
||||||
const QString USER_ID("user_id");
|
const QString USER_ID("user_id");
|
||||||
|
const QString OLD_MESSAGE_ID("old_message_id");
|
||||||
const QString MESSAGE_ID("message_id");
|
const QString MESSAGE_ID("message_id");
|
||||||
const QString MESSAGE_IDS("message_ids");
|
const QString MESSAGE_IDS("message_ids");
|
||||||
const QString MESSAGE("message");
|
const QString MESSAGE("message");
|
||||||
|
@ -334,8 +335,8 @@ void TDLibReceiver::processMessages(const QVariantMap &receivedInformation)
|
||||||
void TDLibReceiver::processUpdateNewMessage(const QVariantMap &receivedInformation)
|
void TDLibReceiver::processUpdateNewMessage(const QVariantMap &receivedInformation)
|
||||||
{
|
{
|
||||||
const QVariantMap message = receivedInformation.value(MESSAGE).toMap();
|
const QVariantMap message = receivedInformation.value(MESSAGE).toMap();
|
||||||
const QString chatId = message.value(CHAT_ID).toString();
|
const qlonglong chatId = message.value(CHAT_ID).toLongLong();
|
||||||
LOG("Received new message for chat " << chatId);
|
LOG("Received new message for chat" << chatId);
|
||||||
emit newMessageReceived(chatId, message);
|
emit newMessageReceived(chatId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,10 +350,10 @@ void TDLibReceiver::processMessage(const QVariantMap &receivedInformation)
|
||||||
|
|
||||||
void TDLibReceiver::processMessageSendSucceeded(const QVariantMap &receivedInformation)
|
void TDLibReceiver::processMessageSendSucceeded(const QVariantMap &receivedInformation)
|
||||||
{
|
{
|
||||||
const QString oldMessageId = receivedInformation.value("old_message_id").toString();
|
const qlonglong oldMessageId = receivedInformation.value(OLD_MESSAGE_ID).toLongLong();
|
||||||
const QVariantMap message = receivedInformation.value(MESSAGE).toMap();
|
const QVariantMap message = receivedInformation.value(MESSAGE).toMap();
|
||||||
const QString messageId = message.value(ID).toString();
|
const qlonglong messageId = message.value(ID).toLongLong();
|
||||||
LOG("Message send succeeded " << messageId << oldMessageId);
|
LOG("Message send succeeded" << messageId << oldMessageId);
|
||||||
emit messageSendSucceeded(messageId, oldMessageId, message);
|
emit messageSendSucceeded(messageId, oldMessageId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,18 +384,24 @@ void TDLibReceiver::processUpdateChatNotificationSettings(const QVariantMap &rec
|
||||||
|
|
||||||
void TDLibReceiver::processUpdateMessageContent(const QVariantMap &receivedInformation)
|
void TDLibReceiver::processUpdateMessageContent(const QVariantMap &receivedInformation)
|
||||||
{
|
{
|
||||||
const QString chatId = receivedInformation.value(CHAT_ID).toString();
|
const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong();
|
||||||
const QString messageId = receivedInformation.value(MESSAGE_ID).toString();
|
const qlonglong messageId = receivedInformation.value(MESSAGE_ID).toLongLong();
|
||||||
LOG("Message content updated " << chatId << messageId);
|
LOG("Message content updated" << chatId << messageId);
|
||||||
emit messageContentUpdated(chatId, messageId, receivedInformation.value("new_content").toMap());
|
emit messageContentUpdated(chatId, messageId, receivedInformation.value("new_content").toMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TDLibReceiver::processUpdateDeleteMessages(const QVariantMap &receivedInformation)
|
void TDLibReceiver::processUpdateDeleteMessages(const QVariantMap &receivedInformation)
|
||||||
{
|
{
|
||||||
const QString chatId = receivedInformation.value(CHAT_ID).toString();
|
const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong();
|
||||||
const QVariantList messageIds = receivedInformation.value(MESSAGE_IDS).toList();
|
const QVariantList messageIds = receivedInformation.value(MESSAGE_IDS).toList();
|
||||||
LOG("Some messages were deleted " << chatId);
|
QList<qlonglong> ids;
|
||||||
emit messagesDeleted(chatId, messageIds);
|
const int n = messageIds.size();
|
||||||
|
ids.reserve(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ids.append(messageIds.at(i).toLongLong());
|
||||||
|
}
|
||||||
|
LOG(n << "messages were deleted from chat" << chatId);
|
||||||
|
emit messagesDeleted(chatId, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TDLibReceiver::processChats(const QVariantMap &receivedInformation)
|
void TDLibReceiver::processChats(const QVariantMap &receivedInformation)
|
||||||
|
|
|
@ -55,15 +55,15 @@ signals:
|
||||||
void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
|
void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
|
||||||
void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount);
|
void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount);
|
||||||
void messagesReceived(const QVariantList &messages, int totalCount);
|
void messagesReceived(const QVariantList &messages, int totalCount);
|
||||||
void newMessageReceived(const QString &chatId, const QVariantMap &message);
|
void newMessageReceived(qlonglong chatId, const QVariantMap &message);
|
||||||
void messageInformation(const QString &messageId, const QVariantMap &message);
|
void messageInformation(const QString &messageId, const QVariantMap &message);
|
||||||
void messageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message);
|
void messageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message);
|
||||||
void activeNotificationsUpdated(const QVariantList notificationGroups);
|
void activeNotificationsUpdated(const QVariantList notificationGroups);
|
||||||
void notificationGroupUpdated(const QVariantMap notificationGroupUpdate);
|
void notificationGroupUpdated(const QVariantMap notificationGroupUpdate);
|
||||||
void notificationUpdated(const QVariantMap updatedNotification);
|
void notificationUpdated(const QVariantMap updatedNotification);
|
||||||
void chatNotificationSettingsUpdated(const QString &chatId, const QVariantMap updatedChatNotificationSettings);
|
void chatNotificationSettingsUpdated(const QString &chatId, const QVariantMap updatedChatNotificationSettings);
|
||||||
void messageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent);
|
void messageContentUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &newContent);
|
||||||
void messagesDeleted(const QString &chatId, const QVariantList &messageIds);
|
void messagesDeleted(qlonglong chatId, const QList<qlonglong> &messageIds);
|
||||||
void chats(const QVariantMap &chats);
|
void chats(const QVariantMap &chats);
|
||||||
void chat(const QVariantMap &chats);
|
void chat(const QVariantMap &chats);
|
||||||
void recentStickersUpdated(const QVariantList &stickerIds);
|
void recentStickersUpdated(const QVariantList &stickerIds);
|
||||||
|
|
|
@ -88,15 +88,15 @@ TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface,
|
||||||
connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SIGNAL(chatOnlineMemberCountUpdated(QString, int)));
|
connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SIGNAL(chatOnlineMemberCountUpdated(QString, int)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SIGNAL(messagesReceived(QVariantList, int)));
|
connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SIGNAL(messagesReceived(QVariantList, int)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SIGNAL(newMessageReceived(QString, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(newMessageReceived(qlonglong, QVariantMap)), this, SIGNAL(newMessageReceived(qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(messageInformation(QString, QVariantMap)), this, SIGNAL(receivedMessage(QString, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(messageInformation(QString, QVariantMap)), this, SIGNAL(receivedMessage(QString, QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SIGNAL(activeNotificationsUpdated(QVariantList)));
|
connect(this->tdLibReceiver, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SIGNAL(activeNotificationsUpdated(QVariantList)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SIGNAL(notificationGroupUpdated(QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SIGNAL(notificationGroupUpdated(QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(notificationUpdated(QVariantMap)), this, SIGNAL(notificationUpdated(QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(notificationUpdated(QVariantMap)), this, SIGNAL(notificationUpdated(QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)), this, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(messageContentUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageContentUpdated(qlonglong, qlonglong, QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(messagesDeleted(QString, QVariantList)), this, SIGNAL(messagesDeleted(QString, QVariantList)));
|
connect(this->tdLibReceiver, SIGNAL(messagesDeleted(qlonglong, QList<qlonglong>)), this, SIGNAL(messagesDeleted(qlonglong, QList<qlonglong>)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(chats(QVariantMap)), this, SIGNAL(chatsReceived(QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(chats(QVariantMap)), this, SIGNAL(chatsReceived(QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(chat(QVariantMap)), this, SLOT(handleChatReceived(QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(chat(QVariantMap)), this, SLOT(handleChatReceived(QVariantMap)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(secretChat(qlonglong, QVariantMap)), this, SLOT(handleSecretChatReceived(qlonglong, QVariantMap)));
|
connect(this->tdLibReceiver, SIGNAL(secretChat(qlonglong, QVariantMap)), this, SLOT(handleSecretChatReceived(qlonglong, QVariantMap)));
|
||||||
|
|
|
@ -208,17 +208,17 @@ signals:
|
||||||
void superGroupUpdated(qlonglong groupId);
|
void superGroupUpdated(qlonglong groupId);
|
||||||
void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount);
|
void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount);
|
||||||
void messagesReceived(const QVariantList &messages, int totalCount);
|
void messagesReceived(const QVariantList &messages, int totalCount);
|
||||||
void newMessageReceived(const QString &chatId, const QVariantMap &message);
|
void newMessageReceived(qlonglong chatId, const QVariantMap &message);
|
||||||
void copyToDownloadsSuccessful(const QString &fileName, const QString &filePath);
|
void copyToDownloadsSuccessful(const QString &fileName, const QString &filePath);
|
||||||
void copyToDownloadsError(const QString &fileName, const QString &filePath);
|
void copyToDownloadsError(const QString &fileName, const QString &filePath);
|
||||||
void receivedMessage(const QString &messageId, const QVariantMap &message);
|
void receivedMessage(const QString &messageId, const QVariantMap &message);
|
||||||
void messageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message);
|
void messageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message);
|
||||||
void activeNotificationsUpdated(const QVariantList notificationGroups);
|
void activeNotificationsUpdated(const QVariantList notificationGroups);
|
||||||
void notificationGroupUpdated(const QVariantMap notificationGroupUpdate);
|
void notificationGroupUpdated(const QVariantMap notificationGroupUpdate);
|
||||||
void notificationUpdated(const QVariantMap updatedNotification);
|
void notificationUpdated(const QVariantMap updatedNotification);
|
||||||
void chatNotificationSettingsUpdated(const QString &chatId, const QVariantMap chatNotificationSettings);
|
void chatNotificationSettingsUpdated(const QString &chatId, const QVariantMap chatNotificationSettings);
|
||||||
void messageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent);
|
void messageContentUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &newContent);
|
||||||
void messagesDeleted(const QString &chatId, const QVariantList &messageIds);
|
void messagesDeleted(qlonglong chatId, const QList<qlonglong> &messageIds);
|
||||||
void chatsReceived(const QVariantMap &chats);
|
void chatsReceived(const QVariantMap &chats);
|
||||||
void chatReceived(const QVariantMap &chat);
|
void chatReceived(const QVariantMap &chat);
|
||||||
void secretChatReceived(qlonglong secretChatId, const QVariantMap &secretChat);
|
void secretChatReceived(qlonglong secretChatId, const QVariantMap &secretChat);
|
||||||
|
|
Loading…
Reference in a new issue