2020-09-02 23:49:15 +03:00
/*
Copyright ( C ) 2020 Sebastian J . Wolf
This file is part of Fernschreiber .
Fernschreiber is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Fernschreiber is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Fernschreiber . If not , see < http : //www.gnu.org/licenses/>.
*/
2020-08-19 10:55:13 +03:00
# include "chatlistmodel.h"
2020-08-20 01:24:24 +03:00
# include <QListIterator>
2020-09-02 23:49:15 +03:00
# include <QDebug>
2020-08-19 10:55:13 +03:00
ChatListModel : : ChatListModel ( TDLibWrapper * tdLibWrapper )
{
this - > tdLibWrapper = tdLibWrapper ;
2020-08-20 19:45:56 +03:00
this - > deltaUpdates = false ;
2020-08-19 10:55:13 +03:00
connect ( this - > tdLibWrapper , SIGNAL ( newChatDiscovered ( QString , QVariantMap ) ) , this , SLOT ( handleChatDiscovered ( QString , QVariantMap ) ) ) ;
2020-08-20 15:58:32 +03:00
connect ( this - > tdLibWrapper , SIGNAL ( chatLastMessageUpdated ( QString , QString , QVariantMap ) ) , this , SLOT ( handleChatLastMessageUpdated ( QString , QString , QVariantMap ) ) ) ;
2020-08-20 11:50:47 +03:00
connect ( this - > tdLibWrapper , SIGNAL ( chatOrderUpdated ( QString , QString ) ) , this , SLOT ( handleChatOrderUpdated ( QString , QString ) ) ) ;
2020-08-31 22:51:52 +03:00
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 ( messageSendSucceeded ( QString , QString , QVariantMap ) ) , this , SLOT ( handleMessageSendSucceeded ( QString , QString , QVariantMap ) ) ) ;
2020-08-19 10:55:13 +03:00
}
ChatListModel : : ~ ChatListModel ( )
{
2020-09-02 23:49:15 +03:00
qDebug ( ) < < " [ChatListModel] Destroying myself... " ;
2020-08-19 10:55:13 +03:00
}
int ChatListModel : : rowCount ( const QModelIndex & ) const
{
return chatList . size ( ) ;
}
QVariant ChatListModel : : data ( const QModelIndex & index , int role ) const
{
if ( index . isValid ( ) & & role = = Qt : : DisplayRole ) {
return QVariant ( chatList . value ( index . row ( ) ) ) ;
}
return QVariant ( ) ;
}
bool ChatListModel : : insertRows ( int row , int count , const QModelIndex & parent )
{
qDebug ( ) < < " [ChatListModel] Inserting at " < < row < < " , row count: " < < count ;
beginInsertRows ( parent , rowCount ( QModelIndex ( ) ) , rowCount ( QModelIndex ( ) ) + count - 1 ) ;
this - > chatList . append ( this - > chatToBeAdded ) ;
2020-08-20 01:24:24 +03:00
this - > chatIndexMap . insert ( this - > chatToBeAdded . value ( " id " ) . toString ( ) , row ) ;
2020-08-19 10:55:13 +03:00
endInsertRows ( ) ;
return true ;
}
2020-08-20 21:06:59 +03:00
void ChatListModel : : enableDeltaUpdates ( )
2020-08-20 19:45:56 +03:00
{
2020-08-20 21:06:59 +03:00
qDebug ( ) < < " [ChatListModel] Enabling delta updates and enforcing UI redraw... " ;
2020-08-20 19:45:56 +03:00
layoutChanged ( ) ;
this - > deltaUpdates = true ;
}
2020-08-20 11:50:47 +03:00
bool compareChats ( const QVariant & chat1 , const QVariant & chat2 )
{
QVariantMap chatMap1 = chat1 . toMap ( ) ;
QVariantMap chatMap2 = chat2 . toMap ( ) ;
// Order comes first...
if ( chatMap1 . value ( " order " ) . toLongLong ( ) > chatMap2 . value ( " order " ) . toLongLong ( ) ) {
return true ;
}
// ID comes next...
if ( chatMap1 . value ( " order " ) . toLongLong ( ) = = chatMap2 . value ( " order " ) . toLongLong ( ) & & chatMap1 . value ( " id " ) . toLongLong ( ) > chatMap2 . value ( " id " ) . toLongLong ( ) ) {
return true ;
} else {
return false ;
}
}
2020-08-19 10:55:13 +03:00
void ChatListModel : : handleChatDiscovered ( const QString & chatId , const QVariantMap & chatInformation )
{
2020-08-20 11:50:47 +03:00
this - > chatListMutex . lock ( ) ;
2020-08-19 10:55:13 +03:00
qDebug ( ) < < " [ChatListModel] Adding new chat " < < chatId ;
this - > chatToBeAdded = chatInformation ;
insertRows ( rowCount ( QModelIndex ( ) ) , 1 ) ;
2020-08-20 11:50:47 +03:00
this - > chatListMutex . unlock ( ) ;
2020-08-19 10:55:13 +03:00
}
2020-08-20 01:24:24 +03:00
2020-08-20 18:06:47 +03:00
2020-08-20 15:58:32 +03:00
void ChatListModel : : handleChatLastMessageUpdated ( const QString & chatId , const QString & order , const QVariantMap & lastMessage )
2020-08-20 01:24:24 +03:00
{
2020-08-20 11:50:47 +03:00
this - > chatListMutex . lock ( ) ;
2020-08-20 01:24:24 +03:00
int chatIndex = this - > chatIndexMap . value ( chatId ) . toInt ( ) ;
qDebug ( ) < < " [ChatListModel] Updating last message for chat " < < chatId < < " at index " < < chatIndex ;
QVariantMap currentChat = this - > chatList . value ( chatIndex ) . toMap ( ) ;
currentChat . insert ( " last_message " , lastMessage ) ;
2020-08-20 15:58:32 +03:00
currentChat . insert ( " order " , order ) ;
2020-08-20 01:24:24 +03:00
this - > chatList . replace ( chatIndex , currentChat ) ;
emit dataChanged ( this - > index ( chatIndex ) , this - > index ( chatIndex ) ) ;
2020-08-20 18:06:47 +03:00
this - > updateChatOrder ( chatIndex , currentChat ) ;
2020-08-21 10:29:19 +03:00
emit chatChanged ( chatId ) ;
2020-08-20 18:06:47 +03:00
2020-08-20 11:50:47 +03:00
this - > chatListMutex . unlock ( ) ;
2020-08-20 01:24:24 +03:00
}
void ChatListModel : : handleChatOrderUpdated ( const QString & chatId , const QString & order )
{
2020-08-20 11:50:47 +03:00
this - > chatListMutex . lock ( ) ;
qDebug ( ) < < " [ChatListModel] Updating chat order because of " < < chatId < < " new order " < < order ;
2020-08-20 18:06:47 +03:00
int chatIndex = this - > chatIndexMap . value ( chatId ) . toInt ( ) ;
QVariantMap currentChat = this - > chatList . at ( chatIndex ) . toMap ( ) ;
2020-08-20 11:50:47 +03:00
currentChat . insert ( " order " , order ) ;
2020-08-20 18:06:47 +03:00
this - > chatList . replace ( chatIndex , currentChat ) ;
emit dataChanged ( this - > index ( chatIndex ) , this - > index ( chatIndex ) ) ;
this - > updateChatOrder ( chatIndex , currentChat ) ;
2020-08-21 10:29:19 +03:00
emit chatChanged ( chatId ) ;
2020-08-20 18:06:47 +03:00
2020-08-20 11:50:47 +03:00
this - > chatListMutex . unlock ( ) ;
2020-08-20 01:24:24 +03:00
}
2020-08-20 18:06:47 +03:00
2020-08-31 22:51:52 +03:00
void ChatListModel : : handleChatReadInboxUpdated ( const QString & chatId , const QString & lastReadInboxMessageId , const int & unreadCount )
2020-08-21 00:56:21 +03:00
{
this - > chatListMutex . lock ( ) ;
2020-08-31 22:51:52 +03:00
qDebug ( ) < < " [ChatListModel] Updating chat unread count for " < < chatId < < " unread messages " < < unreadCount < < " , last read message ID: " < < lastReadInboxMessageId ;
2020-08-21 00:56:21 +03:00
int chatIndex = this - > chatIndexMap . value ( chatId ) . toInt ( ) ;
QVariantMap currentChat = this - > chatList . at ( chatIndex ) . toMap ( ) ;
currentChat . insert ( " unread_count " , unreadCount ) ;
2020-08-31 22:51:52 +03:00
currentChat . insert ( " last_read_inbox_message_id " , lastReadInboxMessageId ) ;
2020-08-21 00:56:21 +03:00
this - > chatList . replace ( chatIndex , currentChat ) ;
emit dataChanged ( this - > index ( chatIndex ) , this - > index ( chatIndex ) ) ;
2020-08-21 10:29:19 +03:00
emit chatChanged ( chatId ) ;
2020-08-21 00:56:21 +03:00
this - > chatListMutex . unlock ( ) ;
}
2020-08-31 22:51:52 +03:00
void ChatListModel : : handleChatReadOutboxUpdated ( const QString & chatId , const QString & lastReadOutboxMessageId )
{
this - > chatListMutex . lock ( ) ;
qDebug ( ) < < " [ChatListModel] Updating last read message for " < < chatId < < " last ID " < < lastReadOutboxMessageId ;
int chatIndex = this - > chatIndexMap . value ( chatId ) . toInt ( ) ;
QVariantMap currentChat = this - > chatList . at ( chatIndex ) . toMap ( ) ;
currentChat . insert ( " last_read_outbox_message_id " , lastReadOutboxMessageId ) ;
this - > chatList . replace ( chatIndex , currentChat ) ;
emit dataChanged ( this - > index ( chatIndex ) , this - > index ( chatIndex ) ) ;
emit chatChanged ( chatId ) ;
this - > chatListMutex . unlock ( ) ;
}
void ChatListModel : : handleMessageSendSucceeded ( const QString & messageId , const QString & oldMessageId , const QVariantMap & message )
{
this - > chatListMutex . lock ( ) ;
QString chatId = message . value ( " chat_id " ) . toString ( ) ;
int chatIndex = this - > chatIndexMap . value ( chatId ) . toInt ( ) ;
qDebug ( ) < < " [ChatListModel] Updating last message for chat " < < chatId < < " at index " < < chatIndex < < " , as message was sent, old ID: " < < oldMessageId < < " , new ID: " < < messageId ;
QVariantMap currentChat = this - > chatList . value ( chatIndex ) . toMap ( ) ;
currentChat . insert ( " last_message " , message ) ;
this - > chatList . replace ( chatIndex , currentChat ) ;
emit dataChanged ( this - > index ( chatIndex ) , this - > index ( chatIndex ) ) ;
emit chatChanged ( chatId ) ;
this - > chatListMutex . unlock ( ) ;
}
2020-08-20 18:06:47 +03:00
void ChatListModel : : updateChatOrder ( const int & currentChatIndex , const QVariantMap & updatedChat )
{
// Finding the new position manually as information is needed by beginMoveRows()
// This seems to be the most convenient way of persisting the list position while changing the items
// Other alternative layoutChanged() after sorting resets the index position - there we would need to calculate the new position as well
// If somebody has a better solution - go for it ;)
int newChatIndex = 0 ;
2020-08-20 19:45:56 +03:00
QVariantMap previousChat ;
2020-08-20 18:06:47 +03:00
for ( int i = 0 ; i < this - > chatList . length ( ) ; i + + ) {
QVariantMap otherChat = this - > chatList . at ( i ) . toMap ( ) ;
if ( compareChats ( updatedChat , otherChat ) ) {
2020-08-20 19:45:56 +03:00
if ( previousChat . value ( " id " ) = = updatedChat . value ( " id " ) ) {
newChatIndex = currentChatIndex ;
} else {
newChatIndex = i ;
}
2020-08-20 18:06:47 +03:00
break ;
}
2020-08-20 19:45:56 +03:00
previousChat = otherChat ;
2020-08-20 18:06:47 +03:00
}
if ( newChatIndex ! = currentChatIndex ) {
// The updated chat now needs to go to the position of the other chat
qDebug ( ) < < " [ChatListModel] Chat " < < updatedChat . value ( " id " ) . toString ( ) < < " will be moved from position " < < currentChatIndex < < " to " < < newChatIndex ;
2020-08-20 19:45:56 +03:00
if ( deltaUpdates ) {
beginMoveRows ( QModelIndex ( ) , currentChatIndex , currentChatIndex , QModelIndex ( ) , ( ( newChatIndex < currentChatIndex ) ? newChatIndex : ( newChatIndex + 1 ) ) ) ;
}
2020-08-20 18:06:47 +03:00
std : : sort ( this - > chatList . begin ( ) , this - > chatList . end ( ) , compareChats ) ;
this - > chatIndexMap . clear ( ) ;
for ( int i = 0 ; i < this - > chatList . length ( ) ; i + + ) {
this - > chatIndexMap . insert ( this - > chatList . at ( i ) . toMap ( ) . value ( " id " ) . toString ( ) , i ) ;
}
2020-08-20 19:45:56 +03:00
if ( deltaUpdates ) {
endMoveRows ( ) ;
}
2020-08-20 18:06:47 +03:00
}
}