Don't show irrelevant groups by default

chatListModel.showAllChats property can be used to switch visibility
of irrelevant groups on and off.
This commit is contained in:
Slava Monich 2020-10-04 04:27:49 +03:00
parent 1b261c224f
commit 56bc1135a7
6 changed files with 470 additions and 150 deletions

View file

@ -27,6 +27,7 @@ namespace {
const QString ID("id"); const QString ID("id");
const QString DATE("date"); const QString DATE("date");
const QString TEXT("text"); const QString TEXT("text");
const QString TYPE("type");
const QString TITLE("title"); const QString TITLE("title");
const QString PHOTO("photo"); const QString PHOTO("photo");
const QString SMALL("small"); const QString SMALL("small");
@ -35,6 +36,8 @@ namespace {
const QString CONTENT("content"); const QString CONTENT("content");
const QString LAST_MESSAGE("last_message"); const QString LAST_MESSAGE("last_message");
const QString SENDER_USER_ID("sender_user_id"); const QString SENDER_USER_ID("sender_user_id");
const QString BASIC_GROUP_ID("basic_group_id");
const QString SUPERGROUP_ID("supergroup_id");
const QString UNREAD_COUNT("unread_count"); const QString UNREAD_COUNT("unread_count");
const QString NOTIFICATION_SETTINGS("notification_settings"); const QString NOTIFICATION_SETTINGS("notification_settings");
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
@ -42,8 +45,12 @@ namespace {
const QString TYPE_MAP("type"); const QString TYPE_MAP("type");
const QString IS_CHANNEL("is_channel"); const QString IS_CHANNEL("is_channel");
const QString TYPE("@type"); const QString _TYPE("@type");
const QString TYPE_MESSAGE_TEXT("messageText"); const QString TYPE_MESSAGE_TEXT("messageText");
const QString TYPE_CHAT_TYPE_PRIVATE("chatTypePrivate");
const QString TYPE_CHAT_TYPE_BASIC_GROUP("chatTypeBasicGroup");
const QString TYPE_CHAT_TYPE_SUPERGROUP("chatTypeSupergroup");
const QString TYPE_CHAT_TYPE_SECRET("chatTypeSecret");
} }
class ChatListModel::ChatData class ChatListModel::ChatData
@ -52,6 +59,7 @@ public:
enum Role { enum Role {
RoleDisplay = Qt::DisplayRole, RoleDisplay = Qt::DisplayRole,
RoleChatId, RoleChatId,
RoleChatType,
RoleTitle, RoleTitle,
RolePhotoSmall, RolePhotoSmall,
RoleUnreadCount, RoleUnreadCount,
@ -59,6 +67,7 @@ public:
RoleLastMessageSenderId, RoleLastMessageSenderId,
RoleLastMessageDate, RoleLastMessageDate,
RoleLastMessageText, RoleLastMessageText,
RoleChatMemberStatus,
RoleIsChannel RoleIsChannel
}; };
@ -75,29 +84,50 @@ public:
qlonglong senderMessageDate() const; qlonglong senderMessageDate() const;
QString senderMessageText() const; QString senderMessageText() const;
bool isChannel() const; bool isChannel() const;
bool isHidden() const;
bool updateUnreadCount(int unreadCount); bool updateUnreadCount(int unreadCount);
bool updateLastReadInboxMessageId(qlonglong messageId); bool updateLastReadInboxMessageId(qlonglong messageId);
QVector<int> updateLastMessage(const QVariantMap &message); QVector<int> updateLastMessage(const QVariantMap &message);
QVector<int> updateGroup(const TDLibWrapper::Group *group);
static TDLibWrapper::ChatType chatTypeFromString(const QString &type);
public: public:
QVariantMap chatData; QVariantMap chatData;
QString chatId; qlonglong chatId;
qlonglong order; qlonglong order;
qlonglong groupId;
TDLibWrapper::ChatType chatType;
TDLibWrapper::ChatMemberStatus memberStatus;
QVariantMap userInformation; QVariantMap userInformation;
}; };
ChatListModel::ChatData::ChatData(const QVariantMap &data, const QVariantMap &userInformation) : ChatListModel::ChatData::ChatData(const QVariantMap &data, const QVariantMap &userInfo) :
chatData(data), chatData(data),
chatId(data.value(ID).toString()), chatId(data.value(ID).toLongLong()),
order(data.value(ORDER).toLongLong()) order(data.value(ORDER).toLongLong()),
groupId(0),
memberStatus(TDLibWrapper::ChatMemberStatusUnknown),
userInformation(userInfo)
{ {
this->userInformation = userInformation; const QVariantMap type(data.value(TYPE).toMap());
switch (chatType = chatTypeFromString(type.value(_TYPE).toString())) {
case TDLibWrapper::ChatTypeBasicGroup:
groupId = type.value(BASIC_GROUP_ID).toLongLong();
break;
case TDLibWrapper::ChatTypeSupergroup:
groupId = type.value(SUPERGROUP_ID).toLongLong();
break;
case TDLibWrapper::ChatTypeUnknown:
case TDLibWrapper::ChatTypePrivate:
case TDLibWrapper::ChatTypeSecret:
break;
}
} }
int ChatListModel::ChatData::compareTo(const ChatData *other) const int ChatListModel::ChatData::compareTo(const ChatData *other) const
{ {
if (order == other->order) { if (order == other->order) {
return chatId.compare(other->chatId); return (chatId < other->chatId) ? 1 : -1;
} else { } else {
// This puts most recent ones to the top of the list // This puts most recent ones to the top of the list
return (order < other->order) ? 1 : -1; return (order < other->order) ? 1 : -1;
@ -159,6 +189,32 @@ bool ChatListModel::ChatData::isChannel() const
return chatData.value(TYPE_MAP).toMap().value(IS_CHANNEL).toBool(); return chatData.value(TYPE_MAP).toMap().value(IS_CHANNEL).toBool();
} }
bool ChatListModel::ChatData::isHidden() const
{
// Cover all enum values so that compiler warns us when/if enum gets extended
switch (chatType) {
case TDLibWrapper::ChatTypeBasicGroup:
case TDLibWrapper::ChatTypeSupergroup:
switch (memberStatus) {
case TDLibWrapper::ChatMemberStatusLeft:
case TDLibWrapper::ChatMemberStatusUnknown:
return true;
case TDLibWrapper::ChatMemberStatusCreator:
case TDLibWrapper::ChatMemberStatusAdministrator:
case TDLibWrapper::ChatMemberStatusMember:
case TDLibWrapper::ChatMemberStatusRestricted:
case TDLibWrapper::ChatMemberStatusBanned:
break;
}
break;
case TDLibWrapper::ChatTypeUnknown:
case TDLibWrapper::ChatTypePrivate:
case TDLibWrapper::ChatTypeSecret:
break;
}
return false;
}
bool ChatListModel::ChatData::updateUnreadCount(int count) bool ChatListModel::ChatData::updateUnreadCount(int count)
{ {
const int prevUnreadCount(unreadCount()); const int prevUnreadCount(unreadCount());
@ -195,7 +251,30 @@ QVector<int> ChatListModel::ChatData::updateLastMessage(const QVariantMap &messa
return changedRoles; return changedRoles;
} }
ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper) QVector<int> ChatListModel::ChatData::updateGroup(const TDLibWrapper::Group *group)
{
QVector<int> changedRoles;
if (group && groupId == group->groupId) {
const TDLibWrapper::ChatMemberStatus groupMemberStatus = group->chatMemberStatus();
if (memberStatus != groupMemberStatus) {
memberStatus = groupMemberStatus;
changedRoles.append(RoleChatMemberStatus);
}
}
return changedRoles;
}
TDLibWrapper::ChatType ChatListModel::ChatData::chatTypeFromString(const QString &type)
{
return (type == TYPE_CHAT_TYPE_PRIVATE) ? TDLibWrapper::ChatTypePrivate :
(type == TYPE_CHAT_TYPE_BASIC_GROUP) ? TDLibWrapper::ChatTypeBasicGroup :
(type == TYPE_CHAT_TYPE_SUPERGROUP) ? TDLibWrapper::ChatTypeSupergroup :
(type == TYPE_CHAT_TYPE_SECRET) ? TDLibWrapper::ChatTypeSecret :
TDLibWrapper::ChatTypeUnknown;
}
ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper) : showHiddenChats(false)
{ {
this->tdLibWrapper = tdLibWrapper; this->tdLibWrapper = tdLibWrapper;
connect(tdLibWrapper, SIGNAL(newChatDiscovered(QString, QVariantMap)), this, SLOT(handleChatDiscovered(QString, QVariantMap))); connect(tdLibWrapper, SIGNAL(newChatDiscovered(QString, QVariantMap)), this, SLOT(handleChatDiscovered(QString, QVariantMap)));
@ -205,6 +284,8 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper)
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(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, QVariantMap))); connect(tdLibWrapper, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, 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(basicGroupUpdated(qlonglong)), this, SLOT(handleGroupUpdated(qlonglong)));
// Don't start the timer until we have at least one chat // Don't start the timer until we have at least one chat
relativeTimeRefreshTimer = new QTimer(this); relativeTimeRefreshTimer = new QTimer(this);
@ -217,6 +298,7 @@ ChatListModel::~ChatListModel()
{ {
LOG("Destroying myself..."); LOG("Destroying myself...");
qDeleteAll(chatList); qDeleteAll(chatList);
qDeleteAll(hiddenChats.values());
} }
QHash<int,QByteArray> ChatListModel::roleNames() const QHash<int,QByteArray> ChatListModel::roleNames() const
@ -224,6 +306,7 @@ QHash<int,QByteArray> ChatListModel::roleNames() const
QHash<int,QByteArray> roles; QHash<int,QByteArray> roles;
roles.insert(ChatData::RoleDisplay, "display"); roles.insert(ChatData::RoleDisplay, "display");
roles.insert(ChatData::RoleChatId, "chat_id"); roles.insert(ChatData::RoleChatId, "chat_id");
roles.insert(ChatData::RoleChatType, "chat_type");
roles.insert(ChatData::RoleTitle, "title"); roles.insert(ChatData::RoleTitle, "title");
roles.insert(ChatData::RolePhotoSmall, "photo_small"); roles.insert(ChatData::RolePhotoSmall, "photo_small");
roles.insert(ChatData::RoleUnreadCount, "unread_count"); roles.insert(ChatData::RoleUnreadCount, "unread_count");
@ -231,6 +314,7 @@ QHash<int,QByteArray> ChatListModel::roleNames() const
roles.insert(ChatData::RoleLastMessageSenderId, "last_message_sender_id"); roles.insert(ChatData::RoleLastMessageSenderId, "last_message_sender_id");
roles.insert(ChatData::RoleLastMessageDate, "last_message_date"); roles.insert(ChatData::RoleLastMessageDate, "last_message_date");
roles.insert(ChatData::RoleLastMessageText, "last_message_text"); roles.insert(ChatData::RoleLastMessageText, "last_message_text");
roles.insert(ChatData::RoleChatMemberStatus, "chat_member_status");
roles.insert(ChatData::RoleIsChannel, "is_channel"); roles.insert(ChatData::RoleIsChannel, "is_channel");
return roles; return roles;
} }
@ -248,6 +332,7 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const
switch ((ChatData::Role)role) { switch ((ChatData::Role)role) {
case ChatData::RoleDisplay: return data->chatData; case ChatData::RoleDisplay: return data->chatData;
case ChatData::RoleChatId: return data->chatId; case ChatData::RoleChatId: return data->chatId;
case ChatData::RoleChatType: return data->chatType;
case ChatData::RoleTitle: return data->title(); case ChatData::RoleTitle: return data->title();
case ChatData::RolePhotoSmall: return data->photoSmall(); case ChatData::RolePhotoSmall: return data->photoSmall();
case ChatData::RoleUnreadCount: return data->unreadCount(); case ChatData::RoleUnreadCount: return data->unreadCount();
@ -255,6 +340,7 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const
case ChatData::RoleLastMessageSenderId: return data->senderUserId(); case ChatData::RoleLastMessageSenderId: return data->senderUserId();
case ChatData::RoleLastMessageText: return data->senderMessageText(); case ChatData::RoleLastMessageText: return data->senderMessageText();
case ChatData::RoleLastMessageDate: return data->senderMessageDate(); case ChatData::RoleLastMessageDate: return data->senderMessageDate();
case ChatData::RoleChatMemberStatus: return data->memberStatus;
case ChatData::RoleIsChannel: return data->isChannel(); case ChatData::RoleIsChannel: return data->isChannel();
} }
} }
@ -307,30 +393,98 @@ int ChatListModel::updateChatOrder(int chatIndex)
return newIndex; return newIndex;
} }
void ChatListModel::handleChatDiscovered(const QString &chatId, const QVariantMap &chatToBeAdded) void ChatListModel::addVisibleChat(ChatData *chat)
{ {
ChatData *chat = new ChatData(chatToBeAdded, tdLibWrapper->getUserInformation());
const int n = chatList.size(); const int n = chatList.size();
int chatIndex; int pos;
for (chatIndex = 0; chatIndex < n && chat->compareTo(chatList.at(chatIndex)) >= 0; chatIndex++); for (pos = 0; pos < n && chat->compareTo(chatList.at(pos)) >= 0; pos++);
LOG("Adding new chat" << chatId << "at" << chatIndex); LOG("Adding chat" << chat->chatId << "at" << pos);
beginInsertRows(QModelIndex(), chatIndex, chatIndex); beginInsertRows(QModelIndex(), pos, pos);
chatList.insert(chatIndex, chat); chatList.insert(pos, chat);
chatIndexMap.insert(chat->chatId, chatIndex); chatIndexMap.insert(chat->chatId, pos);
// Update damaged part of the map // Update damaged part of the map
for (int i = chatIndex + 1; i <= n; i++) { for (int i = pos + 1; i <= n; i++) {
chatIndexMap.insert(chatList.at(i)->chatId, i); chatIndexMap.insert(chatList.at(i)->chatId, i);
} }
endInsertRows(); endInsertRows();
}
// Start timestamp refresh timer when the first chat is discovered void ChatListModel::updateChatVisibility(const TDLibWrapper::Group *group)
{
// See if any group has been removed from from view
for (int i = 0; i < chatList.size(); i++) {
ChatData *chat = chatList.at(i);
const QVector<int> changedRoles(chat->updateGroup(group));
if (chat->isHidden() && !showHiddenChats) {
LOG("Hiding chat" << chat->chatId << "at" << i);
beginRemoveRows(QModelIndex(), i, i);
chatList.removeAt(i);
// Update damaged part of the map
const int n = chatList.size();
for (int pos = i; pos < n; pos++) {
chatIndexMap.insert(chatList.at(pos)->chatId, pos);
}
i--;
hiddenChats.insert(chat->chatId, chat);
endRemoveRows();
} else if (!changedRoles.isEmpty()) {
const QModelIndex modelIndex(index(i));
emit dataChanged(modelIndex, modelIndex, changedRoles);
}
}
// And see if any group been added to the view
const QList<ChatData*> hiddenChatList = hiddenChats.values();
const int n = hiddenChatList.size();
for (int j = 0; j < n; j++) {
ChatData *chat = hiddenChatList.at(j);
chat->updateGroup(group);
if (!chat->isHidden() || showHiddenChats) {
hiddenChats.remove(chat->chatId);
addVisibleChat(chat);
}
}
}
bool ChatListModel::showAllChats() const
{
return showHiddenChats;
}
void ChatListModel::setShowAllChats(bool showAll)
{
if (showHiddenChats != showAll) {
showHiddenChats = showAll;
updateChatVisibility(Q_NULLPTR);
emit showAllChatsChanged();
}
}
void ChatListModel::handleChatDiscovered(const QString &, const QVariantMap &chatToBeAdded)
{
ChatData *chat = new ChatData(chatToBeAdded, tdLibWrapper->getUserInformation());
const TDLibWrapper::Group *group = tdLibWrapper->getGroup(chat->groupId);
if (group) {
chat->updateGroup(group);
}
if (chat->isHidden()) {
LOG("Hidden chat" << chat->chatId);
hiddenChats.insert(chat->chatId, chat);
} else {
addVisibleChat(chat);
// Start timestamp refresh timer when the first visible chat is discovered
if (!relativeTimeRefreshTimer->isActive()) { if (!relativeTimeRefreshTimer->isActive()) {
relativeTimeRefreshTimer->start(); relativeTimeRefreshTimer->start();
} }
} }
}
void ChatListModel::handleChatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage) void ChatListModel::handleChatLastMessageUpdated(const QString &id, const QString &order, const QVariantMap &lastMessage)
{ {
bool ok;
const qlonglong chatId = id.toLongLong(&ok);
if (ok) {
if (chatIndexMap.contains(chatId)) { if (chatIndexMap.contains(chatId)) {
int chatIndex = chatIndexMap.value(chatId); int chatIndex = chatIndexMap.value(chatId);
LOG("Updating last message for chat" << chatId <<" at index" << chatIndex << "new order" << order); LOG("Updating last message for chat" << chatId <<" at index" << chatIndex << "new order" << order);
@ -340,22 +494,44 @@ void ChatListModel::handleChatLastMessageUpdated(const QString &chatId, const QS
} }
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, chat->updateLastMessage(lastMessage)); emit dataChanged(modelIndex, modelIndex, chat->updateLastMessage(lastMessage));
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
LOG("Updating last message for hidden chat" << chatId << "new order" << order);
chat->setOrder(order);
chat->chatData.insert(LAST_MESSAGE, lastMessage);
}
}
} }
} }
void ChatListModel::handleChatOrderUpdated(const QString &chatId, const QString &order) void ChatListModel::handleChatOrderUpdated(const QString &id, const QString &order)
{ {
bool ok;
const qlonglong chatId = id.toLongLong(&ok);
if (ok) {
if (chatIndexMap.contains(chatId)) { if (chatIndexMap.contains(chatId)) {
LOG("Updating chat order of" << chatId << "to" << order); LOG("Updating chat order of" << chatId << "to" << order);
int chatIndex = chatIndexMap.value(chatId); int chatIndex = chatIndexMap.value(chatId);
if (chatList.at(chatIndex)->setOrder(order)) { if (chatList.at(chatIndex)->setOrder(order)) {
updateChatOrder(chatIndex); updateChatOrder(chatIndex);
} }
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
LOG("Updating order of hidden chat" << chatId << "to" << order);
chat->setOrder(order);
}
}
} }
} }
void ChatListModel::handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount) void ChatListModel::handleChatReadInboxUpdated(const QString &id, const QString &lastReadInboxMessageId, int unreadCount)
{ {
bool ok;
const qlonglong chatId = id.toLongLong(&ok);
if (ok) {
const qlonglong messageId = lastReadInboxMessageId.toLongLong();
if (chatIndexMap.contains(chatId)) { if (chatIndexMap.contains(chatId)) {
LOG("Updating chat unread count for" << chatId << "unread messages" << unreadCount << ", last read message ID: " << lastReadInboxMessageId); LOG("Updating chat unread count for" << chatId << "unread messages" << unreadCount << ", last read message ID: " << lastReadInboxMessageId);
const int chatIndex = chatIndexMap.value(chatId); const int chatIndex = chatIndexMap.value(chatId);
@ -365,16 +541,27 @@ void ChatListModel::handleChatReadInboxUpdated(const QString &chatId, const QStr
if (chat->updateUnreadCount(unreadCount)) { if (chat->updateUnreadCount(unreadCount)) {
changedRoles.append(ChatData::RoleUnreadCount); changedRoles.append(ChatData::RoleUnreadCount);
} }
if (chat->updateLastReadInboxMessageId(lastReadInboxMessageId.toLongLong())) { if (chat->updateLastReadInboxMessageId(messageId)) {
changedRoles.append(ChatData::RoleLastReadInboxMessageId); changedRoles.append(ChatData::RoleLastReadInboxMessageId);
} }
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, changedRoles); emit dataChanged(modelIndex, modelIndex, changedRoles);
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
LOG("Updating unread count for hidden chat" << chatId << "unread messages" << unreadCount << ", last read message ID: " << lastReadInboxMessageId);
chat->updateUnreadCount(unreadCount);
chat->updateLastReadInboxMessageId(messageId);
}
}
} }
} }
void ChatListModel::handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId) void ChatListModel::handleChatReadOutboxUpdated(const QString &id, const QString &lastReadOutboxMessageId)
{ {
bool ok;
const qlonglong chatId = id.toLongLong(&ok);
if (ok) {
if (chatIndexMap.contains(chatId)) { if (chatIndexMap.contains(chatId)) {
LOG("Updating last read message for" << chatId << "last ID" << lastReadOutboxMessageId); LOG("Updating last read message for" << chatId << "last ID" << lastReadOutboxMessageId);
const int chatIndex = chatIndexMap.value(chatId); const int chatIndex = chatIndexMap.value(chatId);
@ -382,22 +569,40 @@ void ChatListModel::handleChatReadOutboxUpdated(const QString &chatId, const QSt
chat->chatData.insert(LAST_READ_OUTBOX_MESSAGE_ID, lastReadOutboxMessageId); chat->chatData.insert(LAST_READ_OUTBOX_MESSAGE_ID, lastReadOutboxMessageId);
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex); emit dataChanged(modelIndex, modelIndex);
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
chat->chatData.insert(LAST_READ_OUTBOX_MESSAGE_ID, lastReadOutboxMessageId);
}
}
} }
} }
void ChatListModel::handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message) void ChatListModel::handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message)
{ {
const QString chatId(message.value(CHAT_ID).toString()); bool ok;
const qlonglong chatId(message.value(CHAT_ID).toLongLong(&ok));
if (ok) {
if (chatIndexMap.contains(chatId)) { if (chatIndexMap.contains(chatId)) {
const int chatIndex = chatIndexMap.value(chatId); const int chatIndex = chatIndexMap.value(chatId);
LOG("Updating last message for chat" << chatId << "at index" << chatIndex << ", as message was sent, old ID:" << oldMessageId << ", new ID:" << messageId); LOG("Updating last message for chat" << chatId << "at index" << chatIndex << ", as message was sent, old ID:" << oldMessageId << ", new ID:" << messageId);
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, chatList.at(chatIndex)->updateLastMessage(message)); emit dataChanged(modelIndex, modelIndex, chatList.at(chatIndex)->updateLastMessage(message));
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
LOG("Updating last message for hidden chat" << chatId << ", as message was sent, old ID:" << oldMessageId << ", new ID:" << messageId);
chat->chatData.insert(LAST_MESSAGE, message);
}
}
} }
} }
void ChatListModel::handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings) void ChatListModel::handleChatNotificationSettingsUpdated(const QString &id, const QVariantMap &chatNotificationSettings)
{ {
bool ok;
const qlonglong chatId = id.toLongLong(&ok);
if (ok) {
if (chatIndexMap.contains(chatId)) { if (chatIndexMap.contains(chatId)) {
const int chatIndex = chatIndexMap.value(chatId); const int chatIndex = chatIndexMap.value(chatId);
LOG("Updating notification settings for chat" << chatId << "at index" << chatIndex); LOG("Updating notification settings for chat" << chatId << "at index" << chatIndex);
@ -405,8 +610,19 @@ void ChatListModel::handleChatNotificationSettingsUpdated(const QString &chatId,
chat->chatData.insert(NOTIFICATION_SETTINGS, chatNotificationSettings); chat->chatData.insert(NOTIFICATION_SETTINGS, chatNotificationSettings);
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex); emit dataChanged(modelIndex, modelIndex);
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
chat->chatData.insert(NOTIFICATION_SETTINGS, chatNotificationSettings);
} }
} }
}
}
void ChatListModel::handleGroupUpdated(qlonglong groupId)
{
updateChatVisibility(tdLibWrapper->getGroup(groupId));
}
void ChatListModel::handleRelativeTimeRefreshTimer() void ChatListModel::handleRelativeTimeRefreshTimer()
{ {

View file

@ -26,6 +26,8 @@
class ChatListModel : public QAbstractListModel class ChatListModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool showAllChats READ showAllChats WRITE setShowAllChats NOTIFY showAllChatsChanged)
public: public:
ChatListModel(TDLibWrapper *tdLibWrapper); ChatListModel(TDLibWrapper *tdLibWrapper);
~ChatListModel() override; ~ChatListModel() override;
@ -36,6 +38,9 @@ public:
Q_INVOKABLE void redrawModel(); Q_INVOKABLE void redrawModel();
bool showAllChats() const;
void setShowAllChats(bool showAll);
private slots: private slots:
void handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation); void handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation);
void handleChatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage); void handleChatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage);
@ -44,18 +49,25 @@ private slots:
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(const QString &messageId, const QString &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 handleRelativeTimeRefreshTimer(); void handleRelativeTimeRefreshTimer();
private: signals:
int updateChatOrder(int chatIndex); void showAllChatsChanged();
private: private:
class ChatData; class ChatData;
void addVisibleChat(ChatData *chat);
void updateChatVisibility(const TDLibWrapper::Group *group);
int updateChatOrder(int chatIndex);
private:
TDLibWrapper *tdLibWrapper; TDLibWrapper *tdLibWrapper;
QTimer *relativeTimeRefreshTimer; QTimer *relativeTimeRefreshTimer;
QList<ChatData*> chatList; QList<ChatData*> chatList;
QHash<QString,int> chatIndexMap; QHash<qlonglong,int> chatIndexMap;
QHash<qlonglong,ChatData*> hiddenChats;
bool showHiddenChats;
}; };
#endif // CHATLISTMODEL_H #endif // CHATLISTMODEL_H

