2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04: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 16:16:42 +03: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 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2016-02-08 13:56:18 +03:00
Copyright ( c ) 2014 - 2016 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# pragma once
void historyInit ( ) ;
class HistoryItem ;
2014-10-10 16:46:20 +04:00
2014-08-20 09:32:50 +04:00
typedef QMap < int32 , HistoryItem * > SelectedItemSet ;
2015-04-04 23:01:34 +03:00
# include "structs.h"
2016-04-09 22:45:55 +04:00
# include "dialogs/dialogs_common.h"
2014-12-23 02:11:37 +03:00
2015-09-20 11:55:41 +03:00
enum NewMessageType {
NewMessageUnread ,
NewMessageLast ,
NewMessageExisting ,
} ;
2015-09-19 12:13:21 +03:00
class History ;
2015-12-08 15:33:37 +03:00
class Histories {
2015-09-19 12:13:21 +03:00
public :
typedef QHash < PeerId , History * > Map ;
Map map ;
2014-05-30 12:53:19 +04:00
2016-02-28 14:58:30 +03:00
Histories ( ) : _a_typings ( animation ( this , & Histories : : step_typings ) ) , _unreadFull ( 0 ) , _unreadMuted ( 0 ) {
2014-05-30 12:53:19 +04:00
}
2015-08-01 11:33:00 +03:00
void regSendAction ( History * history , UserData * user , const MTPSendMessageAction & action ) ;
2015-12-08 15:33:37 +03:00
void step_typings ( uint64 ms , bool timer ) ;
2014-12-12 19:27:03 +03:00
2015-09-19 12:13:21 +03:00
History * find ( const PeerId & peerId ) ;
2016-05-20 19:01:06 +03:00
History * findOrInsert ( const PeerId & peerId , int32 unreadCount , int32 maxInboxRead , int32 maxOutboxRead ) ;
2015-09-19 12:13:21 +03:00
2014-05-30 12:53:19 +04:00
void clear ( ) ;
2014-12-18 21:40:49 +03:00
void remove ( const PeerId & peer ) ;
2014-05-30 12:53:19 +04:00
~ Histories ( ) {
2016-02-28 14:58:30 +03:00
_unreadFull = _unreadMuted = 0 ;
2014-05-30 12:53:19 +04:00
}
2015-09-21 23:57:42 +03:00
HistoryItem * addNewMessage ( const MTPMessage & msg , NewMessageType type ) ;
2014-05-30 12:53:19 +04:00
typedef QMap < History * , uint64 > TypingHistories ; // when typing in this history started
TypingHistories typing ;
2015-12-08 15:33:37 +03:00
Animation _a_typings ;
2014-05-30 12:53:19 +04:00
2016-02-28 14:58:30 +03:00
int32 unreadBadge ( ) const {
return _unreadFull - ( cIncludeMuted ( ) ? 0 : _unreadMuted ) ;
}
2016-04-11 14:59:01 +04:00
int32 unreadMutedCount ( ) const {
return _unreadMuted ;
}
2016-02-28 14:58:30 +03:00
bool unreadOnlyMuted ( ) const {
return cIncludeMuted ( ) ? ( _unreadMuted > = _unreadFull ) : false ;
}
void unreadIncrement ( int32 count , bool muted ) {
_unreadFull + = count ;
if ( muted ) {
_unreadMuted + = count ;
}
}
void unreadMuteChanged ( int32 count , bool muted ) {
if ( muted ) {
_unreadMuted + = count ;
} else {
_unreadMuted - = count ;
}
}
private :
int32 _unreadFull , _unreadMuted ;
2014-05-30 12:53:19 +04:00
} ;
2015-09-19 12:13:21 +03:00
class HistoryBlock ;
2014-05-30 12:53:19 +04:00
2014-08-15 15:19:32 +04:00
enum HistoryMediaType {
MediaTypePhoto ,
MediaTypeVideo ,
MediaTypeContact ,
2016-02-12 19:35:06 +03:00
MediaTypeFile ,
2015-12-08 22:07:50 +03:00
MediaTypeGif ,
2014-12-23 02:11:37 +03:00
MediaTypeSticker ,
2016-02-28 16:54:04 +03:00
MediaTypeLocation ,
2015-04-04 23:01:34 +03:00
MediaTypeWebPage ,
2016-02-12 19:35:06 +03:00
MediaTypeMusicFile ,
MediaTypeVoiceFile ,
2014-08-15 15:19:32 +04:00
MediaTypeCount
} ;
enum MediaOverviewType {
2016-02-12 19:35:06 +03:00
OverviewPhotos = 0 ,
OverviewVideos = 1 ,
OverviewMusicFiles = 2 ,
OverviewFiles = 3 ,
OverviewVoiceFiles = 4 ,
OverviewLinks = 5 ,
2016-05-20 19:01:06 +03:00
OverviewChatPhotos = 6 ,
2014-08-15 15:19:32 +04:00
OverviewCount
} ;
inline MTPMessagesFilter typeToMediaFilter ( MediaOverviewType & type ) {
switch ( type ) {
case OverviewPhotos : return MTP_inputMessagesFilterPhotos ( ) ;
case OverviewVideos : return MTP_inputMessagesFilterVideo ( ) ;
2016-02-12 19:35:06 +03:00
case OverviewMusicFiles : return MTP_inputMessagesFilterMusic ( ) ;
case OverviewFiles : return MTP_inputMessagesFilterDocument ( ) ;
case OverviewVoiceFiles : return MTP_inputMessagesFilterVoice ( ) ;
2015-08-21 14:23:44 +03:00
case OverviewLinks : return MTP_inputMessagesFilterUrl ( ) ;
2016-05-20 19:01:06 +03:00
case OverviewChatPhotos : return MTP_inputMessagesFilterChatPhotos ( ) ;
2016-04-06 15:07:05 +04:00
case OverviewCount : break ;
2014-08-15 15:19:32 +04:00
default : type = OverviewCount ; break ;
}
return MTPMessagesFilter ( ) ;
}
2015-08-01 11:33:00 +03:00
enum SendActionType {
SendActionTyping ,
SendActionRecordVideo ,
SendActionUploadVideo ,
2016-02-12 19:35:06 +03:00
SendActionRecordVoice ,
SendActionUploadVoice ,
2015-08-01 11:33:00 +03:00
SendActionUploadPhoto ,
SendActionUploadFile ,
SendActionChooseLocation ,
SendActionChooseContact ,
} ;
struct SendAction {
SendAction ( SendActionType type , uint64 until , int32 progress = 0 ) : type ( type ) , until ( until ) , progress ( progress ) {
}
SendActionType type ;
uint64 until ;
int32 progress ;
} ;
2016-05-05 19:04:17 +03:00
using TextWithTags = FlatTextarea : : TextWithTags ;
2016-02-25 13:32:31 +03:00
struct HistoryDraft {
HistoryDraft ( ) : msgId ( 0 ) , previewCancelled ( false ) {
}
2016-05-05 19:04:17 +03:00
HistoryDraft ( const TextWithTags & textWithTags , MsgId msgId , const MessageCursor & cursor , bool previewCancelled )
: textWithTags ( textWithTags )
2016-02-25 13:32:31 +03:00
, msgId ( msgId )
, cursor ( cursor )
, previewCancelled ( previewCancelled ) {
}
HistoryDraft ( const FlatTextarea & field , MsgId msgId , bool previewCancelled )
2016-05-05 19:04:17 +03:00
: textWithTags ( field . getTextWithTags ( ) )
2016-02-25 13:32:31 +03:00
, msgId ( msgId )
, cursor ( field )
, previewCancelled ( previewCancelled ) {
}
2016-05-05 19:04:17 +03:00
TextWithTags textWithTags ;
2016-02-25 13:32:31 +03:00
MsgId msgId ; // replyToId for message draft, editMsgId for edit draft
MessageCursor cursor ;
bool previewCancelled ;
} ;
struct HistoryEditDraft : public HistoryDraft {
HistoryEditDraft ( )
: HistoryDraft ( )
, saveRequest ( 0 ) {
}
2016-05-05 19:04:17 +03:00
HistoryEditDraft ( const TextWithTags & textWithTags , MsgId msgId , const MessageCursor & cursor , bool previewCancelled , mtpRequestId saveRequest = 0 )
: HistoryDraft ( textWithTags , msgId , cursor , previewCancelled )
2016-02-25 13:32:31 +03:00
, saveRequest ( saveRequest ) {
}
HistoryEditDraft ( const FlatTextarea & field , MsgId msgId , bool previewCancelled , mtpRequestId saveRequest = 0 )
: HistoryDraft ( field , msgId , previewCancelled )
, saveRequest ( saveRequest ) {
}
mtpRequestId saveRequest ;
} ;
2014-05-30 12:53:19 +04:00
class HistoryMedia ;
class HistoryMessage ;
2015-09-19 12:13:21 +03:00
2016-01-03 09:43:42 +08:00
enum AddToOverviewMethod {
AddToOverviewNew , // when new message is added to history
AddToOverviewFront , // when old messages slice was received
AddToOverviewBack , // when new messages slice was received and it is the last one, we index all media
} ;
2016-04-09 22:45:55 +04:00
namespace Dialogs {
class Row ;
class IndexedList ;
} // namespace Dialogs
2015-09-19 12:13:21 +03:00
class ChannelHistory ;
class History {
public :
2014-05-30 12:53:19 +04:00
History ( const PeerId & peerId ) ;
2016-03-22 12:51:20 +03:00
History ( const History & ) = delete ;
History & operator = ( const History & ) = delete ;
2015-09-03 13:48:40 +03:00
ChannelId channelId ( ) const {
return peerToChannel ( peer - > id ) ;
}
2015-09-19 12:13:21 +03:00
bool isChannel ( ) const {
return peerIsChannel ( peer - > id ) ;
}
2015-11-02 17:33:57 -05:00
bool isMegagroup ( ) const {
return peer - > isMegagroup ( ) ;
}
2015-09-19 12:13:21 +03:00
ChannelHistory * asChannelHistory ( ) ;
const ChannelHistory * asChannelHistory ( ) const ;
2014-05-30 12:53:19 +04:00
2015-09-19 12:13:21 +03:00
bool isEmpty ( ) const {
return blocks . isEmpty ( ) ;
}
2016-06-03 15:45:33 +03:00
bool isDisplayedEmpty ( ) const ;
2014-07-04 15:12:54 +04:00
void clear ( bool leaveItems = false ) ;
2014-05-30 12:53:19 +04:00
2016-02-25 13:32:31 +03:00
virtual ~ History ( ) ;
2014-05-30 12:53:19 +04:00
2016-03-29 20:17:00 +03:00
HistoryItem * addNewService ( MsgId msgId , QDateTime date , const QString & text , MTPDmessage : : Flags flags = 0 , bool newMsg = true ) ;
2015-09-21 23:57:42 +03:00
HistoryItem * addNewMessage ( const MTPMessage & msg , NewMessageType type ) ;
HistoryItem * addToHistory ( const MTPMessage & msg ) ;
2016-03-19 19:55:15 +03:00
HistoryItem * addNewForwarded ( MsgId id , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * item ) ;
2016-04-06 12:00:37 +04:00
HistoryItem * addNewDocument ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption , const MTPReplyMarkup & markup ) ;
HistoryItem * addNewPhoto ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption , const MTPReplyMarkup & markup ) ;
2015-01-02 17:55:24 +03:00
2016-05-27 19:47:46 +03:00
void addOlderSlice ( const QVector < MTPMessage > & slice ) ;
void addNewerSlice ( const QVector < MTPMessage > & slice ) ;
2016-01-03 09:43:42 +08:00
bool addToOverview ( MediaOverviewType type , MsgId msgId , AddToOverviewMethod method ) ;
void eraseFromOverview ( MediaOverviewType type , MsgId msgId ) ;
2014-07-04 15:12:54 +04:00
void newItemAdded ( HistoryItem * item ) ;
2014-10-22 22:39:03 +04:00
void unregTyping ( UserData * from ) ;
2014-07-04 15:12:54 +04:00
2016-03-22 18:23:34 +03:00
int countUnread ( MsgId upTo ) ;
2015-09-19 12:13:21 +03:00
void updateShowFrom ( ) ;
2015-09-06 13:17:09 +03:00
MsgId inboxRead ( MsgId upTo ) ;
MsgId inboxRead ( HistoryItem * wasRead ) ;
MsgId outboxRead ( MsgId upTo ) ;
MsgId outboxRead ( HistoryItem * wasRead ) ;
2014-05-30 12:53:19 +04:00
2015-09-20 11:55:41 +03:00
HistoryItem * lastImportantMessage ( ) const ;
2016-04-11 14:59:01 +04:00
int unreadCount ( ) const {
return _unreadCount ;
}
2016-04-14 22:24:42 +03:00
void setUnreadCount ( int newUnreadCount ) ;
2016-04-11 14:59:01 +04:00
bool mute ( ) const {
return _mute ;
}
2014-05-30 12:53:19 +04:00
void setMute ( bool newMute ) ;
2016-03-22 18:23:34 +03:00
void getNextShowFrom ( HistoryBlock * block , int i ) ;
2014-05-30 12:53:19 +04:00
void addUnreadBar ( ) ;
2016-03-18 22:05:08 +03:00
void destroyUnreadBar ( ) ;
2014-07-04 15:12:54 +04:00
void clearNotifications ( ) ;
bool loadedAtBottom ( ) const ; // last message is in the list
2015-09-13 11:41:27 +03:00
void setNotLoadedAtBottom ( ) ;
2014-07-04 15:12:54 +04:00
bool loadedAtTop ( ) const ; // nothing was added after loading history back
2016-05-27 19:47:46 +03:00
bool isReadyFor ( MsgId msgId ) ; // has messages for showing history at msgId
void getReadyFor ( MsgId msgId ) ;
2014-07-04 15:12:54 +04:00
2015-09-21 23:57:42 +03:00
void setLastMessage ( HistoryItem * msg ) ;
2014-07-04 15:12:54 +04:00
void fixLastMessage ( bool wasAtBottom ) ;
2016-02-28 14:58:30 +03:00
void setChatsListDate ( const QDateTime & date ) ;
uint64 sortKeyInChatList ( ) const {
return _sortKeyInChatList ;
}
2016-04-11 15:14:54 +04:00
struct PositionInChatListChange {
int movedFrom ;
int movedTo ;
} ;
PositionInChatListChange adjustByPosInChatList ( Dialogs : : Mode list , Dialogs : : IndexedList * indexed ) ;
2016-04-11 14:59:01 +04:00
bool inChatList ( Dialogs : : Mode list ) const {
return ! chatListLinks ( list ) . isEmpty ( ) ;
2016-02-28 14:58:30 +03:00
}
2016-04-11 14:59:01 +04:00
int posInChatList ( Dialogs : : Mode list ) const ;
Dialogs : : Row * addToChatList ( Dialogs : : Mode list , Dialogs : : IndexedList * indexed ) ;
void removeFromChatList ( Dialogs : : Mode list , Dialogs : : IndexedList * indexed ) ;
void removeChatListEntryByLetter ( Dialogs : : Mode list , QChar letter ) ;
void addChatListEntryByLetter ( Dialogs : : Mode list , QChar letter , Dialogs : : Row * row ) ;
2016-02-28 14:58:30 +03:00
void updateChatListEntry ( ) const ;
2014-07-04 15:12:54 +04:00
MsgId minMsgId ( ) const ;
MsgId maxMsgId ( ) const ;
2015-09-06 13:17:09 +03:00
MsgId msgIdForRead ( ) const ;
2014-05-30 12:53:19 +04:00
2016-03-21 21:40:00 +03:00
int resizeGetHeight ( int newWidth ) ;
2014-07-04 15:12:54 +04:00
void removeNotification ( HistoryItem * item ) {
if ( ! notifies . isEmpty ( ) ) {
2016-03-15 13:37:56 +03:00
for ( auto i = notifies . begin ( ) , e = notifies . end ( ) ; i ! = e ; + + i ) {
2014-07-04 15:12:54 +04:00
if ( ( * i ) = = item ) {
notifies . erase ( i ) ;
break ;
}
}
}
}
HistoryItem * currentNotification ( ) {
return notifies . isEmpty ( ) ? 0 : notifies . front ( ) ;
}
2015-04-23 18:50:11 +03:00
bool hasNotification ( ) const {
return ! notifies . isEmpty ( ) ;
}
2014-07-04 15:12:54 +04:00
void skipNotification ( ) {
if ( ! notifies . isEmpty ( ) ) {
notifies . pop_front ( ) ;
}
}
2015-03-19 12:18:19 +03:00
void popNotification ( HistoryItem * item ) {
if ( ! notifies . isEmpty ( ) & & notifies . back ( ) = = item ) notifies . pop_back ( ) ;
}
2014-07-04 15:12:54 +04:00
2016-03-19 19:55:15 +03:00
bool hasPendingResizedItems ( ) const {
return _flags & Flag : : f_has_pending_resized_items ;
}
void setHasPendingResizedItems ( ) ;
void setPendingResize ( ) {
_flags | = Flag : : f_pending_resize ;
setHasPendingResizedItems ( ) ;
}
2015-09-19 12:13:21 +03:00
void paintDialog ( Painter & p , int32 w , bool sel ) const ;
2016-01-05 12:52:40 +08:00
bool updateTyping ( uint64 ms , bool force = false ) ;
2015-09-19 12:13:21 +03:00
void clearLastKeyboard ( ) ;
2016-03-23 14:47:32 +03:00
// optimization for userpics displayed on the left
// if this returns false there is no need to even try to handle them
bool canHaveFromPhotos ( ) const ;
2015-09-19 12:13:21 +03:00
typedef QList < HistoryBlock * > Blocks ;
Blocks blocks ;
2016-04-08 18:16:52 +04:00
int width = 0 ;
int height = 0 ;
int32 msgCount = 0 ;
MsgId inboxReadBefore = 1 ;
MsgId outboxReadBefore = 1 ;
HistoryItem * showFrom = nullptr ;
HistoryItem * unreadBar = nullptr ;
2015-09-19 12:13:21 +03:00
PeerData * peer ;
2016-04-08 18:16:52 +04:00
bool oldLoaded = false ;
bool newLoaded = true ;
HistoryItem * lastMsg = nullptr ;
2016-04-23 14:40:42 +03:00
HistoryItem * lastSentMsg = nullptr ;
2015-09-19 12:13:21 +03:00
QDateTime lastMsgDate ;
typedef QList < HistoryItem * > NotifyQueue ;
NotifyQueue notifies ;
2016-04-08 18:16:52 +04:00
HistoryDraft * msgDraft ( ) {
2016-04-10 23:20:48 +04:00
return _msgDraft . get ( ) ;
2016-04-08 18:16:52 +04:00
}
HistoryEditDraft * editDraft ( ) {
2016-04-10 23:20:48 +04:00
return _editDraft . get ( ) ;
2016-04-08 18:16:52 +04:00
}
2016-04-10 23:20:48 +04:00
void setMsgDraft ( std_ : : unique_ptr < HistoryDraft > & & draft ) {
2016-04-08 18:16:52 +04:00
_msgDraft = std_ : : move ( draft ) ;
}
void takeMsgDraft ( History * from ) {
if ( auto & draft = from - > _msgDraft ) {
2016-05-05 19:04:17 +03:00
if ( ! draft - > textWithTags . text . isEmpty ( ) & & ! _msgDraft ) {
2016-04-08 18:16:52 +04:00
_msgDraft = std_ : : move ( draft ) ;
_msgDraft - > msgId = 0 ; // edit and reply to drafts can't migrate
}
from - > clearMsgDraft ( ) ;
}
2016-02-25 13:32:31 +03:00
}
2016-04-10 23:20:48 +04:00
void setEditDraft ( std_ : : unique_ptr < HistoryEditDraft > & & draft ) {
2016-04-08 18:16:52 +04:00
_editDraft = std_ : : move ( draft ) ;
2016-02-25 13:32:31 +03:00
}
2016-04-08 18:16:52 +04:00
void clearMsgDraft ( ) {
2016-04-10 23:20:48 +04:00
_msgDraft = nullptr ;
2016-04-08 18:16:52 +04:00
}
void clearEditDraft ( ) {
2016-04-10 23:20:48 +04:00
_editDraft = nullptr ;
2016-04-08 18:16:52 +04:00
}
HistoryDraft * draft ( ) {
return _editDraft ? editDraft ( ) : msgDraft ( ) ;
2016-02-25 13:32:31 +03:00
}
2016-03-21 21:40:00 +03:00
// some fields below are a property of a currently displayed instance of this
// conversation history not a property of the conversation history itself
public :
// we save the last showAtMsgId to restore the state when switching
// between different conversation histories
2016-04-08 18:16:52 +04:00
MsgId showAtMsgId = ShowAtUnreadMsgId ;
2016-03-21 21:40:00 +03:00
// we save a pointer of the history item at the top of the displayed window
// together with an offset from the window top to the top of this message
// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
2016-04-08 18:16:52 +04:00
HistoryItem * scrollTopItem = nullptr ;
int scrollTopOffset = 0 ;
2016-03-21 21:40:00 +03:00
void forgetScrollState ( ) {
scrollTopItem = nullptr ;
}
// find the correct scrollTopItem and scrollTopOffset using given top
// of the displayed window relative to the history start coord
void countScrollState ( int top ) ;
protected :
// when this item is destroyed scrollTopItem just points to the next one
// and scrollTopOffset remains the same
// if we are at the bottom of the window scrollTopItem == nullptr and
// scrollTopOffset is undefined
void getNextScrollTopItem ( HistoryBlock * block , int32 i ) ;
// helper method for countScrollState(int top)
void countScrollTopItem ( int top ) ;
public :
2016-04-08 18:16:52 +04:00
bool lastKeyboardInited = false ;
bool lastKeyboardUsed = false ;
MsgId lastKeyboardId = 0 ;
MsgId lastKeyboardHiddenId = 0 ;
PeerId lastKeyboardFrom = 0 ;
2015-06-15 20:19:24 +03:00
2016-04-08 18:16:52 +04:00
mtpRequestId sendRequestId = 0 ;
2014-11-05 20:43:32 +03:00
2016-04-08 18:16:52 +04:00
mutable const HistoryItem * textCachedFor = nullptr ; // cache
mutable Text lastItemTextCache = Text { int ( st : : dlgRichMinWidth ) } ;
2014-05-30 12:53:19 +04:00
typedef QMap < UserData * , uint64 > TypingUsers ;
TypingUsers typing ;
2015-08-01 11:33:00 +03:00
typedef QMap < UserData * , SendAction > SendActionUsers ;
SendActionUsers sendActions ;
2014-05-30 12:53:19 +04:00
QString typingStr ;
2016-04-08 18:16:52 +04:00
Text typingText = Text { int ( st : : dlgRichMinWidth ) } ;
2016-01-05 12:52:40 +08:00
uint32 typingDots ;
2015-08-01 11:33:00 +03:00
QMap < SendActionType , uint64 > mySendActions ;
2014-05-30 12:53:19 +04:00
2014-08-11 13:03:45 +04:00
typedef QList < MsgId > MediaOverview ;
2015-09-19 12:13:21 +03:00
MediaOverview overview [ OverviewCount ] ;
2015-11-18 16:11:56 +03:00
bool overviewCountLoaded ( int32 overviewIndex ) const {
return overviewCountData [ overviewIndex ] > = 0 ;
2015-11-16 19:04:37 +03:00
}
2015-11-18 16:11:56 +03:00
bool overviewLoaded ( int32 overviewIndex ) const {
return overviewCount ( overviewIndex ) = = overview [ overviewIndex ] . size ( ) ;
}
int32 overviewCount ( int32 overviewIndex , int32 defaultValue = - 1 ) const {
int32 result = overviewCountData [ overviewIndex ] , loaded = overview [ overviewIndex ] . size ( ) ;
if ( result < 0 ) return defaultValue ;
if ( result < loaded ) {
if ( result > 0 ) {
const_cast < History * > ( this ) - > overviewCountData [ overviewIndex ] = 0 ;
}
return loaded ;
}
return result ;
}
MsgId overviewMinId ( int32 overviewIndex ) const {
for ( MediaOverviewIds : : const_iterator i = overviewIds [ overviewIndex ] . cbegin ( ) , e = overviewIds [ overviewIndex ] . cend ( ) ; i ! = e ; + + i ) {
if ( i . key ( ) > 0 ) {
return i . key ( ) ;
}
}
return 0 ;
}
void overviewSliceDone ( int32 overviewIndex , const MTPmessages_Messages & result , bool onlyCounts = false ) ;
bool overviewHasMsgId ( int32 overviewIndex , MsgId msgId ) const {
return overviewIds [ overviewIndex ] . constFind ( msgId ) ! = overviewIds [ overviewIndex ] . cend ( ) ;
2015-11-16 19:04:37 +03:00
}
2015-11-18 16:11:56 +03:00
void changeMsgId ( MsgId oldId , MsgId newId ) ;
2016-03-15 13:37:56 +03:00
protected :
void clearOnDestroy ( ) ;
2016-03-19 21:32:17 +03:00
HistoryItem * addNewToLastBlock ( const MTPMessage & msg , NewMessageType type ) ;
2016-03-15 13:37:56 +03:00
2016-03-31 14:37:58 +04:00
friend class HistoryBlock ;
// this method just removes a block from the blocks list
// when the last item from this block was detached and
// calls the required previousItemChanged()
void removeBlock ( HistoryBlock * block ) ;
void clearBlocks ( bool leaveItems ) ;
HistoryItem * createItem ( const MTPMessage & msg , bool applyServiceAction , bool detachExistingItem ) ;
HistoryItem * createItemForwarded ( MsgId id , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * msg ) ;
2016-04-06 12:00:37 +04:00
HistoryItem * createItemDocument ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption , const MTPReplyMarkup & markup ) ;
HistoryItem * createItemPhoto ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption , const MTPReplyMarkup & markup ) ;
2016-03-31 14:37:58 +04:00
HistoryItem * addNewItem ( HistoryItem * adding , bool newMsg ) ;
HistoryItem * addNewInTheMiddle ( HistoryItem * newItem , int32 blockIndex , int32 itemIndex ) ;
// All this methods add a new item to the first or last block
// depending on if we are in isBuildingFronBlock() state.
// The last block is created on the go if it is needed.
// Adds the item to the back or front block, depending on
// isBuildingFrontBlock(), creating the block if necessary.
void addItemToBlock ( HistoryItem * item ) ;
// Usually all new items are added to the last block.
// Only when we scroll up and add a new slice to the
// front we want to create a new front block.
void startBuildingFrontBlock ( int expectedItemsCount = 1 ) ;
HistoryBlock * finishBuildingFrontBlock ( ) ; // Returns the built block or nullptr if nothing was added.
bool isBuildingFrontBlock ( ) const {
2016-04-10 23:20:48 +04:00
return _buildingFrontBlock ! = nullptr ;
2016-03-31 14:37:58 +04:00
}
2015-09-19 12:13:21 +03:00
private :
2014-08-15 15:19:32 +04:00
2016-04-11 11:43:40 +04:00
// After adding a new history slice check the lastMsg and newLoaded.
void checkLastMsg ( ) ;
2016-03-31 14:37:58 +04:00
enum class Flag {
2016-03-19 19:55:15 +03:00
f_has_pending_resized_items = ( 1 < < 0 ) ,
2016-03-31 14:37:58 +04:00
f_pending_resize = ( 1 < < 1 ) ,
2016-03-19 19:55:15 +03:00
} ;
Q_DECLARE_FLAGS ( Flags , Flag ) ;
2016-03-31 14:37:58 +04:00
Q_DECL_CONSTEXPR friend inline QFlags < Flags : : enum_type > operator | ( Flags : : enum_type f1 , Flags : : enum_type f2 ) noexcept {
2016-03-19 19:55:15 +03:00
return QFlags < Flags : : enum_type > ( f1 ) | f2 ;
}
2016-03-31 14:37:58 +04:00
Q_DECL_CONSTEXPR friend inline QFlags < Flags : : enum_type > operator | ( Flags : : enum_type f1 , QFlags < Flags : : enum_type > f2 ) noexcept {
2016-03-19 19:55:15 +03:00
return f2 | f1 ;
}
2016-03-31 14:37:58 +04:00
Q_DECL_CONSTEXPR friend inline QFlags < Flags : : enum_type > operator ~ ( Flags : : enum_type f ) noexcept {
return ~ QFlags < Flags : : enum_type > ( f ) ;
}
2016-03-19 19:55:15 +03:00
Flags _flags ;
2016-04-11 14:59:01 +04:00
bool _mute ;
int32 _unreadCount = 0 ;
2016-03-19 19:55:15 +03:00
2016-04-11 14:59:01 +04:00
Dialogs : : RowsByLetter _chatListLinks [ 2 ] ;
Dialogs : : RowsByLetter & chatListLinks ( Dialogs : : Mode list ) {
return _chatListLinks [ static_cast < int > ( list ) ] ;
}
const Dialogs : : RowsByLetter & chatListLinks ( Dialogs : : Mode list ) const {
return _chatListLinks [ static_cast < int > ( list ) ] ;
}
Dialogs : : Row * mainChatListLink ( Dialogs : : Mode list ) const {
auto it = chatListLinks ( list ) . constFind ( 0 ) ;
t_assert ( it ! = chatListLinks ( list ) . cend ( ) ) ;
2016-03-24 16:27:34 +03:00
return it . value ( ) ;
}
2016-04-08 18:16:52 +04:00
uint64 _sortKeyInChatList = 0 ; // like ((unixtime) << 32) | (incremented counter)
2016-02-28 14:58:30 +03:00
2015-11-18 16:11:56 +03:00
typedef QMap < MsgId , NullType > MediaOverviewIds ;
MediaOverviewIds overviewIds [ OverviewCount ] ;
int32 overviewCountData [ OverviewCount ] ; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
2016-03-31 14:37:58 +04:00
// A pointer to the block that is currently being built.
// We hold this pointer so we can destroy it while building
// and then create a new one if it is necessary.
struct BuildingBlock {
int expectedItemsCount = 0 ; // optimization for block->items.reserve() call
HistoryBlock * block = nullptr ;
} ;
2016-04-10 23:20:48 +04:00
std_ : : unique_ptr < BuildingBlock > _buildingFrontBlock ;
2015-09-19 12:13:21 +03:00
2016-03-31 14:37:58 +04:00
// Creates if necessary a new block for adding item.
// Depending on isBuildingFrontBlock() gets front or back block.
HistoryBlock * prepareBlockForAddingItem ( ) ;
2016-03-22 12:51:20 +03:00
2016-04-10 23:20:48 +04:00
std_ : : unique_ptr < HistoryDraft > _msgDraft ;
std_ : : unique_ptr < HistoryEditDraft > _editDraft ;
2016-04-08 18:16:52 +04:00
2016-03-22 12:51:20 +03:00
} ;
2015-09-19 12:13:21 +03:00
2015-09-21 23:57:42 +03:00
class HistoryJoined ;
2015-09-19 12:13:21 +03:00
class ChannelHistory : public History {
public :
ChannelHistory ( const PeerId & peer ) ;
void messageDetached ( HistoryItem * msg ) ;
2015-09-21 23:57:42 +03:00
void getRangeDifference ( ) ;
void getRangeDifferenceNext ( int32 pts ) ;
HistoryJoined * insertJoinedMessage ( bool unread ) ;
2015-09-25 10:47:32 +03:00
void checkJoinedMessage ( bool createUnread = false ) ;
2015-09-21 23:57:42 +03:00
const QDateTime & maxReadMessageDate ( ) ;
2016-03-15 13:37:56 +03:00
~ ChannelHistory ( ) ;
2015-09-19 12:13:21 +03:00
private :
2015-09-20 11:55:41 +03:00
friend class History ;
HistoryItem * addNewChannelMessage ( const MTPMessage & msg , NewMessageType type ) ;
HistoryItem * addNewToBlocks ( const MTPMessage & msg , NewMessageType type ) ;
2015-09-21 23:57:42 +03:00
void checkMaxReadMessageDate ( ) ;
2015-09-19 12:13:21 +03:00
HistoryItem * findPrevItem ( HistoryItem * item ) const ;
2015-09-21 23:57:42 +03:00
2016-04-14 22:24:42 +03:00
void cleared ( bool leaveItems ) ;
2015-09-21 23:57:42 +03:00
QDateTime _maxReadMessageDate ;
HistoryJoined * _joinedMessage ;
2015-09-19 12:13:21 +03:00
2015-09-21 23:57:42 +03:00
MsgId _rangeDifferenceFromId , _rangeDifferenceToId ;
int32 _rangeDifferencePts ;
mtpRequestId _rangeDifferenceRequestId ;
2015-07-03 11:47:16 +03:00
2014-05-30 12:53:19 +04:00
} ;
2015-09-19 12:13:21 +03:00
class HistoryBlock {
public :
2016-03-18 22:05:08 +03:00
HistoryBlock ( History * hist ) : y ( 0 ) , height ( 0 ) , history ( hist ) , _indexInHistory ( - 1 ) {
2014-05-30 12:53:19 +04:00
}
2016-03-18 22:05:08 +03:00
HistoryBlock ( const HistoryBlock & ) = delete ;
HistoryBlock & operator = ( const HistoryBlock & ) = delete ;
2015-09-19 12:13:21 +03:00
typedef QVector < HistoryItem * > Items ;
Items items ;
2014-07-04 15:12:54 +04:00
void clear ( bool leaveItems = false ) ;
2014-05-30 12:53:19 +04:00
~ HistoryBlock ( ) {
clear ( ) ;
}
void removeItem ( HistoryItem * item ) ;
2016-03-21 21:40:00 +03:00
int resizeGetHeight ( int newWidth , bool resizeAllItems ) ;
2014-05-30 12:53:19 +04:00
int32 y , height ;
History * history ;
2016-03-15 13:37:56 +03:00
2016-03-18 22:05:08 +03:00
HistoryBlock * previous ( ) const {
2016-03-21 21:40:00 +03:00
t_assert ( _indexInHistory > = 0 ) ;
2016-03-18 22:05:08 +03:00
return ( _indexInHistory > 0 ) ? history - > blocks . at ( _indexInHistory - 1 ) : nullptr ;
}
2016-03-19 21:32:17 +03:00
void setIndexInHistory ( int index ) {
_indexInHistory = index ;
}
2016-03-21 21:40:00 +03:00
int indexInHistory ( ) const {
t_assert ( _indexInHistory > = 0 ) ;
t_assert ( history - > blocks . at ( _indexInHistory ) = = this ) ;
return _indexInHistory ;
}
2016-03-18 22:05:08 +03:00
protected :
int _indexInHistory ;
2014-05-30 12:53:19 +04:00
} ;
class HistoryElem {
public :
2015-12-20 17:05:07 +03:00
HistoryElem ( ) : _maxw ( 0 ) , _minh ( 0 ) , _height ( 0 ) {
2014-05-30 12:53:19 +04:00
}
int32 maxWidth ( ) const {
return _maxw ;
}
2015-04-04 23:01:34 +03:00
int32 minHeight ( ) const {
return _minh ;
}
2015-12-20 17:05:07 +03:00
int32 height ( ) const {
return _height ;
}
2014-05-30 12:53:19 +04:00
virtual ~ HistoryElem ( ) {
}
protected :
2015-12-20 17:05:07 +03:00
mutable int32 _maxw , _minh , _height ;
2015-12-17 20:31:28 +03:00
HistoryElem & operator = ( const HistoryElem & ) ;
2014-05-30 12:53:19 +04:00
} ;
2016-04-13 21:29:32 +03:00
class HistoryMessage ;
2015-03-19 12:18:19 +03:00
2015-06-27 16:02:00 +03:00
enum HistoryCursorState {
HistoryDefaultCursorState ,
HistoryInTextCursorState ,
2016-02-19 14:53:49 +03:00
HistoryInDateCursorState ,
HistoryInForwardedCursorState ,
2015-06-27 16:02:00 +03:00
} ;
2016-04-13 21:29:32 +03:00
struct HistoryTextState {
HistoryTextState ( ) = default ;
HistoryTextState ( const Text : : StateResult & state )
: cursor ( state . uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState )
, link ( state . link )
, afterSymbol ( state . afterSymbol )
, symbol ( state . symbol ) {
}
HistoryTextState & operator = ( const Text : : StateResult & state ) {
cursor = state . uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState ;
link = state . link ;
afterSymbol = state . afterSymbol ;
symbol = state . symbol ;
return * this ;
}
HistoryCursorState cursor = HistoryDefaultCursorState ;
ClickHandlerPtr link ;
bool afterSymbol = false ;
uint16 symbol = 0 ;
} ;
struct HistoryStateRequest {
Text : : StateRequest : : Flags flags = Text : : StateRequest : : Flag : : LookupLink ;
Text : : StateRequest forText ( ) const {
Text : : StateRequest result ;
result . flags = flags ;
return result ;
}
} ;
2015-09-15 11:50:54 +03:00
enum InfoDisplayType {
InfoDisplayDefault ,
InfoDisplayOverImage ,
2016-03-31 18:06:40 +04:00
InfoDisplayOverBackground ,
2015-09-15 11:50:54 +03:00
} ;
2015-09-19 12:13:21 +03:00
enum HistoryItemType {
HistoryItemMsg = 0 ,
2015-09-21 23:57:42 +03:00
HistoryItemJoined
2015-09-19 12:13:21 +03:00
} ;
2016-03-25 14:29:45 +03:00
struct HistoryMessageVia : public BaseComponent < HistoryMessageVia > {
2016-02-18 22:12:50 +03:00
void create ( int32 userId ) ;
void resize ( int32 availw ) const ;
2016-03-25 14:29:45 +03:00
UserData * _bot = nullptr ;
2016-02-18 22:12:50 +03:00
mutable QString _text ;
2016-03-25 14:29:45 +03:00
mutable int _width = 0 ;
mutable int _maxWidth = 0 ;
2016-03-29 20:17:00 +03:00
ClickHandlerPtr _lnk ;
2016-02-18 22:12:50 +03:00
} ;
2016-03-25 14:29:45 +03:00
struct HistoryMessageViews : public BaseComponent < HistoryMessageViews > {
2016-02-18 22:12:50 +03:00
QString _viewsText ;
2016-03-25 14:29:45 +03:00
int _views = 0 ;
int _viewsWidth = 0 ;
2016-02-18 22:12:50 +03:00
} ;
2016-03-25 14:29:45 +03:00
struct HistoryMessageSigned : public BaseComponent < HistoryMessageSigned > {
2016-02-18 22:12:50 +03:00
void create ( UserData * from , const QDateTime & date ) ;
2016-03-25 14:29:45 +03:00
int maxWidth ( ) const ;
2016-02-18 22:12:50 +03:00
Text _signature ;
} ;
2016-04-23 14:40:42 +03:00
struct HistoryMessageEdited : public BaseComponent < HistoryMessageEdited > {
void create ( const QDateTime & editDate , const QDateTime & date ) ;
int maxWidth ( ) const ;
QDateTime _editDate ;
Text _edited ;
} ;
2016-03-25 14:29:45 +03:00
struct HistoryMessageForwarded : public BaseComponent < HistoryMessageForwarded > {
2016-02-19 14:53:49 +03:00
void create ( const HistoryMessageVia * via ) const ;
2016-02-18 22:12:50 +03:00
2016-03-25 14:29:45 +03:00
PeerData * _authorOriginal = nullptr ;
PeerData * _fromOriginal = nullptr ;
MsgId _originalId = 0 ;
mutable Text _text = { 1 } ;
} ;
struct HistoryMessageReply : public BaseComponent < HistoryMessageReply > {
HistoryMessageReply & operator = ( HistoryMessageReply & & other ) {
replyToMsgId = other . replyToMsgId ;
std : : swap ( replyToMsg , other . replyToMsg ) ;
2016-03-28 15:51:22 +03:00
replyToLnk = std_ : : move ( other . replyToLnk ) ;
replyToName = std_ : : move ( other . replyToName ) ;
replyToText = std_ : : move ( other . replyToText ) ;
2016-03-25 14:29:45 +03:00
replyToVersion = other . replyToVersion ;
_maxReplyWidth = other . _maxReplyWidth ;
2016-03-28 15:51:22 +03:00
_replyToVia = std_ : : move ( other . _replyToVia ) ;
2016-03-25 14:29:45 +03:00
return * this ;
}
~ HistoryMessageReply ( ) {
// clearData() should be called by holder
t_assert ( replyToMsg = = nullptr ) ;
2016-04-10 23:20:48 +04:00
t_assert ( _replyToVia = = nullptr ) ;
2016-03-25 14:29:45 +03:00
}
2016-03-28 15:51:22 +03:00
2016-03-25 14:29:45 +03:00
bool updateData ( HistoryMessage * holder , bool force = false ) ;
void clearData ( HistoryMessage * holder ) ; // must be called before destructor
void checkNameUpdate ( ) const ;
void updateName ( ) const ;
void resize ( int width ) const ;
void itemRemoved ( HistoryMessage * holder , HistoryItem * removed ) ;
enum PaintFlag {
PaintInBubble = 0x01 ,
PaintSelected = 0x02 ,
} ;
Q_DECLARE_FLAGS ( PaintFlags , PaintFlag ) ;
void paint ( Painter & p , const HistoryItem * holder , int x , int y , int w , PaintFlags flags ) const ;
MsgId replyToId ( ) const {
return replyToMsgId ;
}
int replyToWidth ( ) const {
return _maxReplyWidth ;
}
2016-03-29 20:17:00 +03:00
ClickHandlerPtr replyToLink ( ) const {
2016-03-25 14:29:45 +03:00
return replyToLnk ;
}
MsgId replyToMsgId = 0 ;
HistoryItem * replyToMsg = nullptr ;
2016-03-29 20:17:00 +03:00
ClickHandlerPtr replyToLnk ;
2016-03-25 14:29:45 +03:00
mutable Text replyToName , replyToText ;
mutable int replyToVersion = 0 ;
mutable int _maxReplyWidth = 0 ;
2016-04-10 23:20:48 +04:00
std_ : : unique_ptr < HistoryMessageVia > _replyToVia ;
2016-03-25 14:29:45 +03:00
int toWidth = 0 ;
2016-02-18 22:12:50 +03:00
} ;
2016-03-25 14:29:45 +03:00
Q_DECLARE_OPERATORS_FOR_FLAGS ( HistoryMessageReply : : PaintFlags ) ;
2016-02-18 22:12:50 +03:00
2016-03-30 20:42:01 +04:00
class ReplyKeyboard ;
struct HistoryMessageReplyMarkup : public BaseComponent < HistoryMessageReplyMarkup > {
HistoryMessageReplyMarkup ( ) = default ;
HistoryMessageReplyMarkup ( MTPDreplyKeyboardMarkup : : Flags f ) : flags ( f ) {
}
void create ( const MTPReplyMarkup & markup ) ;
struct Button {
enum Type {
Default ,
Url ,
Callback ,
RequestPhone ,
RequestLocation ,
2016-04-07 14:03:10 +04:00
SwitchInline ,
2016-03-30 20:42:01 +04:00
} ;
Type type ;
2016-04-01 14:23:40 +04:00
QString text ;
QByteArray data ;
2016-04-06 21:02:22 +04:00
mutable mtpRequestId requestId ;
2016-03-30 20:42:01 +04:00
} ;
using ButtonRow = QVector < Button > ;
using ButtonRows = QVector < ButtonRow > ;
ButtonRows rows ;
MTPDreplyKeyboardMarkup : : Flags flags = 0 ;
2016-04-10 23:20:48 +04:00
std_ : : unique_ptr < ReplyKeyboard > inlineKeyboard ;
2016-04-06 12:00:37 +04:00
2016-04-08 13:20:10 +04:00
// If >= 0 it holds the y coord of the inlineKeyboard before the last edition.
int oldTop = - 1 ;
2016-04-06 12:00:37 +04:00
private :
void createFromButtonRows ( const QVector < MTPKeyboardButtonRow > & v ) ;
2016-03-30 20:42:01 +04:00
} ;
2016-04-06 19:32:05 +04:00
class ReplyMarkupClickHandler ;
2016-03-29 20:17:00 +03:00
class ReplyKeyboard {
2016-03-30 20:42:01 +04:00
private :
struct Button ;
2016-03-28 15:51:22 +03:00
public :
2016-03-28 20:15:17 +03:00
class Style {
public :
Style ( const style : : botKeyboardButton & st ) : _st ( & st ) {
}
virtual void startPaint ( Painter & p ) const = 0 ;
virtual style : : font textFont ( ) const = 0 ;
int buttonSkip ( ) const {
return _st - > margin ;
}
int buttonPadding ( ) const {
return _st - > padding ;
}
int buttonHeight ( ) const {
return _st - > height ;
}
virtual void repaint ( const HistoryItem * item ) const = 0 ;
2016-04-07 14:35:09 +04:00
virtual ~ Style ( ) {
}
2016-03-28 20:15:17 +03:00
protected :
2016-03-29 20:17:00 +03:00
virtual void paintButtonBg ( Painter & p , const QRect & rect , bool pressed , float64 howMuchOver ) const = 0 ;
2016-03-30 20:42:01 +04:00
virtual void paintButtonIcon ( Painter & p , const QRect & rect , HistoryMessageReplyMarkup : : Button : : Type type ) const = 0 ;
2016-04-06 21:02:22 +04:00
virtual void paintButtonLoading ( Painter & p , const QRect & rect ) const = 0 ;
2016-03-30 20:42:01 +04:00
virtual int minButtonWidth ( HistoryMessageReplyMarkup : : Button : : Type type ) const = 0 ;
2016-03-28 20:15:17 +03:00
private :
const style : : botKeyboardButton * _st ;
2016-03-30 20:42:01 +04:00
void paintButton ( Painter & p , const ReplyKeyboard : : Button & button ) const ;
friend class ReplyKeyboard ;
2016-03-28 20:15:17 +03:00
} ;
2016-04-10 23:20:48 +04:00
typedef std_ : : unique_ptr < Style > StylePtr ;
2016-03-28 20:15:17 +03:00
ReplyKeyboard ( const HistoryItem * item , StylePtr & & s ) ;
ReplyKeyboard ( const ReplyKeyboard & other ) = delete ;
ReplyKeyboard & operator = ( const ReplyKeyboard & other ) = delete ;
bool isEnoughSpace ( int width , const style : : botKeyboardButton & st ) const ;
void setStyle ( StylePtr & & s ) ;
void resize ( int width , int height ) ;
2016-03-30 20:42:01 +04:00
// what width and height will best fit this keyboard
int naturalWidth ( ) const ;
2016-03-28 20:15:17 +03:00
int naturalHeight ( ) const ;
void paint ( Painter & p , const QRect & clip ) const ;
2016-04-13 21:29:32 +03:00
ClickHandlerPtr getState ( int x , int y ) const ;
2016-03-29 20:17:00 +03:00
void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) ;
void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) ;
2016-03-28 20:15:17 +03:00
void clearSelection ( ) ;
private :
const HistoryItem * _item ;
int _width = 0 ;
2016-03-30 20:42:01 +04:00
friend class Style ;
using ReplyMarkupClickHandlerPtr = QSharedPointer < ReplyMarkupClickHandler > ;
2016-03-28 20:15:17 +03:00
struct Button {
Text text = { 1 } ;
QRect rect ;
int characters = 0 ;
float64 howMuchOver = 0. ;
2016-03-30 20:42:01 +04:00
HistoryMessageReplyMarkup : : Button : : Type type ;
ReplyMarkupClickHandlerPtr link ;
2016-03-28 20:15:17 +03:00
} ;
using ButtonRow = QVector < Button > ;
using ButtonRows = QVector < ButtonRow > ;
ButtonRows _rows ;
using Animations = QMap < int , uint64 > ;
Animations _animations ;
Animation _a_selected ;
void step_selected ( uint64 ms , bool timer ) ;
2016-03-28 15:51:22 +03:00
2016-03-28 20:15:17 +03:00
StylePtr _st ;
2016-03-28 15:51:22 +03:00
} ;
class HistoryDependentItemCallback : public SharedCallback < void , ChannelData * , MsgId > {
2016-03-10 13:15:21 +03:00
public :
HistoryDependentItemCallback ( FullMsgId dependent ) : _dependent ( dependent ) {
}
void call ( ChannelData * channel , MsgId msgId ) const override ;
private :
FullMsgId _dependent ;
} ;
2016-03-18 22:05:08 +03:00
// any HistoryItem can have this Interface for
// displaying the day mark above the message
2016-03-25 14:29:45 +03:00
struct HistoryMessageDate : public BaseComponent < HistoryMessageDate > {
2016-03-18 22:05:08 +03:00
void init ( const QDateTime & date ) ;
2016-03-19 19:55:15 +03:00
int height ( ) const ;
void paint ( Painter & p , int y , int w ) const ;
2016-03-18 22:05:08 +03:00
QString _text ;
2016-03-25 14:29:45 +03:00
int _width = 0 ;
2016-03-18 22:05:08 +03:00
} ;
// any HistoryItem can have this Interface for
// displaying the unread messages bar above the message
2016-03-25 14:29:45 +03:00
struct HistoryMessageUnreadBar : public BaseComponent < HistoryMessageUnreadBar > {
2016-03-18 22:05:08 +03:00
void init ( int count ) ;
2016-03-31 18:06:40 +04:00
static int height ( ) ;
static int marginTop ( ) ;
2016-03-19 19:55:15 +03:00
void paint ( Painter & p , int y , int w ) const ;
2016-03-18 22:05:08 +03:00
QString _text ;
2016-03-25 14:29:45 +03:00
int _width = 0 ;
2016-03-18 22:05:08 +03:00
// if unread bar is freezed the new messages do not
// increment the counter displayed by this bar
//
// it happens when we've opened the conversation and
// we've seen the bar and new messages are marked as read
// as soon as they are added to the chat history
2016-03-25 14:29:45 +03:00
bool _freezed = false ;
2016-03-18 22:05:08 +03:00
} ;
2016-03-29 20:17:00 +03:00
// HistoryMedia has a special owning smart pointer
// which regs/unregs this media to the holding HistoryItem
2014-08-11 13:03:45 +04:00
class HistoryMedia ;
2016-03-29 20:17:00 +03:00
class HistoryMediaPtr {
public :
HistoryMediaPtr ( ) = default ;
HistoryMediaPtr ( const HistoryMediaPtr & other ) = delete ;
HistoryMediaPtr & operator = ( const HistoryMediaPtr & other ) = delete ;
HistoryMedia * data ( ) const {
return _p ;
}
2016-04-10 18:53:01 +04:00
void reset ( HistoryMedia * p = nullptr ) ;
void clear ( ) {
reset ( ) ;
}
2016-03-29 20:17:00 +03:00
bool isNull ( ) const {
return data ( ) = = nullptr ;
}
HistoryMedia * operator - > ( ) const {
return data ( ) ;
}
HistoryMedia & operator * ( ) const {
t_assert ( ! isNull ( ) ) ;
return * data ( ) ;
}
explicit operator bool ( ) const {
return ! isNull ( ) ;
}
~ HistoryMediaPtr ( ) {
2016-04-10 18:53:01 +04:00
clear ( ) ;
2016-03-29 20:17:00 +03:00
}
private :
2016-03-30 12:03:29 +04:00
HistoryMedia * _p = nullptr ;
2016-03-29 20:17:00 +03:00
} ;
2016-04-14 14:00:23 +03:00
namespace internal {
TextSelection unshiftSelection ( TextSelection selection , const Text & byText ) ;
TextSelection shiftSelection ( TextSelection selection , const Text & byText ) ;
} // namespace internal
2016-03-29 20:17:00 +03:00
class HistoryItem : public HistoryElem , public Composer , public ClickHandlerHost {
2014-05-30 12:53:19 +04:00
public :
2016-03-18 22:05:08 +03:00
HistoryItem ( const HistoryItem & ) = delete ;
HistoryItem & operator = ( const HistoryItem & ) = delete ;
2014-05-30 12:53:19 +04:00
2016-03-21 21:40:00 +03:00
int resizeGetHeight ( int width ) {
2016-03-19 19:55:15 +03:00
if ( _flags & MTPDmessage_ClientFlag : : f_pending_init_dimensions ) {
_flags & = ~ MTPDmessage_ClientFlag : : f_pending_init_dimensions ;
initDimensions ( ) ;
}
if ( _flags & MTPDmessage_ClientFlag : : f_pending_resize ) {
_flags & = ~ MTPDmessage_ClientFlag : : f_pending_resize ;
}
2016-03-21 21:40:00 +03:00
return resizeGetHeight_ ( width ) ;
2016-03-19 19:55:15 +03:00
}
2016-04-13 21:29:32 +03:00
virtual void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const = 0 ;
2015-09-10 13:30:59 +03:00
2016-03-05 23:12:55 +02:00
virtual void dependencyItemRemoved ( HistoryItem * dependency ) {
}
virtual bool updateDependencyItem ( ) {
return true ;
}
virtual MsgId dependencyMsgId ( ) const {
return 0 ;
}
2016-03-11 15:20:58 +03:00
virtual bool notificationReady ( ) const {
return true ;
}
2016-03-05 23:12:55 +02:00
2016-03-25 14:29:45 +03:00
UserData * viaBot ( ) const {
if ( const HistoryMessageVia * via = Get < HistoryMessageVia > ( ) ) {
return via - > _bot ;
}
return nullptr ;
2015-12-31 23:27:21 +08:00
}
2015-12-22 11:01:02 +03:00
History * history ( ) const {
2014-05-30 12:53:19 +04:00
return _history ;
}
2015-09-04 16:01:31 +03:00
PeerData * from ( ) const {
2014-05-30 12:53:19 +04:00
return _from ;
}
HistoryBlock * block ( ) {
return _block ;
}
const HistoryBlock * block ( ) const {
return _block ;
}
2016-05-20 19:01:06 +03:00
void destroy ( ) ;
2014-07-04 15:12:54 +04:00
void detach ( ) ;
void detachFast ( ) ;
bool detached ( ) const {
return ! _block ;
2014-05-30 12:53:19 +04:00
}
2016-03-18 22:05:08 +03:00
void attachToBlock ( HistoryBlock * block , int index ) {
2016-03-25 19:03:57 +03:00
t_assert ( _block = = nullptr ) ;
t_assert ( _indexInBlock < 0 ) ;
t_assert ( block ! = nullptr ) ;
t_assert ( index > = 0 ) ;
2016-03-19 19:55:15 +03:00
2015-05-01 02:05:19 +03:00
_block = block ;
2016-03-18 22:05:08 +03:00
_indexInBlock = index ;
2016-03-19 19:55:15 +03:00
if ( pendingResize ( ) ) {
_history - > setHasPendingResizedItems ( ) ;
}
2016-03-18 22:05:08 +03:00
}
void setIndexInBlock ( int index ) {
2016-03-25 19:03:57 +03:00
t_assert ( _block ! = nullptr ) ;
t_assert ( index > = 0 ) ;
2016-03-18 22:05:08 +03:00
_indexInBlock = index ;
2015-05-01 02:05:19 +03:00
}
2016-03-21 21:40:00 +03:00
int indexInBlock ( ) const {
if ( _indexInBlock > = 0 ) {
t_assert ( _block ! = nullptr ) ;
t_assert ( _block - > items . at ( _indexInBlock ) = = this ) ;
} else if ( _block ! = nullptr ) {
t_assert ( _indexInBlock > = 0 ) ;
t_assert ( _block - > items . at ( _indexInBlock ) = = this ) ;
}
return _indexInBlock ;
}
2014-05-30 12:53:19 +04:00
bool out ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage : : Flag : : f_out ;
2014-05-30 12:53:19 +04:00
}
2016-05-20 19:01:06 +03:00
bool unread ( ) const ;
2015-10-28 20:16:52 -04:00
bool mentionsMe ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage : : Flag : : f_mentioned ;
2014-05-30 12:53:19 +04:00
}
2015-04-30 16:53:36 +03:00
bool isMediaUnread ( ) const {
2016-03-19 19:55:15 +03:00
return ( _flags & MTPDmessage : : Flag : : f_media_unread ) & & ( channelId ( ) = = NoChannel ) ;
2015-04-30 16:53:36 +03:00
}
void markMediaRead ( ) {
2016-03-19 19:55:15 +03:00
_flags & = ~ MTPDmessage : : Flag : : f_media_unread ;
2015-04-30 16:53:36 +03:00
}
2016-03-28 15:51:22 +03:00
bool definesReplyKeyboard ( ) const {
2016-04-08 14:44:35 +04:00
if ( auto markup = Get < HistoryMessageReplyMarkup > ( ) ) {
2016-04-06 12:00:37 +04:00
if ( markup - > flags & MTPDreplyKeyboardMarkup_ClientFlag : : f_inline ) {
2016-03-28 15:51:22 +03:00
return false ;
}
return true ;
}
// optimization: don't create markup component for the case
// MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag
return ( _flags & MTPDmessage : : Flag : : f_reply_markup ) ;
}
MTPDreplyKeyboardMarkup : : Flags replyKeyboardFlags ( ) const {
t_assert ( definesReplyKeyboard ( ) ) ;
2016-04-08 14:44:35 +04:00
if ( auto markup = Get < HistoryMessageReplyMarkup > ( ) ) {
2016-03-28 15:51:22 +03:00
return markup - > flags ;
}
// optimization: don't create markup component for the case
// MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag
return qFlags ( MTPDreplyKeyboardMarkup_ClientFlag : : f_zero ) ;
2015-06-15 20:19:24 +03:00
}
2016-04-08 18:16:52 +04:00
bool hasSwitchInlineButton ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_has_switch_inline_button ;
}
2015-08-21 14:23:44 +03:00
bool hasTextLinks ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage_ClientFlag : : f_has_text_links ;
2015-08-21 14:23:44 +03:00
}
2015-11-13 18:14:33 +03:00
bool isGroupMigrate ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage_ClientFlag : : f_is_group_migrate ;
2015-11-13 18:14:33 +03:00
}
2015-09-21 23:57:42 +03:00
bool hasViews ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage : : Flag : : f_views ;
2015-09-21 23:57:42 +03:00
}
2016-02-17 19:37:21 +03:00
bool isPost ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage : : Flag : : f_post ;
2015-09-13 20:27:29 +03:00
}
2015-11-02 17:33:57 -05:00
bool indexInOverview ( ) const {
2016-02-17 19:37:21 +03:00
return ( id > 0 ) & & ( ! history ( ) - > isChannel ( ) | | history ( ) - > isMegagroup ( ) | | isPost ( ) ) ;
}
bool isSilent ( ) const {
2016-03-19 19:55:15 +03:00
return _flags & MTPDmessage : : Flag : : f_silent ;
2016-02-17 19:37:21 +03:00
}
2016-03-25 14:29:45 +03:00
bool hasOutLayout ( ) const {
return out ( ) & & ! isPost ( ) ;
}
2016-02-17 19:37:21 +03:00
virtual int32 viewsCount ( ) const {
return hasViews ( ) ? 1 : - 1 ;
2015-11-02 17:33:57 -05:00
}
2014-05-30 12:53:19 +04:00
virtual bool needCheck ( ) const {
2015-10-27 20:29:39 -04:00
return out ( ) | | ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
virtual bool hasPoint ( int x , int y ) const {
2014-05-30 12:53:19 +04:00
return false ;
}
2016-04-13 21:29:32 +03:00
virtual HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const = 0 ;
virtual TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const {
return selection ;
2014-05-30 12:53:19 +04:00
}
2016-03-29 20:17:00 +03:00
// ClickHandlerHost interface
void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) override ;
void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) override ;
2015-09-19 12:13:21 +03:00
virtual HistoryItemType type ( ) const {
return HistoryItemMsg ;
2014-05-30 12:53:19 +04:00
}
virtual bool serviceMsg ( ) const {
return false ;
}
2016-04-01 14:23:40 +04:00
virtual void applyEdition ( const MTPDmessage & message ) {
}
2016-04-01 19:32:26 +04:00
virtual void updateMedia ( const MTPMessageMedia * media ) {
2014-05-30 12:53:19 +04:00
}
2016-01-03 09:43:42 +08:00
virtual int32 addToOverview ( AddToOverviewMethod method ) {
return 0 ;
}
2016-05-20 19:01:06 +03:00
virtual void eraseFromOverview ( ) {
}
2015-12-09 21:06:20 +03:00
virtual bool hasBubble ( ) const {
return false ;
}
2016-03-18 22:05:08 +03:00
virtual void previousItemChanged ( ) ;
2014-05-30 12:53:19 +04:00
2016-05-06 20:33:48 +03:00
virtual TextWithEntities selectedText ( TextSelection selection ) const {
return { qsl ( " [-] " ) , EntitiesInText ( ) } ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
virtual QString inDialogsText ( ) const {
return qsl ( " - " ) ;
}
virtual QString inReplyText ( ) const {
return inDialogsText ( ) ;
}
2016-05-06 20:33:48 +03:00
virtual TextWithEntities originalText ( ) const {
return { QString ( ) , EntitiesInText ( ) } ;
}
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
virtual void drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const {
2015-09-15 11:50:54 +03:00
}
2016-03-19 19:55:15 +03:00
virtual void setViewsCount ( int32 count ) {
2015-09-15 11:50:54 +03:00
}
2015-11-18 16:11:56 +03:00
virtual void setId ( MsgId newId ) ;
2015-09-15 11:50:54 +03:00
virtual void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const = 0 ;
2014-06-14 23:32:11 +04:00
virtual QString notificationHeader ( ) const {
return QString ( ) ;
}
virtual QString notificationText ( ) const = 0 ;
2014-05-30 12:53:19 +04:00
2015-09-21 23:57:42 +03:00
bool canDelete ( ) const {
ChannelData * channel = _history - > peer - > asChannel ( ) ;
2016-03-19 19:55:15 +03:00
if ( ! channel ) return ! ( _flags & MTPDmessage_ClientFlag : : f_is_group_migrate ) ;
2015-09-21 23:57:42 +03:00
if ( id = = 1 ) return false ;
if ( channel - > amCreator ( ) ) return true ;
2016-02-17 19:37:21 +03:00
if ( isPost ( ) ) {
2015-09-21 23:57:42 +03:00
if ( channel - > amEditor ( ) & & out ( ) ) return true ;
return false ;
}
return ( channel - > amEditor ( ) | | channel - > amModerator ( ) | | out ( ) ) ;
}
2016-03-10 13:15:21 +03:00
bool canPin ( ) const {
return id > 0 & & _history - > peer - > isMegagroup ( ) & & ( _history - > peer - > asChannel ( ) - > amEditor ( ) | | _history - > peer - > asChannel ( ) - > amCreator ( ) ) & & toHistoryMessage ( ) ;
}
2016-02-21 15:30:16 +03:00
bool canEdit ( const QDateTime & cur ) const ;
2016-04-23 14:40:42 +03:00
bool wasEdited ( ) const {
return _flags & MTPDmessage : : Flag : : f_edit_date ;
}
2016-03-10 13:15:21 +03:00
2016-03-13 18:45:00 +03:00
bool suggestBanReportDeleteAll ( ) const {
2016-03-14 19:59:18 +03:00
ChannelData * channel = history ( ) - > peer - > asChannel ( ) ;
2016-03-13 18:45:00 +03:00
if ( ! channel | | ( ! channel - > amEditor ( ) & & ! channel - > amCreator ( ) ) ) return false ;
return ! isPost ( ) & & ! out ( ) & & from ( ) - > isUser ( ) & & toHistoryMessage ( ) ;
}
2016-02-25 20:23:42 +03:00
bool hasDirectLink ( ) const {
2016-03-13 16:21:26 +03:00
return id > 0 & & _history - > peer - > isChannel ( ) & & _history - > peer - > asChannel ( ) - > isPublic ( ) & & ! _history - > peer - > isMegagroup ( ) ;
2016-02-25 20:23:42 +03:00
}
QString directLink ( ) const {
return hasDirectLink ( ) ? qsl ( " https://telegram.me/ " ) + _history - > peer - > asChannel ( ) - > username + ' / ' + QString : : number ( id ) : QString ( ) ;
}
2016-02-21 15:30:16 +03:00
2015-09-03 13:48:40 +03:00
int32 y ;
MsgId id ;
2014-05-30 12:53:19 +04:00
QDateTime date ;
2015-09-03 13:48:40 +03:00
ChannelId channelId ( ) const {
return _history - > channelId ( ) ;
}
FullMsgId fullId ( ) const {
return FullMsgId ( channelId ( ) , id ) ;
}
2016-05-20 19:01:06 +03:00
HistoryMedia * getMedia ( ) const {
return _media . data ( ) ;
2014-08-11 13:03:45 +04:00
}
2016-05-06 20:33:48 +03:00
virtual void setText ( const TextWithEntities & textWithEntities ) {
2015-08-28 18:15:56 +03:00
}
2016-05-06 20:33:48 +03:00
virtual bool textHasLinks ( ) const {
2015-09-02 00:33:44 +03:00
return false ;
}
2015-09-15 11:50:54 +03:00
2016-03-29 20:17:00 +03:00
virtual int infoWidth ( ) const {
2015-09-15 11:50:54 +03:00
return 0 ;
}
2016-03-29 20:17:00 +03:00
virtual int timeLeft ( ) const {
2015-09-15 11:50:54 +03:00
return 0 ;
}
2016-03-29 20:17:00 +03:00
virtual int timeWidth ( ) const {
2015-09-15 11:50:54 +03:00
return 0 ;
}
2016-04-10 18:53:01 +04:00
virtual bool pointInTime ( int32 right , int32 bottom , int x , int y , InfoDisplayType type ) const {
2015-09-15 11:50:54 +03:00
return false ;
}
int32 skipBlockWidth ( ) const {
return st : : msgDateSpace + infoWidth ( ) - st : : msgDateDelta . x ( ) ;
}
int32 skipBlockHeight ( ) const {
return st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ;
}
QString skipBlock ( ) const {
return textcmdSkipBlock ( skipBlockWidth ( ) , skipBlockHeight ( ) ) ;
}
2015-04-23 18:50:11 +03:00
virtual HistoryMessage * toHistoryMessage ( ) { // dynamic_cast optimize
2016-03-29 20:17:00 +03:00
return nullptr ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
virtual const HistoryMessage * toHistoryMessage ( ) const { // dynamic_cast optimize
2016-03-29 20:17:00 +03:00
return nullptr ;
2015-03-19 12:18:19 +03:00
}
2016-03-25 14:29:45 +03:00
MsgId replyToId ( ) const {
2016-04-08 14:44:35 +04:00
if ( auto reply = Get < HistoryMessageReply > ( ) ) {
2016-03-25 14:29:45 +03:00
return reply - > replyToId ( ) ;
}
2015-04-13 09:58:13 +01:00
return 0 ;
}
2015-03-19 12:18:19 +03:00
2015-12-09 22:09:29 +03:00
bool hasFromName ( ) const {
2016-02-17 19:37:21 +03:00
return ( ! out ( ) | | isPost ( ) ) & & ! history ( ) - > peer - > isUser ( ) ;
}
PeerData * author ( ) const {
return isPost ( ) ? history ( ) - > peer : _from ;
2015-09-13 20:27:29 +03:00
}
2015-09-03 13:48:40 +03:00
2016-02-18 22:12:50 +03:00
PeerData * fromOriginal ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return fwd - > _fromOriginal ;
}
2016-02-18 19:36:33 +03:00
return from ( ) ;
}
2016-02-18 22:12:50 +03:00
PeerData * authorOriginal ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return fwd - > _authorOriginal ;
}
2016-02-18 19:36:33 +03:00
return author ( ) ;
}
2016-03-18 22:05:08 +03:00
// count > 0 - creates the unread bar if necessary and
// sets unread messages count if bar is not freezed yet
// count <= 0 - destroys the unread bar
void setUnreadBarCount ( int count ) ;
void destroyUnreadBar ( ) ;
// marks the unread bar as freezed so that unread
// messages count will not change for this bar
// when the new messages arrive in this chat history
void setUnreadBarFreezed ( ) ;
2016-03-19 19:55:15 +03:00
bool pendingResize ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_pending_resize ;
}
void setPendingResize ( ) {
_flags | = MTPDmessage_ClientFlag : : f_pending_resize ;
if ( ! detached ( ) ) {
_history - > setHasPendingResizedItems ( ) ;
}
}
bool pendingInitDimensions ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_pending_init_dimensions ;
}
void setPendingInitDimensions ( ) {
_flags | = MTPDmessage_ClientFlag : : f_pending_init_dimensions ;
setPendingResize ( ) ;
}
2016-03-21 21:40:00 +03:00
int displayedDateHeight ( ) const {
2016-04-08 14:44:35 +04:00
if ( auto date = Get < HistoryMessageDate > ( ) ) {
2016-03-21 21:40:00 +03:00
return date - > height ( ) ;
}
return 0 ;
}
int marginTop ( ) const {
int result = 0 ;
if ( isAttachedToPrevious ( ) ) {
result + = st : : msgMarginTopAttached ;
} else {
result + = st : : msgMargin . top ( ) ;
}
result + = displayedDateHeight ( ) ;
2016-04-08 14:44:35 +04:00
if ( auto unreadbar = Get < HistoryMessageUnreadBar > ( ) ) {
2016-03-21 21:40:00 +03:00
result + = unreadbar - > height ( ) ;
}
return result ;
}
int marginBottom ( ) const {
return st : : msgMargin . bottom ( ) ;
}
2016-03-22 22:43:47 +03:00
bool isAttachedToPrevious ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_attach_to_previous ;
}
2016-03-21 21:40:00 +03:00
2016-06-03 15:45:33 +03:00
bool isEmpty ( ) const {
return _text . isEmpty ( ) & & ! _media ;
}
2015-12-29 00:20:04 +03:00
void clipCallback ( ClipReaderNotification notification ) ;
2014-05-30 12:53:19 +04:00
virtual ~ HistoryItem ( ) ;
protected :
2016-03-19 19:55:15 +03:00
HistoryItem ( History * history , MsgId msgId , MTPDmessage : : Flags flags , QDateTime msgDate , int32 from ) ;
// to completely create history item we need to call
// a virtual method, it can not be done from constructor
virtual void finishCreate ( ) ;
2016-03-18 22:05:08 +03:00
2016-03-21 21:40:00 +03:00
// called from resizeGetHeight() when MTPDmessage_ClientFlag::f_pending_init_dimensions is set
2016-03-19 19:55:15 +03:00
virtual void initDimensions ( ) = 0 ;
2016-03-21 21:40:00 +03:00
virtual int resizeGetHeight_ ( int width ) = 0 ;
2016-03-18 22:05:08 +03:00
2015-09-04 16:01:31 +03:00
PeerData * _from ;
2014-05-30 12:53:19 +04:00
History * _history ;
2016-03-18 22:05:08 +03:00
HistoryBlock * _block = nullptr ;
int _indexInBlock = - 1 ;
2016-03-19 19:55:15 +03:00
MTPDmessage : : Flags _flags ;
2014-05-30 12:53:19 +04:00
2016-02-17 19:37:21 +03:00
mutable int32 _authorNameVersion ;
2016-03-18 22:05:08 +03:00
HistoryItem * previous ( ) const {
if ( _block & & _indexInBlock > = 0 ) {
2016-03-31 18:06:40 +04:00
if ( _indexInBlock > 0 ) {
return _block - > items . at ( _indexInBlock - 1 ) ;
}
2016-03-18 22:05:08 +03:00
if ( HistoryBlock * previousBlock = _block - > previous ( ) ) {
2016-03-31 18:06:40 +04:00
t_assert ( ! previousBlock - > items . isEmpty ( ) ) ;
2016-03-18 22:05:08 +03:00
return previousBlock - > items . back ( ) ;
}
}
return nullptr ;
}
2016-03-19 21:32:17 +03:00
// this should be used only in previousItemChanged()
2016-03-28 15:51:22 +03:00
// to add required bits to the Composer mask
2016-03-25 14:29:45 +03:00
// after that always use Has<HistoryMessageDate>()
2016-03-18 22:05:08 +03:00
bool displayDate ( ) const {
2016-05-14 20:28:35 +03:00
if ( auto prev = previous ( ) ) {
return prev - > date . date ( ) ! = date . date ( ) ;
2016-03-18 22:05:08 +03:00
}
return true ;
}
2016-03-21 21:40:00 +03:00
// this should be used only in previousItemChanged() or when
2016-03-28 15:51:22 +03:00
// HistoryMessageDate or HistoryMessageUnreadBar bit is changed in the Composer mask
2016-03-21 21:40:00 +03:00
// then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous
void recountAttachToPrevious ( ) ;
2016-03-28 15:51:22 +03:00
const HistoryMessageReplyMarkup * inlineReplyMarkup ( ) const {
2016-04-08 14:44:35 +04:00
if ( auto markup = Get < HistoryMessageReplyMarkup > ( ) ) {
2016-04-06 12:00:37 +04:00
if ( markup - > flags & MTPDreplyKeyboardMarkup_ClientFlag : : f_inline ) {
2016-03-28 15:51:22 +03:00
return markup ;
}
}
return nullptr ;
}
2016-03-28 20:15:17 +03:00
const ReplyKeyboard * inlineReplyKeyboard ( ) const {
2016-04-08 14:44:35 +04:00
if ( auto markup = inlineReplyMarkup ( ) ) {
2016-04-10 23:20:48 +04:00
return markup - > inlineKeyboard . get ( ) ;
2016-03-28 20:15:17 +03:00
}
return nullptr ;
}
2016-03-28 15:51:22 +03:00
HistoryMessageReplyMarkup * inlineReplyMarkup ( ) {
return const_cast < HistoryMessageReplyMarkup * > ( static_cast < const HistoryItem * > ( this ) - > inlineReplyMarkup ( ) ) ;
}
2016-03-28 20:15:17 +03:00
ReplyKeyboard * inlineReplyKeyboard ( ) {
return const_cast < ReplyKeyboard * > ( static_cast < const HistoryItem * > ( this ) - > inlineReplyKeyboard ( ) ) ;
}
2016-03-28 15:51:22 +03:00
2016-04-13 21:29:32 +03:00
TextSelection toMediaSelection ( TextSelection selection ) const {
2016-04-14 14:00:23 +03:00
return internal : : unshiftSelection ( selection , _text ) ;
2016-04-13 21:29:32 +03:00
}
TextSelection fromMediaSelection ( TextSelection selection ) const {
2016-04-14 14:00:23 +03:00
return internal : : shiftSelection ( selection , _text ) ;
2016-04-13 21:29:32 +03:00
}
2016-03-29 20:17:00 +03:00
Text _text = { int ( st : : msgMinWidth ) } ;
2016-05-04 19:46:24 +03:00
int _textWidth = - 1 ;
int _textHeight = 0 ;
2016-03-29 20:17:00 +03:00
HistoryMediaPtr _media ;
2016-03-18 22:05:08 +03:00
} ;
// make all the constructors in HistoryItem children protected
// and wrapped with a static create() call with the same args
// so that history item can not be created directly, without
2016-03-19 19:55:15 +03:00
// calling a virtual finishCreate() method
2016-03-18 22:05:08 +03:00
template < typename T >
class HistoryItemInstantiated {
public :
template < typename . . . Args >
static T * _create ( Args . . . args ) {
T * result = new T ( args . . . ) ;
result - > finishCreate ( ) ;
return result ;
}
2014-05-30 12:53:19 +04:00
} ;
2016-03-29 20:17:00 +03:00
class MessageClickHandler : public LeftButtonClickHandler {
2015-03-19 12:18:19 +03:00
public :
2016-03-29 20:17:00 +03:00
MessageClickHandler ( PeerId peer , MsgId msgid ) : _peer ( peer ) , _msgid ( msgid ) {
2015-03-19 12:18:19 +03:00
}
2016-03-29 20:17:00 +03:00
MessageClickHandler ( HistoryItem * item ) : _peer ( item - > history ( ) - > peer - > id ) , _msgid ( item - > id ) {
2015-12-21 16:14:29 +03:00
}
2015-03-19 12:18:19 +03:00
PeerId peer ( ) const {
return _peer ;
}
MsgId msgid ( ) const {
return _msgid ;
}
private :
PeerId _peer ;
MsgId _msgid ;
2016-03-29 20:17:00 +03:00
} ;
2015-09-19 12:13:21 +03:00
2016-03-29 20:17:00 +03:00
class GoToMessageClickHandler : public MessageClickHandler {
2015-09-19 12:13:21 +03:00
public :
2016-03-29 20:17:00 +03:00
using MessageClickHandler : : MessageClickHandler ;
protected :
void onClickImpl ( ) const override ;
} ;
2015-12-31 23:27:21 +08:00
2016-03-29 20:17:00 +03:00
class CommentsClickHandler : public MessageClickHandler {
public :
using MessageClickHandler : : MessageClickHandler ;
protected :
void onClickImpl ( ) const override ;
2015-09-19 12:13:21 +03:00
} ;
2015-12-11 21:11:38 +03:00
class RadialAnimation {
public :
2015-12-29 00:20:04 +03:00
RadialAnimation ( AnimationCreator creator ) ;
2015-12-11 21:11:38 +03:00
float64 opacity ( ) const {
return _opacity ;
}
bool animating ( ) const {
return _animation . animating ( ) ;
}
void start ( float64 prg ) ;
void update ( float64 prg , bool finished , uint64 ms ) ;
void stop ( ) ;
2015-12-13 01:29:33 +03:00
void step ( uint64 ms ) ;
void step ( ) {
step ( getms ( ) ) ;
}
2015-12-22 15:49:42 +03:00
void draw ( Painter & p , const QRect & inner , int32 thickness , const style : : color & color ) ;
2015-12-11 21:11:38 +03:00
private :
uint64 _firstStart , _lastStart , _lastTime ;
float64 _opacity ;
2015-12-13 01:29:33 +03:00
anim : : ivalue a_arcEnd , a_arcStart ;
2015-12-11 21:11:38 +03:00
Animation _animation ;
} ;
2014-05-30 12:53:19 +04:00
class HistoryMedia : public HistoryElem {
public :
2016-04-10 18:53:01 +04:00
HistoryMedia ( HistoryItem * parent ) : _parent ( parent ) {
2015-04-04 23:01:34 +03:00
}
2016-04-10 18:53:01 +04:00
HistoryMedia ( const HistoryMedia & other ) = delete ;
HistoryMedia & operator = ( const HistoryMedia & other ) = delete ;
2014-11-18 15:41:33 +03:00
2014-05-30 12:53:19 +04:00
virtual HistoryMediaType type ( ) const = 0 ;
2016-04-14 14:00:23 +03:00
virtual QString inDialogsText ( ) const = 0 ;
2016-05-06 20:33:48 +03:00
virtual TextWithEntities selectedText ( TextSelection selection ) const = 0 ;
2015-12-19 21:09:24 +03:00
2016-04-10 18:53:01 +04:00
bool hasPoint ( int x , int y ) const {
2015-12-19 21:09:24 +03:00
return ( x > = 0 & & y > = 0 & & x < _width & & y < _height ) ;
}
2015-05-20 22:28:24 +03:00
virtual bool isDisplayed ( ) const {
return true ;
}
2016-04-20 15:56:59 +03:00
virtual bool hasTextForCopy ( ) const {
return false ;
}
2016-04-10 18:53:01 +04:00
virtual void initDimensions ( ) = 0 ;
virtual int resizeGetHeight ( int width ) {
2015-12-19 21:09:24 +03:00
_width = qMin ( width , _maxw ) ;
2014-11-18 15:41:33 +03:00
return _height ;
}
2016-04-13 21:29:32 +03:00
virtual void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const = 0 ;
virtual HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const = 0 ;
2016-03-29 20:17:00 +03:00
// if we are in selecting items mode perhaps we want to
// toggle selection instead of activating the pressed link
virtual bool toggleSelectionByHandlerClick ( const ClickHandlerPtr & p ) const = 0 ;
// if we press and drag on this media should we drag the item
virtual bool dragItem ( ) const {
return false ;
}
2016-04-13 21:29:32 +03:00
virtual TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const {
return selection ;
}
2016-03-29 20:17:00 +03:00
// if we press and drag this link should we drag the item
virtual bool dragItemByHandler ( const ClickHandlerPtr & p ) const = 0 ;
2015-12-19 21:09:24 +03:00
2016-04-10 18:53:01 +04:00
virtual void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) {
2015-12-11 21:11:38 +03:00
}
2016-04-10 18:53:01 +04:00
virtual void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) {
2015-12-11 21:11:38 +03:00
}
2015-12-19 21:09:24 +03:00
2014-05-30 12:53:19 +04:00
virtual bool uploading ( ) const {
return false ;
}
2016-04-10 18:53:01 +04:00
virtual HistoryMedia * clone ( HistoryItem * newParent ) const = 0 ;
2014-05-30 12:53:19 +04:00
2015-12-19 00:36:16 +03:00
virtual DocumentData * getDocument ( ) {
2016-04-07 14:03:10 +04:00
return nullptr ;
2015-12-19 00:36:16 +03:00
}
2015-12-29 00:20:04 +03:00
virtual ClipReader * getClipReader ( ) {
2016-04-07 14:03:10 +04:00
return nullptr ;
2015-12-29 00:20:04 +03:00
}
2015-12-19 00:36:16 +03:00
2016-04-10 18:53:01 +04:00
bool playInline ( /*bool autoplay = false*/ ) {
return playInline ( false ) ;
2016-03-19 19:55:15 +03:00
}
2016-04-10 18:53:01 +04:00
virtual bool playInline ( bool autoplay ) {
2015-12-19 00:36:16 +03:00
return false ;
}
2016-04-10 18:53:01 +04:00
virtual void stopInline ( ) {
2015-12-19 00:36:16 +03:00
}
2016-04-10 18:53:01 +04:00
virtual void attachToParent ( ) {
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
virtual void detachFromParent ( ) {
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
virtual void updateSentMedia ( const MTPMessageMedia & media ) {
}
// After sending an inline result we may want to completely recreate
// the media (all media that was generated on client side, for example)
virtual bool needReSetInlineResultMedia ( const MTPMessageMedia & media ) {
return true ;
2014-05-30 12:53:19 +04:00
}
2015-01-05 23:17:33 +03:00
2014-09-30 07:11:09 -07:00
virtual bool animating ( ) const {
return false ;
}
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
virtual bool hasReplyPreview ( ) const {
return false ;
}
virtual ImagePtr replyPreview ( ) {
return ImagePtr ( ) ;
}
2016-05-06 20:33:48 +03:00
virtual TextWithEntities getCaption ( ) const {
return TextWithEntities ( ) ;
2015-10-11 10:37:24 +02:00
}
2016-04-10 18:53:01 +04:00
virtual bool needsBubble ( ) const = 0 ;
2015-12-09 21:06:20 +03:00
virtual bool customInfoLayout ( ) const = 0 ;
2015-12-19 00:36:16 +03:00
virtual QMargins bubbleMargins ( ) const {
return QMargins ( ) ;
}
2015-12-09 22:09:29 +03:00
virtual bool hideFromName ( ) const {
return false ;
}
virtual bool hideForwardedFrom ( ) const {
return false ;
}
2015-03-19 12:18:19 +03:00
2016-04-07 14:03:10 +04:00
int currentWidth ( ) const {
2015-12-19 21:09:24 +03:00
return _width ;
2014-11-18 15:41:33 +03:00
}
protected :
2016-04-10 18:53:01 +04:00
HistoryItem * _parent ;
int _width = 0 ;
2014-11-18 15:41:33 +03:00
2014-05-30 12:53:19 +04:00
} ;
2015-12-13 01:29:33 +03:00
class HistoryFileMedia : public HistoryMedia {
public :
2016-04-10 18:53:01 +04:00
using HistoryMedia : : HistoryMedia ;
2015-12-13 01:29:33 +03:00
2016-03-29 20:17:00 +03:00
bool toggleSelectionByHandlerClick ( const ClickHandlerPtr & p ) const override {
return p = = _openl | | p = = _savel | | p = = _cancell ;
}
bool dragItemByHandler ( const ClickHandlerPtr & p ) const override {
return p = = _openl | | p = = _savel | | p = = _cancell ;
}
2016-04-10 18:53:01 +04:00
void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) override ;
void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) override ;
2015-12-13 01:29:33 +03:00
~ HistoryFileMedia ( ) ;
protected :
2016-03-29 20:17:00 +03:00
ClickHandlerPtr _openl , _savel , _cancell ;
void setLinks ( ClickHandlerPtr & & openl , ClickHandlerPtr & & savel , ClickHandlerPtr & & cancell ) ;
void setDocumentLinks ( DocumentData * document , bool inlinegif = false ) {
ClickHandlerPtr open , save ;
if ( inlinegif ) {
open . reset ( new GifOpenClickHandler ( document ) ) ;
} else {
open . reset ( new DocumentOpenClickHandler ( document ) ) ;
}
if ( inlinegif ) {
save . reset ( new GifOpenClickHandler ( document ) ) ;
} else if ( document - > voice ( ) ) {
save . reset ( new DocumentOpenClickHandler ( document ) ) ;
} else {
save . reset ( new DocumentSaveClickHandler ( document ) ) ;
}
setLinks ( std_ : : move ( open ) , std_ : : move ( save ) , MakeShared < DocumentCancelClickHandler > ( document ) ) ;
}
2015-12-13 01:29:33 +03:00
// >= 0 will contain download / upload string, _statusSize = loaded bytes
// < 0 will contain played string, _statusSize = -(seconds + 1) played
// 0x7FFFFFF0 will contain status for not yet downloaded file
// 0x7FFFFFF1 will contain status for already downloaded file
// 0x7FFFFFF2 will contain status for failed to download / upload file
mutable int32 _statusSize ;
mutable QString _statusText ;
2015-12-13 20:05:32 +03:00
// duration = -1 - no duration, duration = -2 - "GIF" duration
2015-12-13 01:29:33 +03:00
void setStatusSize ( int32 newSize , int32 fullSize , int32 duration , qint64 realDuration ) const ;
2016-04-10 18:53:01 +04:00
void step_thumbOver ( float64 ms , bool timer ) ;
void step_radial ( uint64 ms , bool timer ) ;
2015-12-13 01:29:33 +03:00
2016-04-10 18:53:01 +04:00
void ensureAnimation ( ) const ;
2015-12-13 01:29:33 +03:00
void checkAnimationFinished ( ) ;
bool isRadialAnimation ( uint64 ms ) const {
if ( ! _animation | | ! _animation - > radial . animating ( ) ) return false ;
_animation - > radial . step ( ms ) ;
return _animation & & _animation - > radial . animating ( ) ;
}
2015-12-28 00:37:48 +03:00
bool isThumbAnimation ( uint64 ms ) const {
if ( ! _animation | | ! _animation - > _a_thumbOver . animating ( ) ) return false ;
2015-12-31 23:27:21 +08:00
2015-12-28 00:37:48 +03:00
_animation - > _a_thumbOver . step ( ms ) ;
return _animation & & _animation - > _a_thumbOver . animating ( ) ;
}
2015-12-13 01:29:33 +03:00
virtual float64 dataProgress ( ) const = 0 ;
virtual bool dataFinished ( ) const = 0 ;
virtual bool dataLoaded ( ) const = 0 ;
struct AnimationData {
2015-12-29 00:20:04 +03:00
AnimationData ( AnimationCreator thumbOverCallbacks , AnimationCreator radialCallbacks ) : a_thumbOver ( 0 , 0 )
2015-12-13 01:29:33 +03:00
, _a_thumbOver ( thumbOverCallbacks )
2015-12-22 15:49:42 +03:00
, radial ( radialCallbacks ) {
2015-12-13 01:29:33 +03:00
}
anim : : fvalue a_thumbOver ;
Animation _a_thumbOver ;
RadialAnimation radial ;
} ;
2016-04-10 18:53:01 +04:00
mutable AnimationData * _animation = nullptr ;
2015-12-17 20:31:28 +03:00
2015-12-13 01:29:33 +03:00
} ;
2015-12-24 22:26:28 +03:00
class HistoryPhoto : public HistoryFileMedia {
public :
2016-04-10 18:53:01 +04:00
HistoryPhoto ( HistoryItem * parent , PhotoData * photo , const QString & caption ) ;
HistoryPhoto ( HistoryItem * parent , PeerData * chat , const MTPDphoto & photo , int width ) ;
HistoryPhoto ( HistoryItem * parent , const HistoryPhoto & other ) ;
2015-12-24 22:26:28 +03:00
void init ( ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2015-12-24 22:26:28 +03:00
return MediaTypePhoto ;
}
2016-04-10 18:53:01 +04:00
HistoryPhoto * clone ( HistoryItem * newParent ) const override {
return new HistoryPhoto ( newParent , * this ) ;
2015-12-24 22:26:28 +03:00
}
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int width ) override ;
2015-12-24 22:26:28 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override {
return _caption . adjustSelection ( selection , type ) ;
}
2016-04-20 15:56:59 +03:00
bool hasTextForCopy ( ) const override {
return ! _caption . isEmpty ( ) ;
}
2015-12-24 22:26:28 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2015-12-24 22:26:28 +03:00
PhotoData * photo ( ) const {
return _data ;
}
2016-04-10 18:53:01 +04:00
void updateSentMedia ( const MTPMessageMedia & media ) override ;
bool needReSetInlineResultMedia ( const MTPMessageMedia & media ) override ;
2015-12-24 22:26:28 +03:00
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
2015-12-25 16:09:14 +03:00
2016-03-21 21:57:03 +03:00
bool hasReplyPreview ( ) const override {
2015-12-24 22:26:28 +03:00
return ! _data - > thumb - > isNull ( ) ;
}
2016-03-21 21:57:03 +03:00
ImagePtr replyPreview ( ) override ;
2015-12-24 22:26:28 +03:00
2016-05-06 20:33:48 +03:00
TextWithEntities getCaption ( ) const override {
return _caption . originalTextWithEntities ( ) ;
2015-12-24 22:26:28 +03:00
}
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
if ( ! _caption . isEmpty ( ) ) {
return true ;
}
if ( _parent - > viaBot ( ) ) {
return true ;
}
return ( _parent - > Has < HistoryMessageForwarded > ( ) | | _parent - > Has < HistoryMessageReply > ( ) ) ;
2015-12-24 22:26:28 +03:00
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-24 22:26:28 +03:00
return _caption . isEmpty ( ) ;
}
2016-03-21 21:57:03 +03:00
bool hideFromName ( ) const override {
2015-12-24 22:26:28 +03:00
return true ;
}
protected :
2016-03-21 21:57:03 +03:00
float64 dataProgress ( ) const override {
2015-12-24 22:26:28 +03:00
return _data - > progress ( ) ;
}
2016-03-21 21:57:03 +03:00
bool dataFinished ( ) const override {
2015-12-24 22:26:28 +03:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
}
2016-03-21 21:57:03 +03:00
bool dataLoaded ( ) const override {
2015-12-24 22:26:28 +03:00
return _data - > loaded ( ) ;
}
private :
PhotoData * _data ;
2016-03-29 20:17:00 +03:00
int16 _pixw = 1 ;
int16 _pixh = 1 ;
2015-12-24 22:26:28 +03:00
Text _caption ;
} ;
2015-12-13 18:21:20 +03:00
class HistoryVideo : public HistoryFileMedia {
public :
2016-04-10 18:53:01 +04:00
HistoryVideo ( HistoryItem * parent , DocumentData * document , const QString & caption ) ;
HistoryVideo ( HistoryItem * parent , const HistoryVideo & other ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2015-12-19 21:09:24 +03:00
return MediaTypeVideo ;
}
2016-04-10 18:53:01 +04:00
HistoryVideo * clone ( HistoryItem * newParent ) const override {
return new HistoryVideo ( newParent , * this ) ;
2015-12-19 21:09:24 +03:00
}
2015-12-17 20:31:28 +03:00
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int width ) override ;
2015-12-13 18:21:20 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override {
return _caption . adjustSelection ( selection , type ) ;
}
2016-04-20 15:56:59 +03:00
bool hasTextForCopy ( ) const override {
return ! _caption . isEmpty ( ) ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2015-12-19 21:09:24 +03:00
2016-03-21 21:57:03 +03:00
DocumentData * getDocument ( ) override {
2015-12-19 21:09:24 +03:00
return _data ;
}
2016-03-21 21:57:03 +03:00
bool uploading ( ) const override {
2015-12-24 22:26:28 +03:00
return _data - > uploading ( ) ;
2015-12-13 18:21:20 +03:00
}
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
bool needReSetInlineResultMedia ( const MTPMessageMedia & media ) override ;
2015-12-13 18:21:20 +03:00
2016-03-21 21:57:03 +03:00
bool hasReplyPreview ( ) const override {
2015-12-13 18:21:20 +03:00
return ! _data - > thumb - > isNull ( ) ;
}
2016-03-21 21:57:03 +03:00
ImagePtr replyPreview ( ) override ;
2015-12-13 18:21:20 +03:00
2016-05-06 20:33:48 +03:00
TextWithEntities getCaption ( ) const override {
return _caption . originalTextWithEntities ( ) ;
2016-03-10 13:15:21 +03:00
}
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
if ( ! _caption . isEmpty ( ) ) {
return true ;
}
if ( _parent - > viaBot ( ) ) {
return true ;
}
return ( _parent - > Has < HistoryMessageForwarded > ( ) | | _parent - > Has < HistoryMessageReply > ( ) ) ;
2015-12-13 18:21:20 +03:00
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-13 18:21:20 +03:00
return _caption . isEmpty ( ) ;
}
2016-03-21 21:57:03 +03:00
bool hideFromName ( ) const override {
2015-12-13 18:21:20 +03:00
return true ;
}
protected :
2016-03-21 21:57:03 +03:00
float64 dataProgress ( ) const override {
2015-12-13 18:21:20 +03:00
return _data - > progress ( ) ;
}
2016-03-21 21:57:03 +03:00
bool dataFinished ( ) const override {
2015-12-24 22:26:28 +03:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
2015-12-13 18:21:20 +03:00
}
2016-03-21 21:57:03 +03:00
bool dataLoaded ( ) const override {
2015-12-24 22:26:28 +03:00
return _data - > loaded ( ) ;
2015-12-13 18:21:20 +03:00
}
private :
2016-02-12 21:18:32 +03:00
DocumentData * _data ;
int32 _thumbw ;
2015-12-13 18:21:20 +03:00
Text _caption ;
void setStatusSize ( int32 newSize ) const ;
2016-04-10 18:53:01 +04:00
void updateStatusText ( ) const ;
2015-12-13 18:21:20 +03:00
} ;
2016-03-25 14:29:45 +03:00
struct HistoryDocumentThumbed : public BaseComponent < HistoryDocumentThumbed > {
2016-03-29 20:17:00 +03:00
ClickHandlerPtr _linksavel , _linkcancell ;
2016-03-25 14:29:45 +03:00
int _thumbw = 0 ;
2015-05-29 21:52:43 +03:00
2016-03-25 14:29:45 +03:00
mutable int _linkw = 0 ;
2016-02-12 19:35:06 +03:00
mutable QString _link ;
} ;
2016-03-25 14:29:45 +03:00
struct HistoryDocumentCaptioned : public BaseComponent < HistoryDocumentCaptioned > {
2016-04-07 14:35:09 +04:00
Text _caption = { int ( st : : msgFileMinWidth ) - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) } ;
2016-02-12 19:35:06 +03:00
} ;
2016-03-25 14:29:45 +03:00
struct HistoryDocumentNamed : public BaseComponent < HistoryDocumentNamed > {
2016-02-12 19:35:06 +03:00
QString _name ;
2016-03-25 14:29:45 +03:00
int _namew = 0 ;
2016-02-12 19:35:06 +03:00
} ;
class HistoryDocument ;
struct HistoryDocumentVoicePlayback {
HistoryDocumentVoicePlayback ( const HistoryDocument * that ) ;
2015-12-08 22:07:50 +03:00
2016-02-12 19:35:06 +03:00
int32 _position ;
anim : : fvalue a_progress ;
Animation _a_progress ;
} ;
2016-03-25 14:29:45 +03:00
struct HistoryDocumentVoice : public BaseComponent < HistoryDocumentVoice > {
HistoryDocumentVoice & operator = ( HistoryDocumentVoice & & other ) {
std : : swap ( _playback , other . _playback ) ;
return * this ;
2015-12-13 01:29:33 +03:00
}
2016-02-12 19:35:06 +03:00
~ HistoryDocumentVoice ( ) {
deleteAndMark ( _playback ) ;
2015-12-13 01:29:33 +03:00
}
2016-02-12 19:35:06 +03:00
void ensurePlayback ( const HistoryDocument * interfaces ) const ;
void checkPlaybackFinished ( ) const ;
2016-03-25 14:29:45 +03:00
mutable HistoryDocumentVoicePlayback * _playback = nullptr ;
2014-05-30 12:53:19 +04:00
} ;
2016-03-25 14:29:45 +03:00
class HistoryDocument : public HistoryFileMedia , public Composer {
2014-05-30 12:53:19 +04:00
public :
2016-04-10 18:53:01 +04:00
HistoryDocument ( HistoryItem * parent , DocumentData * document , const QString & caption ) ;
HistoryDocument ( HistoryItem * parent , const HistoryDocument & other ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2016-02-12 19:35:06 +03:00
return _data - > voice ( ) ? MediaTypeVoiceFile : ( _data - > song ( ) ? MediaTypeMusicFile : MediaTypeFile ) ;
2015-12-19 21:09:24 +03:00
}
2016-04-10 18:53:01 +04:00
HistoryDocument * clone ( HistoryItem * newParent ) const override {
return new HistoryDocument ( newParent , * this ) ;
2015-12-19 21:09:24 +03:00
}
2015-12-17 20:31:28 +03:00
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int width ) override ;
2014-05-30 12:53:19 +04:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override {
if ( auto captioned = Get < HistoryDocumentCaptioned > ( ) ) {
return captioned - > _caption . adjustSelection ( selection , type ) ;
}
return selection ;
}
2016-04-20 15:56:59 +03:00
bool hasTextForCopy ( ) const override {
return Has < HistoryDocumentCaptioned > ( ) ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2015-12-19 21:09:24 +03:00
2016-03-21 21:57:03 +03:00
bool uploading ( ) const override {
2015-12-24 22:26:28 +03:00
return _data - > uploading ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
2016-03-21 21:57:03 +03:00
DocumentData * getDocument ( ) override {
2015-12-08 22:07:50 +03:00
return _data ;
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
2014-05-30 12:53:19 +04:00
2016-04-10 18:53:01 +04:00
void updateSentMedia ( const MTPMessageMedia & media ) override ;
bool needReSetInlineResultMedia ( const MTPMessageMedia & media ) override ;
2014-05-30 12:53:19 +04:00
2016-03-21 21:57:03 +03:00
bool hasReplyPreview ( ) const override {
2015-12-08 22:07:50 +03:00
return ! _data - > thumb - > isNull ( ) ;
2015-03-19 12:18:19 +03:00
}
2016-03-21 21:57:03 +03:00
ImagePtr replyPreview ( ) override ;
2015-03-19 12:18:19 +03:00
2016-05-06 20:33:48 +03:00
TextWithEntities getCaption ( ) const override {
2016-02-12 19:35:06 +03:00
if ( const HistoryDocumentCaptioned * captioned = Get < HistoryDocumentCaptioned > ( ) ) {
2016-05-06 20:33:48 +03:00
return captioned - > _caption . originalTextWithEntities ( ) ;
2016-02-12 19:35:06 +03:00
}
2016-05-06 20:33:48 +03:00
return TextWithEntities ( ) ;
2015-12-28 13:28:00 +03:00
}
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
2015-12-08 22:07:50 +03:00
return true ;
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-08 22:07:50 +03:00
return false ;
}
2016-03-21 21:57:03 +03:00
QMargins bubbleMargins ( ) const override {
2016-02-12 19:35:06 +03:00
return Get < HistoryDocumentThumbed > ( ) ? QMargins ( st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . top ( ) , st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . bottom ( ) ) : st : : msgPadding ;
2015-12-19 00:36:16 +03:00
}
2016-03-21 21:57:03 +03:00
bool hideForwardedFrom ( ) const override {
2015-12-09 22:09:29 +03:00
return _data - > song ( ) ;
}
2015-12-08 22:07:50 +03:00
2016-02-12 19:35:06 +03:00
void step_voiceProgress ( float64 ms , bool timer ) ;
2015-12-13 01:29:33 +03:00
protected :
2016-03-21 21:57:03 +03:00
float64 dataProgress ( ) const override {
2015-12-13 01:29:33 +03:00
return _data - > progress ( ) ;
}
2016-03-21 21:57:03 +03:00
bool dataFinished ( ) const override {
2015-12-24 22:26:28 +03:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
2015-12-13 01:29:33 +03:00
}
2016-03-21 21:57:03 +03:00
bool dataLoaded ( ) const override {
2015-12-23 19:48:44 +03:00
return _data - > loaded ( ) ;
2015-12-13 01:29:33 +03:00
}
2015-12-11 21:11:38 +03:00
2014-05-30 12:53:19 +04:00
private :
2016-03-28 15:51:22 +03:00
void createComponents ( bool caption ) ;
2015-12-08 22:07:50 +03:00
DocumentData * _data ;
2015-12-28 13:28:00 +03:00
2015-12-09 21:06:20 +03:00
void setStatusSize ( int32 newSize , qint64 realDuration = 0 ) const ;
2016-04-10 18:53:01 +04:00
bool updateStatusText ( ) const ; // returns showPause
2015-12-11 21:11:38 +03:00
2015-12-08 22:07:50 +03:00
} ;
2015-12-13 20:05:32 +03:00
class HistoryGif : public HistoryFileMedia {
2015-12-08 22:07:50 +03:00
public :
2016-04-10 18:53:01 +04:00
HistoryGif ( HistoryItem * parent , DocumentData * document , const QString & caption ) ;
HistoryGif ( HistoryItem * parent , const HistoryGif & other ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2015-12-19 21:09:24 +03:00
return MediaTypeGif ;
}
2016-04-10 18:53:01 +04:00
HistoryGif * clone ( HistoryItem * newParent ) const override {
return new HistoryGif ( newParent , * this ) ;
2015-12-19 21:09:24 +03:00
}
2015-12-17 20:31:28 +03:00
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int width ) override ;
2015-12-08 22:07:50 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override {
return _caption . adjustSelection ( selection , type ) ;
}
2016-04-20 15:56:59 +03:00
bool hasTextForCopy ( ) const override {
return ! _caption . isEmpty ( ) ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2015-12-19 21:09:24 +03:00
2016-03-21 21:57:03 +03:00
bool uploading ( ) const override {
2015-12-24 22:26:28 +03:00
return _data - > uploading ( ) ;
2015-12-08 22:07:50 +03:00
}
2016-03-21 21:57:03 +03:00
DocumentData * getDocument ( ) override {
2015-12-08 22:07:50 +03:00
return _data ;
}
2016-03-21 21:57:03 +03:00
ClipReader * getClipReader ( ) override {
2015-12-29 00:20:04 +03:00
return gif ( ) ;
}
2015-12-19 21:09:24 +03:00
2016-04-10 18:53:01 +04:00
bool playInline ( bool autoplay ) override ;
void stopInline ( ) override ;
2015-12-08 22:07:50 +03:00
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
2015-12-08 22:07:50 +03:00
2016-04-10 18:53:01 +04:00
void updateSentMedia ( const MTPMessageMedia & media ) override ;
bool needReSetInlineResultMedia ( const MTPMessageMedia & media ) override ;
2015-12-08 22:07:50 +03:00
2016-03-21 21:57:03 +03:00
bool hasReplyPreview ( ) const override {
2015-12-08 22:07:50 +03:00
return ! _data - > thumb - > isNull ( ) ;
}
2016-03-21 21:57:03 +03:00
ImagePtr replyPreview ( ) override ;
2015-12-08 22:07:50 +03:00
2016-05-06 20:33:48 +03:00
TextWithEntities getCaption ( ) const override {
return _caption . originalTextWithEntities ( ) ;
2015-12-28 13:28:00 +03:00
}
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
if ( ! _caption . isEmpty ( ) ) {
return true ;
}
if ( _parent - > viaBot ( ) ) {
return true ;
}
return ( _parent - > Has < HistoryMessageForwarded > ( ) | | _parent - > Has < HistoryMessageReply > ( ) ) ;
2015-12-08 22:07:50 +03:00
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-28 13:28:00 +03:00
return _caption . isEmpty ( ) ;
2015-12-08 22:07:50 +03:00
}
2016-03-21 21:57:03 +03:00
bool hideFromName ( ) const override {
2015-12-13 20:05:32 +03:00
return true ;
}
2015-12-15 17:50:51 +03:00
~ HistoryGif ( ) ;
2015-12-13 20:05:32 +03:00
protected :
2016-03-21 21:57:03 +03:00
float64 dataProgress ( ) const override ;
bool dataFinished ( ) const override ;
bool dataLoaded ( ) const override ;
2015-12-08 22:07:50 +03:00
private :
DocumentData * _data ;
2015-12-13 20:05:32 +03:00
int32 _thumbw , _thumbh ;
2015-12-28 13:28:00 +03:00
Text _caption ;
2015-12-15 17:50:51 +03:00
ClipReader * _gif ;
2015-12-25 16:10:13 +03:00
ClipReader * gif ( ) {
2016-03-19 19:55:15 +03:00
return ( _gif = = BadClipReader ) ? nullptr : _gif ;
2015-12-25 16:10:13 +03:00
}
const ClipReader * gif ( ) const {
2016-03-19 19:55:15 +03:00
return ( _gif = = BadClipReader ) ? nullptr : _gif ;
2015-12-25 16:10:13 +03:00
}
2014-05-30 12:53:19 +04:00
2015-12-13 20:05:32 +03:00
void setStatusSize ( int32 newSize ) const ;
2016-04-10 18:53:01 +04:00
void updateStatusText ( ) const ;
2015-12-08 22:07:50 +03:00
2014-05-30 12:53:19 +04:00
} ;
2014-12-23 02:11:37 +03:00
class HistorySticker : public HistoryMedia {
public :
2016-04-10 18:53:01 +04:00
HistorySticker ( HistoryItem * parent , DocumentData * document ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2014-12-23 02:11:37 +03:00
return MediaTypeSticker ;
}
2016-04-10 18:53:01 +04:00
HistorySticker * clone ( HistoryItem * newParent ) const override {
return new HistorySticker ( newParent , _data ) ;
2015-12-19 21:09:24 +03:00
}
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int width ) override ;
2015-12-19 21:09:24 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
2016-03-29 20:17:00 +03:00
bool toggleSelectionByHandlerClick ( const ClickHandlerPtr & p ) const override {
return true ;
}
bool dragItem ( ) const override {
return true ;
}
bool dragItemByHandler ( const ClickHandlerPtr & p ) const override {
return true ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2014-12-23 02:11:37 +03:00
2016-03-21 21:57:03 +03:00
DocumentData * getDocument ( ) override {
2015-12-23 15:19:32 +03:00
return _data ;
2014-12-23 02:11:37 +03:00
}
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
2014-12-23 02:11:37 +03:00
2016-04-10 18:53:01 +04:00
void updateSentMedia ( const MTPMessageMedia & media ) override ;
bool needReSetInlineResultMedia ( const MTPMessageMedia & media ) override ;
2014-12-23 02:11:37 +03:00
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
2015-12-08 22:07:50 +03:00
return false ;
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-08 22:07:50 +03:00
return true ;
}
2014-12-23 02:11:37 +03:00
private :
2016-04-07 14:03:10 +04:00
int additionalWidth ( const HistoryMessageVia * via , const HistoryMessageReply * reply ) const ;
2016-04-10 18:53:01 +04:00
int additionalWidth ( ) const {
return additionalWidth ( _parent - > Get < HistoryMessageVia > ( ) , _parent - > Get < HistoryMessageReply > ( ) ) ;
2016-04-07 14:03:10 +04:00
}
2015-12-23 15:19:32 +03:00
int16 _pixw , _pixh ;
2016-04-06 16:02:00 +04:00
ClickHandlerPtr _packLink ;
2015-12-23 15:19:32 +03:00
DocumentData * _data ;
2015-01-05 23:17:33 +03:00
QString _emoji ;
2014-12-23 02:11:37 +03:00
} ;
2016-03-29 20:17:00 +03:00
class SendMessageClickHandler : public PeerClickHandler {
2015-12-13 01:29:33 +03:00
public :
2016-03-29 20:17:00 +03:00
using PeerClickHandler : : PeerClickHandler ;
protected :
void onClickImpl ( ) const override ;
2015-12-13 01:29:33 +03:00
} ;
2016-03-29 20:17:00 +03:00
class AddContactClickHandler : public MessageClickHandler {
2015-12-13 01:29:33 +03:00
public :
2016-03-29 20:17:00 +03:00
using MessageClickHandler : : MessageClickHandler ;
protected :
void onClickImpl ( ) const override ;
2015-12-13 01:29:33 +03:00
} ;
2014-05-30 12:53:19 +04:00
class HistoryContact : public HistoryMedia {
public :
2016-04-10 18:53:01 +04:00
HistoryContact ( HistoryItem * parent , int32 userId , const QString & first , const QString & last , const QString & phone ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2014-05-30 12:53:19 +04:00
return MediaTypeContact ;
}
2016-04-10 18:53:01 +04:00
HistoryContact * clone ( HistoryItem * newParent ) const override {
return new HistoryContact ( newParent , _userId , _fname , _lname , _phone ) ;
2015-12-19 21:09:24 +03:00
}
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
2015-12-19 21:09:24 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
2016-03-29 20:17:00 +03:00
bool toggleSelectionByHandlerClick ( const ClickHandlerPtr & p ) const override {
return true ;
}
bool dragItemByHandler ( const ClickHandlerPtr & p ) const override {
return true ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2014-05-30 12:53:19 +04:00
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
2015-12-13 01:29:33 +03:00
2016-04-10 18:53:01 +04:00
void updateSentMedia ( const MTPMessageMedia & media ) override ;
2014-08-22 18:55:23 +04:00
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
2015-12-08 22:07:50 +03:00
return true ;
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-08 22:07:50 +03:00
return false ;
}
2015-12-13 01:29:33 +03:00
const QString & fname ( ) const {
return _fname ;
}
const QString & lname ( ) const {
return _lname ;
}
const QString & phone ( ) const {
return _phone ;
}
2014-05-30 12:53:19 +04:00
private :
2015-12-13 01:29:33 +03:00
int32 _userId ;
UserData * _contact ;
int32 _phonew ;
QString _fname , _lname , _phone ;
Text _name ;
2016-03-29 20:17:00 +03:00
ClickHandlerPtr _linkl ;
2015-12-13 01:29:33 +03:00
int32 _linkw ;
QString _link ;
2014-05-30 12:53:19 +04:00
} ;
2015-04-04 23:01:34 +03:00
class HistoryWebPage : public HistoryMedia {
public :
2016-04-10 18:53:01 +04:00
HistoryWebPage ( HistoryItem * parent , WebPageData * data ) ;
HistoryWebPage ( HistoryItem * parent , const HistoryWebPage & other ) ;
2016-03-21 21:57:03 +03:00
HistoryMediaType type ( ) const override {
2015-12-19 21:09:24 +03:00
return MediaTypeWebPage ;
}
2016-04-10 18:53:01 +04:00
HistoryWebPage * clone ( HistoryItem * newParent ) const override {
return new HistoryWebPage ( newParent , * this ) ;
2015-12-19 21:09:24 +03:00
}
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int width ) override ;
2015-12-19 21:09:24 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override ;
2016-04-20 15:56:59 +03:00
bool hasTextForCopy ( ) const override {
return false ; // we do not add _title and _description in FullSelection text copy.
}
2016-03-29 20:17:00 +03:00
bool toggleSelectionByHandlerClick ( const ClickHandlerPtr & p ) const override {
return _attach & & _attach - > toggleSelectionByHandlerClick ( p ) ;
}
bool dragItemByHandler ( const ClickHandlerPtr & p ) const override {
return _attach & & _attach - > dragItemByHandler ( p ) ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2015-04-04 23:01:34 +03:00
2016-04-10 18:53:01 +04:00
void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) override ;
void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) override ;
2015-12-19 00:36:16 +03:00
2016-03-21 21:57:03 +03:00
bool isDisplayed ( ) const override {
2015-12-19 00:36:16 +03:00
return ! _data - > pendingTill ;
2015-05-20 22:28:24 +03:00
}
2016-03-21 21:57:03 +03:00
DocumentData * getDocument ( ) override {
2015-12-19 00:36:16 +03:00
return _attach ? _attach - > getDocument ( ) : 0 ;
}
2016-03-21 21:57:03 +03:00
ClipReader * getClipReader ( ) override {
2016-01-01 09:56:21 +08:00
return _attach ? _attach - > getClipReader ( ) : 0 ;
}
2016-04-10 18:53:01 +04:00
bool playInline ( bool autoplay ) override {
return _attach ? _attach - > playInline ( autoplay ) : false ;
2015-12-19 00:36:16 +03:00
}
2016-04-10 18:53:01 +04:00
void stopInline ( ) override {
if ( _attach ) _attach - > stopInline ( ) ;
2015-12-19 00:36:16 +03:00
}
2016-04-10 18:53:01 +04:00
void attachToParent ( ) override ;
void detachFromParent ( ) override ;
2015-04-04 23:01:34 +03:00
2016-03-21 21:57:03 +03:00
bool hasReplyPreview ( ) const override {
2016-04-08 13:20:10 +04:00
return ( _data - > photo & & ! _data - > photo - > thumb - > isNull ( ) ) | | ( _data - > document & & ! _data - > document - > thumb - > isNull ( ) ) ;
2015-04-04 23:01:34 +03:00
}
2016-03-21 21:57:03 +03:00
ImagePtr replyPreview ( ) override ;
2015-04-04 23:01:34 +03:00
2015-08-28 18:15:56 +03:00
WebPageData * webpage ( ) {
2015-12-19 00:36:16 +03:00
return _data ;
2015-08-28 18:15:56 +03:00
}
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
2015-12-08 22:07:50 +03:00
return true ;
}
2016-03-21 21:57:03 +03:00
bool customInfoLayout ( ) const override {
2015-12-08 22:07:50 +03:00
return false ;
}
2015-12-28 00:37:48 +03:00
HistoryMedia * attach ( ) const {
return _attach ;
}
2015-12-31 23:27:21 +08:00
2015-12-28 00:37:48 +03:00
~ HistoryWebPage ( ) ;
2015-04-04 23:01:34 +03:00
private :
2016-04-13 21:29:32 +03:00
TextSelection toDescriptionSelection ( TextSelection selection ) const {
2016-04-14 14:00:23 +03:00
return internal : : unshiftSelection ( selection , _title ) ;
2016-04-13 21:29:32 +03:00
}
TextSelection fromDescriptionSelection ( TextSelection selection ) const {
2016-04-14 14:00:23 +03:00
return internal : : shiftSelection ( selection , _title ) ;
2016-04-13 21:29:32 +03:00
}
2015-12-19 00:36:16 +03:00
WebPageData * _data ;
2016-03-29 20:17:00 +03:00
ClickHandlerPtr _openl ;
2015-12-19 00:36:16 +03:00
HistoryMedia * _attach ;
2015-04-04 23:01:34 +03:00
bool _asArticle ;
2015-12-19 00:36:16 +03:00
int32 _titleLines , _descriptionLines ;
2015-04-04 23:01:34 +03:00
Text _title , _description ;
int32 _siteNameWidth ;
2015-12-19 00:36:16 +03:00
QString _duration ;
int32 _durationWidth ;
2015-04-04 23:01:34 +03:00
int16 _pixw , _pixh ;
} ;
2015-12-31 23:28:54 +08:00
void initImageLinkManager ( ) ;
void reinitImageLinkManager ( ) ;
void deinitImageLinkManager ( ) ;
2016-04-13 00:31:28 +03:00
struct LocationCoords ;
struct LocationData ;
2016-02-28 16:54:04 +03:00
class LocationManager : public QObject {
2015-12-31 23:28:54 +08:00
Q_OBJECT
public :
2016-02-28 16:54:04 +03:00
LocationManager ( ) : manager ( 0 ) , black ( 0 ) {
2015-12-31 23:28:54 +08:00
}
void init ( ) ;
void reinit ( ) ;
void deinit ( ) ;
2016-02-28 16:54:04 +03:00
void getData ( LocationData * data ) ;
2015-12-31 23:28:54 +08:00
2016-02-28 16:54:04 +03:00
~ LocationManager ( ) {
2015-12-31 23:28:54 +08:00
deinit ( ) ;
}
2016-02-28 16:54:04 +03:00
public slots :
2015-12-31 23:28:54 +08:00
void onFinished ( QNetworkReply * reply ) ;
void onFailed ( QNetworkReply * reply ) ;
private :
2016-02-28 16:54:04 +03:00
void failed ( LocationData * data ) ;
2015-12-31 23:28:54 +08:00
QNetworkAccessManager * manager ;
2016-02-28 16:54:04 +03:00
QMap < QNetworkReply * , LocationData * > dataLoadings , imageLoadings ;
QMap < LocationData * , int32 > serverRedirects ;
2015-12-31 23:28:54 +08:00
ImagePtr * black ;
} ;
2016-02-28 16:54:04 +03:00
class HistoryLocation : public HistoryMedia {
2014-11-12 23:18:00 +03:00
public :
2016-04-10 18:53:01 +04:00
HistoryLocation ( HistoryItem * parent , const LocationCoords & coords , const QString & title = QString ( ) , const QString & description = QString ( ) ) ;
HistoryLocation ( HistoryItem * parent , const HistoryLocation & other ) ;
2016-04-07 14:35:09 +04:00
HistoryMediaType type ( ) const override {
2016-02-28 16:54:04 +03:00
return MediaTypeLocation ;
2014-11-12 23:18:00 +03:00
}
2016-04-10 18:53:01 +04:00
HistoryLocation * clone ( HistoryItem * newParent ) const override {
return new HistoryLocation ( newParent , * this ) ;
2015-12-19 21:09:24 +03:00
}
2016-04-10 18:53:01 +04:00
void initDimensions ( ) override ;
int resizeGetHeight ( int32 width ) override ;
2015-12-19 21:09:24 +03:00
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override ;
2016-04-20 15:56:59 +03:00
bool hasTextForCopy ( ) const override {
return ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ;
}
2016-03-29 20:17:00 +03:00
bool toggleSelectionByHandlerClick ( const ClickHandlerPtr & p ) const override {
return p = = _link ;
}
bool dragItemByHandler ( const ClickHandlerPtr & p ) const override {
return p = = _link ;
}
2015-12-19 21:09:24 +03:00
2016-04-14 14:00:23 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2015-04-11 11:04:10 +01:00
2016-04-10 18:53:01 +04:00
bool needsBubble ( ) const override {
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
return true ;
}
if ( _parent - > viaBot ( ) ) {
return true ;
}
return ( _parent - > Has < HistoryMessageForwarded > ( ) | | _parent - > Has < HistoryMessageReply > ( ) ) ;
2015-12-08 22:07:50 +03:00
}
2016-04-07 14:35:09 +04:00
bool customInfoLayout ( ) const override {
2015-12-08 22:07:50 +03:00
return true ;
}
2014-11-12 23:18:00 +03:00
private :
2016-04-13 21:29:32 +03:00
TextSelection toDescriptionSelection ( TextSelection selection ) const {
2016-04-14 14:00:23 +03:00
return internal : : unshiftSelection ( selection , _title ) ;
2016-04-13 21:29:32 +03:00
}
TextSelection fromDescriptionSelection ( TextSelection selection ) const {
2016-04-14 14:00:23 +03:00
return internal : : shiftSelection ( selection , _title ) ;
2016-04-13 21:29:32 +03:00
}
2016-02-28 16:54:04 +03:00
LocationData * _data ;
2015-04-30 16:53:36 +03:00
Text _title , _description ;
2016-03-29 20:17:00 +03:00
ClickHandlerPtr _link ;
2014-11-18 15:41:33 +03:00
2015-12-19 21:09:24 +03:00
int32 fullWidth ( ) const ;
int32 fullHeight ( ) const ;
2014-11-12 23:18:00 +03:00
} ;
2016-03-29 20:17:00 +03:00
class ViaInlineBotClickHandler : public LeftButtonClickHandler {
2015-12-31 23:27:21 +08:00
public :
2016-03-29 20:17:00 +03:00
ViaInlineBotClickHandler ( UserData * bot ) : _bot ( bot ) {
2015-12-31 23:27:21 +08:00
}
2016-03-29 20:17:00 +03:00
protected :
void onClickImpl ( ) const override ;
2015-12-31 23:27:21 +08:00
private :
UserData * _bot ;
} ;
2016-03-18 22:05:08 +03:00
class HistoryMessage : public HistoryItem , private HistoryItemInstantiated < HistoryMessage > {
2014-05-30 12:53:19 +04:00
public :
2016-03-18 22:05:08 +03:00
static HistoryMessage * create ( History * history , const MTPDmessage & msg ) {
return _create ( history , msg ) ;
}
2016-03-19 19:55:15 +03:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * fwd ) {
2016-03-18 22:05:08 +03:00
return _create ( history , msgId , flags , date , from , fwd ) ;
}
2016-05-06 20:33:48 +03:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , const TextWithEntities & textWithEntities ) {
return _create ( history , msgId , flags , replyTo , viaBotId , date , from , textWithEntities ) ;
2016-03-18 22:05:08 +03:00
}
2016-04-06 12:00:37 +04:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , DocumentData * doc , const QString & caption , const MTPReplyMarkup & markup ) {
return _create ( history , msgId , flags , replyTo , viaBotId , date , from , doc , caption , markup ) ;
2016-03-18 22:05:08 +03:00
}
2016-04-06 12:00:37 +04:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , PhotoData * photo , const QString & caption , const MTPReplyMarkup & markup ) {
return _create ( history , msgId , flags , replyTo , viaBotId , date , from , photo , caption , markup ) ;
2016-03-18 22:05:08 +03:00
}
2014-05-30 12:53:19 +04:00
2015-04-30 16:53:36 +03:00
void initTime ( ) ;
2015-08-30 17:57:21 +03:00
void initMedia ( const MTPMessageMedia * media , QString & currentText ) ;
2015-12-28 13:28:00 +03:00
void initMediaFromDocument ( DocumentData * doc , const QString & caption ) ;
2016-01-09 15:11:23 +08:00
void fromNameUpdated ( int32 width ) const ;
2014-05-30 12:53:19 +04:00
2015-12-09 21:06:20 +03:00
int32 plainMaxWidth ( ) const ;
void countPositionAndSize ( int32 & left , int32 & width ) const ;
2015-12-09 22:09:29 +03:00
bool emptyText ( ) const {
2015-12-08 22:07:50 +03:00
return _text . isEmpty ( ) ;
}
bool drawBubble ( ) const {
2016-04-10 18:53:01 +04:00
return _media ? ( ! emptyText ( ) | | _media - > needsBubble ( ) ) : true ;
2015-04-04 23:01:34 +03:00
}
2016-03-21 21:57:03 +03:00
bool hasBubble ( ) const override {
2015-12-09 21:06:20 +03:00
return drawBubble ( ) ;
}
2015-12-09 22:09:29 +03:00
bool displayFromName ( ) const {
2016-03-21 21:40:00 +03:00
if ( ! hasFromName ( ) ) return false ;
if ( isAttachedToPrevious ( ) ) return false ;
2016-03-25 14:29:45 +03:00
return ( ! emptyText ( ) | | ! _media | | ! _media - > isDisplayed ( ) | | Has < HistoryMessageReply > ( ) | | Has < HistoryMessageForwarded > ( ) | | viaBot ( ) | | ! _media - > hideFromName ( ) ) ;
2015-12-09 22:09:29 +03:00
}
2015-12-24 22:26:28 +03:00
bool uploading ( ) const {
return _media & & _media - > uploading ( ) ;
}
2014-05-30 12:53:19 +04:00
2016-03-21 21:57:03 +03:00
void drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const override ;
void setViewsCount ( int32 count ) override ;
void setId ( MsgId newId ) override ;
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
2015-12-11 21:11:38 +03:00
2016-03-25 14:29:45 +03:00
void dependencyItemRemoved ( HistoryItem * dependency ) override ;
2014-05-30 12:53:19 +04:00
2016-04-10 18:53:01 +04:00
bool hasPoint ( int x , int y ) const override ;
bool pointInTime ( int32 right , int32 bottom , int x , int y , InfoDisplayType type ) const override ;
2015-05-14 19:50:04 +03:00
2016-04-13 21:29:32 +03:00
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
2015-05-14 19:50:04 +03:00
2016-04-13 21:29:32 +03:00
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override ;
2016-03-29 20:17:00 +03:00
// ClickHandlerHost interface
void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) override {
2016-04-10 18:53:01 +04:00
if ( _media ) _media - > clickHandlerActiveChanged ( p , active ) ;
2016-03-29 20:17:00 +03:00
HistoryItem : : clickHandlerActiveChanged ( p , active ) ;
2015-12-11 21:11:38 +03:00
}
2016-03-29 20:17:00 +03:00
void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) override {
2016-04-14 22:24:42 +03:00
if ( _media ) _media - > clickHandlerPressedChanged ( p , pressed ) ;
2016-03-29 20:17:00 +03:00
HistoryItem : : clickHandlerPressedChanged ( p , pressed ) ;
2015-12-11 21:11:38 +03:00
}
2014-05-30 12:53:19 +04:00
2016-03-21 21:57:03 +03:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const override ;
QString notificationHeader ( ) const override ;
QString notificationText ( ) const override ;
2015-12-31 23:27:21 +08:00
2016-04-01 14:23:40 +04:00
void applyEdition ( const MTPDmessage & message ) override ;
2016-04-06 12:00:37 +04:00
void updateMedia ( const MTPMessageMedia * media ) override ;
2016-03-21 21:57:03 +03:00
int32 addToOverview ( AddToOverviewMethod method ) override ;
2016-05-20 19:01:06 +03:00
void eraseFromOverview ( ) override ;
2014-05-30 12:53:19 +04:00
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2016-03-21 21:57:03 +03:00
QString inDialogsText ( ) const override ;
2016-05-06 20:33:48 +03:00
void setText ( const TextWithEntities & textWithEntities ) override ;
TextWithEntities originalText ( ) const override ;
bool textHasLinks ( ) const override ;
2014-05-30 12:53:19 +04:00
2016-03-21 21:57:03 +03:00
int32 infoWidth ( ) const override {
2015-09-13 20:27:29 +03:00
int32 result = _timeWidth ;
2016-02-17 19:37:21 +03:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
result + = st : : msgDateViewsSpace + views - > _viewsWidth + st : : msgDateCheckSpace + st : : msgViewsImg . pxWidth ( ) ;
2015-10-27 20:29:39 -04:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-15 11:50:54 +03:00
}
2016-02-17 19:37:21 +03:00
if ( out ( ) & & ! isPost ( ) ) {
2015-09-15 11:50:54 +03:00
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-13 20:27:29 +03:00
}
return result ;
2014-08-15 15:19:32 +04:00
}
2016-03-21 21:57:03 +03:00
int32 timeLeft ( ) const override {
2015-09-15 11:50:54 +03:00
int32 result = 0 ;
2016-02-17 19:37:21 +03:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
result + = st : : msgDateViewsSpace + views - > _viewsWidth + st : : msgDateCheckSpace + st : : msgViewsImg . pxWidth ( ) ;
2015-10-27 20:29:39 -04:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-15 11:50:54 +03:00
}
return result ;
}
2016-03-21 21:57:03 +03:00
int32 timeWidth ( ) const override {
2015-09-15 11:50:54 +03:00
return _timeWidth ;
}
2016-02-17 19:37:21 +03:00
2016-03-21 21:57:03 +03:00
int32 viewsCount ( ) const override {
2016-02-17 19:37:21 +03:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
return views - > _views ;
}
return HistoryItem : : viewsCount ( ) ;
2015-09-15 11:50:54 +03:00
}
2014-08-15 15:19:32 +04:00
2016-03-25 14:29:45 +03:00
bool updateDependencyItem ( ) override {
2016-04-08 14:44:35 +04:00
if ( auto reply = Get < HistoryMessageReply > ( ) ) {
2016-03-25 14:29:45 +03:00
return reply - > updateData ( this , true ) ;
}
return true ;
}
MsgId dependencyMsgId ( ) const override {
return replyToId ( ) ;
}
2016-03-21 21:57:03 +03:00
HistoryMessage * toHistoryMessage ( ) override { // dynamic_cast optimize
2015-04-13 09:58:13 +01:00
return this ;
}
2016-03-21 21:57:03 +03:00
const HistoryMessage * toHistoryMessage ( ) const override { // dynamic_cast optimize
2015-04-13 09:58:13 +01:00
return this ;
}
2016-03-22 22:43:47 +03:00
// hasFromPhoto() returns true even if we don't display the photo
// but we need to skip a place at the left side for this photo
bool displayFromPhoto ( ) const ;
bool hasFromPhoto ( ) const ;
2014-05-30 12:53:19 +04:00
~ HistoryMessage ( ) ;
2016-04-01 14:23:40 +04:00
private :
2014-05-30 12:53:19 +04:00
2016-03-18 22:05:08 +03:00
HistoryMessage ( History * history , const MTPDmessage & msg ) ;
2016-03-19 19:55:15 +03:00
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * fwd ) ; // local forwarded
2016-05-06 20:33:48 +03:00
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , const TextWithEntities & textWithEntities ) ; // local message
2016-04-06 12:00:37 +04:00
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , DocumentData * doc , const QString & caption , const MTPReplyMarkup & markup ) ; // local document
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , PhotoData * photo , const QString & caption , const MTPReplyMarkup & markup ) ; // local photo
2016-03-18 22:05:08 +03:00
friend class HistoryItemInstantiated < HistoryMessage > ;
2016-03-19 19:55:15 +03:00
void initDimensions ( ) override ;
2016-03-21 21:40:00 +03:00
int resizeGetHeight_ ( int width ) override ;
2016-04-08 13:20:10 +04:00
int performResizeGetHeight ( int width ) ;
2016-03-19 19:55:15 +03:00
2016-02-18 22:12:50 +03:00
bool displayForwardedFrom ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
2016-03-25 14:29:45 +03:00
return Has < HistoryMessageVia > ( ) | | ! _media | | ! _media - > isDisplayed ( ) | | fwd - > _authorOriginal - > isChannel ( ) | | ! _media - > hideForwardedFrom ( ) ;
2016-02-18 22:12:50 +03:00
}
return false ;
}
2016-03-25 14:29:45 +03:00
void paintForwardedInfo ( Painter & p , QRect & trect , bool selected ) const ;
void paintReplyInfo ( Painter & p , QRect & trect , bool selected ) const ;
// this method draws "via @bot" if it is not painted in forwarded info or in from name
void paintViaBotIdInfo ( Painter & p , QRect & trect , bool selected ) const ;
2016-02-17 19:37:21 +03:00
2016-04-01 14:23:40 +04:00
void setMedia ( const MTPMessageMedia * media ) ;
void setReplyMarkup ( const MTPReplyMarkup * markup ) ;
2015-09-15 11:50:54 +03:00
QString _timeText ;
2016-03-22 22:43:47 +03:00
int _timeWidth = 0 ;
2015-12-31 23:27:21 +08:00
2016-03-28 15:51:22 +03:00
struct CreateConfig {
MsgId replyTo = 0 ;
UserId viaBotId = 0 ;
int viewsCount = - 1 ;
PeerId authorIdOriginal = 0 ;
PeerId fromIdOriginal = 0 ;
MsgId originalId = 0 ;
2016-04-23 14:40:42 +03:00
QDateTime editDate ;
2016-03-28 15:51:22 +03:00
const MTPReplyMarkup * markup = nullptr ;
} ;
2016-04-06 12:00:37 +04:00
void createComponentsHelper ( MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , const MTPReplyMarkup & markup ) ;
2016-03-28 15:51:22 +03:00
void createComponents ( const CreateConfig & config ) ;
2015-03-19 12:18:19 +03:00
2016-03-28 20:15:17 +03:00
class KeyboardStyle : public ReplyKeyboard : : Style {
public :
using ReplyKeyboard : : Style : : Style ;
void startPaint ( Painter & p ) const override ;
style : : font textFont ( ) const override ;
void repaint ( const HistoryItem * item ) const override ;
protected :
void paintButtonBg ( Painter & p , const QRect & rect , bool down , float64 howMuchOver ) const override ;
2016-03-30 20:42:01 +04:00
void paintButtonIcon ( Painter & p , const QRect & rect , HistoryMessageReplyMarkup : : Button : : Type type ) const override ;
2016-04-06 21:02:22 +04:00
void paintButtonLoading ( Painter & p , const QRect & rect ) const override ;
2016-03-30 20:42:01 +04:00
int minButtonWidth ( HistoryMessageReplyMarkup : : Button : : Type type ) const override ;
2016-03-28 20:15:17 +03:00
} ;
2015-03-19 12:18:19 +03:00
} ;
2016-03-19 19:55:15 +03:00
inline MTPDmessage : : Flags newMessageFlags ( PeerData * p ) {
MTPDmessage : : Flags result = 0 ;
if ( ! p - > isSelf ( ) ) {
result | = MTPDmessage : : Flag : : f_out ;
2016-05-20 19:01:06 +03:00
//if (p->isChat() || (p->isUser() && !p->asUser()->botInfo)) {
// result |= MTPDmessage::Flag::f_unread;
//}
2016-03-19 19:55:15 +03:00
}
return result ;
2016-01-11 12:45:07 +08:00
}
2016-03-25 14:29:45 +03:00
struct HistoryServicePinned : public BaseComponent < HistoryServicePinned > {
MsgId msgId = 0 ;
HistoryItem * msg = nullptr ;
2016-03-29 20:17:00 +03:00
ClickHandlerPtr lnk ;
2016-03-05 23:12:55 +02:00
} ;
2016-03-25 14:29:45 +03:00
class HistoryService : public HistoryItem , private HistoryItemInstantiated < HistoryService > {
2014-05-30 12:53:19 +04:00
public :
2016-03-25 14:29:45 +03:00
static HistoryService * create ( History * history , const MTPDmessageService & msg ) {
2016-03-18 22:05:08 +03:00
return _create ( history , msg ) ;
}
2016-03-29 20:17:00 +03:00
static HistoryService * create ( History * history , MsgId msgId , QDateTime date , const QString & msg , MTPDmessage : : Flags flags = 0 , int32 from = 0 ) {
return _create ( history , msgId , date , msg , flags , from ) ;
2016-03-18 22:05:08 +03:00
}
2014-05-30 12:53:19 +04:00
2016-03-05 23:12:55 +02:00
bool updateDependencyItem ( ) override {
return updatePinned ( true ) ;
}
MsgId dependencyMsgId ( ) const override {
if ( const HistoryServicePinned * pinned = Get < HistoryServicePinned > ( ) ) {
return pinned - > msgId ;
}
return 0 ;
}
2016-03-11 15:20:58 +03:00
bool notificationReady ( ) const override {
if ( const HistoryServicePinned * pinned = Get < HistoryServicePinned > ( ) ) {
return ( pinned - > msg | | ! pinned - > msgId ) ;
}
return true ;
}
2016-03-05 23:12:55 +02:00
2016-02-09 19:05:08 +03:00
void countPositionAndSize ( int32 & left , int32 & width ) const ;
2016-04-13 21:29:32 +03:00
void draw ( Painter & p , const QRect & r , TextSelection selection , uint64 ms ) const override ;
2016-04-10 18:53:01 +04:00
bool hasPoint ( int x , int y ) const override ;
2016-04-13 21:29:32 +03:00
HistoryTextState getState ( int x , int y , HistoryStateRequest request ) const override ;
TextSelection adjustSelection ( TextSelection selection , TextSelectType type ) const override {
return _text . adjustSelection ( selection , type ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-29 20:17:00 +03:00
void clickHandlerActiveChanged ( const ClickHandlerPtr & p , bool active ) override {
2016-04-10 18:53:01 +04:00
if ( _media ) _media - > clickHandlerActiveChanged ( p , active ) ;
2016-03-29 20:17:00 +03:00
HistoryItem : : clickHandlerActiveChanged ( p , active ) ;
2015-12-28 00:37:48 +03:00
}
2016-03-29 20:17:00 +03:00
void clickHandlerPressedChanged ( const ClickHandlerPtr & p , bool pressed ) override {
2016-04-10 18:53:01 +04:00
if ( _media ) _media - > clickHandlerPressedChanged ( p , pressed ) ;
2016-03-29 20:17:00 +03:00
HistoryItem : : clickHandlerPressedChanged ( p , pressed ) ;
2015-12-28 00:37:48 +03:00
}
2016-03-11 18:28:32 +03:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const override ;
QString notificationText ( ) const override ;
2014-06-14 23:32:11 +04:00
2016-05-20 19:01:06 +03:00
int32 addToOverview ( AddToOverviewMethod method ) override ;
void eraseFromOverview ( ) override ;
2016-03-11 18:28:32 +03:00
bool needCheck ( ) const override {
2014-05-30 12:53:19 +04:00
return false ;
}
2016-03-11 18:28:32 +03:00
bool serviceMsg ( ) const override {
2014-05-30 12:53:19 +04:00
return true ;
}
2016-05-06 20:33:48 +03:00
TextWithEntities selectedText ( TextSelection selection ) const override ;
2016-03-11 18:28:32 +03:00
QString inDialogsText ( ) const override ;
QString inReplyText ( ) const override ;
2014-05-30 12:53:19 +04:00
2015-09-22 13:19:57 +03:00
void setServiceText ( const QString & text ) ;
2015-09-19 12:13:21 +03:00
2016-03-25 14:29:45 +03:00
~ HistoryService ( ) ;
2014-05-30 12:53:19 +04:00
protected :
2016-03-25 14:29:45 +03:00
HistoryService ( History * history , const MTPDmessageService & msg ) ;
2016-03-29 20:17:00 +03:00
HistoryService ( History * history , MsgId msgId , QDateTime date , const QString & msg , MTPDmessage : : Flags flags = 0 , int32 from = 0 ) ;
2016-03-25 14:29:45 +03:00
friend class HistoryItemInstantiated < HistoryService > ;
2016-03-18 22:05:08 +03:00
2016-03-19 19:55:15 +03:00
void initDimensions ( ) override ;
2016-03-21 21:40:00 +03:00
int resizeGetHeight_ ( int width ) override ;
2016-03-19 19:55:15 +03:00
2014-12-18 21:40:49 +03:00
void setMessageByAction ( const MTPmessageAction & action ) ;
2016-03-05 23:12:55 +02:00
bool updatePinned ( bool force = false ) ;
bool updatePinnedText ( const QString * pfrom = nullptr , QString * ptext = nullptr ) ;
2014-05-30 12:53:19 +04:00
} ;
2016-03-25 14:29:45 +03:00
class HistoryJoined : public HistoryService , private HistoryItemInstantiated < HistoryJoined > {
2015-09-21 23:57:42 +03:00
public :
2016-03-19 19:55:15 +03:00
static HistoryJoined * create ( History * history , const QDateTime & date , UserData * from , MTPDmessage : : Flags flags ) {
2016-03-18 22:05:08 +03:00
return _create ( history , date , from , flags ) ;
2015-09-21 23:57:42 +03:00
}
2014-05-30 12:53:19 +04:00
2015-09-19 12:13:21 +03:00
HistoryItemType type ( ) const {
2016-03-18 22:05:08 +03:00
return HistoryItemJoined ;
2014-05-30 12:53:19 +04:00
}
protected :
2016-03-19 19:55:15 +03:00
HistoryJoined ( History * history , const QDateTime & date , UserData * from , MTPDmessage : : Flags flags ) ;
2016-03-18 22:05:08 +03:00
using HistoryItemInstantiated < HistoryJoined > : : _create ;
friend class HistoryItemInstantiated < HistoryJoined > ;
2014-05-30 12:53:19 +04:00
} ;