2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2014-12-01 10:47:38 +00:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 08:53:19 +00:00
Telegram Desktop 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 .
It 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 .
2015-10-03 13:16:42 +00:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 08:53:19 +00:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 18:31:31 +00:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2014-05-30 08:53:19 +00:00
*/
# include "stdafx.h"
2016-04-09 18:45:55 +00:00
# include "history.h"
2016-09-28 10:15:03 +00:00
# include "history/history_media_types.h"
2016-04-09 18:45:55 +00:00
# include "dialogs/dialogs_indexed_list.h"
2016-06-07 19:59:39 +00:00
# include "styles/style_dialogs.h"
2016-06-09 14:31:10 +00:00
# include "data/data_drafts.h"
2014-05-30 08:53:19 +00:00
# include "lang.h"
2017-01-18 10:26:33 +00:00
# include "apiwrap.h"
2014-05-30 08:53:19 +00:00
# include "mainwidget.h"
2016-04-12 21:31:28 +00:00
# include "mainwindow.h"
2014-11-22 09:45:04 +00:00
# include "localstorage.h"
2016-04-12 21:31:28 +00:00
# include "window/top_bar_widget.h"
2016-06-03 07:20:24 +00:00
# include "observer_peer.h"
2014-09-04 07:33:44 +00:00
2016-09-30 16:40:00 +00:00
namespace {
2016-12-01 19:20:33 +00:00
constexpr int kStatusShowClientsideTyping = 6000 ;
2016-09-30 16:40:00 +00:00
constexpr int kStatusShowClientsideRecordVideo = 6000 ;
constexpr int kStatusShowClientsideUploadVideo = 6000 ;
constexpr int kStatusShowClientsideRecordVoice = 6000 ;
constexpr int kStatusShowClientsideUploadVoice = 6000 ;
constexpr int kStatusShowClientsideUploadPhoto = 6000 ;
constexpr int kStatusShowClientsideUploadFile = 6000 ;
constexpr int kStatusShowClientsideChooseLocation = 6000 ;
constexpr int kStatusShowClientsideChooseContact = 6000 ;
constexpr int kStatusShowClientsidePlayGame = 10000 ;
2016-12-01 19:20:33 +00:00
constexpr int kSetMyActionForMs = 10000 ;
2016-09-30 16:40:00 +00:00
2016-12-13 07:59:57 +00:00
auto GlobalPinnedIndex = 0 ;
2016-12-31 15:19:22 +00:00
HistoryItem * createUnsupportedMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from ) {
QString text ( lng_message_unsupported ( lt_link , qsl ( " https://desktop.telegram.org " ) ) ) ;
EntitiesInText entities ;
textParseEntities ( text , _historyTextNoMonoOptions . flags , & entities ) ;
entities . push_front ( EntityInText ( EntityInTextItalic , 0 , text . size ( ) ) ) ;
return HistoryMessage : : create ( history , msgId , flags , replyTo , viaBotId , date , from , { text , entities } ) ;
}
2016-09-30 16:40:00 +00:00
} // namespace
2014-05-30 08:53:19 +00:00
void historyInit ( ) {
2016-09-27 14:20:49 +00:00
historyInitMessages ( ) ;
historyInitMedia ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-04-08 14:16:52 +00:00
History : : History ( const PeerId & peerId )
: peer ( App : : peer ( peerId ) )
2016-06-07 19:59:39 +00:00
, lastItemTextCache ( st : : dialogsTextWidthMin )
, cloudDraftTextCache ( st : : dialogsTextWidthMin )
2016-12-04 19:40:41 +00:00
, _mute ( isNotifyMuted ( peer - > notify ) )
, _sendActionText ( st : : dialogsTextWidthMin ) {
2016-05-20 16:01:06 +00:00
if ( peer - > isUser ( ) & & peer - > asUser ( ) - > botInfo ) {
2015-09-08 17:59:36 +00:00
outboxReadBefore = INT_MAX ;
}
2016-03-23 11:47:32 +00:00
for ( auto & countData : overviewCountData ) {
countData = - 1 ; // not loaded yet
2014-08-15 11:19:32 +00:00
}
2014-05-30 08:53:19 +00:00
}
2015-06-24 17:24:48 +00:00
void History : : clearLastKeyboard ( ) {
2015-11-24 16:19:18 +00:00
if ( lastKeyboardId ) {
if ( lastKeyboardId = = lastKeyboardHiddenId ) {
lastKeyboardHiddenId = 0 ;
}
lastKeyboardId = 0 ;
2016-07-19 11:37:01 +00:00
if ( auto main = App : : main ( ) ) {
main - > updateBotKeyboard ( this ) ;
}
2015-11-24 16:19:18 +00:00
}
2015-06-24 17:24:48 +00:00
lastKeyboardInited = true ;
lastKeyboardFrom = 0 ;
}
2016-03-23 11:47:32 +00:00
bool History : : canHaveFromPhotos ( ) const {
2017-01-14 18:50:16 +00:00
if ( peer - > isUser ( ) & & ! Adaptive : : ChatWide ( ) ) {
2016-03-23 11:47:32 +00:00
return false ;
2016-05-27 16:47:46 +00:00
} else if ( isChannel ( ) & & ! peer - > isMegagroup ( ) ) {
2016-03-23 11:47:32 +00:00
return false ;
}
return true ;
}
2016-03-19 16:55:15 +00:00
void History : : setHasPendingResizedItems ( ) {
_flags | = Flag : : f_has_pending_resized_items ;
Global : : RefHandleHistoryUpdate ( ) . call ( ) ;
}
2016-06-09 14:31:10 +00:00
void History : : setLocalDraft ( std_ : : unique_ptr < Data : : Draft > & & draft ) {
_localDraft = std_ : : move ( draft ) ;
}
void History : : takeLocalDraft ( History * from ) {
if ( auto & draft = from - > _localDraft ) {
if ( ! draft - > textWithTags . text . isEmpty ( ) & & ! _localDraft ) {
_localDraft = std_ : : move ( draft ) ;
// Edit and reply to drafts can't migrate.
// Cloud drafts do not migrate automatically.
_localDraft - > msgId = 0 ;
}
from - > clearLocalDraft ( ) ;
2017-01-18 10:26:33 +00:00
App : : api ( ) - > saveDraftToCloudDelayed ( from ) ;
2016-06-09 14:31:10 +00:00
}
}
2016-06-03 18:24:27 +00:00
void History : : createLocalDraftFromCloud ( ) {
auto draft = cloudDraft ( ) ;
2016-06-09 14:31:10 +00:00
if ( Data : : draftIsNull ( draft ) | | ! draft - > date . isValid ( ) ) return ;
2016-06-03 18:24:27 +00:00
auto existing = localDraft ( ) ;
2016-06-09 14:31:10 +00:00
if ( Data : : draftIsNull ( existing ) | | ! existing - > date . isValid ( ) | | draft - > date > = existing - > date ) {
2016-06-03 18:24:27 +00:00
if ( ! existing ) {
2016-06-09 14:31:10 +00:00
setLocalDraft ( std_ : : make_unique < Data : : Draft > ( draft - > textWithTags , draft - > msgId , draft - > cursor , draft - > previewCancelled ) ) ;
2016-06-03 18:24:27 +00:00
existing = localDraft ( ) ;
} else if ( existing ! = draft ) {
existing - > textWithTags = draft - > textWithTags ;
existing - > msgId = draft - > msgId ;
existing - > cursor = draft - > cursor ;
existing - > previewCancelled = draft - > previewCancelled ;
}
existing - > date = draft - > date ;
}
}
2016-06-09 14:31:10 +00:00
void History : : setCloudDraft ( std_ : : unique_ptr < Data : : Draft > & & draft ) {
_cloudDraft = std_ : : move ( draft ) ;
cloudDraftTextCache . clear ( ) ;
}
Data : : Draft * History : : createCloudDraft ( Data : : Draft * fromDraft ) {
if ( Data : : draftIsNull ( fromDraft ) ) {
setCloudDraft ( std_ : : make_unique < Data : : Draft > ( TextWithTags ( ) , 0 , MessageCursor ( ) , false ) ) ;
2016-06-03 18:24:27 +00:00
cloudDraft ( ) - > date = QDateTime ( ) ;
} else {
auto existing = cloudDraft ( ) ;
if ( ! existing ) {
2016-06-09 14:31:10 +00:00
setCloudDraft ( std_ : : make_unique < Data : : Draft > ( fromDraft - > textWithTags , fromDraft - > msgId , fromDraft - > cursor , fromDraft - > previewCancelled ) ) ;
2016-06-03 18:24:27 +00:00
existing = cloudDraft ( ) ;
} else if ( existing ! = fromDraft ) {
existing - > textWithTags = fromDraft - > textWithTags ;
existing - > msgId = fromDraft - > msgId ;
existing - > cursor = fromDraft - > cursor ;
existing - > previewCancelled = fromDraft - > previewCancelled ;
}
existing - > date = : : date ( myunixtime ( ) ) ;
}
cloudDraftTextCache . clear ( ) ;
updateChatListSortPosition ( ) ;
return cloudDraft ( ) ;
}
2016-06-09 14:31:10 +00:00
void History : : setEditDraft ( std_ : : unique_ptr < Data : : Draft > & & draft ) {
_editDraft = std_ : : move ( draft ) ;
}
void History : : clearLocalDraft ( ) {
_localDraft = nullptr ;
}
2016-06-03 18:24:27 +00:00
void History : : clearCloudDraft ( ) {
if ( _cloudDraft ) {
_cloudDraft = nullptr ;
cloudDraftTextCache . clear ( ) ;
updateChatListSortPosition ( ) ;
}
}
2016-06-09 14:31:10 +00:00
void History : : clearEditDraft ( ) {
_editDraft = nullptr ;
}
void History : : draftSavedToCloud ( ) {
updateChatListEntry ( ) ;
if ( App : : main ( ) ) App : : main ( ) - > writeDrafts ( this ) ;
}
2016-12-01 19:20:33 +00:00
bool History : : updateSendActionNeedsAnimating ( UserData * user , const MTPSendMessageAction & action ) {
using Type = SendAction : : Type ;
if ( action . type ( ) = = mtpc_sendMessageCancelAction ) {
unregSendAction ( user ) ;
return false ;
}
auto ms = getms ( ) ;
switch ( action . type ( ) ) {
case mtpc_sendMessageTypingAction : _typing . insert ( user , ms + kStatusShowClientsideTyping ) ; break ;
case mtpc_sendMessageRecordVideoAction : _sendActions . insert ( user , { Type : : RecordVideo , ms + kStatusShowClientsideRecordVideo } ) ; break ;
case mtpc_sendMessageUploadVideoAction : _sendActions . insert ( user , { Type : : UploadVideo , ms + kStatusShowClientsideUploadVideo , action . c_sendMessageUploadVideoAction ( ) . vprogress . v } ) ; break ;
case mtpc_sendMessageRecordAudioAction : _sendActions . insert ( user , { Type : : RecordVoice , ms + kStatusShowClientsideRecordVoice } ) ; break ;
case mtpc_sendMessageUploadAudioAction : _sendActions . insert ( user , { Type : : UploadVoice , ms + kStatusShowClientsideUploadVoice , action . c_sendMessageUploadAudioAction ( ) . vprogress . v } ) ; break ;
case mtpc_sendMessageUploadPhotoAction : _sendActions . insert ( user , { Type : : UploadPhoto , ms + kStatusShowClientsideUploadPhoto , action . c_sendMessageUploadPhotoAction ( ) . vprogress . v } ) ; break ;
case mtpc_sendMessageUploadDocumentAction : _sendActions . insert ( user , { Type : : UploadFile , ms + kStatusShowClientsideUploadFile , action . c_sendMessageUploadDocumentAction ( ) . vprogress . v } ) ; break ;
case mtpc_sendMessageGeoLocationAction : _sendActions . insert ( user , { Type : : ChooseLocation , ms + kStatusShowClientsideChooseLocation } ) ; break ;
case mtpc_sendMessageChooseContactAction : _sendActions . insert ( user , { Type : : ChooseContact , ms + kStatusShowClientsideChooseContact } ) ; break ;
2016-12-13 07:59:57 +00:00
case mtpc_sendMessageGamePlayAction : {
auto it = _sendActions . find ( user ) ;
if ( it = = _sendActions . end ( ) | | it - > type = = Type : : PlayGame | | it - > until < = ms ) {
_sendActions . insert ( user , { Type : : PlayGame , ms + kStatusShowClientsidePlayGame } ) ;
}
} break ;
2016-12-01 19:20:33 +00:00
default : return false ;
}
return updateSendActionNeedsAnimating ( ms , true ) ;
}
bool History : : mySendActionUpdated ( SendAction : : Type type , bool doing ) {
auto ms = getms ( true ) ;
auto i = _mySendActions . find ( type ) ;
if ( doing ) {
if ( i = = _mySendActions . cend ( ) ) {
_mySendActions . insert ( type , ms + kSetMyActionForMs ) ;
} else if ( i . value ( ) > ms + ( kSetMyActionForMs / 2 ) ) {
return false ;
} else {
i . value ( ) = ms + kSetMyActionForMs ;
}
} else {
if ( i = = _mySendActions . cend ( ) ) {
return false ;
} else if ( i . value ( ) < = ms ) {
return false ;
} else {
_mySendActions . erase ( i ) ;
}
}
return true ;
}
2016-12-23 13:21:01 +00:00
bool History : : paintSendAction ( Painter & p , int x , int y , int availableWidth , int outerWidth , style : : color color , TimeMs ms ) {
2016-12-01 19:20:33 +00:00
if ( _sendActionAnimation ) {
_sendActionAnimation . paint ( p , color , x , y + st : : normalFont - > ascent , outerWidth , ms ) ;
auto animationWidth = _sendActionAnimation . width ( ) ;
x + = animationWidth ;
availableWidth - = animationWidth ;
p . setPen ( color ) ;
_sendActionText . drawElided ( p , x , y , availableWidth ) ;
return true ;
}
return false ;
}
bool History : : updateSendActionNeedsAnimating ( TimeMs ms , bool force ) {
auto changed = force ;
for ( auto i = _typing . begin ( ) , e = _typing . end ( ) ; i ! = e ; ) {
2014-05-30 08:53:19 +00:00
if ( ms > = i . value ( ) ) {
2016-12-01 19:20:33 +00:00
i = _typing . erase ( i ) ;
2014-05-30 08:53:19 +00:00
changed = true ;
} else {
+ + i ;
}
}
2016-12-01 19:20:33 +00:00
for ( auto i = _sendActions . begin ( ) ; i ! = _sendActions . cend ( ) ; ) {
2015-08-01 08:33:00 +00:00
if ( ms > = i . value ( ) . until ) {
2016-12-01 19:20:33 +00:00
i = _sendActions . erase ( i ) ;
2015-08-01 08:33:00 +00:00
changed = true ;
} else {
+ + i ;
}
}
2014-05-30 08:53:19 +00:00
if ( changed ) {
2016-12-01 19:20:33 +00:00
QString newTypingString ;
auto typingCount = _typing . size ( ) ;
2016-09-30 13:40:22 +00:00
if ( typingCount > 2 ) {
2016-12-01 19:20:33 +00:00
newTypingString = lng_many_typing ( lt_count , typingCount ) ;
2016-09-30 13:40:22 +00:00
} else if ( typingCount > 1 ) {
2016-12-01 19:20:33 +00:00
newTypingString = lng_users_typing ( lt_user , _typing . begin ( ) . key ( ) - > firstName , lt_second_user , ( _typing . end ( ) - 1 ) . key ( ) - > firstName ) ;
2016-09-30 13:40:22 +00:00
} else if ( typingCount ) {
2016-12-01 19:20:33 +00:00
newTypingString = peer - > isUser ( ) ? lang ( lng_typing ) : lng_user_typing ( lt_user , _typing . begin ( ) . key ( ) - > firstName ) ;
} else if ( ! _sendActions . isEmpty ( ) ) {
2016-09-30 13:40:22 +00:00
// Handles all actions except game playing.
2016-12-01 19:20:33 +00:00
using Type = SendAction : : Type ;
auto sendActionString = [ ] ( Type type , const QString & name ) - > QString {
2016-09-30 13:40:22 +00:00
switch ( type ) {
2016-12-01 19:20:33 +00:00
case Type : : RecordVideo : return name . isEmpty ( ) ? lang ( lng_send_action_record_video ) : lng_user_action_record_video ( lt_user , name ) ;
case Type : : UploadVideo : return name . isEmpty ( ) ? lang ( lng_send_action_upload_video ) : lng_user_action_upload_video ( lt_user , name ) ;
case Type : : RecordVoice : return name . isEmpty ( ) ? lang ( lng_send_action_record_audio ) : lng_user_action_record_audio ( lt_user , name ) ;
case Type : : UploadVoice : return name . isEmpty ( ) ? lang ( lng_send_action_upload_audio ) : lng_user_action_upload_audio ( lt_user , name ) ;
case Type : : UploadPhoto : return name . isEmpty ( ) ? lang ( lng_send_action_upload_photo ) : lng_user_action_upload_photo ( lt_user , name ) ;
case Type : : UploadFile : return name . isEmpty ( ) ? lang ( lng_send_action_upload_file ) : lng_user_action_upload_file ( lt_user , name ) ;
case Type : : ChooseLocation : return name . isEmpty ( ) ? lang ( lng_send_action_geo_location ) : lng_user_action_geo_location ( lt_user , name ) ;
case Type : : ChooseContact : return name . isEmpty ( ) ? lang ( lng_send_action_choose_contact ) : lng_user_action_choose_contact ( lt_user , name ) ;
2016-09-30 13:40:22 +00:00
default : break ;
} ;
return QString ( ) ;
} ;
2016-12-01 19:20:33 +00:00
for ( auto i = _sendActions . cbegin ( ) , e = _sendActions . cend ( ) ; i ! = e ; + + i ) {
newTypingString = sendActionString ( i - > type , peer - > isUser ( ) ? QString ( ) : i . key ( ) - > firstName ) ;
if ( ! newTypingString . isEmpty ( ) ) {
_sendActionAnimation . start ( i - > type ) ;
2016-09-30 13:40:22 +00:00
break ;
}
}
// Everyone in sendActions are playing a game.
2016-12-01 19:20:33 +00:00
if ( newTypingString . isEmpty ( ) ) {
int playingCount = _sendActions . size ( ) ;
2016-09-30 13:40:22 +00:00
if ( playingCount > 2 ) {
2016-12-01 19:20:33 +00:00
newTypingString = lng_many_playing_game ( lt_count , playingCount ) ;
2016-09-30 13:40:22 +00:00
} else if ( playingCount > 1 ) {
2016-12-01 19:20:33 +00:00
newTypingString = lng_users_playing_game ( lt_user , _sendActions . begin ( ) . key ( ) - > firstName , lt_second_user , ( _sendActions . end ( ) - 1 ) . key ( ) - > firstName ) ;
2016-09-30 13:40:22 +00:00
} else {
2016-12-01 19:20:33 +00:00
newTypingString = peer - > isUser ( ) ? lang ( lng_playing_game ) : lng_user_playing_game ( lt_user , _sendActions . begin ( ) . key ( ) - > firstName ) ;
2016-09-30 13:40:22 +00:00
}
2016-12-01 19:20:33 +00:00
_sendActionAnimation . start ( Type : : PlayGame ) ;
2015-08-01 08:33:00 +00:00
}
2014-05-30 08:53:19 +00:00
}
2016-12-01 19:20:33 +00:00
if ( typingCount > 0 ) {
_sendActionAnimation . start ( SendAction : : Type : : Typing ) ;
} else if ( newTypingString . isEmpty ( ) ) {
_sendActionAnimation . stop ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-12-01 19:20:33 +00:00
if ( _sendActionString ! = newTypingString ) {
_sendActionString = newTypingString ;
2016-12-23 13:21:01 +00:00
_sendActionText . setText ( st : : dialogsTextStyle , _sendActionString , _textNameOptions ) ;
2014-05-30 08:53:19 +00:00
}
}
2016-12-01 19:20:33 +00:00
auto result = ( ! _typing . isEmpty ( ) | | ! _sendActions . isEmpty ( ) ) ;
if ( changed | | result ) {
2016-12-05 08:45:56 +00:00
App : : histories ( ) . sendActionAnimationUpdated ( ) . notify ( {
this ,
_sendActionAnimation . width ( ) ,
st : : normalFont - > height ,
changed
} ) ;
2014-05-30 08:53:19 +00:00
}
2016-12-01 19:20:33 +00:00
return result ;
}
2015-09-21 20:57:42 +00:00
void ChannelHistory : : getRangeDifference ( ) {
2017-02-10 14:16:50 +00:00
auto fromId = MsgId ( 0 ) , toId = MsgId ( 0 ) ;
for ( auto blockIndex = 0 , blocksCount = blocks . size ( ) ; blockIndex < blocksCount ; + + blockIndex ) {
auto block = blocks . at ( blockIndex ) ;
for ( auto itemIndex = 0 , itemsCount = block - > items . size ( ) ; itemIndex < itemsCount ; + + itemIndex ) {
auto item = block - > items . at ( itemIndex ) ;
if ( item - > id > 0 ) {
2015-09-21 20:57:42 +00:00
fromId = item - > id ;
break ;
}
}
if ( fromId ) break ;
}
if ( ! fromId ) return ;
2017-02-10 14:16:50 +00:00
for ( auto blockIndex = blocks . size ( ) ; blockIndex > 0 ; ) {
auto block = blocks . at ( - - blockIndex ) ;
for ( auto itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
auto item = block - > items . at ( - - itemIndex ) ;
if ( item - > id > 0 ) {
2015-09-21 20:57:42 +00:00
toId = item - > id ;
break ;
}
}
if ( toId ) break ;
}
if ( fromId > 0 & & peer - > asChannel ( ) - > pts ( ) > 0 ) {
if ( _rangeDifferenceRequestId ) {
MTP : : cancel ( _rangeDifferenceRequestId ) ;
}
_rangeDifferenceFromId = fromId ;
_rangeDifferenceToId = toId ;
MTP_LOG ( 0 , ( " getChannelDifference { good - after channelDifferenceTooLong was received, validating history part }%1 " ) . arg ( cTestMode ( ) ? " TESTMODE " : " " ) ) ;
getRangeDifferenceNext ( peer - > asChannel ( ) - > pts ( ) ) ;
}
}
void ChannelHistory : : getRangeDifferenceNext ( int32 pts ) {
if ( ! App : : main ( ) | | _rangeDifferenceToId < _rangeDifferenceFromId ) return ;
2016-10-23 21:03:10 +00:00
int limit = _rangeDifferenceToId + 1 - _rangeDifferenceFromId ;
auto filter = MTP_channelMessagesFilter ( MTP_flags ( MTPDchannelMessagesFilter : : Flags ( 0 ) ) , MTP_vector < MTPMessageRange > ( 1 , MTP_messageRange ( MTP_int ( _rangeDifferenceFromId ) , MTP_int ( _rangeDifferenceToId ) ) ) ) ;
MTPupdates_GetChannelDifference : : Flags flags = MTPupdates_GetChannelDifference : : Flag : : f_force ;
_rangeDifferenceRequestId = MTP : : send ( MTPupdates_GetChannelDifference ( MTP_flags ( flags ) , peer - > asChannel ( ) - > inputChannel , filter , MTP_int ( pts ) , MTP_int ( limit ) ) , App : : main ( ) - > rpcDone ( & MainWidget : : gotRangeDifference , peer - > asChannel ( ) ) ) ;
2015-09-21 20:57:42 +00:00
}
HistoryJoined * ChannelHistory : : insertJoinedMessage ( bool unread ) {
2015-11-20 18:24:44 +00:00
if ( _joinedMessage | | ! peer - > asChannel ( ) - > amIn ( ) | | ( peer - > isMegagroup ( ) & & peer - > asChannel ( ) - > mgInfo - > joinedMessageFound ) ) {
2015-11-09 09:51:22 +00:00
return _joinedMessage ;
}
2015-09-21 20:57:42 +00:00
2016-03-19 18:32:17 +00:00
UserData * inviter = ( peer - > asChannel ( ) - > inviter > 0 ) ? App : : userLoaded ( peer - > asChannel ( ) - > inviter ) : nullptr ;
if ( ! inviter ) return nullptr ;
2015-09-21 20:57:42 +00:00
2016-03-19 16:55:15 +00:00
MTPDmessage : : Flags flags = 0 ;
2016-03-19 18:32:17 +00:00
if ( peerToUser ( inviter - > id ) = = MTP : : authedId ( ) ) {
unread = false ;
2016-05-20 16:01:06 +00:00
//} else if (unread) {
// flags |= MTPDmessage::Flag::f_unread;
2016-03-19 16:55:15 +00:00
}
2016-03-19 18:32:17 +00:00
2015-09-21 20:57:42 +00:00
QDateTime inviteDate = peer - > asChannel ( ) - > inviteDate ;
if ( unread ) _maxReadMessageDate = inviteDate ;
if ( isEmpty ( ) ) {
2016-03-18 19:05:08 +00:00
_joinedMessage = HistoryJoined : : create ( this , inviteDate , inviter , flags ) ;
2016-03-19 18:32:17 +00:00
addNewItem ( _joinedMessage , unread ) ;
2015-09-21 20:57:42 +00:00
return _joinedMessage ;
}
2016-03-19 18:32:17 +00:00
2017-02-10 14:16:50 +00:00
for ( auto blockIndex = blocks . size ( ) ; blockIndex > 0 ; ) {
auto block = blocks . at ( - - blockIndex ) ;
for ( auto itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
auto item = block - > items . at ( - - itemIndex ) ;
// Due to a server bug sometimes inviteDate is less (before) than the
// first message in the megagroup (message about migration), let us
// ignore that and think, that the inviteDate is always greater-or-equal.
if ( item - > isGroupMigrate ( ) & & peer - > isMegagroup ( ) & & peer - > migrateFrom ( ) ) {
peer - > asChannel ( ) - > mgInfo - > joinedMessageFound = true ;
return nullptr ;
}
if ( item - > date < = inviteDate ) {
+ + itemIndex ;
_joinedMessage = HistoryJoined : : create ( this , inviteDate , inviter , flags ) ;
addNewInTheMiddle ( _joinedMessage , blockIndex , itemIndex ) ;
if ( lastMsgDate . isNull ( ) | | inviteDate > = lastMsgDate ) {
setLastMessage ( _joinedMessage ) ;
if ( unread ) {
newItemAdded ( _joinedMessage ) ;
2015-09-21 20:57:42 +00:00
}
}
2017-02-10 14:16:50 +00:00
return _joinedMessage ;
2015-09-21 20:57:42 +00:00
}
}
}
2016-03-31 10:37:58 +00:00
startBuildingFrontBlock ( ) ;
2015-09-21 20:57:42 +00:00
2016-03-18 19:05:08 +00:00
_joinedMessage = HistoryJoined : : create ( this , inviteDate , inviter , flags ) ;
2016-03-31 10:37:58 +00:00
addItemToBlock ( _joinedMessage ) ;
2016-03-19 18:32:17 +00:00
2016-03-31 10:37:58 +00:00
finishBuildingFrontBlock ( ) ;
2016-03-19 18:32:17 +00:00
2015-09-21 20:57:42 +00:00
return _joinedMessage ;
}
2015-09-25 07:47:32 +00:00
void ChannelHistory : : checkJoinedMessage ( bool createUnread ) {
2015-11-20 18:24:44 +00:00
if ( _joinedMessage | | peer - > asChannel ( ) - > inviter < = 0 ) {
2015-11-09 09:51:22 +00:00
return ;
}
2015-09-21 20:57:42 +00:00
if ( isEmpty ( ) ) {
if ( loadedAtTop ( ) & & loadedAtBottom ( ) ) {
2015-09-25 07:47:32 +00:00
if ( insertJoinedMessage ( createUnread ) ) {
2015-11-20 18:24:44 +00:00
if ( ! _joinedMessage - > detached ( ) ) {
setLastMessage ( _joinedMessage ) ;
}
2015-09-21 20:57:42 +00:00
}
return ;
}
}
QDateTime inviteDate = peer - > asChannel ( ) - > inviteDate ;
QDateTime firstDate , lastDate ;
2017-02-10 14:16:50 +00:00
if ( ! blocks . isEmpty ( ) ) {
firstDate = blocks . front ( ) - > items . front ( ) - > date ;
lastDate = blocks . back ( ) - > items . back ( ) - > date ;
2015-09-21 20:57:42 +00:00
}
if ( ! firstDate . isNull ( ) & & ! lastDate . isNull ( ) & & ( firstDate < = inviteDate | | loadedAtTop ( ) ) & & ( lastDate > inviteDate | | loadedAtBottom ( ) ) ) {
2015-09-25 07:47:32 +00:00
bool willBeLastMsg = ( inviteDate > = lastDate ) ;
if ( insertJoinedMessage ( createUnread & & willBeLastMsg ) & & willBeLastMsg ) {
2015-11-20 18:24:44 +00:00
if ( ! _joinedMessage - > detached ( ) ) {
setLastMessage ( _joinedMessage ) ;
}
2015-09-21 20:57:42 +00:00
}
}
}
void ChannelHistory : : checkMaxReadMessageDate ( ) {
if ( _maxReadMessageDate . isValid ( ) ) return ;
2016-03-22 15:23:34 +00:00
for ( int blockIndex = blocks . size ( ) ; blockIndex > 0 ; ) {
2015-09-21 20:57:42 +00:00
HistoryBlock * block = blocks . at ( - - blockIndex ) ;
2016-03-22 15:23:34 +00:00
for ( int itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
2015-09-21 20:57:42 +00:00
HistoryItem * item = block - > items . at ( - - itemIndex ) ;
2016-05-27 16:47:46 +00:00
if ( ! item - > unread ( ) ) {
2015-09-21 20:57:42 +00:00
_maxReadMessageDate = item - > date ;
2015-11-20 18:24:44 +00:00
if ( item - > isGroupMigrate ( ) & & isMegagroup ( ) & & peer - > migrateFrom ( ) ) {
_maxReadMessageDate = date ( MTP_int ( peer - > asChannel ( ) - > date + 1 ) ) ; // no report spam panel
}
2015-09-21 20:57:42 +00:00
return ;
}
}
}
2015-11-20 18:24:44 +00:00
if ( loadedAtTop ( ) & & ( ! isMegagroup ( ) | | ! isEmpty ( ) ) ) {
2015-09-21 20:57:42 +00:00
_maxReadMessageDate = date ( MTP_int ( peer - > asChannel ( ) - > date ) ) ;
}
}
const QDateTime & ChannelHistory : : maxReadMessageDate ( ) {
return _maxReadMessageDate ;
}
2015-09-20 08:55:41 +00:00
HistoryItem * ChannelHistory : : addNewChannelMessage ( const MTPMessage & msg , NewMessageType type ) {
if ( type = = NewMessageExisting ) return addToHistory ( msg ) ;
2016-05-27 16:47:46 +00:00
return addNewToBlocks ( msg , type ) ;
2015-09-20 08:55:41 +00:00
}
HistoryItem * ChannelHistory : : addNewToBlocks ( const MTPMessage & msg , NewMessageType type ) {
if ( ! loadedAtBottom ( ) ) {
HistoryItem * item = addToHistory ( msg ) ;
2016-05-27 16:47:46 +00:00
if ( item ) {
2015-09-20 08:55:41 +00:00
setLastMessage ( item ) ;
if ( type = = NewMessageUnread ) {
2015-10-28 00:29:39 +00:00
newItemAdded ( item ) ;
2015-09-20 08:55:41 +00:00
}
}
return item ;
}
2016-03-19 18:32:17 +00:00
return addNewToLastBlock ( msg , type ) ;
2015-09-20 08:55:41 +00:00
}
2016-04-14 19:24:42 +00:00
void ChannelHistory : : cleared ( bool leaveItems ) {
_joinedMessage = nullptr ;
2015-09-19 09:13:21 +00:00
}
void ChannelHistory : : messageDetached ( HistoryItem * msg ) {
2016-05-27 16:47:46 +00:00
if ( _joinedMessage = = msg ) {
2016-03-21 18:40:00 +00:00
_joinedMessage = nullptr ;
2015-09-19 09:13:21 +00:00
}
}
2016-03-15 10:37:56 +00:00
ChannelHistory : : ~ ChannelHistory ( ) {
// all items must be destroyed before ChannelHistory is destroyed
// or they will call history()->asChannelHistory() -> undefined behaviour
clearOnDestroy ( ) ;
}
2015-09-19 09:13:21 +00:00
History * Histories : : find ( const PeerId & peerId ) {
Map : : const_iterator i = map . constFind ( peerId ) ;
return ( i = = map . cend ( ) ) ? 0 : i . value ( ) ;
}
2016-09-25 19:04:02 +00:00
History * Histories : : findOrInsert ( const PeerId & peerId ) {
auto i = map . constFind ( peerId ) ;
if ( i = = map . cend ( ) ) {
auto history = peerIsChannel ( peerId ) ? static_cast < History * > ( new ChannelHistory ( peerId ) ) : ( new History ( peerId ) ) ;
i = map . insert ( peerId , history ) ;
}
return i . value ( ) ;
}
2016-05-20 16:01:06 +00:00
History * Histories : : findOrInsert ( const PeerId & peerId , int32 unreadCount , int32 maxInboxRead , int32 maxOutboxRead ) {
auto i = map . constFind ( peerId ) ;
2015-09-19 09:13:21 +00:00
if ( i = = map . cend ( ) ) {
2016-05-31 09:46:31 +00:00
auto history = peerIsChannel ( peerId ) ? static_cast < History * > ( new ChannelHistory ( peerId ) ) : ( new History ( peerId ) ) ;
i = map . insert ( peerId , history ) ;
history - > setUnreadCount ( unreadCount ) ;
history - > inboxReadBefore = maxInboxRead + 1 ;
history - > outboxReadBefore = maxOutboxRead + 1 ;
} else {
auto history = i . value ( ) ;
2016-09-25 19:04:02 +00:00
if ( unreadCount > history - > unreadCount ( ) ) {
2016-05-31 09:46:31 +00:00
history - > setUnreadCount ( unreadCount ) ;
}
2016-09-25 19:04:02 +00:00
accumulate_max ( history - > inboxReadBefore , maxInboxRead + 1 ) ;
2016-05-31 09:46:31 +00:00
accumulate_max ( history - > outboxReadBefore , maxOutboxRead + 1 ) ;
2015-09-19 09:13:21 +00:00
}
return i . value ( ) ;
}
2014-05-30 08:53:19 +00:00
void Histories : : clear ( ) {
App : : historyClearMsgs ( ) ;
2016-04-14 19:24:42 +00:00
2016-12-13 07:59:57 +00:00
_pinnedDialogs . clear ( ) ;
auto temp = base : : take ( map ) ;
2016-04-14 19:24:42 +00:00
for_const ( auto history , temp ) {
delete history ;
2014-05-30 08:53:19 +00:00
}
2016-03-31 14:06:40 +00:00
2016-03-26 06:41:23 +00:00
_unreadFull = _unreadMuted = 0 ;
2016-04-14 19:24:42 +00:00
Notify : : unreadCounterUpdated ( ) ;
2014-05-30 08:53:19 +00:00
App : : historyClearItems ( ) ;
typing . clear ( ) ;
}
2016-06-22 18:41:13 +00:00
void Histories : : regSendAction ( History * history , UserData * user , const MTPSendMessageAction & action , TimeId when ) {
2016-12-01 19:20:33 +00:00
if ( history - > updateSendActionNeedsAnimating ( user , action ) ) {
user - > madeAction ( when ) ;
2015-08-01 08:33:00 +00:00
2016-12-01 19:20:33 +00:00
auto i = typing . find ( history ) ;
if ( i = = typing . cend ( ) ) {
typing . insert ( history , getms ( ) ) ;
_a_typings . start ( ) ;
2016-09-30 13:40:22 +00:00
}
2015-08-01 08:33:00 +00:00
}
2014-12-12 16:27:03 +00:00
}
2016-12-01 19:20:33 +00:00
void Histories : : step_typings ( TimeMs ms , bool timer ) {
for ( auto i = typing . begin ( ) , e = typing . end ( ) ; i ! = e ; ) {
if ( i . key ( ) - > updateSendActionNeedsAnimating ( ms ) ) {
2014-12-12 16:27:03 +00:00
+ + i ;
2016-12-01 19:20:33 +00:00
} else {
i = typing . erase ( i ) ;
2014-12-12 16:27:03 +00:00
}
}
2015-12-08 12:33:37 +00:00
if ( typing . isEmpty ( ) ) {
_a_typings . stop ( ) ;
}
2014-12-12 16:27:03 +00:00
}
2014-12-18 18:40:49 +00:00
void Histories : : remove ( const PeerId & peer ) {
2015-09-19 09:13:21 +00:00
Map : : iterator i = map . find ( peer ) ;
if ( i ! = map . cend ( ) ) {
typing . remove ( i . value ( ) ) ;
delete i . value ( ) ;
map . erase ( i ) ;
2014-12-18 18:40:49 +00:00
}
}
2016-04-08 14:16:52 +00:00
namespace {
void checkForSwitchInlineButton ( HistoryItem * item ) {
if ( item - > out ( ) | | ! item - > hasSwitchInlineButton ( ) ) {
return ;
}
if ( UserData * user = item - > history ( ) - > peer - > asUser ( ) ) {
if ( ! user - > botInfo | | ! user - > botInfo - > inlineReturnPeerId ) {
return ;
}
if ( auto markup = item - > Get < HistoryMessageReplyMarkup > ( ) ) {
2016-09-03 21:27:22 +00:00
for_const ( auto & row , markup - > rows ) {
for_const ( auto & button , row ) {
2016-09-02 16:11:23 +00:00
if ( button . type = = HistoryMessageReplyMarkup : : Button : : Type : : SwitchInline ) {
2016-04-08 14:16:52 +00:00
Notify : : switchInlineBotButtonReceived ( QString : : fromUtf8 ( button . data ) ) ;
return ;
}
}
}
}
}
}
} // namespace
2015-09-21 20:57:42 +00:00
HistoryItem * Histories : : addNewMessage ( const MTPMessage & msg , NewMessageType type ) {
2016-08-12 16:28:10 +00:00
auto peer = peerFromMessage ( msg ) ;
2016-04-08 14:16:52 +00:00
if ( ! peer ) return nullptr ;
2014-05-30 08:53:19 +00:00
2016-08-12 16:28:10 +00:00
auto result = App : : history ( peer ) - > addNewMessage ( msg , type ) ;
2016-04-08 14:16:52 +00:00
if ( result & & type = = NewMessageUnread ) {
checkForSwitchInlineButton ( result ) ;
}
return result ;
2014-05-30 08:53:19 +00:00
}
2014-07-04 11:12:54 +00:00
2016-08-27 04:49:18 +00:00
int Histories : : unreadBadge ( ) const {
return _unreadFull - ( Global : : IncludeMuted ( ) ? 0 : _unreadMuted ) ;
}
bool Histories : : unreadOnlyMuted ( ) const {
return Global : : IncludeMuted ( ) ? ( _unreadMuted > = _unreadFull ) : false ;
}
2016-12-13 07:59:57 +00:00
void Histories : : setIsPinned ( History * history , bool isPinned ) {
if ( isPinned ) {
_pinnedDialogs . insert ( history ) ;
if ( _pinnedDialogs . size ( ) > Global : : PinnedDialogsCountMax ( ) ) {
auto minIndex = GlobalPinnedIndex + 1 ;
auto minIndexHistory = ( History * ) nullptr ;
for_const ( auto pinned , _pinnedDialogs ) {
if ( pinned - > getPinnedIndex ( ) < minIndex ) {
minIndex = pinned - > getPinnedIndex ( ) ;
minIndexHistory = pinned ;
}
}
t_assert ( minIndexHistory ! = nullptr ) ;
minIndexHistory - > setPinnedDialog ( false ) ;
}
} else {
_pinnedDialogs . remove ( history ) ;
}
}
void Histories : : clearPinned ( ) {
for ( auto pinned : base : : take ( _pinnedDialogs ) ) {
pinned - > setPinnedDialog ( false ) ;
}
}
2017-01-02 17:11:49 +00:00
int Histories : : pinnedCount ( ) const {
return _pinnedDialogs . size ( ) ;
}
2017-01-30 15:27:13 +00:00
QList < History * > Histories : : getPinnedOrder ( ) const {
QMap < int , History * > sorter ;
for_const ( auto pinned , _pinnedDialogs ) {
sorter . insert ( pinned - > getPinnedIndex ( ) , pinned ) ;
}
QList < History * > result ;
for ( auto i = sorter . cend ( ) , e = sorter . cbegin ( ) ; i ! = e ; ) {
- - i ;
result . push_back ( i . value ( ) ) ;
}
return result ;
}
2017-02-16 16:47:50 +00:00
void Histories : : savePinnedToServer ( ) const {
auto order = getPinnedOrder ( ) ;
auto peers = QVector < MTPInputPeer > ( ) ;
peers . reserve ( order . size ( ) ) ;
for_const ( auto history , order ) {
peers . push_back ( history - > peer - > input ) ;
}
auto flags = MTPmessages_ReorderPinnedDialogs : : Flag : : f_force ;
MTP : : send ( MTPmessages_ReorderPinnedDialogs ( MTP_flags ( qFlags ( flags ) ) , MTP_vector ( peers ) ) ) ;
}
2016-03-19 18:32:17 +00:00
HistoryItem * History : : createItem ( const MTPMessage & msg , bool applyServiceAction , bool detachExistingItem ) {
2016-12-31 15:19:22 +00:00
auto msgId = MsgId ( 0 ) ;
2015-04-30 13:53:36 +00:00
switch ( msg . type ( ) ) {
case mtpc_messageEmpty : msgId = msg . c_messageEmpty ( ) . vid . v ; break ;
case mtpc_message : msgId = msg . c_message ( ) . vid . v ; break ;
case mtpc_messageService : msgId = msg . c_messageService ( ) . vid . v ; break ;
}
2016-03-15 10:37:56 +00:00
if ( ! msgId ) return nullptr ;
2015-04-30 13:53:36 +00:00
2016-12-31 15:19:22 +00:00
auto result = App : : histItemById ( channelId ( ) , msgId ) ;
2015-12-23 12:55:32 +00:00
if ( result ) {
2016-03-19 18:32:17 +00:00
if ( ! result - > detached ( ) & & detachExistingItem ) {
result - > detach ( ) ;
2015-04-30 23:05:19 +00:00
}
2015-12-27 21:37:48 +00:00
if ( msg . type ( ) = = mtpc_message ) {
2016-01-09 07:11:23 +00:00
result - > updateMedia ( msg . c_message ( ) . has_media ( ) ? ( & msg . c_message ( ) . vmedia ) : 0 ) ;
2015-12-27 21:37:48 +00:00
if ( applyServiceAction ) {
App : : checkSavedGif ( result ) ;
2015-12-23 12:55:32 +00:00
}
2015-04-30 13:53:36 +00:00
}
2015-12-27 21:37:48 +00:00
return result ;
2015-04-30 13:53:36 +00:00
}
2014-05-30 08:53:19 +00:00
switch ( msg . type ( ) ) {
case mtpc_messageEmpty :
2016-03-25 11:29:45 +00:00
result = HistoryService : : create ( this , msg . c_messageEmpty ( ) . vid . v , date ( ) , lang ( lng_message_empty ) ) ;
2014-05-30 08:53:19 +00:00
break ;
2015-07-15 11:23:59 +00:00
case mtpc_message : {
2016-12-31 15:19:22 +00:00
auto & m = msg . c_message ( ) ;
enum class MediaCheckResult {
Good ,
Unsupported ,
Empty ,
} ;
auto badMedia = MediaCheckResult : : Good ;
2015-08-30 14:57:21 +00:00
if ( m . has_media ( ) ) switch ( m . vmedia . type ( ) ) {
2015-07-21 14:55:23 +00:00
case mtpc_messageMediaEmpty :
case mtpc_messageMediaContact : break ;
2015-07-15 11:23:59 +00:00
case mtpc_messageMediaGeo :
switch ( m . vmedia . c_messageMediaGeo ( ) . vgeo . type ( ) ) {
case mtpc_geoPoint : break ;
2016-12-31 15:19:22 +00:00
case mtpc_geoPointEmpty : badMedia = MediaCheckResult : : Empty ; break ;
default : badMedia = MediaCheckResult : : Unsupported ; break ;
2015-07-15 11:23:59 +00:00
}
break ;
case mtpc_messageMediaVenue :
switch ( m . vmedia . c_messageMediaVenue ( ) . vgeo . type ( ) ) {
case mtpc_geoPoint : break ;
2016-12-31 15:19:22 +00:00
case mtpc_geoPointEmpty : badMedia = MediaCheckResult : : Empty ; break ;
default : badMedia = MediaCheckResult : : Unsupported ; break ;
2015-07-15 11:23:59 +00:00
}
break ;
case mtpc_messageMediaPhoto :
switch ( m . vmedia . c_messageMediaPhoto ( ) . vphoto . type ( ) ) {
case mtpc_photo : break ;
2016-12-31 15:19:22 +00:00
case mtpc_photoEmpty : badMedia = MediaCheckResult : : Empty ; break ;
default : badMedia = MediaCheckResult : : Unsupported ; break ;
2015-07-15 11:23:59 +00:00
}
break ;
case mtpc_messageMediaDocument :
switch ( m . vmedia . c_messageMediaDocument ( ) . vdocument . type ( ) ) {
2015-12-28 10:28:00 +00:00
case mtpc_document : break ;
2016-12-31 15:19:22 +00:00
case mtpc_documentEmpty : badMedia = MediaCheckResult : : Empty ; break ;
default : badMedia = MediaCheckResult : : Unsupported ; break ;
2015-07-15 11:23:59 +00:00
}
break ;
case mtpc_messageMediaWebPage :
switch ( m . vmedia . c_messageMediaWebPage ( ) . vwebpage . type ( ) ) {
case mtpc_webPage :
case mtpc_webPageEmpty :
case mtpc_webPagePending : break ;
2016-12-13 07:59:57 +00:00
case mtpc_webPageNotModified :
2016-12-31 15:19:22 +00:00
default : badMedia = MediaCheckResult : : Unsupported ; break ;
2015-07-15 11:23:59 +00:00
}
break ;
2016-09-27 13:37:18 +00:00
case mtpc_messageMediaGame :
switch ( m . vmedia . c_messageMediaGame ( ) . vgame . type ( ) ) {
case mtpc_game : break ;
2016-12-31 15:19:22 +00:00
default : badMedia = MediaCheckResult : : Unsupported ; break ;
2016-09-27 13:37:18 +00:00
}
break ;
2015-07-15 11:23:59 +00:00
case mtpc_messageMediaUnsupported :
2016-12-31 15:19:22 +00:00
default : badMedia = MediaCheckResult : : Unsupported ; break ;
}
if ( badMedia = = MediaCheckResult : : Unsupported ) {
result = createUnsupportedMessage ( this , m . vid . v , m . vflags . v , m . vreply_to_msg_id . v , m . vvia_bot_id . v , date ( m . vdate ) , m . vfrom_id . v ) ;
} else if ( badMedia = = MediaCheckResult : : Empty ) {
2016-03-29 17:17:00 +00:00
result = HistoryService : : create ( this , m . vid . v , date ( m . vdate ) , lang ( lng_message_empty ) , m . vflags . v , m . has_from_id ( ) ? m . vfrom_id . v : 0 ) ;
2015-07-15 11:23:59 +00:00
} else {
2016-03-25 11:29:45 +00:00
result = HistoryMessage : : create ( this , m ) ;
2015-06-15 17:19:24 +00:00
}
2015-07-15 11:23:59 +00:00
} break ;
2014-05-30 08:53:19 +00:00
case mtpc_messageService : {
2016-12-31 15:19:22 +00:00
auto & m = msg . c_messageService ( ) ;
if ( m . vaction . type ( ) = = mtpc_messageActionPhoneCall ) {
auto viaBotId = 0 ;
result = createUnsupportedMessage ( this , m . vid . v , mtpCastFlags ( m . vflags . v ) , m . vreply_to_msg_id . v , viaBotId , date ( m . vdate ) , m . vfrom_id . v ) ;
} else {
result = HistoryService : : create ( this , m ) ;
}
2014-05-30 08:53:19 +00:00
2015-09-20 08:55:41 +00:00
if ( applyServiceAction ) {
2016-12-31 15:19:22 +00:00
auto & action = m . vaction ;
switch ( action . type ( ) ) {
2014-05-30 08:53:19 +00:00
case mtpc_messageActionChatAddUser : {
2016-12-31 15:19:22 +00:00
auto & d = action . c_messageActionChatAddUser ( ) ;
2015-11-19 15:56:29 +00:00
if ( peer - > isMegagroup ( ) ) {
2016-12-31 15:19:22 +00:00
auto & v = d . vusers . c_vector ( ) . v ;
for ( auto i = 0 , l = v . size ( ) ; i ! = l ; + + i ) {
if ( auto user = App : : userLoaded ( peerFromUser ( v [ i ] ) ) ) {
2015-11-19 15:56:29 +00:00
if ( peer - > asChannel ( ) - > mgInfo - > lastParticipants . indexOf ( user ) < 0 ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipants . push_front ( user ) ;
2015-11-24 10:40:18 +00:00
peer - > asChannel ( ) - > mgInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsAdminsOutdated ;
2016-06-03 07:20:24 +00:00
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : MembersChanged ) ;
2015-11-19 15:56:29 +00:00
}
2015-11-20 13:34:37 +00:00
if ( user - > botInfo ) {
2016-03-10 15:42:01 +00:00
peer - > asChannel ( ) - > mgInfo - > bots . insert ( user ) ;
2015-11-20 13:34:37 +00:00
if ( peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 & & peer - > asChannel ( ) - > mgInfo - > botStatus < 2 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = 2 ;
}
}
2015-11-19 15:56:29 +00:00
}
}
}
2014-05-30 08:53:19 +00:00
} break ;
2015-04-30 13:53:36 +00:00
case mtpc_messageActionChatJoinedByLink : {
2016-12-31 15:19:22 +00:00
auto & d = action . c_messageActionChatJoinedByLink ( ) ;
2015-11-19 15:56:29 +00:00
if ( peer - > isMegagroup ( ) ) {
2015-11-20 13:34:37 +00:00
if ( result - > from ( ) - > isUser ( ) ) {
if ( peer - > asChannel ( ) - > mgInfo - > lastParticipants . indexOf ( result - > from ( ) - > asUser ( ) ) < 0 ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipants . push_front ( result - > from ( ) - > asUser ( ) ) ;
2016-06-03 07:20:24 +00:00
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : MembersChanged ) ;
2015-11-20 13:34:37 +00:00
}
if ( result - > from ( ) - > asUser ( ) - > botInfo ) {
2016-03-10 15:42:01 +00:00
peer - > asChannel ( ) - > mgInfo - > bots . insert ( result - > from ( ) - > asUser ( ) ) ;
2015-11-20 13:34:37 +00:00
if ( peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 & & peer - > asChannel ( ) - > mgInfo - > botStatus < 2 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = 2 ;
}
}
2015-11-19 15:56:29 +00:00
}
}
2015-04-30 13:53:36 +00:00
} break ;
2014-05-30 08:53:19 +00:00
case mtpc_messageActionChatDeletePhoto : {
2016-12-31 15:19:22 +00:00
auto chat = peer - > asChat ( ) ;
2014-05-30 08:53:19 +00:00
if ( chat ) chat - > setPhoto ( MTP_chatPhotoEmpty ( ) ) ;
} break ;
case mtpc_messageActionChatDeleteUser : {
2016-12-31 15:19:22 +00:00
auto & d = action . c_messageActionChatDeleteUser ( ) ;
auto uid = peerFromUser ( d . vuser_id ) ;
2015-11-20 13:34:37 +00:00
if ( lastKeyboardFrom = = uid ) {
2015-06-24 17:24:48 +00:00
clearLastKeyboard ( ) ;
2015-06-18 17:24:54 +00:00
}
2015-11-20 13:34:37 +00:00
if ( peer - > isMegagroup ( ) ) {
2016-06-02 13:02:55 +00:00
if ( auto user = App : : userLoaded ( uid ) ) {
auto channel = peer - > asChannel ( ) ;
auto megagroupInfo = channel - > mgInfo ;
int32 index = megagroupInfo - > lastParticipants . indexOf ( user ) ;
2015-11-20 13:34:37 +00:00
if ( index > = 0 ) {
2016-06-02 13:02:55 +00:00
megagroupInfo - > lastParticipants . removeAt ( index ) ;
2016-06-03 07:20:24 +00:00
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : MembersChanged ) ;
2015-11-20 13:34:37 +00:00
}
2016-06-02 13:02:55 +00:00
if ( peer - > asChannel ( ) - > membersCount ( ) > 1 ) {
peer - > asChannel ( ) - > setMembersCount ( channel - > membersCount ( ) - 1 ) ;
2016-03-14 06:10:24 +00:00
} else {
2016-06-02 13:02:55 +00:00
megagroupInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsCountOutdated ;
megagroupInfo - > lastParticipantsCount = 0 ;
2016-03-14 06:10:24 +00:00
}
2016-06-02 13:02:55 +00:00
if ( megagroupInfo - > lastAdmins . contains ( user ) ) {
megagroupInfo - > lastAdmins . remove ( user ) ;
if ( channel - > adminsCount ( ) > 1 ) {
channel - > setAdminsCount ( channel - > adminsCount ( ) - 1 ) ;
2016-03-14 06:10:24 +00:00
}
2016-06-03 07:20:24 +00:00
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : AdminsChanged ) ;
2016-03-14 06:10:24 +00:00
}
2016-06-02 13:02:55 +00:00
megagroupInfo - > bots . remove ( user ) ;
if ( megagroupInfo - > bots . isEmpty ( ) & & megagroupInfo - > botStatus > 0 ) {
megagroupInfo - > botStatus = - 1 ;
2015-11-20 13:34:37 +00:00
}
}
}
2014-05-30 08:53:19 +00:00
} break ;
case mtpc_messageActionChatEditPhoto : {
2016-04-08 10:44:35 +00:00
const auto & d ( action . c_messageActionChatEditPhoto ( ) ) ;
2014-05-30 08:53:19 +00:00
if ( d . vphoto . type ( ) = = mtpc_photo ) {
2016-04-08 10:44:35 +00:00
const auto & sizes ( d . vphoto . c_photo ( ) . vsizes . c_vector ( ) . v ) ;
2014-05-30 08:53:19 +00:00
if ( ! sizes . isEmpty ( ) ) {
2015-09-03 10:48:40 +00:00
PhotoData * photo = App : : feedPhoto ( d . vphoto . c_photo ( ) ) ;
if ( photo ) photo - > peer = peer ;
2016-04-08 10:44:35 +00:00
const auto & smallSize ( sizes . front ( ) ) , & bigSize ( sizes . back ( ) ) ;
2015-09-03 10:48:40 +00:00
const MTPFileLocation * smallLoc = 0 , * bigLoc = 0 ;
switch ( smallSize . type ( ) ) {
case mtpc_photoSize : smallLoc = & smallSize . c_photoSize ( ) . vlocation ; break ;
case mtpc_photoCachedSize : smallLoc = & smallSize . c_photoCachedSize ( ) . vlocation ; break ;
}
switch ( bigSize . type ( ) ) {
case mtpc_photoSize : bigLoc = & bigSize . c_photoSize ( ) . vlocation ; break ;
case mtpc_photoCachedSize : bigLoc = & bigSize . c_photoCachedSize ( ) . vlocation ; break ;
}
if ( smallLoc & & bigLoc ) {
if ( peer - > isChat ( ) ) {
peer - > asChat ( ) - > setPhoto ( MTP_chatPhoto ( * smallLoc , * bigLoc ) , photo ? photo - > id : 0 ) ;
} else if ( peer - > isChannel ( ) ) {
peer - > asChannel ( ) - > setPhoto ( MTP_chatPhoto ( * smallLoc , * bigLoc ) , photo ? photo - > id : 0 ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-18 10:18:30 +00:00
peer - > loadUserpic ( ) ;
2014-05-30 08:53:19 +00:00
}
}
}
} break ;
case mtpc_messageActionChatEditTitle : {
2016-12-31 15:19:22 +00:00
auto & d = action . c_messageActionChatEditTitle ( ) ;
2016-05-25 12:09:05 +00:00
if ( auto chat = peer - > asChat ( ) ) {
chat - > setName ( qs ( d . vtitle ) ) ;
}
2014-05-30 08:53:19 +00:00
} break ;
2015-11-06 17:48:49 +00:00
case mtpc_messageActionChatMigrateTo : {
2016-03-19 16:55:15 +00:00
peer - > asChat ( ) - > flags | = MTPDchat : : Flag : : f_deactivated ;
2015-11-06 17:48:49 +00:00
2016-12-31 15:19:22 +00:00
//auto &d = action.c_messageActionChatMigrateTo();
//auto channel = App::channelLoaded(d.vchannel_id.v);
2015-11-06 17:48:49 +00:00
} break ;
case mtpc_messageActionChannelMigrateFrom : {
2016-12-31 15:19:22 +00:00
//auto &d = action.c_messageActionChannelMigrateFrom();
//auto chat = App::chatLoaded(d.vchat_id.v);
2015-11-06 17:48:49 +00:00
} break ;
2016-03-05 21:12:55 +00:00
case mtpc_messageActionPinMessage : {
2016-12-31 15:19:22 +00:00
if ( m . has_reply_to_msg_id ( ) & & result & & result - > history ( ) - > peer - > isMegagroup ( ) ) {
result - > history ( ) - > peer - > asChannel ( ) - > mgInfo - > pinnedMsgId = m . vreply_to_msg_id . v ;
2016-03-05 21:12:55 +00:00
if ( App : : main ( ) ) emit App : : main ( ) - > peerUpdated ( result - > history ( ) - > peer ) ;
}
} break ;
2014-05-30 08:53:19 +00:00
}
}
} break ;
}
2015-12-27 21:37:48 +00:00
if ( applyServiceAction ) {
App : : checkSavedGif ( result ) ;
}
2016-03-18 19:05:08 +00:00
return result ;
2014-05-30 08:53:19 +00:00
}
2016-03-19 16:55:15 +00:00
HistoryItem * History : : createItemForwarded ( MsgId id , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * msg ) {
2016-03-18 19:05:08 +00:00
return HistoryMessage : : create ( this , id , flags , date , from , msg ) ;
2014-05-30 08:53:19 +00:00
}
2016-04-06 08:00:37 +00:00
HistoryItem * History : : createItemDocument ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption , const MTPReplyMarkup & markup ) {
return HistoryMessage : : create ( this , id , flags , replyTo , viaBotId , date , from , doc , caption , markup ) ;
2015-12-31 05:34:43 +00:00
}
2016-04-06 08:00:37 +00:00
HistoryItem * History : : createItemPhoto ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption , const MTPReplyMarkup & markup ) {
return HistoryMessage : : create ( this , id , flags , replyTo , viaBotId , date , from , photo , caption , markup ) ;
2014-05-30 08:53:19 +00:00
}
2015-01-02 14:55:24 +00:00
2016-09-28 16:23:25 +00:00
HistoryItem * History : : createItemGame ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , GameData * game , const MTPReplyMarkup & markup ) {
return HistoryMessage : : create ( this , id , flags , replyTo , viaBotId , date , from , game , markup ) ;
}
2016-03-29 17:17:00 +00:00
HistoryItem * History : : addNewService ( MsgId msgId , QDateTime date , const QString & text , MTPDmessage : : Flags flags , bool newMsg ) {
return addNewItem ( HistoryService : : create ( this , msgId , date , text , flags ) , newMsg ) ;
2014-05-30 08:53:19 +00:00
}
2015-09-21 20:57:42 +00:00
HistoryItem * History : : addNewMessage ( const MTPMessage & msg , NewMessageType type ) {
2015-09-20 08:55:41 +00:00
if ( isChannel ( ) ) return asChannelHistory ( ) - > addNewChannelMessage ( msg , type ) ;
if ( type = = NewMessageExisting ) return addToHistory ( msg ) ;
2015-11-13 15:14:33 +00:00
if ( ! loadedAtBottom ( ) | | peer - > migrateTo ( ) ) {
2015-09-20 08:55:41 +00:00
HistoryItem * item = addToHistory ( msg ) ;
if ( item ) {
setLastMessage ( item ) ;
if ( type = = NewMessageUnread ) {
2015-10-28 00:29:39 +00:00
newItemAdded ( item ) ;
2015-09-20 08:55:41 +00:00
}
}
return item ;
}
2016-03-19 18:32:17 +00:00
return addNewToLastBlock ( msg , type ) ;
}
HistoryItem * History : : addNewToLastBlock ( const MTPMessage & msg , NewMessageType type ) {
2016-10-22 15:58:14 +00:00
auto applyServiceAction = ( type = = NewMessageUnread ) ;
auto detachExistingItem = ( type ! = NewMessageLast ) ;
auto item = createItem ( msg , applyServiceAction , detachExistingItem ) ;
2016-03-19 18:32:17 +00:00
if ( ! item | | ! item - > detached ( ) ) {
return item ;
2015-12-24 21:27:45 +00:00
}
2016-03-19 18:32:17 +00:00
return addNewItem ( item , ( type = = NewMessageUnread ) ) ;
2014-05-30 08:53:19 +00:00
}
2015-09-21 20:57:42 +00:00
HistoryItem * History : : addToHistory ( const MTPMessage & msg ) {
2016-03-19 18:32:17 +00:00
return createItem ( msg , false , false ) ;
2014-07-04 11:12:54 +00:00
}
2016-03-19 16:55:15 +00:00
HistoryItem * History : : addNewForwarded ( MsgId id , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * item ) {
2016-03-19 18:32:17 +00:00
return addNewItem ( createItemForwarded ( id , flags , date , from , item ) , true ) ;
2014-05-30 08:53:19 +00:00
}
2016-04-06 08:00:37 +00:00
HistoryItem * History : : addNewDocument ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption , const MTPReplyMarkup & markup ) {
return addNewItem ( createItemDocument ( id , flags , viaBotId , replyTo , date , from , doc , caption , markup ) , true ) ;
2015-12-31 05:34:43 +00:00
}
2016-04-06 08:00:37 +00:00
HistoryItem * History : : addNewPhoto ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption , const MTPReplyMarkup & markup ) {
return addNewItem ( createItemPhoto ( id , flags , viaBotId , replyTo , date , from , photo , caption , markup ) , true ) ;
2014-05-30 08:53:19 +00:00
}
2016-09-28 16:23:25 +00:00
HistoryItem * History : : addNewGame ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , GameData * game , const MTPReplyMarkup & markup ) {
return addNewItem ( createItemGame ( id , flags , viaBotId , replyTo , date , from , game , markup ) , true ) ;
}
2016-01-03 01:43:42 +00:00
bool History : : addToOverview ( MediaOverviewType type , MsgId msgId , AddToOverviewMethod method ) {
bool adding = false ;
switch ( method ) {
case AddToOverviewNew :
case AddToOverviewFront : adding = ( overviewIds [ type ] . constFind ( msgId ) = = overviewIds [ type ] . cend ( ) ) ; break ;
case AddToOverviewBack : adding = ( overviewCountData [ type ] ! = 0 ) ; break ;
}
if ( ! adding ) return false ;
2016-09-29 11:37:16 +00:00
overviewIds [ type ] . insert ( msgId ) ;
2016-01-03 01:43:42 +00:00
switch ( method ) {
case AddToOverviewNew :
case AddToOverviewBack : overview [ type ] . push_back ( msgId ) ; break ;
case AddToOverviewFront : overview [ type ] . push_front ( msgId ) ; break ;
}
if ( method = = AddToOverviewNew ) {
2015-11-18 13:11:56 +00:00
if ( overviewCountData [ type ] > 0 ) {
+ + overviewCountData [ type ] ;
}
2017-01-01 16:45:20 +00:00
Notify : : mediaOverviewUpdated ( peer , type ) ;
2015-08-28 15:15:56 +00:00
}
2016-01-03 01:43:42 +00:00
return true ;
2015-08-28 15:15:56 +00:00
}
2016-01-03 01:43:42 +00:00
void History : : eraseFromOverview ( MediaOverviewType type , MsgId msgId ) {
if ( overviewIds [ type ] . isEmpty ( ) ) return ;
2016-09-29 11:37:16 +00:00
auto i = overviewIds [ type ] . find ( msgId ) ;
2016-01-03 01:43:42 +00:00
if ( i = = overviewIds [ type ] . cend ( ) ) return ;
overviewIds [ type ] . erase ( i ) ;
2016-09-29 11:37:16 +00:00
for ( auto i = overview [ type ] . begin ( ) , e = overview [ type ] . end ( ) ; i ! = e ; + + i ) {
2016-01-03 01:43:42 +00:00
if ( ( * i ) = = msgId ) {
overview [ type ] . erase ( i ) ;
if ( overviewCountData [ type ] > 0 ) {
- - overviewCountData [ type ] ;
}
break ;
}
2015-08-28 15:15:56 +00:00
}
2017-01-01 16:45:20 +00:00
Notify : : mediaOverviewUpdated ( peer , type ) ;
2015-08-28 15:15:56 +00:00
}
2016-03-19 18:32:17 +00:00
HistoryItem * History : : addNewItem ( HistoryItem * adding , bool newMsg ) {
2016-03-31 10:37:58 +00:00
t_assert ( ! isBuildingFrontBlock ( ) ) ;
addItemToBlock ( adding ) ;
2016-03-19 18:32:17 +00:00
2015-08-07 12:11:50 +00:00
setLastMessage ( adding ) ;
2014-05-30 08:53:19 +00:00
if ( newMsg ) {
2015-10-28 00:29:39 +00:00
newItemAdded ( adding ) ;
2014-07-04 11:12:54 +00:00
}
2015-08-07 12:11:50 +00:00
2016-01-03 01:43:42 +00:00
adding - > addToOverview ( AddToOverviewNew ) ;
2015-06-15 17:19:24 +00:00
if ( adding - > from ( ) - > id ) {
2015-11-09 09:51:22 +00:00
if ( adding - > from ( ) - > isUser ( ) ) {
QList < UserData * > * lastAuthors = 0 ;
if ( peer - > isChat ( ) ) {
lastAuthors = & peer - > asChat ( ) - > lastAuthors ;
2015-11-19 15:56:29 +00:00
} else if ( peer - > isMegagroup ( ) ) {
2015-11-09 09:51:22 +00:00
lastAuthors = & peer - > asChannel ( ) - > mgInfo - > lastParticipants ;
2015-11-20 13:34:37 +00:00
if ( adding - > from ( ) - > asUser ( ) - > botInfo ) {
2016-03-10 15:42:01 +00:00
peer - > asChannel ( ) - > mgInfo - > bots . insert ( adding - > from ( ) - > asUser ( ) ) ;
2015-11-20 13:34:37 +00:00
if ( peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 & & peer - > asChannel ( ) - > mgInfo - > botStatus < 2 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = 2 ;
}
}
2015-11-09 09:51:22 +00:00
}
if ( lastAuthors ) {
int prev = lastAuthors - > indexOf ( adding - > from ( ) - > asUser ( ) ) ;
if ( prev > 0 ) {
lastAuthors - > removeAt ( prev ) ;
2015-11-24 10:40:18 +00:00
} else if ( prev < 0 & & peer - > isMegagroup ( ) ) { // nothing is outdated if just reordering
peer - > asChannel ( ) - > mgInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsAdminsOutdated ;
2015-11-09 09:51:22 +00:00
}
if ( prev ) {
lastAuthors - > push_front ( adding - > from ( ) - > asUser ( ) ) ;
}
2016-06-03 07:20:24 +00:00
if ( peer - > isMegagroup ( ) ) {
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : MembersChanged ) ;
}
2015-06-15 17:19:24 +00:00
}
}
2016-03-28 12:51:22 +00:00
if ( adding - > definesReplyKeyboard ( ) ) {
MTPDreplyKeyboardMarkup : : Flags markupFlags = adding - > replyKeyboardFlags ( ) ;
2016-03-19 16:55:15 +00:00
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup : : Flag : : f_selective ) | | adding - > mentionsMe ( ) ) {
2016-03-10 15:42:01 +00:00
OrderedSet < PeerData * > * markupSenders = 0 ;
2015-09-21 20:57:42 +00:00
if ( peer - > isChat ( ) ) {
2015-11-09 09:51:22 +00:00
markupSenders = & peer - > asChat ( ) - > markupSenders ;
} else if ( peer - > isMegagroup ( ) ) {
markupSenders = & peer - > asChannel ( ) - > mgInfo - > markupSenders ;
}
if ( markupSenders ) {
2016-03-10 15:42:01 +00:00
markupSenders - > insert ( adding - > from ( ) ) ;
2015-06-22 08:51:39 +00:00
}
2016-03-19 16:55:15 +00:00
if ( markupFlags & MTPDreplyKeyboardMarkup_ClientFlag : : f_zero ) { // zero markup means replyKeyboardHide
2015-11-09 09:51:22 +00:00
if ( lastKeyboardFrom = = adding - > from ( ) - > id | | ( ! lastKeyboardInited & & ! peer - > isChat ( ) & & ! peer - > isMegagroup ( ) & & ! adding - > out ( ) ) ) {
2015-06-24 17:24:48 +00:00
clearLastKeyboard ( ) ;
2015-06-22 08:51:39 +00:00
}
} else {
2015-11-09 09:51:22 +00:00
bool botNotInChat = false ;
if ( peer - > isChat ( ) ) {
botNotInChat = adding - > from ( ) - > isUser ( ) & & ( ! peer - > canWrite ( ) | | ! peer - > asChat ( ) - > participants . isEmpty ( ) ) & & ! peer - > asChat ( ) - > participants . contains ( adding - > from ( ) - > asUser ( ) ) ;
} else if ( peer - > isMegagroup ( ) ) {
2015-11-24 16:19:18 +00:00
botNotInChat = adding - > from ( ) - > isUser ( ) & & ( ! peer - > canWrite ( ) | | peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 ) & & ! peer - > asChannel ( ) - > mgInfo - > bots . contains ( adding - > from ( ) - > asUser ( ) ) ;
2015-11-09 09:51:22 +00:00
}
if ( botNotInChat ) {
clearLastKeyboard ( ) ;
} else {
lastKeyboardInited = true ;
lastKeyboardId = adding - > id ;
lastKeyboardFrom = adding - > from ( ) - > id ;
lastKeyboardUsed = false ;
}
2015-06-17 19:43:03 +00:00
}
}
2015-03-19 09:18:19 +00:00
}
}
2015-09-21 20:57:42 +00:00
2014-07-04 11:12:54 +00:00
return adding ;
}
2016-12-01 19:20:33 +00:00
void History : : unregSendAction ( UserData * from ) {
auto updateAtMs = TimeMs ( 0 ) ;
auto i = _typing . find ( from ) ;
if ( i ! = _typing . cend ( ) ) {
2016-01-05 04:52:40 +00:00
updateAtMs = getms ( ) ;
2015-08-01 08:33:00 +00:00
i . value ( ) = updateAtMs ;
}
2016-12-01 19:20:33 +00:00
auto j = _sendActions . find ( from ) ;
if ( j ! = _sendActions . cend ( ) ) {
2016-01-05 04:52:40 +00:00
if ( ! updateAtMs ) updateAtMs = getms ( ) ;
2015-08-01 08:33:00 +00:00
j . value ( ) . until = updateAtMs ;
}
if ( updateAtMs ) {
2016-12-01 19:20:33 +00:00
updateSendActionNeedsAnimating ( updateAtMs , true ) ;
2014-10-22 18:39:03 +00:00
}
}
2014-07-04 11:12:54 +00:00
void History : : newItemAdded ( HistoryItem * item ) {
App : : checkImageCacheSize ( ) ;
2015-09-04 13:01:31 +00:00
if ( item - > from ( ) & & item - > from ( ) - > isUser ( ) ) {
2016-02-17 16:37:21 +00:00
if ( item - > from ( ) = = item - > author ( ) ) {
2016-12-01 19:20:33 +00:00
unregSendAction ( item - > from ( ) - > asUser ( ) ) ;
2016-02-17 16:37:21 +00:00
}
2016-06-22 18:41:13 +00:00
MTPint itemServerTime ;
toServerTime ( item - > date . toTime_t ( ) , itemServerTime ) ;
item - > from ( ) - > asUser ( ) - > madeAction ( itemServerTime . v ) ;
2014-05-30 08:53:19 +00:00
}
2014-07-04 11:12:54 +00:00
if ( item - > out ( ) ) {
2016-03-18 19:05:08 +00:00
if ( unreadBar ) unreadBar - > destroyUnreadBar ( ) ;
2015-10-28 00:29:39 +00:00
if ( ! item - > unread ( ) ) {
outboxRead ( item ) ;
}
2014-07-04 11:12:54 +00:00
} else if ( item - > unread ( ) ) {
2015-09-23 17:43:08 +00:00
if ( ! isChannel ( ) | | peer - > asChannel ( ) - > amIn ( ) ) {
notifies . push_back ( item ) ;
App : : main ( ) - > newUnreadMsg ( this , item ) ;
}
2015-11-13 15:14:33 +00:00
} else if ( ! item - > isGroupMigrate ( ) | | ! peer - > isMegagroup ( ) ) {
2015-10-28 00:29:39 +00:00
inboxRead ( item ) ;
2014-07-04 11:12:54 +00:00
}
2014-05-30 08:53:19 +00:00
}
2016-03-31 10:37:58 +00:00
HistoryBlock * History : : prepareBlockForAddingItem ( ) {
if ( isBuildingFrontBlock ( ) ) {
2016-03-31 11:18:21 +00:00
if ( _buildingFrontBlock - > block ) {
return _buildingFrontBlock - > block ;
2016-03-31 10:37:58 +00:00
}
2016-09-23 16:04:26 +00:00
auto result = _buildingFrontBlock - > block = new HistoryBlock ( this ) ;
2016-03-31 11:18:21 +00:00
if ( _buildingFrontBlock - > expectedItemsCount > 0 ) {
result - > items . reserve ( _buildingFrontBlock - > expectedItemsCount + 1 ) ;
2016-03-31 10:37:58 +00:00
}
result - > setIndexInHistory ( 0 ) ;
blocks . push_front ( result ) ;
for ( int i = 1 , l = blocks . size ( ) ; i < l ; + + i ) {
blocks . at ( i ) - > setIndexInHistory ( i ) ;
}
return result ;
}
bool addNewBlock = blocks . isEmpty ( ) | | ( blocks . back ( ) - > items . size ( ) > = MessagesPerPage ) ;
if ( ! addNewBlock ) {
return blocks . back ( ) ;
}
2016-09-23 16:04:26 +00:00
auto result = new HistoryBlock ( this ) ;
2016-03-31 10:37:58 +00:00
result - > setIndexInHistory ( blocks . size ( ) ) ;
blocks . push_back ( result ) ;
result - > items . reserve ( MessagesPerPage ) ;
return result ;
} ;
void History : : addItemToBlock ( HistoryItem * item ) {
t_assert ( item ! = nullptr ) ;
t_assert ( item - > detached ( ) ) ;
2016-09-23 16:04:26 +00:00
auto block = prepareBlockForAddingItem ( ) ;
2016-03-31 10:37:58 +00:00
2016-03-18 19:05:08 +00:00
item - > attachToBlock ( block , block - > items . size ( ) ) ;
2015-09-19 09:13:21 +00:00
block - > items . push_back ( item ) ;
2016-03-19 16:55:15 +00:00
item - > previousItemChanged ( ) ;
2015-09-19 09:13:21 +00:00
2016-03-31 11:18:21 +00:00
if ( isBuildingFrontBlock ( ) & & _buildingFrontBlock - > expectedItemsCount > 0 ) {
- - _buildingFrontBlock - > expectedItemsCount ;
2015-09-19 09:13:21 +00:00
}
}
2016-05-27 16:47:46 +00:00
void History : : addOlderSlice ( const QVector < MTPMessage > & slice ) {
2014-07-04 11:12:54 +00:00
if ( slice . isEmpty ( ) ) {
oldLoaded = true ;
2016-05-27 16:47:46 +00:00
if ( isChannel ( ) ) {
asChannelHistory ( ) - > checkJoinedMessage ( ) ;
asChannelHistory ( ) - > checkMaxReadMessageDate ( ) ;
2015-09-21 20:57:42 +00:00
}
2016-05-27 16:47:46 +00:00
return ;
2014-07-04 11:12:54 +00:00
}
2014-05-30 08:53:19 +00:00
2016-05-27 16:47:46 +00:00
startBuildingFrontBlock ( slice . size ( ) ) ;
2016-03-19 18:32:17 +00:00
2016-03-15 10:37:56 +00:00
for ( auto i = slice . cend ( ) , e = slice . cbegin ( ) ; i ! = e ; ) {
2015-09-19 09:13:21 +00:00
- - i ;
2016-09-23 16:04:26 +00:00
auto adding = createItem ( * i , false , true ) ;
2015-09-19 09:13:21 +00:00
if ( ! adding ) continue ;
2016-03-31 10:37:58 +00:00
addItemToBlock ( adding ) ;
2015-09-19 09:13:21 +00:00
}
2016-09-23 16:04:26 +00:00
auto block = finishBuildingFrontBlock ( ) ;
2016-03-31 10:37:58 +00:00
if ( ! block ) {
// If no items were added it means we've loaded everything old.
2016-03-19 18:32:17 +00:00
oldLoaded = true ;
} else if ( loadedAtBottom ( ) ) { // add photos to overview and authors to lastAuthors / lastParticipants
bool channel = isChannel ( ) ;
int32 mask = 0 ;
2016-09-23 16:04:26 +00:00
QList < UserData * > * lastAuthors = nullptr ;
OrderedSet < PeerData * > * markupSenders = nullptr ;
2016-03-19 18:32:17 +00:00
if ( peer - > isChat ( ) ) {
lastAuthors = & peer - > asChat ( ) - > lastAuthors ;
markupSenders = & peer - > asChat ( ) - > markupSenders ;
} else if ( peer - > isMegagroup ( ) ) {
lastAuthors = & peer - > asChannel ( ) - > mgInfo - > lastParticipants ;
markupSenders = & peer - > asChannel ( ) - > mgInfo - > markupSenders ;
}
for ( int32 i = block - > items . size ( ) ; i > 0 ; - - i ) {
2016-09-23 16:04:26 +00:00
auto item = block - > items [ i - 1 ] ;
2016-03-19 18:32:17 +00:00
mask | = item - > addToOverview ( AddToOverviewFront ) ;
if ( item - > from ( ) - > id ) {
if ( lastAuthors ) { // chats
if ( item - > from ( ) - > isUser ( ) ) {
if ( ! lastAuthors - > contains ( item - > from ( ) - > asUser ( ) ) ) {
lastAuthors - > push_back ( item - > from ( ) - > asUser ( ) ) ;
if ( peer - > isMegagroup ( ) ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsAdminsOutdated ;
2016-06-03 07:20:24 +00:00
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : MembersChanged ) ;
2015-11-24 10:40:18 +00:00
}
2015-06-17 19:43:03 +00:00
}
2015-11-09 09:51:22 +00:00
}
2016-02-17 16:37:21 +00:00
}
2016-03-19 18:32:17 +00:00
}
if ( item - > author ( ) - > id ) {
if ( markupSenders ) { // chats with bots
2016-03-28 12:51:22 +00:00
if ( ! lastKeyboardInited & & item - > definesReplyKeyboard ( ) & & ! item - > out ( ) ) {
2016-09-23 16:04:26 +00:00
auto markupFlags = item - > replyKeyboardFlags ( ) ;
2016-03-19 18:32:17 +00:00
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup : : Flag : : f_selective ) | | item - > mentionsMe ( ) ) {
bool wasKeyboardHide = markupSenders - > contains ( item - > author ( ) ) ;
if ( ! wasKeyboardHide ) {
markupSenders - > insert ( item - > author ( ) ) ;
}
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup_ClientFlag : : f_zero ) ) {
if ( ! lastKeyboardInited ) {
bool botNotInChat = false ;
if ( peer - > isChat ( ) ) {
botNotInChat = ( ! peer - > canWrite ( ) | | ! peer - > asChat ( ) - > participants . isEmpty ( ) ) & & item - > author ( ) - > isUser ( ) & & ! peer - > asChat ( ) - > participants . contains ( item - > author ( ) - > asUser ( ) ) ;
} else if ( peer - > isMegagroup ( ) ) {
botNotInChat = ( ! peer - > canWrite ( ) | | peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 ) & & item - > author ( ) - > isUser ( ) & & ! peer - > asChannel ( ) - > mgInfo - > bots . contains ( item - > author ( ) - > asUser ( ) ) ;
}
if ( wasKeyboardHide | | botNotInChat ) {
clearLastKeyboard ( ) ;
} else {
lastKeyboardInited = true ;
lastKeyboardId = item - > id ;
lastKeyboardFrom = item - > author ( ) - > id ;
lastKeyboardUsed = false ;
2015-06-17 19:43:03 +00:00
}
}
}
}
2016-03-19 18:32:17 +00:00
}
2016-03-28 12:51:22 +00:00
} else if ( ! lastKeyboardInited & & item - > definesReplyKeyboard ( ) & & ! item - > out ( ) ) { // conversations with bots
MTPDreplyKeyboardMarkup : : Flags markupFlags = item - > replyKeyboardFlags ( ) ;
2016-03-19 18:32:17 +00:00
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup : : Flag : : f_selective ) | | item - > mentionsMe ( ) ) {
if ( markupFlags & MTPDreplyKeyboardMarkup_ClientFlag : : f_zero ) {
clearLastKeyboard ( ) ;
} else {
lastKeyboardInited = true ;
lastKeyboardId = item - > id ;
lastKeyboardFrom = item - > author ( ) - > id ;
lastKeyboardUsed = false ;
2015-06-15 17:19:24 +00:00
}
}
}
2014-08-11 09:03:45 +00:00
}
}
2017-01-01 16:45:20 +00:00
if ( mask ) {
Notify : : PeerUpdate update ( peer ) ;
update . flags | = Notify : : PeerUpdate : : Flag : : SharedMediaChanged ;
update . mediaTypesMask | = mask ;
Notify : : peerUpdatedDelayed ( update ) ;
2016-03-19 18:32:17 +00:00
}
}
2015-09-21 20:57:42 +00:00
if ( isChannel ( ) ) {
asChannelHistory ( ) - > checkJoinedMessage ( ) ;
asChannelHistory ( ) - > checkMaxReadMessageDate ( ) ;
}
2016-04-11 07:43:40 +00:00
checkLastMsg ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-05-27 16:47:46 +00:00
void History : : addNewerSlice ( const QVector < MTPMessage > & slice ) {
2015-09-24 16:05:06 +00:00
bool wasEmpty = isEmpty ( ) , wasLoadedAtBottom = loadedAtBottom ( ) ;
2014-07-04 11:12:54 +00:00
if ( slice . isEmpty ( ) ) {
newLoaded = true ;
2016-04-11 07:43:40 +00:00
if ( ! lastMsg ) {
2017-02-10 14:16:50 +00:00
setLastMessage ( lastAvailableMessage ( ) ) ;
2016-04-11 07:43:40 +00:00
}
2014-07-04 11:12:54 +00:00
}
2016-03-31 10:37:58 +00:00
t_assert ( ! isBuildingFrontBlock ( ) ) ;
2016-05-27 16:47:46 +00:00
if ( ! slice . isEmpty ( ) ) {
2016-03-31 10:37:58 +00:00
bool atLeastOneAdded = false ;
2016-03-15 10:37:56 +00:00
for ( auto i = slice . cend ( ) , e = slice . cbegin ( ) ; i ! = e ; ) {
2015-09-24 16:05:06 +00:00
- - i ;
2016-09-23 16:04:26 +00:00
auto adding = createItem ( * i , false , true ) ;
2015-09-24 16:05:06 +00:00
if ( ! adding ) continue ;
2014-07-04 11:12:54 +00:00
2016-03-31 10:37:58 +00:00
addItemToBlock ( adding ) ;
atLeastOneAdded = true ;
2015-09-24 16:05:06 +00:00
}
2015-09-19 09:13:21 +00:00
2016-03-31 10:37:58 +00:00
if ( ! atLeastOneAdded ) {
2015-09-24 16:05:06 +00:00
newLoaded = true ;
2017-02-10 14:16:50 +00:00
setLastMessage ( lastAvailableMessage ( ) ) ;
2015-09-24 16:05:06 +00:00
}
2014-07-04 11:12:54 +00:00
}
2015-12-23 14:18:42 +00:00
2016-08-14 19:15:45 +00:00
if ( ! wasLoadedAtBottom ) {
checkAddAllToOverview ( ) ;
2014-08-11 09:03:45 +00:00
}
2015-09-21 20:57:42 +00:00
if ( isChannel ( ) ) asChannelHistory ( ) - > checkJoinedMessage ( ) ;
2016-04-11 07:43:40 +00:00
checkLastMsg ( ) ;
}
void History : : checkLastMsg ( ) {
if ( lastMsg ) {
2016-05-27 16:47:46 +00:00
if ( ! newLoaded & & ! lastMsg - > detached ( ) ) {
2016-04-11 07:43:40 +00:00
newLoaded = true ;
2016-08-14 19:15:45 +00:00
checkAddAllToOverview ( ) ;
2016-04-11 07:43:40 +00:00
}
} else if ( newLoaded ) {
2017-02-10 14:16:50 +00:00
setLastMessage ( lastAvailableMessage ( ) ) ;
2016-04-11 07:43:40 +00:00
}
2014-07-04 11:12:54 +00:00
}
2016-08-14 19:15:45 +00:00
void History : : checkAddAllToOverview ( ) {
if ( ! loadedAtBottom ( ) ) {
return ;
}
int32 mask = 0 ;
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
if ( overviewCountData [ i ] = = 0 ) continue ; // all loaded
if ( ! overview [ i ] . isEmpty ( ) | | ! overviewIds [ i ] . isEmpty ( ) ) {
overview [ i ] . clear ( ) ;
overviewIds [ i ] . clear ( ) ;
mask | = ( 1 < < i ) ;
}
}
for_const ( HistoryBlock * block , blocks ) {
for_const ( HistoryItem * item , block - > items ) {
mask | = item - > addToOverview ( AddToOverviewBack ) ;
}
}
2017-01-01 16:45:20 +00:00
if ( mask ) {
Notify : : PeerUpdate update ( peer ) ;
update . flags | = Notify : : PeerUpdate : : Flag : : SharedMediaChanged ;
update . mediaTypesMask | = mask ;
Notify : : peerUpdatedDelayed ( update ) ;
2016-08-14 19:15:45 +00:00
}
}
2016-03-22 15:23:34 +00:00
int History : : countUnread ( MsgId upTo ) {
int result = 0 ;
2016-03-15 10:37:56 +00:00
for ( auto i = blocks . cend ( ) , e = blocks . cbegin ( ) ; i ! = e ; ) {
2015-09-06 10:17:09 +00:00
- - i ;
2016-03-15 10:37:56 +00:00
for ( auto j = ( * i ) - > items . cend ( ) , en = ( * i ) - > items . cbegin ( ) ; j ! = en ; ) {
2015-09-06 10:17:09 +00:00
- - j ;
if ( ( * j ) - > id > 0 & & ( * j ) - > id < = upTo ) {
break ;
} else if ( ! ( * j ) - > out ( ) & & ( * j ) - > unread ( ) & & ( * j ) - > id > upTo ) {
+ + result ;
}
}
}
return result ;
}
2015-09-19 09:13:21 +00:00
void History : : updateShowFrom ( ) {
if ( showFrom ) return ;
2016-03-15 10:37:56 +00:00
for ( auto i = blocks . cend ( ) ; i ! = blocks . cbegin ( ) ; ) {
2015-09-19 09:13:21 +00:00
- - i ;
2016-03-15 10:37:56 +00:00
for ( auto j = ( * i ) - > items . cend ( ) ; j ! = ( * i ) - > items . cbegin ( ) ; ) {
2015-09-19 09:13:21 +00:00
- - j ;
2017-02-10 14:16:50 +00:00
if ( ( * j ) - > id > 0 & & ( ! ( * j ) - > out ( ) | | ! showFrom ) ) {
2015-09-19 09:13:21 +00:00
if ( ( * j ) - > id > = inboxReadBefore ) {
showFrom = * j ;
} else {
return ;
}
}
}
}
}
2015-09-06 10:17:09 +00:00
MsgId History : : inboxRead ( MsgId upTo ) {
2015-09-25 07:47:32 +00:00
if ( upTo < 0 ) return upTo ;
2016-04-11 10:59:01 +00:00
if ( unreadCount ( ) ) {
2015-03-13 13:01:25 +00:00
if ( upTo & & loadedAtBottom ( ) ) App : : main ( ) - > historyToDown ( this ) ;
2015-09-06 10:17:09 +00:00
setUnreadCount ( upTo ? countUnread ( upTo ) : 0 ) ;
2014-05-30 08:53:19 +00:00
}
2015-09-06 10:17:09 +00:00
if ( ! upTo ) upTo = msgIdForRead ( ) ;
2016-05-20 16:01:06 +00:00
accumulate_max ( inboxReadBefore , upTo + 1 ) ;
2015-09-06 10:17:09 +00:00
2016-02-28 11:58:30 +00:00
updateChatListEntry ( ) ;
if ( peer - > migrateTo ( ) ) {
2016-09-25 19:04:02 +00:00
if ( auto migrateTo = App : : historyLoaded ( peer - > migrateTo ( ) - > id ) ) {
migrateTo - > updateChatListEntry ( ) ;
2015-11-13 15:14:33 +00:00
}
}
2015-10-03 10:09:09 +00:00
2016-04-23 11:40:42 +00:00
showFrom = nullptr ;
2014-07-06 03:32:21 +00:00
App : : wnd ( ) - > notifyClear ( this ) ;
2015-09-06 10:17:09 +00:00
return upTo ;
2014-05-30 08:53:19 +00:00
}
2015-09-06 10:17:09 +00:00
MsgId History : : inboxRead ( HistoryItem * wasRead ) {
2015-03-13 13:01:25 +00:00
return inboxRead ( wasRead ? wasRead - > id : 0 ) ;
}
2015-09-06 10:17:09 +00:00
MsgId History : : outboxRead ( int32 upTo ) {
2015-09-25 07:47:32 +00:00
if ( upTo < 0 ) return upTo ;
2015-09-06 10:17:09 +00:00
if ( ! upTo ) upTo = msgIdForRead ( ) ;
2016-05-20 16:01:06 +00:00
accumulate_max ( outboxReadBefore , upTo + 1 ) ;
2015-09-06 10:17:09 +00:00
return upTo ;
2014-05-30 08:53:19 +00:00
}
2015-09-06 10:17:09 +00:00
MsgId History : : outboxRead ( HistoryItem * wasRead ) {
2015-03-13 13:01:25 +00:00
return outboxRead ( wasRead ? wasRead - > id : 0 ) ;
}
2017-02-10 14:16:50 +00:00
HistoryItem * History : : lastAvailableMessage ( ) const {
return isEmpty ( ) ? nullptr : blocks . back ( ) - > items . back ( ) ;
2015-09-20 08:55:41 +00:00
}
2016-04-14 19:24:42 +00:00
void History : : setUnreadCount ( int newUnreadCount ) {
2016-04-11 10:59:01 +00:00
if ( _unreadCount ! = newUnreadCount ) {
2015-09-07 07:52:37 +00:00
if ( newUnreadCount = = 1 ) {
2017-02-10 14:16:50 +00:00
if ( loadedAtBottom ( ) ) showFrom = lastAvailableMessage ( ) ;
2015-09-07 07:52:37 +00:00
inboxReadBefore = qMax ( inboxReadBefore , msgIdForRead ( ) ) ;
2014-05-30 08:53:19 +00:00
} else if ( ! newUnreadCount ) {
2016-03-26 06:41:23 +00:00
showFrom = nullptr ;
2015-09-07 07:52:37 +00:00
inboxReadBefore = qMax ( inboxReadBefore , msgIdForRead ( ) + 1 ) ;
2016-06-03 12:45:33 +00:00
} else {
if ( ! showFrom & & ! unreadBar & & loadedAtBottom ( ) ) updateShowFrom ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-04-11 10:59:01 +00:00
if ( inChatList ( Dialogs : : Mode : : All ) ) {
App : : histories ( ) . unreadIncrement ( newUnreadCount - _unreadCount , mute ( ) ) ;
2016-08-27 04:49:18 +00:00
if ( ! mute ( ) | | Global : : IncludeMuted ( ) ) {
2016-04-14 19:24:42 +00:00
Notify : : unreadCounterUpdated ( ) ;
2016-02-28 11:58:30 +00:00
}
}
2016-04-11 10:59:01 +00:00
_unreadCount = newUnreadCount ;
2016-06-03 12:45:33 +00:00
if ( auto main = App : : main ( ) ) {
main - > unreadCountChanged ( this ) ;
}
2015-11-13 15:14:33 +00:00
if ( unreadBar ) {
2016-04-11 10:59:01 +00:00
int32 count = _unreadCount ;
2015-11-13 15:14:33 +00:00
if ( peer - > migrateTo ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateTo ( ) - > id ) ) {
2016-04-11 10:59:01 +00:00
count + = h - > unreadCount ( ) ;
2015-11-13 15:14:33 +00:00
}
}
2016-03-18 19:05:08 +00:00
if ( count > 0 ) {
unreadBar - > setUnreadBarCount ( count ) ;
} else {
unreadBar - > setUnreadBarFreezed ( ) ;
}
2015-11-13 15:14:33 +00:00
}
2014-05-30 08:53:19 +00:00
}
}
void History : : setMute ( bool newMute ) {
2016-04-11 10:59:01 +00:00
if ( _mute ! = newMute ) {
_mute = newMute ;
if ( inChatList ( Dialogs : : Mode : : All ) ) {
if ( _unreadCount ) {
App : : histories ( ) . unreadMuteChanged ( _unreadCount , newMute ) ;
2016-04-14 19:24:42 +00:00
Notify : : unreadCounterUpdated ( ) ;
2016-04-11 10:59:01 +00:00
}
Notify : : historyMuteUpdated ( this ) ;
2016-02-28 11:58:30 +00:00
}
updateChatListEntry ( ) ;
2014-05-30 08:53:19 +00:00
}
}
2016-03-22 15:23:34 +00:00
void History : : getNextShowFrom ( HistoryBlock * block , int i ) {
2014-05-30 08:53:19 +00:00
if ( i > = 0 ) {
2017-02-10 14:16:50 +00:00
auto l = block - > items . size ( ) ;
2014-05-30 08:53:19 +00:00
for ( + + i ; i < l ; + + i ) {
2017-02-10 14:16:50 +00:00
if ( block - > items [ i ] - > id > 0 ) {
2016-03-21 18:40:00 +00:00
showFrom = block - > items . at ( i ) ;
2014-05-30 08:53:19 +00:00
return ;
}
}
}
2017-02-10 14:16:50 +00:00
for ( auto j = block - > indexInHistory ( ) + 1 , s = blocks . size ( ) ; j < s ; + + j ) {
2016-03-21 18:40:00 +00:00
block = blocks . at ( j ) ;
2017-02-10 14:16:50 +00:00
for_const ( auto item , block - > items ) {
if ( item - > id > 0 ) {
2016-03-21 18:40:00 +00:00
showFrom = item ;
return ;
}
}
}
showFrom = nullptr ;
}
void History : : countScrollState ( int top ) {
countScrollTopItem ( top ) ;
if ( scrollTopItem ) {
scrollTopOffset = ( top - scrollTopItem - > block ( ) - > y - scrollTopItem - > y ) ;
}
}
void History : : countScrollTopItem ( int top ) {
if ( isEmpty ( ) ) {
forgetScrollState ( ) ;
return ;
}
int itemIndex = 0 , blockIndex = 0 , itemTop = 0 ;
if ( scrollTopItem & & ! scrollTopItem - > detached ( ) ) {
itemIndex = scrollTopItem - > indexInBlock ( ) ;
blockIndex = scrollTopItem - > block ( ) - > indexInHistory ( ) ;
itemTop = blocks . at ( blockIndex ) - > y + scrollTopItem - > y ;
}
if ( itemTop > top ) {
// go backward through history while we don't find an item that starts above
do {
HistoryBlock * block = blocks . at ( blockIndex ) ;
for ( - - itemIndex ; itemIndex > = 0 ; - - itemIndex ) {
HistoryItem * item = block - > items . at ( itemIndex ) ;
itemTop = block - > y + item - > y ;
if ( itemTop < = top ) {
scrollTopItem = item ;
2014-05-30 08:53:19 +00:00
return ;
}
}
2016-03-21 18:40:00 +00:00
if ( - - blockIndex > = 0 ) {
itemIndex = blocks . at ( blockIndex ) - > items . size ( ) ;
} else {
break ;
}
} while ( true ) ;
scrollTopItem = blocks . front ( ) - > items . front ( ) ;
} else {
// go forward through history while we don't find the last item that starts above
for ( int blocksCount = blocks . size ( ) ; blockIndex < blocksCount ; + + blockIndex ) {
HistoryBlock * block = blocks . at ( blockIndex ) ;
for ( int itemsCount = block - > items . size ( ) ; itemIndex < itemsCount ; + + itemIndex ) {
HistoryItem * item = block - > items . at ( itemIndex ) ;
itemTop = block - > y + item - > y ;
if ( itemTop > top ) {
t_assert ( itemIndex > 0 | | blockIndex > 0 ) ;
if ( itemIndex > 0 ) {
scrollTopItem = block - > items . at ( itemIndex - 1 ) ;
} else {
scrollTopItem = blocks . at ( blockIndex - 1 ) - > items . back ( ) ;
}
return ;
}
}
itemIndex = 0 ;
2014-05-30 08:53:19 +00:00
}
2016-03-21 18:40:00 +00:00
scrollTopItem = blocks . back ( ) - > items . back ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-21 18:40:00 +00:00
}
void History : : getNextScrollTopItem ( HistoryBlock * block , int32 i ) {
+ + i ;
if ( i > 0 & & i < block - > items . size ( ) ) {
scrollTopItem = block - > items . at ( i ) ;
return ;
}
int j = block - > indexInHistory ( ) + 1 ;
if ( j > 0 & & j < blocks . size ( ) ) {
scrollTopItem = blocks . at ( j ) - > items . front ( ) ;
return ;
}
scrollTopItem = nullptr ;
2014-05-30 08:53:19 +00:00
}
void History : : addUnreadBar ( ) {
2016-04-11 10:59:01 +00:00
if ( unreadBar | | ! showFrom | | showFrom - > detached ( ) | | ! unreadCount ( ) ) return ;
2015-12-31 15:27:21 +00:00
2016-04-11 10:59:01 +00:00
int32 count = unreadCount ( ) ;
2015-11-13 15:14:33 +00:00
if ( peer - > migrateTo ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateTo ( ) - > id ) ) {
2016-04-11 10:59:01 +00:00
count + = h - > unreadCount ( ) ;
2015-11-13 15:14:33 +00:00
}
}
2016-03-18 19:05:08 +00:00
showFrom - > setUnreadBarCount ( count ) ;
unreadBar = showFrom ;
}
void History : : destroyUnreadBar ( ) {
if ( unreadBar ) {
unreadBar - > destroyUnreadBar ( ) ;
2015-09-19 09:13:21 +00:00
}
}
2014-05-30 08:53:19 +00:00
2015-09-19 09:13:21 +00:00
HistoryItem * History : : addNewInTheMiddle ( HistoryItem * newItem , int32 blockIndex , int32 itemIndex ) {
2016-03-21 18:40:00 +00:00
t_assert ( blockIndex > = 0 ) ;
t_assert ( blockIndex < blocks . size ( ) ) ;
t_assert ( itemIndex > = 0 ) ;
2016-11-18 16:27:47 +00:00
t_assert ( itemIndex < = blocks [ blockIndex ] - > items . size ( ) ) ;
2014-05-30 08:53:19 +00:00
2016-11-18 16:27:47 +00:00
auto block = blocks . at ( blockIndex ) ;
2016-03-18 19:05:08 +00:00
newItem - > attachToBlock ( block , itemIndex ) ;
2015-09-19 09:13:21 +00:00
block - > items . insert ( itemIndex , newItem ) ;
2016-03-19 16:55:15 +00:00
newItem - > previousItemChanged ( ) ;
2016-03-21 18:40:00 +00:00
if ( itemIndex + 1 < block - > items . size ( ) ) {
2016-11-18 16:27:47 +00:00
for ( int i = itemIndex + 1 , l = block - > items . size ( ) ; i < l ; + + i ) {
block - > items [ i ] - > setIndexInBlock ( i ) ;
}
block - > items [ itemIndex + 1 ] - > previousItemChanged ( ) ;
} else if ( blockIndex + 1 < blocks . size ( ) & & ! blocks [ blockIndex + 1 ] - > items . empty ( ) ) {
blocks [ blockIndex + 1 ] - > items . front ( ) - > previousItemChanged ( ) ;
} else {
newItem - > nextItemChanged ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-21 18:40:00 +00:00
2015-09-19 09:13:21 +00:00
return newItem ;
2014-05-30 08:53:19 +00:00
}
2016-03-31 10:37:58 +00:00
void History : : startBuildingFrontBlock ( int expectedItemsCount ) {
t_assert ( ! isBuildingFrontBlock ( ) ) ;
t_assert ( expectedItemsCount > 0 ) ;
2016-03-31 11:18:21 +00:00
_buildingFrontBlock . reset ( new BuildingBlock ( ) ) ;
_buildingFrontBlock - > expectedItemsCount = expectedItemsCount ;
2016-03-31 10:37:58 +00:00
}
HistoryBlock * History : : finishBuildingFrontBlock ( ) {
t_assert ( isBuildingFrontBlock ( ) ) ;
// Some checks if there was some message history already
2016-11-18 16:27:47 +00:00
auto block = _buildingFrontBlock - > block ;
if ( block ) {
if ( blocks . size ( ) > 1 ) {
auto last = block - > items . back ( ) ; // ... item, item, item, last ], [ first, item, item ...
auto first = blocks . at ( 1 ) - > items . front ( ) ;
// we've added a new front block, so previous item for
// the old first item of a first block was changed
first - > previousItemChanged ( ) ;
} else {
block - > items . back ( ) - > nextItemChanged ( ) ;
}
2016-03-22 09:51:20 +00:00
}
2016-03-31 10:37:58 +00:00
2016-04-10 19:20:48 +00:00
_buildingFrontBlock = nullptr ;
2016-03-31 10:37:58 +00:00
return block ;
2016-03-22 09:51:20 +00:00
}
2014-07-04 11:12:54 +00:00
void History : : clearNotifications ( ) {
notifies . clear ( ) ;
}
bool History : : loadedAtBottom ( ) const {
return newLoaded ;
}
bool History : : loadedAtTop ( ) const {
return oldLoaded ;
}
2016-05-27 16:47:46 +00:00
bool History : : isReadyFor ( MsgId msgId ) {
2015-11-13 15:14:33 +00:00
if ( msgId < 0 & & - msgId < ServerMaxMsgId & & peer - > migrateFrom ( ) ) { // old group history
2016-05-27 16:47:46 +00:00
return App : : history ( peer - > migrateFrom ( ) - > id ) - > isReadyFor ( - msgId ) ;
2015-11-13 15:14:33 +00:00
}
2015-07-17 19:17:37 +00:00
if ( msgId = = ShowAtTheEndMsgId ) {
return loadedAtBottom ( ) ;
2015-09-19 09:13:21 +00:00
}
if ( msgId = = ShowAtUnreadMsgId ) {
2015-11-13 15:14:33 +00:00
if ( peer - > migrateFrom ( ) ) { // old group history
if ( History * h = App : : historyLoaded ( peer - > migrateFrom ( ) - > id ) ) {
2016-04-11 10:59:01 +00:00
if ( h - > unreadCount ( ) ) {
2016-05-27 16:47:46 +00:00
return h - > isReadyFor ( msgId ) ;
2015-11-13 15:14:33 +00:00
}
}
}
2016-04-11 10:59:01 +00:00
if ( unreadCount ( ) ) {
2015-09-19 09:13:21 +00:00
if ( ! isEmpty ( ) ) {
return ( loadedAtTop ( ) | | minMsgId ( ) < = inboxReadBefore ) & & ( loadedAtBottom ( ) | | maxMsgId ( ) > = inboxReadBefore ) ;
2015-09-08 13:34:22 +00:00
}
2015-09-19 09:13:21 +00:00
return false ;
2015-09-08 13:34:22 +00:00
}
2015-09-19 09:13:21 +00:00
return loadedAtBottom ( ) ;
2015-07-17 19:17:37 +00:00
}
2015-09-19 09:13:21 +00:00
HistoryItem * item = App : : histItemById ( channelId ( ) , msgId ) ;
return item & & ( item - > history ( ) = = this ) & & ! item - > detached ( ) ;
2015-07-17 19:17:37 +00:00
}
2016-05-27 16:47:46 +00:00
void History : : getReadyFor ( MsgId msgId ) {
2015-11-13 15:14:33 +00:00
if ( msgId < 0 & & - msgId < ServerMaxMsgId & & peer - > migrateFrom ( ) ) {
History * h = App : : history ( peer - > migrateFrom ( ) - > id ) ;
2016-05-27 16:47:46 +00:00
h - > getReadyFor ( - msgId ) ;
2015-11-13 15:14:33 +00:00
if ( h - > isEmpty ( ) ) {
clear ( true ) ;
}
return ;
}
if ( msgId = = ShowAtUnreadMsgId & & peer - > migrateFrom ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateFrom ( ) - > id ) ) {
2016-04-11 10:59:01 +00:00
if ( h - > unreadCount ( ) ) {
2015-11-13 15:14:33 +00:00
clear ( true ) ;
2016-05-27 16:47:46 +00:00
h - > getReadyFor ( msgId ) ;
2015-11-13 15:14:33 +00:00
return ;
}
}
}
2016-05-27 16:47:46 +00:00
if ( ! isReadyFor ( msgId ) ) {
2015-07-17 19:17:37 +00:00
clear ( true ) ;
2016-06-02 13:02:55 +00:00
2016-03-21 18:40:00 +00:00
if ( msgId = = ShowAtTheEndMsgId ) {
newLoaded = true ;
}
2015-07-17 19:17:37 +00:00
}
}
2015-09-13 08:41:27 +00:00
void History : : setNotLoadedAtBottom ( ) {
newLoaded = false ;
}
2015-09-06 10:17:09 +00:00
namespace {
uint32 _dialogsPosToTopShift = 0x80000000UL ;
}
inline uint64 dialogPosFromDate ( const QDateTime & date ) {
2016-06-21 15:58:07 +00:00
if ( date . isNull ( ) ) return 0 ;
2015-09-06 10:17:09 +00:00
return ( uint64 ( date . toTime_t ( ) ) < < 32 ) | ( + + _dialogsPosToTopShift ) ;
}
2016-12-13 07:59:57 +00:00
inline uint64 pinnedDialogPos ( int pinnedIndex ) {
return 0xFFFFFFFF00000000ULL + pinnedIndex ;
}
2015-09-21 20:57:42 +00:00
void History : : setLastMessage ( HistoryItem * msg ) {
2015-08-07 12:11:50 +00:00
if ( msg ) {
if ( ! lastMsg ) Local : : removeSavedPeer ( peer ) ;
lastMsg = msg ;
2016-02-28 11:58:30 +00:00
setChatsListDate ( msg - > date ) ;
2015-08-07 12:11:50 +00:00
} else {
lastMsg = 0 ;
2016-06-21 15:58:07 +00:00
updateChatListEntry ( ) ;
2015-08-07 12:11:50 +00:00
}
}
2016-06-03 18:24:27 +00:00
bool History : : needUpdateInChatList ( ) const {
2016-12-13 07:59:57 +00:00
if ( inChatList ( Dialogs : : Mode : : All ) | | isPinnedDialog ( ) ) {
2016-06-03 18:24:27 +00:00
return true ;
} else if ( peer - > migrateTo ( ) ) {
return false ;
2015-11-13 15:14:33 +00:00
}
2016-06-03 18:24:27 +00:00
return ( ! peer - > isChannel ( ) | | peer - > asChannel ( ) - > amIn ( ) ) ;
}
void History : : setChatsListDate ( const QDateTime & date ) {
2015-09-21 20:57:42 +00:00
if ( ! lastMsgDate . isNull ( ) & & lastMsgDate > = date ) {
2016-12-13 07:59:57 +00:00
if ( ! needUpdateInChatList ( ) | | ! inChatList ( Dialogs : : Mode : : All ) ) {
2015-09-21 20:57:42 +00:00
return ;
}
}
2015-09-06 10:17:09 +00:00
lastMsgDate = date ;
2016-06-03 18:24:27 +00:00
updateChatListSortPosition ( ) ;
}
void History : : updateChatListSortPosition ( ) {
auto chatListDate = [ this ] ( ) {
if ( auto draft = cloudDraft ( ) ) {
2016-06-21 15:58:07 +00:00
if ( ! Data : : draftIsNull ( draft ) & & draft - > date > lastMsgDate ) {
2016-06-03 18:24:27 +00:00
return draft - > date ;
}
}
return lastMsgDate ;
} ;
2016-12-13 07:59:57 +00:00
_sortKeyInChatList = isPinnedDialog ( ) ? pinnedDialogPos ( _pinnedIndex ) : dialogPosFromDate ( chatListDate ( ) ) ;
2016-06-21 15:58:07 +00:00
if ( auto m = App : : main ( ) ) {
if ( needUpdateInChatList ( ) ) {
if ( _sortKeyInChatList ) {
m - > createDialog ( this ) ;
updateChatListEntry ( ) ;
} else {
m - > deleteConversation ( peer , false ) ;
}
}
2015-09-06 10:17:09 +00:00
}
}
2014-07-04 11:12:54 +00:00
void History : : fixLastMessage ( bool wasAtBottom ) {
2017-02-10 14:16:50 +00:00
setLastMessage ( wasAtBottom ? lastAvailableMessage ( ) : 0 ) ;
2014-07-04 11:12:54 +00:00
}
MsgId History : : minMsgId ( ) const {
2016-03-15 10:37:56 +00:00
for_const ( const HistoryBlock * block , blocks ) {
for_const ( const HistoryItem * item , block - > items ) {
if ( item - > id > 0 ) {
return item - > id ;
2014-05-30 08:53:19 +00:00
}
}
}
2014-07-04 11:12:54 +00:00
return 0 ;
2014-05-30 08:53:19 +00:00
}
2014-07-04 11:12:54 +00:00
MsgId History : : maxMsgId ( ) const {
2016-03-15 10:37:56 +00:00
for ( auto i = blocks . cend ( ) , e = blocks . cbegin ( ) ; i ! = e ; ) {
2014-07-04 11:12:54 +00:00
- - i ;
2016-03-15 10:37:56 +00:00
for ( auto j = ( * i ) - > items . cend ( ) , en = ( * i ) - > items . cbegin ( ) ; j ! = en ; ) {
2014-07-04 11:12:54 +00:00
- - j ;
if ( ( * j ) - > id > 0 ) {
return ( * j ) - > id ;
}
}
}
return 0 ;
2014-05-30 08:53:19 +00:00
}
2015-09-06 10:17:09 +00:00
MsgId History : : msgIdForRead ( ) const {
MsgId result = ( lastMsg & & lastMsg - > id > 0 ) ? lastMsg - > id : 0 ;
if ( loadedAtBottom ( ) ) result = qMax ( result , maxMsgId ( ) ) ;
return result ;
}
2016-03-21 18:40:00 +00:00
int History : : resizeGetHeight ( int newWidth ) {
2016-04-08 09:20:10 +00:00
bool resizeAllItems = ( _flags & Flag : : f_pending_resize ) | | ( width ! = newWidth ) ;
2016-03-21 18:40:00 +00:00
if ( ! resizeAllItems & & ! hasPendingResizedItems ( ) ) {
return height ;
}
2016-03-19 16:55:15 +00:00
_flags & = ~ ( Flag : : f_pending_resize | Flag : : f_has_pending_resized_items ) ;
2016-03-21 18:40:00 +00:00
width = newWidth ;
int y = 0 ;
for_const ( HistoryBlock * block , blocks ) {
block - > y = y ;
y + = block - > resizeGetHeight ( newWidth , resizeAllItems ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-21 18:40:00 +00:00
height = y ;
2014-05-30 08:53:19 +00:00
return height ;
}
2015-09-19 09:13:21 +00:00
ChannelHistory * History : : asChannelHistory ( ) {
return isChannel ( ) ? static_cast < ChannelHistory * > ( this ) : 0 ;
}
const ChannelHistory * History : : asChannelHistory ( ) const {
return isChannel ( ) ? static_cast < const ChannelHistory * > ( this ) : 0 ;
}
2016-06-03 12:45:33 +00:00
bool History : : isDisplayedEmpty ( ) const {
2016-06-08 10:24:20 +00:00
return isEmpty ( ) | | ( ( blocks . size ( ) = = 1 ) & & blocks . front ( ) - > items . size ( ) = = 1 & & blocks . front ( ) - > items . front ( ) - > isEmpty ( ) ) ;
2016-06-03 12:45:33 +00:00
}
2014-07-04 11:12:54 +00:00
void History : : clear ( bool leaveItems ) {
if ( unreadBar ) {
2016-03-18 19:05:08 +00:00
unreadBar = nullptr ;
2014-07-04 11:12:54 +00:00
}
if ( showFrom ) {
2016-03-18 19:05:08 +00:00
showFrom = nullptr ;
2014-07-04 11:12:54 +00:00
}
2016-04-23 11:40:42 +00:00
if ( lastSentMsg ) {
lastSentMsg = nullptr ;
}
2016-03-21 18:40:00 +00:00
if ( scrollTopItem ) {
forgetScrollState ( ) ;
}
2015-08-04 15:01:47 +00:00
if ( ! leaveItems ) {
2016-03-18 19:05:08 +00:00
setLastMessage ( nullptr ) ;
2016-04-14 19:24:42 +00:00
notifies . clear ( ) ;
auto & pending = Global : : RefPendingRepaintItems ( ) ;
for ( auto i = pending . begin ( ) ; i ! = pending . end ( ) ; ) {
if ( ( * i ) - > history ( ) = = this ) {
i = pending . erase ( i ) ;
} else {
+ + i ;
}
}
2015-08-04 15:01:47 +00:00
}
2014-08-15 11:19:32 +00:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
2015-09-19 09:13:21 +00:00
if ( ! overview [ i ] . isEmpty ( ) | | ! overviewIds [ i ] . isEmpty ( ) ) {
2015-08-04 15:01:47 +00:00
if ( leaveItems ) {
2015-11-18 13:11:56 +00:00
if ( overviewCountData [ i ] = = 0 ) {
overviewCountData [ i ] = overview [ i ] . size ( ) ;
}
2015-08-04 15:01:47 +00:00
} else {
2015-11-18 13:11:56 +00:00
overviewCountData [ i ] = - 1 ; // not loaded yet
2015-08-04 15:01:47 +00:00
}
2015-09-19 09:13:21 +00:00
overview [ i ] . clear ( ) ;
overviewIds [ i ] . clear ( ) ;
2017-01-01 16:45:20 +00:00
if ( ! App : : quitting ( ) ) Notify : : mediaOverviewUpdated ( peer , MediaOverviewType ( i ) ) ;
2015-07-03 08:47:16 +00:00
}
2014-08-15 11:19:32 +00:00
}
2016-03-15 10:37:56 +00:00
clearBlocks ( leaveItems ) ;
2015-06-17 19:43:03 +00:00
if ( leaveItems ) {
lastKeyboardInited = false ;
} else {
2014-07-04 11:12:54 +00:00
setUnreadCount ( 0 ) ;
2016-04-14 19:24:42 +00:00
if ( peer - > isMegagroup ( ) ) {
peer - > asChannel ( ) - > mgInfo - > pinnedMsgId = 0 ;
}
clearLastKeyboard ( ) ;
2014-07-04 11:12:54 +00:00
}
2016-03-21 18:40:00 +00:00
setPendingResize ( ) ;
newLoaded = oldLoaded = false ;
forgetScrollState ( ) ;
2015-09-03 10:48:40 +00:00
if ( peer - > isChat ( ) ) {
2015-06-17 19:43:03 +00:00
peer - > asChat ( ) - > lastAuthors . clear ( ) ;
peer - > asChat ( ) - > markupSenders . clear ( ) ;
2015-09-21 20:57:42 +00:00
} else if ( isChannel ( ) ) {
2016-04-14 19:24:42 +00:00
asChannelHistory ( ) - > cleared ( leaveItems ) ;
2015-11-09 09:51:22 +00:00
if ( isMegagroup ( ) ) {
peer - > asChannel ( ) - > mgInfo - > markupSenders . clear ( ) ;
}
2015-06-17 19:43:03 +00:00
}
if ( leaveItems & & App : : main ( ) ) App : : main ( ) - > historyCleared ( this ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-15 10:37:56 +00:00
void History : : clearBlocks ( bool leaveItems ) {
Blocks lst ;
std : : swap ( lst , blocks ) ;
for_const ( HistoryBlock * block , lst ) {
if ( leaveItems ) {
block - > clear ( true ) ;
}
delete block ;
}
}
void History : : clearOnDestroy ( ) {
clearBlocks ( false ) ;
}
2016-04-11 11:14:54 +00:00
History : : PositionInChatListChange History : : adjustByPosInChatList ( Dialogs : : Mode list , Dialogs : : IndexedList * indexed ) {
2016-04-09 18:45:55 +00:00
t_assert ( indexed ! = nullptr ) ;
2016-04-11 10:59:01 +00:00
Dialogs : : Row * lnk = mainChatListLink ( list ) ;
2016-04-11 11:14:54 +00:00
int32 movedFrom = lnk - > pos ( ) ;
2016-04-11 10:59:01 +00:00
indexed - > adjustByPos ( chatListLinks ( list ) ) ;
2016-04-11 11:14:54 +00:00
int32 movedTo = lnk - > pos ( ) ;
return { movedFrom , movedTo } ;
2016-02-28 11:58:30 +00:00
}
2016-04-11 10:59:01 +00:00
int History : : posInChatList ( Dialogs : : Mode list ) const {
return mainChatListLink ( list ) - > pos ( ) ;
2016-04-09 18:45:55 +00:00
}
2016-04-11 10:59:01 +00:00
Dialogs : : Row * History : : addToChatList ( Dialogs : : Mode list , Dialogs : : IndexedList * indexed ) {
2016-04-09 18:45:55 +00:00
t_assert ( indexed ! = nullptr ) ;
2016-04-11 10:59:01 +00:00
if ( ! inChatList ( list ) ) {
chatListLinks ( list ) = indexed - > addToEnd ( this ) ;
if ( list = = Dialogs : : Mode : : All & & unreadCount ( ) ) {
App : : histories ( ) . unreadIncrement ( unreadCount ( ) , mute ( ) ) ;
2016-04-14 19:24:42 +00:00
Notify : : unreadCounterUpdated ( ) ;
2016-02-28 11:58:30 +00:00
}
}
2016-04-11 10:59:01 +00:00
return mainChatListLink ( list ) ;
2016-02-28 11:58:30 +00:00
}
2016-04-11 10:59:01 +00:00
void History : : removeFromChatList ( Dialogs : : Mode list , Dialogs : : IndexedList * indexed ) {
2016-04-09 18:45:55 +00:00
t_assert ( indexed ! = nullptr ) ;
2016-04-11 10:59:01 +00:00
if ( inChatList ( list ) ) {
2016-04-09 18:45:55 +00:00
indexed - > del ( peer ) ;
2016-04-11 10:59:01 +00:00
chatListLinks ( list ) . clear ( ) ;
if ( list = = Dialogs : : Mode : : All & & unreadCount ( ) ) {
App : : histories ( ) . unreadIncrement ( - unreadCount ( ) , mute ( ) ) ;
2016-04-14 19:24:42 +00:00
Notify : : unreadCounterUpdated ( ) ;
2016-02-28 11:58:30 +00:00
}
}
}
2016-04-11 10:59:01 +00:00
void History : : removeChatListEntryByLetter ( Dialogs : : Mode list , QChar letter ) {
2016-02-28 11:58:30 +00:00
t_assert ( letter ! = 0 ) ;
2016-04-11 10:59:01 +00:00
if ( inChatList ( list ) ) {
chatListLinks ( list ) . remove ( letter ) ;
2016-02-28 11:58:30 +00:00
}
}
2016-04-11 10:59:01 +00:00
void History : : addChatListEntryByLetter ( Dialogs : : Mode list , QChar letter , Dialogs : : Row * row ) {
2016-02-28 11:58:30 +00:00
t_assert ( letter ! = 0 ) ;
2016-04-11 10:59:01 +00:00
if ( inChatList ( list ) ) {
chatListLinks ( list ) . insert ( letter , row ) ;
2016-02-28 11:58:30 +00:00
}
}
void History : : updateChatListEntry ( ) const {
2016-12-05 08:45:56 +00:00
if ( auto main = App : : main ( ) ) {
2016-04-11 10:59:01 +00:00
if ( inChatList ( Dialogs : : Mode : : All ) ) {
2016-12-05 08:45:56 +00:00
main - > dlgUpdated ( Dialogs : : Mode : : All , mainChatListLink ( Dialogs : : Mode : : All ) ) ;
2016-04-11 10:59:01 +00:00
if ( inChatList ( Dialogs : : Mode : : Important ) ) {
2016-12-05 08:45:56 +00:00
main - > dlgUpdated ( Dialogs : : Mode : : Important , mainChatListLink ( Dialogs : : Mode : : Important ) ) ;
2016-04-11 10:59:01 +00:00
}
2016-02-28 11:58:30 +00:00
}
}
}
2016-12-13 07:59:57 +00:00
void History : : setPinnedDialog ( bool isPinned ) {
2017-01-30 15:27:13 +00:00
setPinnedIndex ( isPinned ? ( + + GlobalPinnedIndex ) : 0 ) ;
}
void History : : setPinnedIndex ( int pinnedIndex ) {
2016-12-13 07:59:57 +00:00
if ( _pinnedIndex ! = pinnedIndex ) {
auto wasPinned = isPinnedDialog ( ) ;
_pinnedIndex = pinnedIndex ;
updateChatListSortPosition ( ) ;
updateChatListEntry ( ) ;
if ( wasPinned ! = isPinnedDialog ( ) ) {
Notify : : peerUpdatedDelayed ( peer , Notify : : PeerUpdate : : Flag : : PinnedChanged ) ;
}
App : : histories ( ) . setIsPinned ( this , isPinnedDialog ( ) ) ;
}
}
2015-11-18 13:11:56 +00:00
void History : : overviewSliceDone ( int32 overviewIndex , const MTPmessages_Messages & result , bool onlyCounts ) {
const QVector < MTPMessage > * v = 0 ;
switch ( result . type ( ) ) {
case mtpc_messages_messages : {
2016-05-27 16:47:46 +00:00
auto & d ( result . c_messages_messages ( ) ) ;
2015-11-18 13:11:56 +00:00
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
v = & d . vmessages . c_vector ( ) . v ;
overviewCountData [ overviewIndex ] = 0 ;
} break ;
case mtpc_messages_messagesSlice : {
2016-05-27 16:47:46 +00:00
auto & d ( result . c_messages_messagesSlice ( ) ) ;
2015-11-18 13:11:56 +00:00
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
overviewCountData [ overviewIndex ] = d . vcount . v ;
v = & d . vmessages . c_vector ( ) . v ;
} break ;
case mtpc_messages_channelMessages : {
2016-05-27 16:47:46 +00:00
auto & d ( result . c_messages_channelMessages ( ) ) ;
2015-11-18 13:11:56 +00:00
if ( peer - > isChannel ( ) ) {
peer - > asChannel ( ) - > ptsReceived ( d . vpts . v ) ;
} else {
2016-01-11 15:43:29 +00:00
LOG ( ( " API Error: received messages.channelMessages when no channel was passed! (History::overviewSliceDone, onlyCounts %1) " ) . arg ( Logs : : b ( onlyCounts ) ) ) ;
2015-11-18 13:11:56 +00:00
}
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
overviewCountData [ overviewIndex ] = d . vcount . v ;
v = & d . vmessages . c_vector ( ) . v ;
} break ;
default : return ;
}
if ( ! onlyCounts & & v - > isEmpty ( ) ) {
overviewCountData [ overviewIndex ] = 0 ;
} else if ( overviewCountData [ overviewIndex ] > 0 ) {
2016-09-29 11:37:16 +00:00
for_const ( auto msgId , overviewIds [ overviewIndex ] ) {
if ( msgId < 0 ) {
2015-11-18 13:11:56 +00:00
+ + overviewCountData [ overviewIndex ] ;
} else {
break ;
}
}
}
for ( QVector < MTPMessage > : : const_iterator i = v - > cbegin ( ) , e = v - > cend ( ) ; i ! = e ; + + i ) {
HistoryItem * item = App : : histories ( ) . addNewMessage ( * i , NewMessageExisting ) ;
if ( item & & overviewIds [ overviewIndex ] . constFind ( item - > id ) = = overviewIds [ overviewIndex ] . cend ( ) ) {
2016-09-29 11:37:16 +00:00
overviewIds [ overviewIndex ] . insert ( item - > id ) ;
2015-11-18 13:11:56 +00:00
overview [ overviewIndex ] . push_front ( item - > id ) ;
}
}
}
void History : : changeMsgId ( MsgId oldId , MsgId newId ) {
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
2016-09-29 11:37:16 +00:00
auto j = overviewIds [ i ] . find ( oldId ) ;
2015-11-18 13:11:56 +00:00
if ( j ! = overviewIds [ i ] . cend ( ) ) {
overviewIds [ i ] . erase ( j ) ;
int32 index = overview [ i ] . indexOf ( oldId ) ;
if ( overviewIds [ i ] . constFind ( newId ) = = overviewIds [ i ] . cend ( ) ) {
2016-09-29 11:37:16 +00:00
overviewIds [ i ] . insert ( newId ) ;
2015-11-18 13:11:56 +00:00
if ( index > = 0 ) {
overview [ i ] [ index ] = newId ;
} else {
overview [ i ] . push_back ( newId ) ;
}
} else if ( index > = 0 ) {
overview [ i ] . removeAt ( index ) ;
}
}
}
}
2014-05-30 08:53:19 +00:00
void History : : removeBlock ( HistoryBlock * block ) {
2016-03-25 16:39:58 +00:00
t_assert ( block - > items . isEmpty ( ) ) ;
2016-03-31 11:18:21 +00:00
if ( _buildingFrontBlock & & block = = _buildingFrontBlock - > block ) {
_buildingFrontBlock - > block = nullptr ;
2016-03-31 10:37:58 +00:00
}
2016-03-21 18:40:00 +00:00
int index = block - > indexInHistory ( ) ;
blocks . removeAt ( index ) ;
if ( index < blocks . size ( ) ) {
2016-11-18 16:27:47 +00:00
for ( int i = index , l = blocks . size ( ) ; i < l ; + + i ) {
blocks . at ( i ) - > setIndexInHistory ( i ) ;
}
2016-03-21 18:40:00 +00:00
blocks . at ( index ) - > items . front ( ) - > previousItemChanged ( ) ;
2016-11-18 16:27:47 +00:00
} else if ( ! blocks . empty ( ) & & ! blocks . back ( ) - > items . empty ( ) ) {
blocks . back ( ) - > items . back ( ) - > nextItemChanged ( ) ;
2014-05-30 08:53:19 +00:00
}
}
2016-02-25 10:32:31 +00:00
History : : ~ History ( ) {
2016-03-15 10:37:56 +00:00
clearOnDestroy ( ) ;
2016-02-25 10:32:31 +00:00
}
2016-03-21 18:40:00 +00:00
int HistoryBlock : : resizeGetHeight ( int newWidth , bool resizeAllItems ) {
int y = 0 ;
for_const ( HistoryItem * item , items ) {
2014-05-30 08:53:19 +00:00
item - > y = y ;
2016-03-21 18:40:00 +00:00
if ( resizeAllItems | | item - > pendingResize ( ) ) {
y + = item - > resizeGetHeight ( newWidth ) ;
2015-09-10 10:30:59 +00:00
} else {
y + = item - > height ( ) ;
}
2014-05-30 08:53:19 +00:00
}
height = y ;
return height ;
}
2014-07-04 11:12:54 +00:00
void HistoryBlock : : clear ( bool leaveItems ) {
2016-03-15 10:37:56 +00:00
Items lst ;
std : : swap ( lst , items ) ;
2014-07-04 11:12:54 +00:00
if ( leaveItems ) {
2016-03-15 10:37:56 +00:00
for_const ( HistoryItem * item , lst ) {
item - > detachFast ( ) ;
2014-07-04 11:12:54 +00:00
}
} else {
2016-03-15 10:37:56 +00:00
for_const ( HistoryItem * item , lst ) {
delete item ;
2014-07-04 11:12:54 +00:00
}
2014-05-30 08:53:19 +00:00
}
}
void HistoryBlock : : removeItem ( HistoryItem * item ) {
2016-03-21 18:40:00 +00:00
t_assert ( item - > block ( ) = = this ) ;
2016-05-27 16:47:46 +00:00
int blockIndex = indexInHistory ( ) ;
2016-03-25 16:39:58 +00:00
int itemIndex = item - > indexInBlock ( ) ;
2014-05-30 08:53:19 +00:00
if ( history - > showFrom = = item ) {
2016-03-21 18:40:00 +00:00
history - > getNextShowFrom ( this , itemIndex ) ;
2014-05-30 08:53:19 +00:00
}
2016-04-23 11:40:42 +00:00
if ( history - > lastSentMsg = = item ) {
history - > lastSentMsg = nullptr ;
}
2016-03-18 19:05:08 +00:00
if ( history - > unreadBar = = item ) {
history - > unreadBar = nullptr ;
}
2016-03-21 18:40:00 +00:00
if ( history - > scrollTopItem = = item ) {
history - > getNextScrollTopItem ( this , itemIndex ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-26 06:41:23 +00:00
item - > detachFast ( ) ;
2016-03-21 18:40:00 +00:00
items . remove ( itemIndex ) ;
for ( int i = itemIndex , l = items . size ( ) ; i < l ; + + i ) {
items . at ( i ) - > setIndexInBlock ( i ) ;
}
2016-03-26 06:41:23 +00:00
if ( items . isEmpty ( ) ) {
history - > removeBlock ( this ) ;
} else if ( itemIndex < items . size ( ) ) {
2016-03-21 18:40:00 +00:00
items . at ( itemIndex ) - > previousItemChanged ( ) ;
2016-03-26 06:41:23 +00:00
} else if ( blockIndex + 1 < history - > blocks . size ( ) ) {
history - > blocks . at ( blockIndex + 1 ) - > items . front ( ) - > previousItemChanged ( ) ;
2016-11-18 16:27:47 +00:00
} else if ( ! history - > blocks . empty ( ) & & ! history - > blocks . back ( ) - > items . empty ( ) ) {
history - > blocks . back ( ) - > items . back ( ) - > nextItemChanged ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-18 19:05:08 +00:00
2016-03-21 18:40:00 +00:00
if ( items . isEmpty ( ) ) {
2016-03-26 06:41:23 +00:00
delete this ;
2014-05-30 08:53:19 +00:00
}
}