View file

@ -27,6 +27,8 @@ namespace {
const QString POSITION("position"); const QString POSITION("position");
const QString POSITIONS("positions"); const QString POSITIONS("positions");
const QString ORDER("order"); const QString ORDER("order");
const QString BASIC_GROUP("basic_group");
const QString SUPERGROUP("supergroup");
const QString LAST_MESSAGE("last_message"); const QString LAST_MESSAGE("last_message");
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");
@ -264,16 +266,18 @@ void TDLibReceiver::processUpdateChatReadOutbox(const QVariantMap &receivedInfor
void TDLibReceiver::processUpdateBasicGroup(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateBasicGroup(const QVariantMap &receivedInformation)
{ {
QString basicGroupId = receivedInformation.value("basic_group").toMap().value(ID).toString(); const QVariantMap basicGroup(receivedInformation.value(BASIC_GROUP).toMap());
const qlonglong basicGroupId = basicGroup.value(ID).toLongLong();
LOG("Basic group information updated for " << basicGroupId); LOG("Basic group information updated for " << basicGroupId);
emit basicGroupUpdated(basicGroupId, receivedInformation.value("basic_group").toMap()); emit basicGroupUpdated(basicGroupId, basicGroup);
} }
void TDLibReceiver::processUpdateSuperGroup(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateSuperGroup(const QVariantMap &receivedInformation)
{ {
QString superGroupId = receivedInformation.value("supergroup").toMap().value(ID).toString(); const QVariantMap supergroup(receivedInformation.value(SUPERGROUP).toMap());
const qlonglong superGroupId = supergroup.value(ID).toLongLong();
LOG("Super group information updated for " << superGroupId); LOG("Super group information updated for " << superGroupId);
emit superGroupUpdated(superGroupId, receivedInformation.value("supergroup").toMap()); emit superGroupUpdated(superGroupId, supergroup);
} }
void TDLibReceiver::processChatOnlineMemberCountUpdated(const QVariantMap &receivedInformation) void TDLibReceiver::processChatOnlineMemberCountUpdated(const QVariantMap &receivedInformation)

View file

@ -50,8 +50,8 @@ signals:
void chatOrderUpdated(const QString &chatId, const QString &order); void chatOrderUpdated(const QString &chatId, const QString &order);
void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount);
void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
void basicGroupUpdated(const QString &groupId, const QVariantMap &groupInformation); void basicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void superGroupUpdated(const QString &groupId, const QVariantMap &groupInformation); void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount);
void messagesReceived(const QVariantList &messages); void messagesReceived(const QVariantList &messages);
void newMessageReceived(const QString &chatId, const QVariantMap &message); void newMessageReceived(const QString &chatId, const QVariantMap &message);

View file

@ -38,6 +38,11 @@
# define VERBOSE(x) # define VERBOSE(x)
#endif #endif
namespace {
const QString STATUS("status");
const QString _TYPE("@type");
}
TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent), settings("harbour-fernschreiber", "settings") TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent), settings("harbour-fernschreiber", "settings")
{ {
LOG("Initializing TD Lib..."); LOG("Initializing TD Lib...");
@ -67,8 +72,8 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent), settings("harbour
connect(this->tdLibReceiver, SIGNAL(chatOrderUpdated(QString, QString)), this, SLOT(handleChatOrderUpdated(QString, QString))); connect(this->tdLibReceiver, SIGNAL(chatOrderUpdated(QString, QString)), this, SLOT(handleChatOrderUpdated(QString, QString)));
connect(this->tdLibReceiver, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int))); connect(this->tdLibReceiver, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int)));
connect(this->tdLibReceiver, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString))); connect(this->tdLibReceiver, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
connect(this->tdLibReceiver, SIGNAL(basicGroupUpdated(QString, QVariantMap)), this, SLOT(handleBasicGroupUpdated(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(basicGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleBasicGroupUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(QString, QVariantMap)), this, SLOT(handleSuperGroupUpdated(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SLOT(handleChatOnlineMemberCountUpdated(QString, int))); connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SLOT(handleChatOnlineMemberCountUpdated(QString, int)));
connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList)), this, SLOT(handleMessagesReceived(QVariantList))); connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList)), this, SLOT(handleMessagesReceived(QVariantList)));
connect(this->tdLibReceiver, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap)));
@ -94,12 +99,14 @@ TDLibWrapper::~TDLibWrapper()
while (this->tdLibReceiver->isRunning()) { while (this->tdLibReceiver->isRunning()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
} }
qDeleteAll(basicGroups.values());
qDeleteAll(superGroups.values());
td_json_client_destroy(this->tdLibClient); td_json_client_destroy(this->tdLibClient);
} }
void TDLibWrapper::sendRequest(const QVariantMap &requestObject) void TDLibWrapper::sendRequest(const QVariantMap &requestObject)
{ {
LOG("Sending request to TD Lib, object type name:" << requestObject.value("@type").toString()); LOG("Sending request to TD Lib, object type name:" << requestObject.value(_TYPE).toString());
QJsonDocument requestDocument = QJsonDocument::fromVariant(requestObject); QJsonDocument requestDocument = QJsonDocument::fromVariant(requestObject);
VERBOSE(requestDocument.toJson().constData()); VERBOSE(requestDocument.toJson().constData());
td_json_client_send(this->tdLibClient, requestDocument.toJson().constData()); td_json_client_send(this->tdLibClient, requestDocument.toJson().constData());
@ -124,7 +131,7 @@ void TDLibWrapper::setAuthenticationPhoneNumber(const QString &phoneNumber)
{ {
LOG("Set authentication phone number " << phoneNumber); LOG("Set authentication phone number " << phoneNumber);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "setAuthenticationPhoneNumber"); requestObject.insert(_TYPE, "setAuthenticationPhoneNumber");
requestObject.insert("phone_number", phoneNumber); requestObject.insert("phone_number", phoneNumber);
QVariantMap phoneNumberSettings; QVariantMap phoneNumberSettings;
phoneNumberSettings.insert("allow_flash_call", false); phoneNumberSettings.insert("allow_flash_call", false);
@ -137,7 +144,7 @@ void TDLibWrapper::setAuthenticationCode(const QString &authenticationCode)
{ {
LOG("Set authentication code " << authenticationCode); LOG("Set authentication code " << authenticationCode);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "checkAuthenticationCode"); requestObject.insert(_TYPE, "checkAuthenticationCode");
requestObject.insert("code", authenticationCode); requestObject.insert("code", authenticationCode);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -146,7 +153,7 @@ void TDLibWrapper::setAuthenticationPassword(const QString &authenticationPasswo
{ {
LOG("Set authentication password " << authenticationPassword); LOG("Set authentication password " << authenticationPassword);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "checkAuthenticationPassword"); requestObject.insert(_TYPE, "checkAuthenticationPassword");
requestObject.insert("password", authenticationPassword); requestObject.insert("password", authenticationPassword);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -155,7 +162,7 @@ void TDLibWrapper::getChats()
{ {
LOG("Getting chats"); LOG("Getting chats");
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "getChats"); requestObject.insert(_TYPE, "getChats");
requestObject.insert("limit", 5); requestObject.insert("limit", 5);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -164,7 +171,7 @@ void TDLibWrapper::downloadFile(const QString &fileId)
{ {
LOG("Downloading file " << fileId); LOG("Downloading file " << fileId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "downloadFile"); requestObject.insert(_TYPE, "downloadFile");
requestObject.insert("file_id", fileId); requestObject.insert("file_id", fileId);
requestObject.insert("synchronous", false); requestObject.insert("synchronous", false);
requestObject.insert("offset", 0); requestObject.insert("offset", 0);
@ -177,7 +184,7 @@ void TDLibWrapper::openChat(const QString &chatId)
{ {
LOG("Opening chat " << chatId); LOG("Opening chat " << chatId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "openChat"); requestObject.insert(_TYPE, "openChat");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -186,7 +193,7 @@ void TDLibWrapper::closeChat(const QString &chatId)
{ {
LOG("Closing chat " << chatId); LOG("Closing chat " << chatId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "closeChat"); requestObject.insert(_TYPE, "closeChat");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -195,7 +202,7 @@ void TDLibWrapper::getChatHistory(const QString &chatId, const qlonglong &fromMe
{ {
LOG("Retrieving chat history" << chatId << fromMessageId << offset << limit << onlyLocal); LOG("Retrieving chat history" << chatId << fromMessageId << offset << limit << onlyLocal);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "getChatHistory"); requestObject.insert(_TYPE, "getChatHistory");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("from_message_id", fromMessageId); requestObject.insert("from_message_id", fromMessageId);
requestObject.insert("offset", offset); requestObject.insert("offset", offset);
@ -208,7 +215,7 @@ void TDLibWrapper::viewMessage(const QString &chatId, const QString &messageId)
{ {
LOG("Mark message as viewed" << chatId << messageId); LOG("Mark message as viewed" << chatId << messageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "viewMessages"); requestObject.insert(_TYPE, "viewMessages");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("force_read", false); requestObject.insert("force_read", false);
QVariantList messageIds; QVariantList messageIds;
@ -221,16 +228,16 @@ void TDLibWrapper::sendTextMessage(const QString &chatId, const QString &message
{ {
LOG("Sending text message" << chatId << message << replyToMessageId); LOG("Sending text message" << chatId << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "sendMessage"); requestObject.insert(_TYPE, "sendMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
if (replyToMessageId != "0") { if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId); requestObject.insert("reply_to_message_id", replyToMessageId);
} }
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert("@type", "inputMessageText"); inputMessageContent.insert(_TYPE, "inputMessageText");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert("@type", "formattedText"); formattedText.insert(_TYPE, "formattedText");
inputMessageContent.insert("text", formattedText); inputMessageContent.insert("text", formattedText);
requestObject.insert("input_message_content", inputMessageContent); requestObject.insert("input_message_content", inputMessageContent);
this->sendRequest(requestObject); this->sendRequest(requestObject);
@ -240,19 +247,19 @@ void TDLibWrapper::sendPhotoMessage(const QString &chatId, const QString &filePa
{ {
LOG("Sending photo message" << chatId << filePath << message << replyToMessageId); LOG("Sending photo message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "sendMessage"); requestObject.insert(_TYPE, "sendMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
if (replyToMessageId != "0") { if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId); requestObject.insert("reply_to_message_id", replyToMessageId);
} }
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert("@type", "inputMessagePhoto"); inputMessageContent.insert(_TYPE, "inputMessagePhoto");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert("@type", "formattedText"); formattedText.insert(_TYPE, "formattedText");
inputMessageContent.insert("caption", formattedText); inputMessageContent.insert("caption", formattedText);
QVariantMap photoInputFile; QVariantMap photoInputFile;
photoInputFile.insert("@type", "inputFileLocal"); photoInputFile.insert(_TYPE, "inputFileLocal");
photoInputFile.insert("path", filePath); photoInputFile.insert("path", filePath);
inputMessageContent.insert("photo", photoInputFile); inputMessageContent.insert("photo", photoInputFile);
@ -264,19 +271,19 @@ void TDLibWrapper::sendVideoMessage(const QString &chatId, const QString &filePa
{ {
LOG("Sending video message" << chatId << filePath << message << replyToMessageId); LOG("Sending video message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "sendMessage"); requestObject.insert(_TYPE, "sendMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
if (replyToMessageId != "0") { if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId); requestObject.insert("reply_to_message_id", replyToMessageId);
} }
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert("@type", "inputMessageVideo"); inputMessageContent.insert(_TYPE, "inputMessageVideo");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert("@type", "formattedText"); formattedText.insert(_TYPE, "formattedText");
inputMessageContent.insert("caption", formattedText); inputMessageContent.insert("caption", formattedText);
QVariantMap videoInputFile; QVariantMap videoInputFile;
videoInputFile.insert("@type", "inputFileLocal"); videoInputFile.insert(_TYPE, "inputFileLocal");
videoInputFile.insert("path", filePath); videoInputFile.insert("path", filePath);
inputMessageContent.insert("video", videoInputFile); inputMessageContent.insert("video", videoInputFile);
@ -288,19 +295,19 @@ void TDLibWrapper::sendDocumentMessage(const QString &chatId, const QString &fil
{ {
LOG("Sending document message" << chatId << filePath << message << replyToMessageId); LOG("Sending document message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "sendMessage"); requestObject.insert(_TYPE, "sendMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
if (replyToMessageId != "0") { if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId); requestObject.insert("reply_to_message_id", replyToMessageId);
} }
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert("@type", "inputMessageDocument"); inputMessageContent.insert(_TYPE, "inputMessageDocument");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert("@type", "formattedText"); formattedText.insert(_TYPE, "formattedText");
inputMessageContent.insert("caption", formattedText); inputMessageContent.insert("caption", formattedText);
QVariantMap documentInputFile; QVariantMap documentInputFile;
documentInputFile.insert("@type", "inputFileLocal"); documentInputFile.insert(_TYPE, "inputFileLocal");
documentInputFile.insert("path", filePath); documentInputFile.insert("path", filePath);
inputMessageContent.insert("document", documentInputFile); inputMessageContent.insert("document", documentInputFile);
@ -312,7 +319,7 @@ void TDLibWrapper::getMessage(const QString &chatId, const QString &messageId)
{ {
LOG("Retrieving message" << chatId << messageId); LOG("Retrieving message" << chatId << messageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "getMessage"); requestObject.insert(_TYPE, "getMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("message_id", messageId); requestObject.insert("message_id", messageId);
this->sendRequest(requestObject); this->sendRequest(requestObject);
@ -322,10 +329,10 @@ void TDLibWrapper::setOptionInteger(const QString &optionName, const int &option
{ {
LOG("Setting integer option" << optionName << optionValue); LOG("Setting integer option" << optionName << optionValue);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "setOption"); requestObject.insert(_TYPE, "setOption");
requestObject.insert("name", optionName); requestObject.insert("name", optionName);
QVariantMap optionValueMap; QVariantMap optionValueMap;
optionValueMap.insert("@type", "optionValueInteger"); optionValueMap.insert(_TYPE, "optionValueInteger");
optionValueMap.insert("value", optionValue); optionValueMap.insert("value", optionValue);
requestObject.insert("value", optionValueMap); requestObject.insert("value", optionValueMap);
this->sendRequest(requestObject); this->sendRequest(requestObject);
@ -335,7 +342,7 @@ void TDLibWrapper::setChatNotificationSettings(const QString &chatId, const QVar
{ {
LOG("Notification settings for chat " << chatId << notificationSettings); LOG("Notification settings for chat " << chatId << notificationSettings);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "setChatNotificationSettings"); requestObject.insert(_TYPE, "setChatNotificationSettings");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("notification_settings", notificationSettings); requestObject.insert("notification_settings", notificationSettings);
this->sendRequest(requestObject); this->sendRequest(requestObject);
@ -345,11 +352,11 @@ void TDLibWrapper::editMessageText(const QString &chatId, const QString &message
{ {
LOG("Editing message text" << chatId << messageId); LOG("Editing message text" << chatId << messageId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "editMessageText"); requestObject.insert(_TYPE, "editMessageText");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("message_id", messageId); requestObject.insert("message_id", messageId);
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert("@type", "inputMessageText"); inputMessageContent.insert(_TYPE, "inputMessageText");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
inputMessageContent.insert("text", formattedText); inputMessageContent.insert("text", formattedText);
@ -361,7 +368,7 @@ void TDLibWrapper::deleteMessages(const QString &chatId, const QVariantList mess
{ {
LOG("Deleting some messages" << chatId << messageIds); LOG("Deleting some messages" << chatId << messageIds);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "deleteMessages"); requestObject.insert(_TYPE, "deleteMessages");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("message_ids", messageIds); requestObject.insert("message_ids", messageIds);
requestObject.insert("revoke", true); requestObject.insert("revoke", true);
@ -380,7 +387,7 @@ void TDLibWrapper::getMapThumbnailFile(const QString &chatId, const double &lati
int boundsHeight = std::min(std::max(height, 16), 1024); int boundsHeight = std::min(std::max(height, 16), 1024);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "getMapThumbnailFile"); requestObject.insert(_TYPE, "getMapThumbnailFile");
requestObject.insert("location", location); requestObject.insert("location", location);
requestObject.insert("zoom", 17); //13-20 requestObject.insert("zoom", 17); //13-20
requestObject.insert("width", boundsWidth); requestObject.insert("width", boundsWidth);
@ -412,16 +419,28 @@ QVariantMap TDLibWrapper::getUnreadChatInformation()
return this->unreadChatInformation; return this->unreadChatInformation;
} }
QVariantMap TDLibWrapper::getBasicGroup(const QString &groupId) QVariantMap TDLibWrapper::getBasicGroup(qlonglong groupId) const
{ {
const Group* group = basicGroups.value(groupId);
if (group) {
LOG("Returning basic group information for ID" << groupId); LOG("Returning basic group information for ID" << groupId);
return this->basicGroups.value(groupId).toMap(); return group->groupInfo;
} else {
LOG("No super group information for ID" << groupId);
return QVariantMap();
}
} }
QVariantMap TDLibWrapper::getSuperGroup(const QString &groupId) QVariantMap TDLibWrapper::getSuperGroup(qlonglong groupId) const
{ {
const Group* group = superGroups.value(groupId);
if (group) {
LOG("Returning super group information for ID" << groupId); LOG("Returning super group information for ID" << groupId);
return this->superGroups.value(groupId).toMap(); return group->groupInfo;
} else {
LOG("No super group information for ID" << groupId);
return QVariantMap();
}
} }
QVariantMap TDLibWrapper::getChat(const QString &chatId) QVariantMap TDLibWrapper::getChat(const QString &chatId)
@ -595,7 +614,7 @@ void TDLibWrapper::handleUserStatusUpdated(const QString &userId, const QVariant
LOG("Own user status information updated :)"); LOG("Own user status information updated :)");
this->userInformation.insert("status", userStatusInformation); this->userInformation.insert("status", userStatusInformation);
} }
LOG("User status information updated:" << userId << userStatusInformation.value("@type").toString()); LOG("User status information updated:" << userId << userStatusInformation.value(_TYPE).toString());
QVariantMap updatedUserInformation = this->allUsers.value(userId).toMap(); QVariantMap updatedUserInformation = this->allUsers.value(userId).toMap();
updatedUserInformation.insert("status", userStatusInformation); updatedUserInformation.insert("status", userStatusInformation);
this->allUsers.insert(userId, updatedUserInformation); this->allUsers.insert(userId, updatedUserInformation);
@ -650,16 +669,14 @@ void TDLibWrapper::handleChatReadOutboxUpdated(const QString &chatId, const QStr
emit chatReadOutboxUpdated(chatId, lastReadOutboxMessageId); emit chatReadOutboxUpdated(chatId, lastReadOutboxMessageId);
} }
void TDLibWrapper::handleBasicGroupUpdated(const QString &groupId, const QVariantMap &groupInformation) void TDLibWrapper::handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation)
{ {
this->basicGroups.insert(groupId, groupInformation); emit basicGroupUpdated(updateGroup(groupId, groupInformation, &basicGroups)->groupId);
emit basicGroupUpdated(groupId, groupInformation);
} }
void TDLibWrapper::handleSuperGroupUpdated(const QString &groupId, const QVariantMap &groupInformation) void TDLibWrapper::handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation)
{ {
this->superGroups.insert(groupId, groupInformation); emit superGroupUpdated(updateGroup(groupId, groupInformation, &superGroups)->groupId);
emit superGroupUpdated(groupId, groupInformation);
} }
void TDLibWrapper::handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount) void TDLibWrapper::handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount)
@ -721,7 +738,7 @@ void TDLibWrapper::setInitialParameters()
{ {
LOG("Sending initial parameters to TD Lib"); LOG("Sending initial parameters to TD Lib");
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "setTdlibParameters"); requestObject.insert(_TYPE, "setTdlibParameters");
QVariantMap initialParameters; QVariantMap initialParameters;
initialParameters.insert("api_id", TDLIB_API_ID); initialParameters.insert("api_id", TDLIB_API_ID);
initialParameters.insert("api_hash", TDLIB_API_HASH); initialParameters.insert("api_hash", TDLIB_API_HASH);
@ -743,7 +760,7 @@ void TDLibWrapper::setEncryptionKey()
{ {
LOG("Setting database encryption key"); LOG("Setting database encryption key");
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "checkDatabaseEncryptionKey"); requestObject.insert(_TYPE, "checkDatabaseEncryptionKey");
// see https://github.com/tdlib/td/issues/188#issuecomment-379536139 // see https://github.com/tdlib/td/issues/188#issuecomment-379536139
requestObject.insert("encryption_key", ""); requestObject.insert("encryption_key", "");
this->sendRequest(requestObject); this->sendRequest(requestObject);
@ -753,7 +770,7 @@ void TDLibWrapper::setLogVerbosityLevel()
{ {
LOG("Setting log verbosity level to something less chatty"); LOG("Setting log verbosity level to something less chatty");
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "setLogVerbosityLevel"); requestObject.insert(_TYPE, "setLogVerbosityLevel");
requestObject.insert("new_verbosity_level", 2); requestObject.insert("new_verbosity_level", 2);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -784,3 +801,40 @@ void TDLibWrapper::initializeOpenWith()
} }
} }
const TDLibWrapper::Group *TDLibWrapper::updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups)
{
Group* group = groups->value(groupId);
if (!group) {
group = new Group(groupId);
groups->insert(groupId, group);
}
group->groupInfo = groupInfo;
return group;
}
const TDLibWrapper::Group* TDLibWrapper::getGroup(qlonglong groupId) const
{
if (groupId) {
const Group* group = superGroups.value(groupId);
return group ? group : basicGroups.value(groupId);
}
return Q_NULLPTR;
}
TDLibWrapper::ChatMemberStatus TDLibWrapper::chatMemberStatusFromString(const QString &status)
{
// Most common ones first
return (status == QStringLiteral("chatMemberStatusMember")) ? ChatMemberStatusMember :
(status == QStringLiteral("chatMemberStatusLeft")) ? ChatMemberStatusLeft :
(status == QStringLiteral("chatMemberStatusCreator")) ? ChatMemberStatusCreator :
(status == QStringLiteral("chatMemberStatusAdministrator")) ? ChatMemberStatusAdministrator :
(status == QStringLiteral("chatMemberStatusRestricted")) ? ChatMemberStatusRestricted :
(status == QStringLiteral("chatMemberStatusBanned")) ? ChatMemberStatusBanned :
ChatMemberStatusUnknown;
}
TDLibWrapper::ChatMemberStatus TDLibWrapper::Group::chatMemberStatus() const
{
const QString statusType(groupInfo.value(STATUS).toMap().value(_TYPE).toString());
return statusType.isEmpty() ? ChatMemberStatusUnknown : chatMemberStatusFromString(statusType);
}

View file

@ -61,6 +61,35 @@ public:
}; };
Q_ENUM(ConnectionState) Q_ENUM(ConnectionState)
enum ChatType {
ChatTypeUnknown,
ChatTypePrivate,
ChatTypeBasicGroup,
ChatTypeSupergroup,
ChatTypeSecret
};
Q_ENUM(ChatType)
enum ChatMemberStatus {
ChatMemberStatusUnknown,
ChatMemberStatusCreator,
ChatMemberStatusAdministrator,
ChatMemberStatusMember,
ChatMemberStatusRestricted,
ChatMemberStatusLeft,
ChatMemberStatusBanned
};
Q_ENUM(ChatMemberStatus)
class Group {
public:
Group(qlonglong id) : groupId(id) { }
ChatMemberStatus chatMemberStatus() const;
public:
const qlonglong groupId;
QVariantMap groupInfo;
};
Q_INVOKABLE QString getVersion(); Q_INVOKABLE QString getVersion();
Q_INVOKABLE TDLibWrapper::AuthorizationState getAuthorizationState(); Q_INVOKABLE TDLibWrapper::AuthorizationState getAuthorizationState();
Q_INVOKABLE TDLibWrapper::ConnectionState getConnectionState(); Q_INVOKABLE TDLibWrapper::ConnectionState getConnectionState();
@ -68,8 +97,8 @@ public:
Q_INVOKABLE QVariantMap getUserInformation(const QString &userId); Q_INVOKABLE QVariantMap getUserInformation(const QString &userId);
Q_INVOKABLE QVariantMap getUnreadMessageInformation(); Q_INVOKABLE QVariantMap getUnreadMessageInformation();
Q_INVOKABLE QVariantMap getUnreadChatInformation(); Q_INVOKABLE QVariantMap getUnreadChatInformation();
Q_INVOKABLE QVariantMap getBasicGroup(const QString &groupId); Q_INVOKABLE QVariantMap getBasicGroup(qlonglong groupId) const;
Q_INVOKABLE QVariantMap getSuperGroup(const QString &groupId); Q_INVOKABLE QVariantMap getSuperGroup(qlonglong groupId) const;
Q_INVOKABLE QVariantMap getChat(const QString &chatId); Q_INVOKABLE QVariantMap getChat(const QString &chatId);
Q_INVOKABLE void copyFileToDownloads(const QString &filePath); Q_INVOKABLE void copyFileToDownloads(const QString &filePath);
Q_INVOKABLE void openFileOnDevice(const QString &filePath); Q_INVOKABLE void openFileOnDevice(const QString &filePath);
@ -101,6 +130,10 @@ public:
Q_INVOKABLE void deleteMessages(const QString &chatId, const QVariantList messageIds); Q_INVOKABLE void deleteMessages(const QString &chatId, const QVariantList messageIds);
Q_INVOKABLE void getMapThumbnailFile(const QString &chatId, const double &latitude, const double &longitude, const int &width, const int &height); Q_INVOKABLE void getMapThumbnailFile(const QString &chatId, const double &latitude, const double &longitude, const int &width, const int &height);
public:
const Group* getGroup(qlonglong groupId) const;
static ChatMemberStatus chatMemberStatusFromString(const QString &status);
signals: signals:
void versionDetected(const QString &version); void versionDetected(const QString &version);
void ownUserIdFound(const QString &ownUserId); void ownUserIdFound(const QString &ownUserId);
@ -116,8 +149,8 @@ signals:
void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount);
void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
void userUpdated(const QString &userId, const QVariantMap &userInformation); void userUpdated(const QString &userId, const QVariantMap &userInformation);
void basicGroupUpdated(const QString &groupId, const QVariantMap &groupInformation); void basicGroupUpdated(qlonglong groupId);
void superGroupUpdated(const QString &groupId, const QVariantMap &groupInformation); void superGroupUpdated(qlonglong groupId);
void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount);
void messagesReceived(const QVariantList &messages); void messagesReceived(const QVariantList &messages);
void newMessageReceived(const QString &chatId, const QVariantMap &message); void newMessageReceived(const QString &chatId, const QVariantMap &message);
@ -147,8 +180,8 @@ public slots:
void handleChatOrderUpdated(const QString &chatId, const QString &order); void handleChatOrderUpdated(const QString &chatId, const QString &order);
void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount);
void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
void handleBasicGroupUpdated(const QString &groupId, const QVariantMap &groupInformation); void handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void handleSuperGroupUpdated(const QString &groupId, const QVariantMap &groupInformation); void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); void handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount);
void handleMessagesReceived(const QVariantList &messages); void handleMessagesReceived(const QVariantList &messages);
void handleNewMessageReceived(const QString &chatId, const QVariantMap &message); void handleNewMessageReceived(const QString &chatId, const QVariantMap &message);
@ -161,6 +194,13 @@ public slots:
void handleMessageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent); void handleMessageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent);
void handleMessagesDeleted(const QString &chatId, const QVariantList &messageIds); void handleMessagesDeleted(const QString &chatId, const QVariantList &messageIds);
private:
void setInitialParameters();
void setEncryptionKey();
void setLogVerbosityLevel();
void initializeOpenWith();
const Group *updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups);
private: private:
void *tdLibClient; void *tdLibClient;
TDLibReceiver *tdLibReceiver; TDLibReceiver *tdLibReceiver;
@ -174,15 +214,9 @@ private:
QVariantMap chats; QVariantMap chats;
QVariantMap unreadMessageInformation; QVariantMap unreadMessageInformation;
QVariantMap unreadChatInformation; QVariantMap unreadChatInformation;
QVariantMap basicGroups; QHash<qlonglong,Group*> basicGroups;
QVariantMap superGroups; QHash<qlonglong,Group*> superGroups;
QSettings settings; QSettings settings;
void setInitialParameters();
void setEncryptionKey();
void setLogVerbosityLevel();
void initializeOpenWith();
}; };
#endif // TDLIBWRAPPER_H #endif // TDLIBWRAPPER_H