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
2015-10-03 16:16:42 +03:00
Copyright ( c ) 2014 - 2015 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# include "stdafx.h"
# include "style.h"
# include "lang.h"
# include "mainwidget.h"
# include "application.h"
# include "fileuploader.h"
# include "window.h"
# include "gui/filedialog.h"
2015-12-13 01:29:33 +03:00
# include "boxes/addcontactbox.h"
2015-12-16 18:04:02 +03:00
# include "boxes/confirmbox.h"
2015-12-13 01:29:33 +03:00
2014-09-04 11:33:44 +04:00
# include "audio.h"
2014-11-22 12:45:04 +03:00
# include "localstorage.h"
2014-09-04 11:33:44 +04:00
2014-08-22 18:55:23 +04:00
namespace {
2014-05-30 12:53:19 +04:00
TextParseOptions _historySrvOptions = {
2015-04-08 02:03:32 +03:00
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText , // flags
2014-05-30 12:53:19 +04:00
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // lang-dependent
} ;
2015-04-04 23:01:34 +03:00
TextParseOptions _webpageTitleOptions = {
TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _webpageDescriptionOptions = {
2015-04-08 02:03:32 +03:00
TextParseLinks | TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _twitterDescriptionOptions = {
TextParseLinks | TextParseMentions | TextTwitterMentions | TextParseHashtags | TextTwitterHashtags | TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _instagramDescriptionOptions = {
TextParseLinks | TextParseMentions | TextInstagramMentions | TextParseHashtags | TextInstagramHashtags | TextParseMultiline | TextParseRichText , // flags
2015-04-04 23:01:34 +03:00
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
2014-05-30 12:53:19 +04:00
inline void _initTextOptions ( ) {
2015-04-19 13:29:19 +03:00
_historySrvOptions . dir = _textNameOptions . dir = _textDlgOptions . dir = cLangDir ( ) ;
2014-05-30 12:53:19 +04:00
_textDlgOptions . maxw = st : : dlgMaxWidth * 2 ;
2015-04-07 01:15:29 +03:00
_webpageTitleOptions . maxw = st : : msgMaxWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) - st : : webPageLeft ;
2015-04-04 23:01:34 +03:00
_webpageTitleOptions . maxh = st : : webPageTitleFont - > height * 2 ;
2015-04-07 01:15:29 +03:00
_webpageDescriptionOptions . maxw = st : : msgMaxWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) - st : : webPageLeft ;
2015-04-04 23:01:34 +03:00
_webpageDescriptionOptions . maxh = st : : webPageDescriptionFont - > height * 3 ;
2014-05-30 12:53:19 +04:00
}
2014-10-10 16:46:20 +04:00
2015-03-19 12:18:19 +03:00
inline HistoryReply * toHistoryReply ( HistoryItem * item ) {
return item ? item - > toHistoryReply ( ) : 0 ;
}
inline const HistoryReply * toHistoryReply ( const HistoryItem * item ) {
return item ? item - > toHistoryReply ( ) : 0 ;
}
2015-04-23 18:50:11 +03:00
inline HistoryForwarded * toHistoryForwarded ( HistoryItem * item ) {
return item ? item - > toHistoryForwarded ( ) : 0 ;
}
inline const HistoryForwarded * toHistoryForwarded ( const HistoryItem * item ) {
return item ? item - > toHistoryForwarded ( ) : 0 ;
}
2015-10-23 18:06:56 +02:00
inline const TextParseOptions & itemTextOptions ( HistoryItem * item ) {
return itemTextOptions ( item - > history ( ) , item - > from ( ) ) ;
}
2015-12-28 13:28:00 +03:00
inline const TextParseOptions & itemTextNoMonoOptions ( const HistoryItem * item ) {
2015-10-23 18:06:56 +02:00
return itemTextNoMonoOptions ( item - > history ( ) , item - > from ( ) ) ;
2015-08-24 13:53:04 +03:00
}
}
2014-05-30 12:53:19 +04:00
void historyInit ( ) {
_initTextOptions ( ) ;
}
2015-09-29 16:24:39 +03:00
void DialogRow : : paint ( Painter & p , int32 w , bool act , bool sel , bool onlyBackground ) const {
2014-05-30 12:53:19 +04:00
QRect fullRect ( 0 , 0 , w , st : : dlgHeight ) ;
p . fillRect ( fullRect , ( act ? st : : dlgActiveBG : ( sel ? st : : dlgHoverBG : st : : dlgBG ) ) - > b ) ;
2015-09-29 16:24:39 +03:00
if ( onlyBackground ) return ;
2015-11-18 16:11:56 +03:00
if ( history - > peer - > migrateTo ( ) ) {
p . drawPixmap ( st : : dlgPaddingHor , st : : dlgPaddingVer , history - > peer - > migrateTo ( ) - > photo - > pix ( st : : dlgPhotoSize ) ) ;
} else {
p . drawPixmap ( st : : dlgPaddingHor , st : : dlgPaddingVer , history - > peer - > photo - > pix ( st : : dlgPhotoSize ) ) ;
}
2014-05-30 12:53:19 +04:00
int32 nameleft = st : : dlgPaddingHor + st : : dlgPhotoSize + st : : dlgPhotoPadding ;
int32 namewidth = w - nameleft - st : : dlgPaddingHor ;
QRect rectForName ( nameleft , st : : dlgPaddingVer + st : : dlgNameTop , namewidth , st : : msgNameFont - > height ) ;
// draw chat icon
2015-11-02 17:33:57 -05:00
if ( history - > peer - > isChat ( ) | | history - > peer - > isMegagroup ( ) ) {
2015-09-15 11:50:54 +03:00
p . drawPixmap ( QPoint ( rectForName . left ( ) + st : : dlgChatImgPos . x ( ) , rectForName . top ( ) + st : : dlgChatImgPos . y ( ) ) , App : : sprite ( ) , ( act ? st : : dlgActiveChatImg : st : : dlgChatImg ) ) ;
rectForName . setLeft ( rectForName . left ( ) + st : : dlgImgSkip ) ;
2015-09-03 13:48:40 +03:00
} else if ( history - > peer - > isChannel ( ) ) {
2015-09-15 11:50:54 +03:00
p . drawPixmap ( QPoint ( rectForName . left ( ) + st : : dlgChannelImgPos . x ( ) , rectForName . top ( ) + st : : dlgChannelImgPos . y ( ) ) , App : : sprite ( ) , ( act ? st : : dlgActiveChannelImg : st : : dlgChannelImg ) ) ;
rectForName . setLeft ( rectForName . left ( ) + st : : dlgImgSkip ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-15 20:19:24 +03:00
HistoryItem * last = history - > lastMsg ;
2014-07-04 15:12:54 +04:00
if ( ! last ) {
2014-05-30 12:53:19 +04:00
p . setFont ( st : : dlgHistFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgSystemColor ) - > p ) ;
2015-08-01 11:33:00 +03:00
if ( history - > typing . isEmpty ( ) & & history - > sendActions . isEmpty ( ) ) {
2014-05-30 12:53:19 +04:00
p . drawText ( nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgFont - > ascent + st : : dlgSep , lang ( lng_empty_history ) ) ;
} else {
history - > typingText . drawElided ( p , nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , namewidth ) ;
}
} else {
// draw date
QDateTime now ( QDateTime : : currentDateTime ( ) ) , lastTime ( last - > date ) ;
QDate nowDate ( now . date ( ) ) , lastDate ( lastTime . date ( ) ) ;
QString dt ;
if ( lastDate = = nowDate ) {
2015-02-10 18:55:04 +00:00
dt = lastTime . toString ( cTimeFormat ( ) ) ;
2014-05-30 12:53:19 +04:00
} else if ( lastDate . year ( ) = = nowDate . year ( ) & & lastDate . weekNumber ( ) = = nowDate . weekNumber ( ) ) {
dt = langDayOfWeek ( lastDate ) ;
} else {
dt = lastDate . toString ( qsl ( " d.MM.yy " ) ) ;
}
2015-10-03 13:09:09 +03:00
int32 dtWidth = st : : dlgDateFont - > width ( dt ) ;
2014-05-30 12:53:19 +04:00
rectForName . setWidth ( rectForName . width ( ) - dtWidth - st : : dlgDateSkip ) ;
p . setFont ( st : : dlgDateFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveDateColor : st : : dlgDateColor ) - > p ) ;
p . drawText ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgDateSkip , rectForName . top ( ) + st : : msgNameFont - > height - st : : msgDateFont - > descent , dt ) ;
// draw check
2015-09-13 20:27:29 +03:00
if ( last - > needCheck ( ) ) {
2014-06-25 11:25:55 +04:00
const style : : sprite * check ;
2014-05-30 12:53:19 +04:00
if ( last - > id > 0 ) {
if ( last - > unread ( ) ) {
check = act ? & st : : dlgActiveCheckImg : & st : : dlgCheckImg ;
} else {
check = act ? & st : : dlgActiveDblCheckImg : & st : : dlgDblCheckImg ;
}
} else {
check = act ? & st : : dlgActiveSendImg : & st : : dlgSendImg ;
}
2014-06-25 11:25:55 +04:00
rectForName . setWidth ( rectForName . width ( ) - check - > pxWidth ( ) - st : : dlgCheckSkip ) ;
2014-05-30 12:53:19 +04:00
p . drawPixmap ( QPoint ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgCheckLeft , rectForName . top ( ) + st : : dlgCheckTop ) , App : : sprite ( ) , * check ) ;
}
// draw unread
int32 lastWidth = namewidth , unread = history - > unreadCount ;
2015-11-13 18:14:33 +03:00
if ( history - > peer - > migrateFrom ( ) ) {
if ( History * h = App : : historyLoaded ( history - > peer - > migrateFrom ( ) - > id ) ) {
unread + = h - > unreadCount ;
}
}
2014-05-30 12:53:19 +04:00
if ( unread ) {
QString unreadStr = QString : : number ( unread ) ;
2015-10-03 13:09:09 +03:00
int32 unreadWidth = st : : dlgUnreadFont - > width ( unreadStr ) ;
2014-05-30 12:53:19 +04:00
int32 unreadRectWidth = unreadWidth + 2 * st : : dlgUnreadPaddingHor ;
int32 unreadRectHeight = st : : dlgUnreadFont - > height + 2 * st : : dlgUnreadPaddingVer ;
int32 unreadRectLeft = w - st : : dlgPaddingHor - unreadRectWidth ;
int32 unreadRectTop = st : : dlgHeight - st : : dlgPaddingVer - unreadRectHeight ;
lastWidth - = unreadRectWidth + st : : dlgUnreadPaddingHor ;
2015-04-30 16:53:36 +03:00
p . setBrush ( ( act ? st : : dlgActiveUnreadBG : ( history - > mute ? st : : dlgUnreadMutedBG : st : : dlgUnreadBG ) ) - > b ) ;
2014-05-30 12:53:19 +04:00
p . setPen ( Qt : : NoPen ) ;
p . drawRoundedRect ( unreadRectLeft , unreadRectTop , unreadRectWidth , unreadRectHeight , st : : dlgUnreadRadius , st : : dlgUnreadRadius ) ;
p . setFont ( st : : dlgUnreadFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveUnreadColor : st : : dlgUnreadColor ) - > p ) ;
p . drawText ( unreadRectLeft + st : : dlgUnreadPaddingHor , unreadRectTop + st : : dlgUnreadPaddingVer + st : : dlgUnreadFont - > ascent , unreadStr ) ;
}
2015-08-01 11:33:00 +03:00
if ( history - > typing . isEmpty ( ) & & history - > sendActions . isEmpty ( ) ) {
2014-05-30 12:53:19 +04:00
last - > drawInDialog ( p , QRect ( nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , lastWidth , st : : dlgFont - > height ) , act , history - > textCachedFor , history - > lastItemTextCache ) ;
} else {
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgSystemColor ) - > p ) ;
history - > typingText . drawElided ( p , nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , lastWidth ) ;
}
}
2015-11-20 16:34:37 +03:00
if ( history - > peer - > isUser ( ) & & history - > peer - > isVerified ( ) ) {
rectForName . setWidth ( rectForName . width ( ) - st : : verifiedCheck . pxWidth ( ) - st : : verifiedCheckPos . x ( ) ) ;
p . drawSprite ( rectForName . topLeft ( ) + QPoint ( qMin ( history - > peer - > dialogName ( ) . maxWidth ( ) , rectForName . width ( ) ) , 0 ) + st : : verifiedCheckPos , ( act ? st : : verifiedCheckInv : st : : verifiedCheck ) ) ;
}
2014-05-30 12:53:19 +04:00
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgNameColor ) - > p ) ;
2015-09-04 16:01:31 +03:00
history - > peer - > dialogName ( ) . drawElided ( p , rectForName . left ( ) , rectForName . top ( ) , rectForName . width ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-29 16:24:39 +03:00
void FakeDialogRow : : paint ( Painter & p , int32 w , bool act , bool sel , bool onlyBackground ) const {
2014-07-04 15:12:54 +04:00
QRect fullRect ( 0 , 0 , w , st : : dlgHeight ) ;
p . fillRect ( fullRect , ( act ? st : : dlgActiveBG : ( sel ? st : : dlgHoverBG : st : : dlgBG ) ) - > b ) ;
2015-09-29 16:24:39 +03:00
if ( onlyBackground ) return ;
2014-07-04 15:12:54 +04:00
History * history = _item - > history ( ) ;
2015-11-18 16:11:56 +03:00
if ( history - > peer - > migrateTo ( ) ) {
p . drawPixmap ( st : : dlgPaddingHor , st : : dlgPaddingVer , history - > peer - > migrateTo ( ) - > photo - > pix ( st : : dlgPhotoSize ) ) ;
} else {
p . drawPixmap ( st : : dlgPaddingHor , st : : dlgPaddingVer , history - > peer - > photo - > pix ( st : : dlgPhotoSize ) ) ;
}
2014-07-04 15:12:54 +04:00
int32 nameleft = st : : dlgPaddingHor + st : : dlgPhotoSize + st : : dlgPhotoPadding ;
int32 namewidth = w - nameleft - st : : dlgPaddingHor ;
QRect rectForName ( nameleft , st : : dlgPaddingVer + st : : dlgNameTop , namewidth , st : : msgNameFont - > height ) ;
// draw chat icon
2015-11-02 17:33:57 -05:00
if ( history - > peer - > isChat ( ) | | history - > peer - > isMegagroup ( ) ) {
2015-09-15 11:50:54 +03:00
p . drawPixmap ( QPoint ( rectForName . left ( ) + st : : dlgChatImgPos . x ( ) , rectForName . top ( ) + st : : dlgChatImgPos . y ( ) ) , App : : sprite ( ) , ( act ? st : : dlgActiveChatImg : st : : dlgChatImg ) ) ;
rectForName . setLeft ( rectForName . left ( ) + st : : dlgImgSkip ) ;
2015-09-03 13:48:40 +03:00
} else if ( history - > peer - > isChannel ( ) ) {
2015-09-15 11:50:54 +03:00
p . drawPixmap ( QPoint ( rectForName . left ( ) + st : : dlgChannelImgPos . x ( ) , rectForName . top ( ) + st : : dlgChannelImgPos . y ( ) ) , App : : sprite ( ) , ( act ? st : : dlgActiveChannelImg : st : : dlgChannelImg ) ) ;
rectForName . setLeft ( rectForName . left ( ) + st : : dlgImgSkip ) ;
2014-07-04 15:12:54 +04:00
}
// draw date
QDateTime now ( QDateTime : : currentDateTime ( ) ) , lastTime ( _item - > date ) ;
QDate nowDate ( now . date ( ) ) , lastDate ( lastTime . date ( ) ) ;
QString dt ;
if ( lastDate = = nowDate ) {
2015-02-10 18:55:04 +00:00
dt = lastTime . toString ( cTimeFormat ( ) ) ;
2014-07-04 15:12:54 +04:00
} else if ( lastDate . year ( ) = = nowDate . year ( ) & & lastDate . weekNumber ( ) = = nowDate . weekNumber ( ) ) {
dt = langDayOfWeek ( lastDate ) ;
} else {
dt = lastDate . toString ( qsl ( " d.MM.yy " ) ) ;
}
2015-10-03 13:09:09 +03:00
int32 dtWidth = st : : dlgDateFont - > width ( dt ) ;
2014-07-04 15:12:54 +04:00
rectForName . setWidth ( rectForName . width ( ) - dtWidth - st : : dlgDateSkip ) ;
p . setFont ( st : : dlgDateFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveDateColor : st : : dlgDateColor ) - > p ) ;
p . drawText ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgDateSkip , rectForName . top ( ) + st : : msgNameFont - > height - st : : msgDateFont - > descent , dt ) ;
// draw check
2015-09-13 20:27:29 +03:00
if ( _item - > needCheck ( ) ) {
2014-07-04 15:12:54 +04:00
const style : : sprite * check ;
if ( _item - > id > 0 ) {
if ( _item - > unread ( ) ) {
check = act ? & st : : dlgActiveCheckImg : & st : : dlgCheckImg ;
} else {
check = act ? & st : : dlgActiveDblCheckImg : & st : : dlgDblCheckImg ;
}
} else {
check = act ? & st : : dlgActiveSendImg : & st : : dlgSendImg ;
}
rectForName . setWidth ( rectForName . width ( ) - check - > pxWidth ( ) - st : : dlgCheckSkip ) ;
p . drawPixmap ( QPoint ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgCheckLeft , rectForName . top ( ) + st : : dlgCheckTop ) , App : : sprite ( ) , * check ) ;
}
// draw unread
2015-11-13 18:14:33 +03:00
int32 lastWidth = namewidth ;
2014-07-04 15:12:54 +04:00
_item - > drawInDialog ( p , QRect ( nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , lastWidth , st : : dlgFont - > height ) , act , _cacheFor , _cache ) ;
2015-11-20 16:34:37 +03:00
if ( history - > peer - > isUser ( ) & & history - > peer - > isVerified ( ) ) {
rectForName . setWidth ( rectForName . width ( ) - st : : verifiedCheck . pxWidth ( ) - st : : verifiedCheckPos . x ( ) ) ;
p . drawSprite ( rectForName . topLeft ( ) + QPoint ( qMin ( history - > peer - > dialogName ( ) . maxWidth ( ) , rectForName . width ( ) ) , 0 ) + st : : verifiedCheckPos , ( act ? st : : verifiedCheckInv : st : : verifiedCheck ) ) ;
}
2014-07-04 15:12:54 +04:00
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgNameColor ) - > p ) ;
2015-09-04 16:01:31 +03:00
history - > peer - > dialogName ( ) . drawElided ( p , rectForName . left ( ) , rectForName . top ( ) , rectForName . width ( ) ) ;
2014-07-04 15:12:54 +04:00
}
2014-06-16 13:31:10 +04:00
History : : History ( const PeerId & peerId ) : width ( 0 ) , height ( 0 )
, unreadCount ( 0 )
2015-09-07 10:52:37 +03:00
, inboxReadBefore ( 1 )
, outboxReadBefore ( 1 )
2014-06-16 13:31:10 +04:00
, showFrom ( 0 )
, unreadBar ( 0 )
, peer ( App : : peer ( peerId ) )
2014-07-04 15:12:54 +04:00
, oldLoaded ( false )
, newLoaded ( true )
2015-06-15 20:19:24 +03:00
, lastMsg ( 0 )
2015-03-19 14:24:23 +03:00
, draftToId ( 0 )
2014-06-16 13:31:10 +04:00
, lastWidth ( 0 )
2015-09-19 12:13:21 +03:00
, lastScrollTop ( ScrollMax )
2015-07-17 22:17:37 +03:00
, lastShowAtMsgId ( ShowAtUnreadMsgId )
2014-06-16 13:31:10 +04:00
, mute ( isNotifyMuted ( peer - > notify ) )
2015-06-17 22:43:03 +03:00
, lastKeyboardInited ( false )
, lastKeyboardUsed ( false )
2015-06-15 20:36:16 +03:00
, lastKeyboardId ( 0 )
2015-11-23 18:34:38 +03:00
, lastKeyboardHiddenId ( 0 )
2015-06-15 20:36:16 +03:00
, lastKeyboardFrom ( 0 )
2014-11-05 20:43:32 +03:00
, sendRequestId ( 0 )
2014-06-16 13:31:10 +04:00
, textCachedFor ( 0 )
, lastItemTextCache ( st : : dlgRichMinWidth )
, posInDialogs ( 0 )
, typingText ( st : : dlgRichMinWidth )
{
2015-09-08 20:59:36 +03:00
if ( peer - > isChannel ( ) | | ( peer - > isUser ( ) & & peer - > asUser ( ) - > botInfo ) ) {
outboxReadBefore = INT_MAX ;
}
2014-08-15 15:19:32 +04:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
2015-11-18 16:11:56 +03:00
overviewCountData [ i ] = - 1 ; // not loaded yet
2014-08-15 15:19:32 +04:00
}
2014-05-30 12:53:19 +04:00
}
2015-06-24 20:24:48 +03:00
void History : : clearLastKeyboard ( ) {
2015-11-24 19:19:18 +03:00
if ( lastKeyboardId ) {
if ( lastKeyboardId = = lastKeyboardHiddenId ) {
lastKeyboardHiddenId = 0 ;
}
lastKeyboardId = 0 ;
}
2015-06-24 20:24:48 +03:00
lastKeyboardInited = true ;
lastKeyboardFrom = 0 ;
}
2014-05-30 12:53:19 +04:00
bool History : : updateTyping ( uint64 ms , uint32 dots , bool force ) {
2014-11-12 23:30:26 +03:00
if ( ! ms ) ms = getms ( true ) ;
2014-05-30 12:53:19 +04:00
bool changed = force ;
for ( TypingUsers : : iterator i = typing . begin ( ) , e = typing . end ( ) ; i ! = e ; ) {
if ( ms > = i . value ( ) ) {
i = typing . erase ( i ) ;
changed = true ;
} else {
+ + i ;
}
}
2015-08-31 18:05:57 +03:00
for ( SendActionUsers : : iterator i = sendActions . begin ( ) ; i ! = sendActions . cend ( ) ; ) {
2015-08-01 11:33:00 +03:00
if ( ms > = i . value ( ) . until ) {
i = sendActions . erase ( i ) ;
changed = true ;
} else {
+ + i ;
}
}
2014-05-30 12:53:19 +04:00
if ( changed ) {
QString newTypingStr ;
int32 cnt = typing . size ( ) ;
if ( cnt > 2 ) {
2014-12-18 21:40:49 +03:00
newTypingStr = lng_many_typing ( lt_count , cnt ) ;
2014-05-30 12:53:19 +04:00
} else if ( cnt > 1 ) {
2014-12-18 21:40:49 +03:00
newTypingStr = lng_users_typing ( lt_user , typing . begin ( ) . key ( ) - > firstName , lt_second_user , ( typing . end ( ) - 1 ) . key ( ) - > firstName ) ;
2014-05-30 12:53:19 +04:00
} else if ( cnt ) {
2015-09-03 13:48:40 +03:00
newTypingStr = peer - > isUser ( ) ? lang ( lng_typing ) : lng_user_typing ( lt_user , typing . begin ( ) . key ( ) - > firstName ) ;
2015-08-01 11:33:00 +03:00
} else if ( ! sendActions . isEmpty ( ) ) {
switch ( sendActions . begin ( ) . value ( ) . type ) {
2015-09-03 13:48:40 +03:00
case SendActionRecordVideo : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_record_video ) : lng_user_action_record_video ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionUploadVideo : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_upload_video ) : lng_user_action_upload_video ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionRecordAudio : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_record_audio ) : lng_user_action_record_audio ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionUploadAudio : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_upload_audio ) : lng_user_action_upload_audio ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionUploadPhoto : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_upload_photo ) : lng_user_action_upload_photo ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionUploadFile : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_upload_file ) : lng_user_action_upload_file ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionChooseLocation : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_geo_location ) : lng_user_action_geo_location ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
case SendActionChooseContact : newTypingStr = peer - > isUser ( ) ? lang ( lng_send_action_choose_contact ) : lng_user_action_choose_contact ( lt_user , sendActions . begin ( ) . key ( ) - > firstName ) ; break ;
2015-08-01 11:33:00 +03:00
}
2014-05-30 12:53:19 +04:00
}
if ( ! newTypingStr . isEmpty ( ) ) {
newTypingStr + = qsl ( " ... " ) ;
}
if ( typingStr ! = newTypingStr ) {
2015-09-21 23:57:42 +03:00
typingText . setText ( st : : dlgHistFont , ( typingStr = newTypingStr ) , _textNameOptions ) ;
2014-05-30 12:53:19 +04:00
}
}
if ( ! typingStr . isEmpty ( ) ) {
if ( typingText . lastDots ( dots % 4 ) ) {
changed = true ;
}
}
2015-10-03 13:09:09 +03:00
if ( changed & & App : : main ( ) ) {
if ( ! dialogs . isEmpty ( ) ) App : : main ( ) - > dlgUpdated ( dialogs [ 0 ] ) ;
if ( App : : main ( ) - > historyPeer ( ) = = peer ) {
App : : main ( ) - > topBar ( ) - > update ( ) ;
}
}
2014-05-30 12:53:19 +04:00
return changed ;
}
2015-07-03 11:47:16 +03:00
void History : : eraseFromOverview ( MediaOverviewType type , MsgId msgId ) {
2015-09-19 12:13:21 +03:00
if ( overviewIds [ type ] . isEmpty ( ) ) return ;
2015-07-03 11:47:16 +03:00
2015-09-19 12:13:21 +03:00
History : : MediaOverviewIds : : iterator i = overviewIds [ type ] . find ( msgId ) ;
if ( i = = overviewIds [ type ] . cend ( ) ) return ;
2015-07-03 11:47:16 +03:00
2015-09-19 12:13:21 +03:00
overviewIds [ type ] . erase ( i ) ;
for ( History : : MediaOverview : : iterator i = overview [ type ] . begin ( ) , e = overview [ type ] . end ( ) ; i ! = e ; + + i ) {
2015-07-03 11:47:16 +03:00
if ( ( * i ) = = msgId ) {
2015-09-19 12:13:21 +03:00
overview [ type ] . erase ( i ) ;
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ type ] > 0 ) {
- - overviewCountData [ type ] ;
2015-07-03 11:47:16 +03:00
}
break ;
}
}
if ( App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , type ) ;
}
2015-09-19 12:13:21 +03:00
ChannelHistory : : ChannelHistory ( const PeerId & peer ) : History ( peer ) ,
unreadCountAll ( 0 ) ,
2015-11-02 17:33:57 -05:00
_onlyImportant ( ! isMegagroup ( ) ) ,
2015-09-20 11:55:41 +03:00
_otherOldLoaded ( false ) , _otherNewLoaded ( true ) ,
2015-09-21 23:57:42 +03:00
_collapseMessage ( 0 ) , _joinedMessage ( 0 ) {
2015-09-19 12:13:21 +03:00
}
bool ChannelHistory : : isSwitchReadyFor ( MsgId switchId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) {
if ( switchId = = SwitchAtTopMsgId ) {
2015-11-02 17:33:57 -05:00
if ( _onlyImportant ) {
if ( isMegagroup ( ) ) switchMode ( ) ;
return true ;
}
2015-09-19 12:13:21 +03:00
int32 bottomUnderScrollTop = 0 ;
HistoryItem * atTopItem = App : : main ( ) - > atTopImportantMsg ( bottomUnderScrollTop ) ;
if ( atTopItem ) {
fixInScrollMsgId = atTopItem - > id ;
fixInScrollMsgTop = atTopItem - > y + atTopItem - > block ( ) - > y + atTopItem - > height ( ) - bottomUnderScrollTop - height ;
if ( _otherList . indexOf ( atTopItem ) > = 0 ) {
switchMode ( ) ;
return true ;
}
return false ;
}
if ( ! _otherList . isEmpty ( ) ) {
switchMode ( ) ;
return true ;
}
return false ;
}
if ( HistoryItem * item = App : : histItemById ( channelId ( ) , switchId ) ) {
HistoryItemType itemType = item - > type ( ) ;
if ( itemType = = HistoryItemGroup | | itemType = = HistoryItemCollapse ) {
2015-11-02 17:33:57 -05:00
if ( isMegagroup ( ) ) return true ;
2015-09-19 12:13:21 +03:00
if ( itemType = = HistoryItemGroup & & ! _onlyImportant ) return true ;
if ( itemType = = HistoryItemCollapse & & _onlyImportant ) return true ;
2015-09-20 11:55:41 +03:00
bool willNeedCollapse = ( itemType = = HistoryItemGroup ) ;
2015-09-19 12:13:21 +03:00
HistoryItem * prev = findPrevItem ( item ) ;
if ( prev ) {
fixInScrollMsgId = prev - > id ;
fixInScrollMsgTop = prev - > y + prev - > block ( ) - > y + prev - > height ( ) - height ;
if ( _otherList . indexOf ( prev ) > = 0 ) {
switchMode ( ) ;
insertCollapseItem ( fixInScrollMsgId ) ;
return true ;
}
return false ;
}
if ( itemType = = HistoryItemGroup ) {
fixInScrollMsgId = qMax ( static_cast < HistoryGroup * > ( item ) - > minId ( ) , 1 ) ;
fixInScrollMsgTop = item - > y + item - > block ( ) - > y - height ;
if ( oldLoaded & & _otherOldLoaded ) {
switchMode ( ) ;
insertCollapseItem ( fixInScrollMsgId ) ;
return true ;
}
} else if ( itemType = = HistoryItemCollapse ) {
fixInScrollMsgId = qMax ( static_cast < HistoryCollapse * > ( item ) - > wasMinId ( ) , 1 ) ;
fixInScrollMsgTop = item - > y + item - > block ( ) - > y - height ;
if ( oldLoaded & & _otherOldLoaded ) {
switchMode ( ) ;
return true ;
}
}
return false ;
}
2015-09-20 11:55:41 +03:00
if ( item - > history ( ) = = this ) {
if ( _onlyImportant & & ! item - > isImportant ( ) ) {
if ( _otherList . indexOf ( item ) > = 0 ) {
switchMode ( ) ;
return true ;
}
return false ;
} else if ( ! item - > detached ( ) ) {
return true ;
}
}
} else if ( switchId < 0 ) {
LOG ( ( " App Error: isSwitchReadyFor() switchId not found! " ) ) ;
switchMode ( ) ;
return true ;
2015-09-19 12:13:21 +03:00
}
2015-09-20 11:55:41 +03:00
return false ;
2015-09-19 12:13:21 +03:00
}
void ChannelHistory : : getSwitchReadyFor ( MsgId switchId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) {
if ( ! isSwitchReadyFor ( switchId , fixInScrollMsgId , fixInScrollMsgTop ) ) {
2015-09-20 11:55:41 +03:00
if ( switchId > 0 ) {
if ( HistoryItem * item = App : : histItemById ( channelId ( ) , switchId ) ) {
if ( _onlyImportant & & ! item - > isImportant ( ) ) {
_otherList . clear ( ) ;
_otherNewLoaded = _otherOldLoaded = false ;
2015-09-19 12:13:21 +03:00
2015-09-20 11:55:41 +03:00
switchMode ( ) ;
} else {
clear ( true ) ;
newLoaded = oldLoaded = false ;
lastWidth = 0 ;
}
} else {
clear ( true ) ;
newLoaded = oldLoaded = false ;
lastWidth = 0 ;
}
} else {
_otherList . clear ( ) ;
_otherNewLoaded = _otherOldLoaded = false ;
switchMode ( ) ;
}
2015-09-19 12:13:21 +03:00
}
}
void ChannelHistory : : insertCollapseItem ( MsgId wasMinId ) {
2015-11-02 17:33:57 -05:00
if ( _onlyImportant | | isMegagroup ( ) ) return ;
2015-09-19 12:13:21 +03:00
bool insertAfter = false ;
2015-09-21 23:57:42 +03:00
for ( int32 blockIndex = 1 , blocksCount = blocks . size ( ) ; blockIndex < blocksCount ; + + blockIndex ) { // skip first date block
2015-09-19 12:13:21 +03:00
HistoryBlock * block = blocks . at ( blockIndex ) ;
for ( int32 itemIndex = 0 , itemsCount = block - > items . size ( ) ; itemIndex < itemsCount ; + + itemIndex ) {
HistoryItem * item = block - > items . at ( itemIndex ) ;
if ( insertAfter | | item - > id > wasMinId | | ( item - > id = = wasMinId & & ! item - > isImportant ( ) ) ) {
2015-09-21 23:57:42 +03:00
_collapseMessage = new HistoryCollapse ( this , block , wasMinId , item - > date ) ;
2015-12-23 15:55:32 +03:00
if ( ! addNewInTheMiddle ( regItem ( _collapseMessage ) , blockIndex , itemIndex ) ) {
2015-09-21 23:57:42 +03:00
_collapseMessage = 0 ;
2015-09-19 12:13:21 +03:00
}
return ;
} else if ( item - > id = = wasMinId & & item - > isImportant ( ) ) {
insertAfter = true ;
}
}
}
}
2015-09-21 23:57:42 +03:00
void ChannelHistory : : getRangeDifference ( ) {
MsgId fromId = 0 , toId = 0 ;
for ( int32 blockIndex = 0 , blocksCount = blocks . size ( ) ; blockIndex < blocksCount ; + + blockIndex ) {
HistoryBlock * block = blocks . at ( blockIndex ) ;
for ( int32 itemIndex = 0 , itemsCount = block - > items . size ( ) ; itemIndex < itemsCount ; + + itemIndex ) {
HistoryItem * item = block - > items . at ( itemIndex ) ;
if ( item - > type ( ) = = HistoryItemMsg & & item - > id > 0 ) {
fromId = item - > id ;
break ;
} else if ( item - > type ( ) = = HistoryItemGroup ) {
fromId = static_cast < HistoryGroup * > ( item ) - > minId ( ) + 1 ;
break ;
}
}
if ( fromId ) break ;
}
if ( ! fromId ) return ;
for ( int32 blockIndex = blocks . size ( ) ; blockIndex > 0 ; ) {
HistoryBlock * block = blocks . at ( - - blockIndex ) ;
for ( int32 itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
HistoryItem * item = block - > items . at ( - - itemIndex ) ;
if ( item - > type ( ) = = HistoryItemMsg & & item - > id > 0 ) {
toId = item - > id ;
break ;
} else if ( item - > type ( ) = = HistoryItemGroup ) {
toId = static_cast < HistoryGroup * > ( item ) - > maxId ( ) - 1 ;
break ;
}
}
if ( toId ) break ;
}
if ( fromId > 0 & & peer - > asChannel ( ) - > pts ( ) > 0 ) {
if ( _rangeDifferenceRequestId ) {
MTP : : cancel ( _rangeDifferenceRequestId ) ;
}
_rangeDifferenceFromId = fromId ;
_rangeDifferenceToId = toId ;
MTP_LOG ( 0 , ( " getChannelDifference { good - after channelDifferenceTooLong was received, validating history part }%1 " ) . arg ( cTestMode ( ) ? " TESTMODE " : " " ) ) ;
getRangeDifferenceNext ( peer - > asChannel ( ) - > pts ( ) ) ;
}
}
void ChannelHistory : : getRangeDifferenceNext ( int32 pts ) {
if ( ! App : : main ( ) | | _rangeDifferenceToId < _rangeDifferenceFromId ) return ;
int32 limit = _rangeDifferenceToId + 1 - _rangeDifferenceFromId ;
_rangeDifferenceRequestId = MTP : : send ( MTPupdates_GetChannelDifference ( peer - > asChannel ( ) - > inputChannel , MTP_channelMessagesFilter ( MTP_int ( 0 ) , MTP_vector < MTPMessageRange > ( 1 , MTP_messageRange ( MTP_int ( _rangeDifferenceFromId ) , MTP_int ( _rangeDifferenceToId ) ) ) ) , MTP_int ( pts ) , MTP_int ( limit ) ) , App : : main ( ) - > rpcDone ( & MainWidget : : gotRangeDifference , peer - > asChannel ( ) ) ) ;
}
void ChannelHistory : : addNewGroup ( const MTPMessageGroup & group ) {
if ( group . type ( ) ! = mtpc_messageGroup ) return ;
const MTPDmessageGroup & d ( group . c_messageGroup ( ) ) ;
if ( onlyImportant ( ) ) {
_otherNewLoaded = false ;
} else if ( _otherNewLoaded ) {
if ( _otherList . isEmpty ( ) | | _otherList . back ( ) - > type ( ) ! = HistoryItemGroup ) {
_otherList . push_back ( regItem ( new HistoryGroup ( this , 0 , d , _otherList . isEmpty ( ) ? date ( d . vdate ) : _otherList . back ( ) - > date ) ) ) ;
} else {
static_cast < HistoryGroup * > ( _otherList . back ( ) ) - > uniteWith ( d . vmin_id . v , d . vmax_id . v , d . vcount . v ) ;
}
}
if ( onlyImportant ( ) ) {
if ( newLoaded ) {
HistoryItem * prev = blocks . isEmpty ( ) ? 0 : blocks . back ( ) - > items . back ( ) ;
HistoryBlock * to = 0 ;
bool newBlock = blocks . isEmpty ( ) ;
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
to - > y = height ;
} else {
to = blocks . back ( ) ;
height - = to - > height ;
}
prev = addMessageGroupAfterPrevToBlock ( d , prev , to ) ;
height + = to - > height ;
if ( newBlock ) {
HistoryBlock * dateBlock = new HistoryBlock ( this ) ;
HistoryItem * dayItem = createDayServiceMsg ( this , dateBlock , blocks . front ( ) - > items . front ( ) - > date ) ;
dateBlock - > items . push_back ( dayItem ) ;
int32 dh = dayItem - > resize ( width ) ;
dateBlock - > height = dh ;
for ( Blocks : : iterator i = blocks . begin ( ) , e = blocks . end ( ) ; i ! = e ; + + i ) {
( * i ) - > y + = dh ;
}
2015-12-25 00:27:45 +03:00
blocks . push_front ( dateBlock ) ; // date block CHECK
2015-09-21 23:57:42 +03:00
height + = dh ;
}
}
} else {
setNotLoadedAtBottom ( ) ;
}
}
HistoryJoined * ChannelHistory : : insertJoinedMessage ( bool unread ) {
2015-11-20 21:24:44 +03:00
if ( _joinedMessage | | ! peer - > asChannel ( ) - > amIn ( ) | | ( peer - > isMegagroup ( ) & & peer - > asChannel ( ) - > mgInfo - > joinedMessageFound ) ) {
2015-11-09 12:51:22 +03:00
return _joinedMessage ;
}
2015-09-21 23:57:42 +03:00
UserData * inviter = ( peer - > asChannel ( ) - > inviter > 0 ) ? App : : userLoaded ( peer - > asChannel ( ) - > inviter ) : 0 ;
if ( ! inviter ) return 0 ;
2015-09-23 20:43:08 +03:00
if ( peerToUser ( inviter - > id ) = = MTP : : authedId ( ) ) unread = false ;
2015-10-28 20:16:52 -04:00
int32 flags = ( unread ? MTPDmessage : : flag_unread : 0 ) ;
2015-09-21 23:57:42 +03:00
QDateTime inviteDate = peer - > asChannel ( ) - > inviteDate ;
if ( unread ) _maxReadMessageDate = inviteDate ;
if ( isEmpty ( ) ) {
HistoryBlock * to = new HistoryBlock ( this ) ;
bool newBlock = true ;
_joinedMessage = new HistoryJoined ( this , to , inviteDate , inviter , flags ) ;
if ( ! addNewItem ( to , newBlock , regItem ( _joinedMessage ) , unread ) ) {
_joinedMessage = 0 ;
}
return _joinedMessage ;
}
HistoryItem * lastSeenDateItem = 0 ;
for ( int32 blockIndex = blocks . size ( ) ; blockIndex > 1 ; ) {
HistoryBlock * block = blocks . at ( - - blockIndex ) ;
for ( int32 itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
HistoryItem * item = block - > items . at ( - - itemIndex ) ;
HistoryItemType type = item - > type ( ) ;
if ( type = = HistoryItemMsg | | type = = HistoryItemGroup ) {
if ( item - > date < = inviteDate ) {
2015-11-20 21:24:44 +03:00
if ( peer - > isMegagroup ( ) & & peer - > migrateFrom ( ) & & item - > isGroupMigrate ( ) ) {
peer - > asChannel ( ) - > mgInfo - > joinedMessageFound = true ;
return 0 ;
}
2015-09-21 23:57:42 +03:00
+ + itemIndex ;
if ( item - > date . date ( ) ! = inviteDate . date ( ) ) {
HistoryDateMsg * joinedDateItem = new HistoryDateMsg ( this , block , inviteDate . date ( ) ) ;
2015-12-23 15:55:32 +03:00
if ( addNewInTheMiddle ( regItem ( joinedDateItem ) , blockIndex , itemIndex ) ) {
2015-09-21 23:57:42 +03:00
+ + itemIndex ;
}
}
_joinedMessage = new HistoryJoined ( this , block , inviteDate , inviter , flags ) ;
2015-12-23 15:55:32 +03:00
if ( ! addNewInTheMiddle ( regItem ( _joinedMessage ) , blockIndex , itemIndex ) ) {
2015-09-21 23:57:42 +03:00
_joinedMessage = 0 ;
}
if ( lastSeenDateItem & & lastSeenDateItem - > date . date ( ) = = inviteDate . date ( ) ) {
lastSeenDateItem - > destroy ( ) ;
}
2015-09-25 10:47:32 +03:00
if ( lastMsgDate . isNull ( ) | | inviteDate > = lastMsgDate ) {
2015-09-21 23:57:42 +03:00
setLastMessage ( _joinedMessage ) ;
if ( unread ) {
newItemAdded ( _joinedMessage ) ;
}
}
return _joinedMessage ;
} else {
lastSeenDateItem = 0 ;
}
} else if ( type = = HistoryItemDate ) {
lastSeenDateItem = item ;
}
}
}
// adding new item to new block
int32 addToH = 0 , skip = 0 ;
if ( ! blocks . isEmpty ( ) ) { // remove date block
if ( width ) addToH = - blocks . front ( ) - > height ;
delete blocks . front ( ) ;
blocks . pop_front ( ) ;
}
HistoryItem * till = blocks . isEmpty ( ) ? 0 : blocks . front ( ) - > items . front ( ) ;
HistoryBlock * block = new HistoryBlock ( this ) ;
_joinedMessage = new HistoryJoined ( this , block , inviteDate , inviter , flags ) ;
2015-12-23 15:55:32 +03:00
addItemAfterPrevToBlock ( regItem ( _joinedMessage ) , 0 , block ) ;
2015-09-21 23:57:42 +03:00
if ( till & & _joinedMessage & & inviteDate . date ( ) ! = till - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , block , till - > date ) ;
block - > items . push_back ( dayItem ) ;
if ( width ) {
dayItem - > y = block - > height ;
block - > height + = dayItem - > resize ( width ) ;
}
}
if ( ! block - > items . isEmpty ( ) ) {
2015-12-25 00:27:45 +03:00
blocks . push_front ( block ) ; // CHECK
2015-09-21 23:57:42 +03:00
if ( width ) {
addToH + = block - > height ;
+ + skip ;
}
} else {
delete block ;
}
if ( ! blocks . isEmpty ( ) ) {
HistoryBlock * dateBlock = new HistoryBlock ( this ) ;
HistoryItem * dayItem = createDayServiceMsg ( this , dateBlock , blocks . front ( ) - > items . front ( ) - > date ) ;
dateBlock - > items . push_back ( dayItem ) ;
if ( width ) {
int32 dh = dayItem - > resize ( width ) ;
dateBlock - > height = dh ;
if ( skip ) {
blocks . front ( ) - > y + = dh ;
}
addToH + = dh ;
+ + skip ;
}
2015-12-25 00:27:45 +03:00
blocks . push_front ( dateBlock ) ; // date block CHECK
2015-09-21 23:57:42 +03:00
}
if ( width & & addToH ) {
for ( Blocks : : iterator i = blocks . begin ( ) , e = blocks . end ( ) ; i ! = e ; + + i ) {
if ( skip ) {
- - skip ;
} else {
( * i ) - > y + = addToH ;
}
}
height + = addToH ;
}
if ( ! lastMsgDate . isNull ( ) & & inviteDate > = lastMsgDate ) {
setLastMessage ( _joinedMessage ) ;
if ( unread ) {
newItemAdded ( _joinedMessage ) ;
}
}
return _joinedMessage ;
}
2015-09-25 10:47:32 +03:00
void ChannelHistory : : checkJoinedMessage ( bool createUnread ) {
2015-11-20 21:24:44 +03:00
if ( _joinedMessage | | peer - > asChannel ( ) - > inviter < = 0 ) {
2015-11-09 12:51:22 +03:00
return ;
}
2015-09-21 23:57:42 +03:00
if ( isEmpty ( ) ) {
if ( loadedAtTop ( ) & & loadedAtBottom ( ) ) {
2015-09-25 10:47:32 +03:00
if ( insertJoinedMessage ( createUnread ) ) {
2015-11-20 21:24:44 +03:00
if ( ! _joinedMessage - > detached ( ) ) {
setLastMessage ( _joinedMessage ) ;
}
2015-09-21 23:57:42 +03:00
}
return ;
}
}
QDateTime inviteDate = peer - > asChannel ( ) - > inviteDate ;
QDateTime firstDate , lastDate ;
for ( int32 blockIndex = 1 , blocksCount = blocks . size ( ) ; blockIndex < blocksCount ; + + blockIndex ) {
HistoryBlock * block = blocks . at ( blockIndex ) ;
int32 itemIndex = 0 , itemsCount = block - > items . size ( ) ;
for ( ; itemIndex < itemsCount ; + + itemIndex ) {
HistoryItem * item = block - > items . at ( itemIndex ) ;
HistoryItemType type = item - > type ( ) ;
if ( type = = HistoryItemMsg | | type = = HistoryItemGroup ) {
firstDate = item - > date ;
break ;
}
}
if ( itemIndex < itemsCount ) break ;
}
for ( int32 blockIndex = blocks . size ( ) ; blockIndex > 1 ; ) {
HistoryBlock * block = blocks . at ( - - blockIndex ) ;
int32 itemIndex = block - > items . size ( ) ;
for ( ; itemIndex > 0 ; ) {
HistoryItem * item = block - > items . at ( - - itemIndex ) ;
HistoryItemType type = item - > type ( ) ;
if ( type = = HistoryItemMsg | | type = = HistoryItemGroup ) {
lastDate = item - > date ;
+ + itemIndex ;
break ;
}
}
if ( itemIndex ) break ;
}
if ( ! firstDate . isNull ( ) & & ! lastDate . isNull ( ) & & ( firstDate < = inviteDate | | loadedAtTop ( ) ) & & ( lastDate > inviteDate | | loadedAtBottom ( ) ) ) {
2015-09-25 10:47:32 +03:00
bool willBeLastMsg = ( inviteDate > = lastDate ) ;
if ( insertJoinedMessage ( createUnread & & willBeLastMsg ) & & willBeLastMsg ) {
2015-11-20 21:24:44 +03:00
if ( ! _joinedMessage - > detached ( ) ) {
setLastMessage ( _joinedMessage ) ;
}
2015-09-21 23:57:42 +03:00
}
}
}
void ChannelHistory : : checkMaxReadMessageDate ( ) {
if ( _maxReadMessageDate . isValid ( ) ) return ;
for ( int32 blockIndex = blocks . size ( ) ; blockIndex > 0 ; ) {
HistoryBlock * block = blocks . at ( - - blockIndex ) ;
for ( int32 itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
HistoryItem * item = block - > items . at ( - - itemIndex ) ;
2015-11-02 17:33:57 -05:00
if ( ( item - > isImportant ( ) | | isMegagroup ( ) ) & & ! item - > unread ( ) ) {
2015-09-21 23:57:42 +03:00
_maxReadMessageDate = item - > date ;
2015-11-20 21:24:44 +03:00
if ( item - > isGroupMigrate ( ) & & isMegagroup ( ) & & peer - > migrateFrom ( ) ) {
_maxReadMessageDate = date ( MTP_int ( peer - > asChannel ( ) - > date + 1 ) ) ; // no report spam panel
}
2015-09-21 23:57:42 +03:00
return ;
}
}
}
2015-11-20 21:24:44 +03:00
if ( loadedAtTop ( ) & & ( ! isMegagroup ( ) | | ! isEmpty ( ) ) ) {
2015-09-21 23:57:42 +03:00
_maxReadMessageDate = date ( MTP_int ( peer - > asChannel ( ) - > date ) ) ;
}
}
const QDateTime & ChannelHistory : : maxReadMessageDate ( ) {
return _maxReadMessageDate ;
}
2015-09-20 11:55:41 +03:00
HistoryItem * ChannelHistory : : addNewChannelMessage ( const MTPMessage & msg , NewMessageType type ) {
if ( type = = NewMessageExisting ) return addToHistory ( msg ) ;
HistoryItem * result = addNewToBlocks ( msg , type ) ;
if ( result ) addNewToOther ( result , type ) ;
return result ;
}
HistoryItem * ChannelHistory : : addNewToBlocks ( const MTPMessage & msg , NewMessageType type ) {
2015-11-02 17:33:57 -05:00
bool isImportantFlags = isImportantChannelMessage ( idFromMessage ( msg ) , flagsFromMessage ( msg ) ) ;
bool isImportant = ( isChannel ( ) & & ! isMegagroup ( ) ) ? isImportantFlags : true ;
2015-09-20 11:55:41 +03:00
if ( ! loadedAtBottom ( ) ) {
HistoryItem * item = addToHistory ( msg ) ;
if ( item & & isImportant ) {
setLastMessage ( item ) ;
if ( type = = NewMessageUnread ) {
2015-10-27 20:29:39 -04:00
newItemAdded ( item ) ;
2015-09-20 11:55:41 +03:00
}
}
return item ;
}
if ( ! isImportant & & onlyImportant ( ) ) {
HistoryItem * item = addToHistory ( msg ) , * prev = isEmpty ( ) ? 0 : blocks . back ( ) - > items . back ( ) ;
HistoryItem * group = addMessageGroupAfterPrev ( item , prev ) ;
if ( group & & group ! = prev ) {
height + = group - > height ( ) ;
}
return item ;
}
2015-11-02 17:33:57 -05:00
if ( ! isImportantFlags & & ! onlyImportant ( ) & & ! isEmpty ( ) & & type = = NewMessageLast ) {
2015-09-20 11:55:41 +03:00
clear ( true ) ;
}
HistoryBlock * to = 0 ;
bool newBlock = blocks . isEmpty ( ) ;
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
to = blocks . back ( ) ;
}
2015-12-28 00:37:48 +03:00
HistoryItem * item = createItem ( ( type = = NewMessageLast ) ? 0 : to , msg , ( type = = NewMessageUnread ) ) ;
if ( type = = NewMessageLast ) {
if ( ! item - > detached ( ) ) {
return item ;
}
item - > attach ( to ) ;
}
return addNewItem ( to , newBlock , item , ( type = = NewMessageUnread ) ) ;
2015-09-20 11:55:41 +03:00
}
void ChannelHistory : : addNewToOther ( HistoryItem * item , NewMessageType type ) {
2015-11-02 17:33:57 -05:00
if ( ! _otherNewLoaded | | isMegagroup ( ) ) return ;
2015-09-20 11:55:41 +03:00
if ( ! item - > isImportant ( ) ) {
if ( onlyImportant ( ) ) {
if ( type = = NewMessageLast ) {
_otherList . clear ( ) ;
_otherOldLoaded = false ;
}
} else {
if ( _otherList . isEmpty ( ) | | _otherList . back ( ) - > type ( ) ! = HistoryItemGroup ) {
_otherList . push_back ( regItem ( new HistoryGroup ( this , 0 , item , _otherList . isEmpty ( ) ? item - > date : _otherList . back ( ) - > date ) ) ) ;
} else {
static_cast < HistoryGroup * > ( _otherList . back ( ) ) - > uniteWith ( item ) ;
}
return ;
}
}
_otherList . push_back ( item ) ;
}
2015-09-19 12:13:21 +03:00
void ChannelHistory : : switchMode ( ) {
2015-11-02 17:33:57 -05:00
if ( isMegagroup ( ) & & ! _onlyImportant ) return ;
2015-09-19 12:13:21 +03:00
OtherList savedList ;
2015-09-20 11:55:41 +03:00
if ( ! blocks . isEmpty ( ) ) {
savedList . reserve ( ( ( blocks . size ( ) - 2 ) * MessagesPerPage + blocks . back ( ) - > items . size ( ) ) * ( onlyImportant ( ) ? 2 : 1 ) ) ;
for ( Blocks : : const_iterator i = blocks . cbegin ( ) , e = blocks . cend ( ) ; i ! = e ; + + i ) {
HistoryBlock * block = * i ;
for ( HistoryBlock : : Items : : const_iterator j = block - > items . cbegin ( ) , end = block - > items . cend ( ) ; j ! = end ; + + j ) {
HistoryItem * item = * j ;
HistoryItemType itemType = item - > type ( ) ;
if ( itemType = = HistoryItemMsg | | itemType = = HistoryItemGroup ) {
savedList . push_back ( item ) ;
}
2015-09-19 12:13:21 +03:00
}
}
}
bool savedNewLoaded = newLoaded , savedOldLoaded = oldLoaded ;
clear ( true ) ;
newLoaded = _otherNewLoaded ;
oldLoaded = _otherOldLoaded ;
if ( int32 count = _otherList . size ( ) ) {
blocks . reserve ( qCeil ( count / float64 ( MessagesPerPage ) ) + 1 ) ;
createInitialDateBlock ( _otherList . front ( ) - > date ) ;
HistoryItem * prev = 0 ;
for ( int32 i = 0 ; i < count ; ) {
HistoryBlock * block = new HistoryBlock ( this ) ;
int32 willAddToBlock = qMin ( int32 ( MessagesPerPage ) , count - i ) ;
block - > items . reserve ( willAddToBlock ) ;
for ( int32 till = i + willAddToBlock ; i < till ; + + i ) {
HistoryItem * item = _otherList . at ( i ) ;
item - > attach ( block ) ;
prev = addItemAfterPrevToBlock ( item , prev , block ) ;
}
2015-12-25 00:27:45 +03:00
blocks . push_back ( block ) ; // CHECK
2015-12-23 17:18:42 +03:00
if ( width ) {
block - > y = height ;
height + = block - > height ;
}
2015-09-19 12:13:21 +03:00
}
}
_otherList = savedList ;
_otherNewLoaded = savedNewLoaded ;
_otherOldLoaded = savedOldLoaded ;
_onlyImportant = ! _onlyImportant ;
lastWidth = 0 ;
2015-09-21 23:57:42 +03:00
checkJoinedMessage ( ) ;
}
void ChannelHistory : : cleared ( ) {
_collapseMessage = 0 ;
_joinedMessage = 0 ;
2015-09-19 12:13:21 +03:00
}
HistoryGroup * ChannelHistory : : findGroup ( MsgId msgId ) const { // find message group using binary search
if ( ! _onlyImportant ) return findGroupInOther ( msgId ) ;
HistoryBlock * block = findGroupBlock ( msgId ) ;
if ( ! block ) return 0 ;
int32 itemIndex = 0 ;
if ( block - > items . size ( ) > 1 ) for ( int32 minItem = 0 , maxItem = block - > items . size ( ) ; ; ) {
for ( int32 startCheckItem = ( minItem + maxItem ) / 2 , checkItem = startCheckItem ; ; ) {
HistoryItem * item = block - > items . at ( checkItem ) ; // out msgs could be a mess in monotonic ids
if ( ( item - > id > 0 & & ! item - > out ( ) ) | | item - > type ( ) = = HistoryItemGroup ) {
MsgId threshold = ( item - > id > 0 ) ? item - > id : static_cast < HistoryGroup * > ( item ) - > minId ( ) ;
if ( threshold > msgId ) {
maxItem = startCheckItem ;
} else {
minItem = checkItem ;
}
break ;
}
if ( + + checkItem = = maxItem ) {
maxItem = startCheckItem ;
break ;
}
}
if ( minItem + 1 = = maxItem ) {
itemIndex = minItem ;
break ;
}
}
HistoryItem * item = block - > items . at ( itemIndex ) ;
if ( item - > type ( ) ! = HistoryItemGroup ) return 0 ;
HistoryGroup * result = static_cast < HistoryGroup * > ( item ) ;
return ( result - > minId ( ) < msgId & & result - > maxId ( ) > msgId ) ? result : 0 ;
}
HistoryBlock * ChannelHistory : : findGroupBlock ( MsgId msgId ) const { // find block with message group using binary search
if ( isEmpty ( ) ) return 0 ;
int32 blockIndex = 0 ;
if ( blocks . size ( ) > 1 ) for ( int32 minBlock = 0 , maxBlock = blocks . size ( ) ; ; ) {
for ( int32 startCheckBlock = ( minBlock + maxBlock ) / 2 , checkBlock = startCheckBlock ; ; ) {
HistoryBlock * block = blocks . at ( checkBlock ) ;
HistoryBlock : : Items : : const_iterator i = block - > items . cbegin ( ) , e = block - > items . cend ( ) ;
for ( ; i ! = e ; + + i ) { // out msgs could be a mess in monotonic ids
if ( ( ( * i ) - > id > 0 & & ! ( * i ) - > out ( ) ) | | ( * i ) - > type ( ) = = HistoryItemGroup ) {
MsgId threshold = ( ( * i ) - > id > 0 ) ? ( * i ) - > id : static_cast < HistoryGroup * > ( * i ) - > minId ( ) ;
if ( threshold > msgId ) {
maxBlock = startCheckBlock ;
} else {
minBlock = checkBlock ;
}
break ;
}
}
if ( i ! = e ) {
break ;
}
if ( + + checkBlock = = maxBlock ) {
maxBlock = startCheckBlock ;
break ;
}
}
if ( minBlock + 1 = = maxBlock ) {
blockIndex = minBlock ;
break ;
}
}
return blocks . at ( blockIndex ) ;
}
HistoryGroup * ChannelHistory : : findGroupInOther ( MsgId msgId ) const { // find message group using binary search in _otherList
if ( _otherList . isEmpty ( ) ) return 0 ;
int32 otherIndex = 0 ;
if ( _otherList . size ( ) > 1 ) for ( int32 minOther = 0 , maxOther = _otherList . size ( ) ; ; ) {
for ( int32 startCheckOther = ( minOther + maxOther ) / 2 , checkOther = startCheckOther ; ; ) {
HistoryItem * item = _otherList . at ( checkOther ) ; // out msgs could be a mess in monotonic ids
if ( ( item - > id > 0 & & ! item - > out ( ) ) | | item - > type ( ) = = HistoryItemGroup ) {
MsgId threshold = ( item - > id > 0 ) ? item - > id : static_cast < HistoryGroup * > ( item ) - > minId ( ) ;
if ( threshold > msgId ) {
maxOther = startCheckOther ;
} else {
minOther = checkOther ;
}
break ;
}
if ( + + checkOther = = maxOther ) {
maxOther = startCheckOther ;
break ;
}
}
if ( minOther + 1 = = maxOther ) {
otherIndex = minOther ;
break ;
}
}
HistoryItem * item = _otherList . at ( otherIndex ) ;
if ( item - > type ( ) ! = HistoryItemGroup ) return 0 ;
HistoryGroup * result = static_cast < HistoryGroup * > ( item ) ;
return ( result - > minId ( ) < msgId & & result - > maxId ( ) > msgId ) ? result : 0 ;
}
HistoryItem * ChannelHistory : : findPrevItem ( HistoryItem * item ) const {
if ( item - > detached ( ) ) return 0 ;
int32 itemIndex = item - > block ( ) - > items . indexOf ( item ) ;
int32 blockIndex = blocks . indexOf ( item - > block ( ) ) ;
if ( itemIndex < 0 | | blockIndex < 0 ) return 0 ;
for ( + + blockIndex , + + itemIndex ; blockIndex > 0 ; ) {
- - blockIndex ;
HistoryBlock * block = blocks . at ( blockIndex ) ;
if ( ! itemIndex ) itemIndex = block - > items . size ( ) ;
for ( ; itemIndex > 0 ; ) {
- - itemIndex ;
if ( block - > items . at ( itemIndex ) - > type ( ) = = HistoryItemMsg ) {
return block - > items . at ( itemIndex ) ;
}
}
}
return 0 ;
}
void ChannelHistory : : messageDetached ( HistoryItem * msg ) {
2015-09-21 23:57:42 +03:00
if ( _collapseMessage = = msg ) {
_collapseMessage = 0 ;
} else if ( _joinedMessage = = msg ) {
_joinedMessage = 0 ;
2015-09-19 12:13:21 +03:00
}
}
void ChannelHistory : : messageDeleted ( HistoryItem * msg ) {
int32 otherIndex = _otherList . indexOf ( msg ) ;
if ( otherIndex > = 0 ) _otherList . removeAt ( otherIndex ) ;
if ( msg - > isImportant ( ) ) { // unite message groups around this important message in _otherList
if ( ! _onlyImportant & & otherIndex > 0 & & otherIndex < _otherList . size ( ) ) {
if ( HistoryGroup * groupPrev = ( _otherList [ otherIndex - 1 ] - > type ( ) = = HistoryItemGroup ) ? static_cast < HistoryGroup * > ( _otherList [ otherIndex - 1 ] ) : 0 ) {
if ( HistoryGroup * groupNext = ( _otherList [ otherIndex ] - > type ( ) = = HistoryItemGroup ) ? static_cast < HistoryGroup * > ( _otherList [ otherIndex ] ) : 0 ) {
groupPrev - > uniteWith ( groupNext ) ;
groupNext - > destroy ( ) ;
}
}
}
} else {
messageWithIdDeleted ( msg - > id ) ;
}
}
void ChannelHistory : : messageWithIdDeleted ( MsgId msgId ) {
if ( HistoryGroup * group = findGroup ( msgId ) ) {
if ( ! group - > decrementCount ( ) ) {
group - > destroy ( ) ;
}
}
}
2014-05-30 12:53:19 +04:00
bool DialogsList : : del ( const PeerId & peerId , DialogRow * replacedBy ) {
RowByPeer : : iterator i = rowByPeer . find ( peerId ) ;
if ( i = = rowByPeer . cend ( ) ) return false ;
DialogRow * row = i . value ( ) ;
emit App : : main ( ) - > dialogRowReplaced ( row , replacedBy ) ;
if ( row = = current ) {
current = row - > next ;
}
for ( DialogRow * change = row - > next ; change ! = end ; change = change - > next ) {
change - > pos - - ;
}
end - > pos - - ;
remove ( row ) ;
delete row ;
- - count ;
rowByPeer . erase ( i ) ;
return true ;
}
void DialogsIndexed : : peerNameChanged ( PeerData * peer , const PeerData : : Names & oldNames , const PeerData : : NameFirstChars & oldChars ) {
2015-06-15 20:19:24 +03:00
if ( sortMode = = DialogsSortByName ) {
2014-05-30 12:53:19 +04:00
DialogRow * mainRow = list . adjustByName ( peer ) ;
if ( ! mainRow ) return ;
History * history = mainRow - > history ;
PeerData : : NameFirstChars toRemove = oldChars , toAdd ;
for ( PeerData : : NameFirstChars : : const_iterator i = peer - > chars . cbegin ( ) , e = peer - > chars . cend ( ) ; i ! = e ; + + i ) {
PeerData : : NameFirstChars : : iterator j = toRemove . find ( * i ) ;
if ( j = = toRemove . cend ( ) ) {
toAdd . insert ( * i ) ;
} else {
toRemove . erase ( j ) ;
DialogsIndex : : iterator k = index . find ( * i ) ;
if ( k ! = index . cend ( ) ) {
k . value ( ) - > adjustByName ( peer ) ;
}
}
}
for ( PeerData : : NameFirstChars : : const_iterator i = toRemove . cbegin ( ) , e = toRemove . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j ! = index . cend ( ) ) {
j . value ( ) - > del ( peer - > id , mainRow ) ;
}
}
if ( ! toAdd . isEmpty ( ) ) {
for ( PeerData : : NameFirstChars : : const_iterator i = toAdd . cbegin ( ) , e = toAdd . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j = = index . cend ( ) ) {
2015-06-15 20:19:24 +03:00
j = index . insert ( * i , new DialogsList ( sortMode ) ) ;
2014-05-30 12:53:19 +04:00
}
j . value ( ) - > addByName ( history ) ;
}
}
} else {
DialogsList : : RowByPeer : : const_iterator i = list . rowByPeer . find ( peer - > id ) ;
if ( i = = list . rowByPeer . cend ( ) ) return ;
DialogRow * mainRow = i . value ( ) ;
History * history = mainRow - > history ;
PeerData : : NameFirstChars toRemove = oldChars , toAdd ;
for ( PeerData : : NameFirstChars : : const_iterator i = peer - > chars . cbegin ( ) , e = peer - > chars . cend ( ) ; i ! = e ; + + i ) {
PeerData : : NameFirstChars : : iterator j = toRemove . find ( * i ) ;
if ( j = = toRemove . cend ( ) ) {
toAdd . insert ( * i ) ;
} else {
toRemove . erase ( j ) ;
}
}
for ( PeerData : : NameFirstChars : : const_iterator i = toRemove . cbegin ( ) , e = toRemove . cend ( ) ; i ! = e ; + + i ) {
2015-06-15 20:19:24 +03:00
if ( sortMode = = DialogsSortByDate ) history - > dialogs . remove ( * i ) ;
2014-05-30 12:53:19 +04:00
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j ! = index . cend ( ) ) {
j . value ( ) - > del ( peer - > id , mainRow ) ;
}
}
for ( PeerData : : NameFirstChars : : const_iterator i = toAdd . cbegin ( ) , e = toAdd . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j = = index . cend ( ) ) {
2015-06-15 20:19:24 +03:00
j = index . insert ( * i , new DialogsList ( sortMode ) ) ;
}
if ( sortMode = = DialogsSortByDate ) {
2015-09-06 13:17:09 +03:00
history - > dialogs . insert ( * i , j . value ( ) - > addToEnd ( history ) ) ;
2015-06-15 20:19:24 +03:00
} else {
j . value ( ) - > addToEnd ( history ) ;
2014-05-30 12:53:19 +04:00
}
}
}
}
void DialogsIndexed : : clear ( ) {
for ( DialogsIndex : : iterator i = index . begin ( ) , e = index . end ( ) ; i ! = e ; + + i ) {
delete i . value ( ) ;
}
index . clear ( ) ;
list . clear ( ) ;
}
2015-09-19 12:13:21 +03:00
History * Histories : : find ( const PeerId & peerId ) {
Map : : const_iterator i = map . constFind ( peerId ) ;
return ( i = = map . cend ( ) ) ? 0 : i . value ( ) ;
}
History * Histories : : findOrInsert ( const PeerId & peerId , int32 unreadCount , int32 maxInboxRead ) {
Map : : const_iterator i = map . constFind ( peerId ) ;
if ( i = = map . cend ( ) ) {
i = map . insert ( peerId , peerIsChannel ( peerId ) ? static_cast < History * > ( new ChannelHistory ( peerId ) ) : ( new History ( peerId ) ) ) ;
i . value ( ) - > setUnreadCount ( unreadCount , false ) ;
i . value ( ) - > inboxReadBefore = maxInboxRead + 1 ;
}
return i . value ( ) ;
}
2014-05-30 12:53:19 +04:00
void Histories : : clear ( ) {
App : : historyClearMsgs ( ) ;
2015-09-19 12:13:21 +03:00
for ( Map : : const_iterator i = map . cbegin ( ) , e = map . cend ( ) ; i ! = e ; + + i ) {
2014-05-30 12:53:19 +04:00
delete i . value ( ) ;
}
App : : historyClearItems ( ) ;
typing . clear ( ) ;
2015-09-19 12:13:21 +03:00
map . clear ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-08-01 11:33:00 +03:00
void Histories : : regSendAction ( History * history , UserData * user , const MTPSendMessageAction & action ) {
if ( action . type ( ) = = mtpc_sendMessageCancelAction ) {
history - > unregTyping ( user ) ;
return ;
}
2014-12-12 19:27:03 +03:00
uint64 ms = getms ( true ) ;
2015-08-01 11:33:00 +03:00
switch ( action . type ( ) ) {
case mtpc_sendMessageTypingAction : history - > typing [ user ] = ms + 6000 ; break ;
case mtpc_sendMessageRecordVideoAction : history - > sendActions . insert ( user , SendAction ( SendActionRecordVideo , ms + 6000 ) ) ; break ;
case mtpc_sendMessageUploadVideoAction : history - > sendActions . insert ( user , SendAction ( SendActionUploadVideo , ms + 6000 , action . c_sendMessageUploadVideoAction ( ) . vprogress . v ) ) ; break ;
case mtpc_sendMessageRecordAudioAction : history - > sendActions . insert ( user , SendAction ( SendActionRecordAudio , ms + 6000 ) ) ; break ;
case mtpc_sendMessageUploadAudioAction : history - > sendActions . insert ( user , SendAction ( SendActionUploadAudio , ms + 6000 , action . c_sendMessageUploadAudioAction ( ) . vprogress . v ) ) ; break ;
case mtpc_sendMessageUploadPhotoAction : history - > sendActions . insert ( user , SendAction ( SendActionUploadPhoto , ms + 6000 , action . c_sendMessageUploadPhotoAction ( ) . vprogress . v ) ) ; break ;
case mtpc_sendMessageUploadDocumentAction : history - > sendActions . insert ( user , SendAction ( SendActionUploadFile , ms + 6000 , action . c_sendMessageUploadDocumentAction ( ) . vprogress . v ) ) ; break ;
case mtpc_sendMessageGeoLocationAction : history - > sendActions . insert ( user , SendAction ( SendActionChooseLocation , ms + 6000 ) ) ; break ;
case mtpc_sendMessageChooseContactAction : history - > sendActions . insert ( user , SendAction ( SendActionChooseContact , ms + 6000 ) ) ; break ;
default : return ;
}
2014-12-12 19:27:03 +03:00
2015-06-10 15:48:26 +03:00
user - > madeAction ( ) ;
2014-12-12 19:27:03 +03:00
TypingHistories : : const_iterator i = typing . find ( history ) ;
if ( i = = typing . cend ( ) ) {
typing . insert ( history , ms ) ;
history - > typingFrame = 0 ;
}
history - > updateTyping ( ms , history - > typingFrame , true ) ;
2015-12-08 15:33:37 +03:00
_a_typings . start ( ) ;
2014-12-12 19:27:03 +03:00
}
2015-12-08 15:33:37 +03:00
void Histories : : step_typings ( uint64 ms , bool timer ) {
2014-12-12 19:27:03 +03:00
for ( TypingHistories : : iterator i = typing . begin ( ) , e = typing . end ( ) ; i ! = e ; ) {
uint32 typingFrame = ( ms - i . value ( ) ) / 150 ;
2015-10-03 13:09:09 +03:00
i . key ( ) - > updateTyping ( ms , typingFrame ) ;
2015-08-01 11:33:00 +03:00
if ( i . key ( ) - > typing . isEmpty ( ) & & i . key ( ) - > sendActions . isEmpty ( ) ) {
2014-12-12 19:27:03 +03:00
i = typing . erase ( i ) ;
} else {
+ + i ;
}
}
2015-12-08 15:33:37 +03:00
if ( typing . isEmpty ( ) ) {
_a_typings . stop ( ) ;
}
2014-12-12 19:27:03 +03:00
}
2014-12-18 21:40:49 +03:00
void Histories : : remove ( const PeerId & peer ) {
2015-09-19 12:13:21 +03:00
Map : : iterator i = map . find ( peer ) ;
if ( i ! = map . cend ( ) ) {
typing . remove ( i . value ( ) ) ;
delete i . value ( ) ;
map . erase ( i ) ;
2014-12-18 21:40:49 +03:00
}
}
2015-09-21 23:57:42 +03:00
HistoryItem * Histories : : addNewMessage ( const MTPMessage & msg , NewMessageType type ) {
2015-09-20 11:55:41 +03:00
PeerId peer = peerFromMessage ( msg ) ;
2014-05-30 12:53:19 +04:00
if ( ! peer ) return 0 ;
2015-09-20 11:55:41 +03:00
return findOrInsert ( peer , 0 , 0 ) - > addNewMessage ( msg , type ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
2015-12-23 15:55:32 +03:00
HistoryItem * History : : createItem ( HistoryBlock * block , const MTPMessage & msg , bool applyServiceAction ) {
2015-04-30 16:53:36 +03:00
MsgId msgId = 0 ;
switch ( msg . type ( ) ) {
case mtpc_messageEmpty : msgId = msg . c_messageEmpty ( ) . vid . v ; break ;
case mtpc_message : msgId = msg . c_message ( ) . vid . v ; break ;
case mtpc_messageService : msgId = msg . c_messageService ( ) . vid . v ; break ;
}
2015-12-23 15:19:32 +03:00
if ( ! msgId ) return 0 ;
2015-04-30 16:53:36 +03:00
2015-12-23 15:55:32 +03:00
HistoryItem * result = App : : histItemById ( channelId ( ) , msgId ) ;
if ( result ) {
if ( block ) {
2015-12-25 00:27:45 +03:00
if ( ! result - > detached ( ) ) {
result - > detach ( ) ;
2015-12-23 15:55:32 +03:00
}
2015-12-25 00:27:45 +03:00
result - > attach ( block ) ;
2015-05-01 02:05:19 +03:00
}
2015-12-28 00:37:48 +03:00
if ( msg . type ( ) = = mtpc_message ) {
result - > updateMedia ( msg . c_message ( ) . has_media ( ) ? ( & msg . c_message ( ) . vmedia ) : 0 , ( block ? false : true ) ) ;
if ( applyServiceAction ) {
App : : checkSavedGif ( result ) ;
2015-12-23 15:55:32 +03:00
}
2015-04-30 16:53:36 +03:00
}
2015-12-28 00:37:48 +03:00
return result ;
2015-04-30 16:53:36 +03:00
}
2014-05-30 12:53:19 +04:00
switch ( msg . type ( ) ) {
case mtpc_messageEmpty :
result = new HistoryServiceMsg ( this , block , msg . c_messageEmpty ( ) . vid . v , date ( ) , lang ( lng_message_empty ) ) ;
break ;
2015-07-15 14:23:59 +03:00
case mtpc_message : {
const MTPDmessage m ( msg . c_message ( ) ) ;
int badMedia = 0 ; // 1 - unsupported, 2 - empty
2015-08-30 17:57:21 +03:00
if ( m . has_media ( ) ) switch ( m . vmedia . type ( ) ) {
2015-07-21 16:55:23 +02:00
case mtpc_messageMediaEmpty :
case mtpc_messageMediaContact : break ;
2015-07-15 14:23:59 +03:00
case mtpc_messageMediaGeo :
switch ( m . vmedia . c_messageMediaGeo ( ) . vgeo . type ( ) ) {
case mtpc_geoPoint : break ;
case mtpc_geoPointEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaVenue :
switch ( m . vmedia . c_messageMediaVenue ( ) . vgeo . type ( ) ) {
case mtpc_geoPoint : break ;
case mtpc_geoPointEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaPhoto :
switch ( m . vmedia . c_messageMediaPhoto ( ) . vphoto . type ( ) ) {
case mtpc_photo : break ;
case mtpc_photoEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaVideo :
switch ( m . vmedia . c_messageMediaVideo ( ) . vvideo . type ( ) ) {
case mtpc_video : break ;
case mtpc_videoEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaAudio :
switch ( m . vmedia . c_messageMediaAudio ( ) . vaudio . type ( ) ) {
case mtpc_audio : break ;
case mtpc_audioEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaDocument :
switch ( m . vmedia . c_messageMediaDocument ( ) . vdocument . type ( ) ) {
2015-12-28 13:28:00 +03:00
case mtpc_document : break ;
2015-07-15 14:23:59 +03:00
case mtpc_documentEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaWebPage :
switch ( m . vmedia . c_messageMediaWebPage ( ) . vwebpage . type ( ) ) {
case mtpc_webPage :
case mtpc_webPageEmpty :
case mtpc_webPagePending : break ;
2015-12-16 18:31:56 +03:00
case mtpc_webPageExternal : LOG ( ( " API Error: should not get webPageExternal in History::createItem " ) ) ;
2015-07-15 14:23:59 +03:00
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaUnsupported :
default : badMedia = 1 ; break ;
2015-03-13 16:01:25 +03:00
}
2015-07-15 14:23:59 +03:00
if ( badMedia ) {
2015-09-08 20:59:36 +03:00
result = new HistoryServiceMsg ( this , block , m . vid . v , date ( m . vdate ) , lang ( ( badMedia = = 2 ) ? lng_message_empty : lng_media_unsupported ) , m . vflags . v , 0 , m . has_from_id ( ) ? m . vfrom_id . v : 0 ) ;
2015-07-15 14:23:59 +03:00
} else {
2015-09-12 14:59:50 +03:00
if ( ( m . has_fwd_date ( ) & & m . vfwd_date . v > 0 ) | | ( m . has_fwd_from_id ( ) & & peerFromMTP ( m . vfwd_from_id ) ! = 0 ) ) {
2015-07-15 14:23:59 +03:00
result = new HistoryForwarded ( this , block , m ) ;
} else if ( m . has_reply_to_msg_id ( ) & & m . vreply_to_msg_id . v > 0 ) {
result = new HistoryReply ( this , block , m ) ;
} else {
result = new HistoryMessage ( this , block , m ) ;
}
if ( m . has_reply_markup ( ) ) {
2015-09-03 13:48:40 +03:00
App : : feedReplyMarkup ( channelId ( ) , msgId , m . vreply_markup ) ;
2015-07-15 14:23:59 +03:00
}
2015-06-15 20:19:24 +03:00
}
2015-07-15 14:23:59 +03:00
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageService : {
const MTPDmessageService & d ( msg . c_messageService ( ) ) ;
result = new HistoryServiceMsg ( this , block , d ) ;
2015-09-20 11:55:41 +03:00
if ( applyServiceAction ) {
2014-05-30 12:53:19 +04:00
const MTPmessageAction & action ( d . vaction ) ;
switch ( d . vaction . type ( ) ) {
case mtpc_messageActionChatAddUser : {
const MTPDmessageActionChatAddUser & d ( action . c_messageActionChatAddUser ( ) ) ;
2015-11-19 18:56:29 +03:00
if ( peer - > isMegagroup ( ) ) {
const QVector < MTPint > & v ( d . vusers . c_vector ( ) . v ) ;
for ( int32 i = 0 , l = v . size ( ) ; i < l ; + + i ) {
if ( UserData * user = App : : userLoaded ( peerFromUser ( v . at ( i ) ) ) ) {
if ( peer - > asChannel ( ) - > mgInfo - > lastParticipants . indexOf ( user ) < 0 ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipants . push_front ( user ) ;
2015-11-24 13:40:18 +03:00
peer - > asChannel ( ) - > mgInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsAdminsOutdated ;
2015-11-19 18:56:29 +03:00
}
2015-11-20 16:34:37 +03:00
if ( user - > botInfo ) {
peer - > asChannel ( ) - > mgInfo - > bots . insert ( user , true ) ;
if ( peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 & & peer - > asChannel ( ) - > mgInfo - > botStatus < 2 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = 2 ;
}
}
2015-11-19 18:56:29 +03:00
}
}
}
2014-05-30 12:53:19 +04:00
} break ;
2015-04-30 16:53:36 +03:00
case mtpc_messageActionChatJoinedByLink : {
const MTPDmessageActionChatJoinedByLink & d ( action . c_messageActionChatJoinedByLink ( ) ) ;
2015-11-19 18:56:29 +03:00
if ( peer - > isMegagroup ( ) ) {
2015-11-20 16:34:37 +03:00
if ( result - > from ( ) - > isUser ( ) ) {
if ( peer - > asChannel ( ) - > mgInfo - > lastParticipants . indexOf ( result - > from ( ) - > asUser ( ) ) < 0 ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipants . push_front ( result - > from ( ) - > asUser ( ) ) ;
}
if ( result - > from ( ) - > asUser ( ) - > botInfo ) {
peer - > asChannel ( ) - > mgInfo - > bots . insert ( result - > from ( ) - > asUser ( ) , true ) ;
if ( peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 & & peer - > asChannel ( ) - > mgInfo - > botStatus < 2 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = 2 ;
}
}
2015-11-19 18:56:29 +03:00
}
}
2015-04-30 16:53:36 +03:00
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageActionChatDeletePhoto : {
ChatData * chat = peer - > asChat ( ) ;
if ( chat ) chat - > setPhoto ( MTP_chatPhotoEmpty ( ) ) ;
} break ;
case mtpc_messageActionChatDeleteUser : {
const MTPDmessageActionChatDeleteUser & d ( action . c_messageActionChatDeleteUser ( ) ) ;
2015-11-20 16:34:37 +03:00
PeerId uid = peerFromUser ( d . vuser_id ) ;
if ( lastKeyboardFrom = = uid ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-11-24 19:19:18 +03:00
if ( App : : main ( ) ) App : : main ( ) - > updateBotKeyboard ( this ) ;
2015-06-18 20:24:54 +03:00
}
2015-11-20 16:34:37 +03:00
if ( peer - > isMegagroup ( ) ) {
if ( UserData * user = App : : userLoaded ( uid ) ) {
int32 index = peer - > asChannel ( ) - > mgInfo - > lastParticipants . indexOf ( user ) ;
if ( index > = 0 ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipants . removeAt ( index ) ;
}
peer - > asChannel ( ) - > mgInfo - > lastAdmins . remove ( user ) ;
peer - > asChannel ( ) - > mgInfo - > bots . remove ( user ) ;
if ( peer - > asChannel ( ) - > mgInfo - > bots . isEmpty ( ) & & peer - > asChannel ( ) - > mgInfo - > botStatus > 0 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = - 1 ;
}
}
}
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageActionChatEditPhoto : {
const MTPDmessageActionChatEditPhoto & d ( action . c_messageActionChatEditPhoto ( ) ) ;
if ( d . vphoto . type ( ) = = mtpc_photo ) {
const QVector < MTPPhotoSize > & sizes ( d . vphoto . c_photo ( ) . vsizes . c_vector ( ) . v ) ;
if ( ! sizes . isEmpty ( ) ) {
2015-09-03 13:48:40 +03:00
PhotoData * photo = App : : feedPhoto ( d . vphoto . c_photo ( ) ) ;
if ( photo ) photo - > peer = peer ;
const MTPPhotoSize & smallSize ( sizes . front ( ) ) , & bigSize ( sizes . back ( ) ) ;
const MTPFileLocation * smallLoc = 0 , * bigLoc = 0 ;
switch ( smallSize . type ( ) ) {
case mtpc_photoSize : smallLoc = & smallSize . c_photoSize ( ) . vlocation ; break ;
case mtpc_photoCachedSize : smallLoc = & smallSize . c_photoCachedSize ( ) . vlocation ; break ;
}
switch ( bigSize . type ( ) ) {
case mtpc_photoSize : bigLoc = & bigSize . c_photoSize ( ) . vlocation ; break ;
case mtpc_photoCachedSize : bigLoc = & bigSize . c_photoCachedSize ( ) . vlocation ; break ;
}
if ( smallLoc & & bigLoc ) {
if ( peer - > isChat ( ) ) {
peer - > asChat ( ) - > setPhoto ( MTP_chatPhoto ( * smallLoc , * bigLoc ) , photo ? photo - > id : 0 ) ;
} else if ( peer - > isChannel ( ) ) {
peer - > asChannel ( ) - > setPhoto ( MTP_chatPhoto ( * smallLoc , * bigLoc ) , photo ? photo - > id : 0 ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-03 13:48:40 +03:00
peer - > photo - > load ( ) ;
2014-05-30 12:53:19 +04:00
}
}
}
} break ;
case mtpc_messageActionChatEditTitle : {
const MTPDmessageActionChatEditTitle & d ( action . c_messageActionChatEditTitle ( ) ) ;
ChatData * chat = peer - > asChat ( ) ;
2014-11-15 02:23:35 +03:00
if ( chat ) chat - > updateName ( qs ( d . vtitle ) , QString ( ) , QString ( ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
2015-11-06 12:48:49 -05:00
case mtpc_messageActionChatMigrateTo : {
peer - > asChat ( ) - > flags | = MTPDchat : : flag_deactivated ;
//const MTPDmessageActionChatMigrateTo &d(action.c_messageActionChatMigrateTo());
//PeerData *channel = App::peerLoaded(peerFromChannel(d.vchannel_id));
} break ;
case mtpc_messageActionChannelMigrateFrom : {
//const MTPDmessageActionChannelMigrateFrom &d(action.c_messageActionChannelMigrateFrom());
//PeerData *chat = App::peerLoaded(peerFromChat(d.vchat_id));
} break ;
2014-05-30 12:53:19 +04:00
}
}
} break ;
}
2015-12-28 00:37:48 +03:00
if ( applyServiceAction ) {
App : : checkSavedGif ( result ) ;
}
2015-12-23 15:55:32 +03:00
return regItem ( result ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-13 20:27:29 +03:00
HistoryItem * History : : createItemForwarded ( HistoryBlock * block , MsgId id , QDateTime date , int32 from , HistoryMessage * msg ) {
2015-12-23 15:55:32 +03:00
return regItem ( new HistoryForwarded ( this , block , id , date , from , msg ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-28 13:28:00 +03:00
HistoryItem * History : : createItemDocument ( HistoryBlock * block , MsgId id , int32 flags , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) {
2014-05-30 12:53:19 +04:00
HistoryItem * result = 0 ;
2015-03-19 12:18:19 +03:00
if ( flags & MTPDmessage : : flag_reply_to_msg_id & & replyTo > 0 ) {
2015-12-28 13:28:00 +03:00
result = new HistoryReply ( this , block , id , flags , replyTo , date , from , doc , caption ) ;
2015-03-19 12:18:19 +03:00
} else {
2015-12-28 13:28:00 +03:00
result = new HistoryMessage ( this , block , id , flags , date , from , doc , caption ) ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
return regItem ( result ) ;
}
2015-01-02 17:55:24 +03:00
2015-09-19 12:13:21 +03:00
HistoryItem * History : : addNewService ( MsgId msgId , QDateTime date , const QString & text , int32 flags , HistoryMedia * media , bool newMsg ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
2015-09-19 12:13:21 +03:00
bool newBlock = blocks . isEmpty ( ) ;
2014-05-30 12:53:19 +04:00
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
2015-09-19 12:13:21 +03:00
to = blocks . back ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-23 15:55:32 +03:00
HistoryItem * result = new HistoryServiceMsg ( this , to , msgId , date , text , flags , media ) ;
return addNewItem ( to , newBlock , regItem ( result ) , newMsg ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-21 23:57:42 +03:00
HistoryItem * History : : addNewMessage ( const MTPMessage & msg , NewMessageType type ) {
2015-09-20 11:55:41 +03:00
if ( isChannel ( ) ) return asChannelHistory ( ) - > addNewChannelMessage ( msg , type ) ;
if ( type = = NewMessageExisting ) return addToHistory ( msg ) ;
2015-11-13 18:14:33 +03:00
if ( ! loadedAtBottom ( ) | | peer - > migrateTo ( ) ) {
2015-09-20 11:55:41 +03:00
HistoryItem * item = addToHistory ( msg ) ;
if ( item ) {
setLastMessage ( item ) ;
if ( type = = NewMessageUnread ) {
2015-10-27 20:29:39 -04:00
newItemAdded ( item ) ;
2015-09-20 11:55:41 +03:00
}
}
return item ;
}
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
2015-09-19 12:13:21 +03:00
bool newBlock = blocks . isEmpty ( ) ;
2014-05-30 12:53:19 +04:00
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
2015-09-19 12:13:21 +03:00
to = blocks . back ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-25 00:27:45 +03:00
HistoryItem * item = createItem ( ( type = = NewMessageLast ) ? 0 : to , msg , ( type = = NewMessageUnread ) ) ;
if ( type = = NewMessageLast ) {
if ( ! item - > detached ( ) ) {
return item ;
}
item - > attach ( to ) ;
}
return addNewItem ( to , newBlock , item , ( type = = NewMessageUnread ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-21 23:57:42 +03:00
HistoryItem * History : : addToHistory ( const MTPMessage & msg ) {
2015-12-23 15:55:32 +03:00
return createItem ( 0 , msg , false ) ;
2014-07-04 15:12:54 +04:00
}
2015-09-19 12:13:21 +03:00
HistoryItem * History : : addNewForwarded ( MsgId id , QDateTime date , int32 from , HistoryMessage * item ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
2015-09-19 12:13:21 +03:00
bool newBlock = blocks . isEmpty ( ) ;
2014-05-30 12:53:19 +04:00
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
2015-09-19 12:13:21 +03:00
to = blocks . back ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
return addNewItem ( to , newBlock , createItemForwarded ( to , id , date , from , item ) , true ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-28 13:28:00 +03:00
HistoryItem * History : : addNewDocument ( MsgId id , int32 flags , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
2015-09-19 12:13:21 +03:00
bool newBlock = blocks . isEmpty ( ) ;
2014-05-30 12:53:19 +04:00
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
2015-09-19 12:13:21 +03:00
to = blocks . back ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-28 13:28:00 +03:00
return addNewItem ( to , newBlock , createItemDocument ( to , id , flags , replyTo , date , from , doc , caption ) , true ) ;
2014-05-30 12:53:19 +04:00
}
void History : : createInitialDateBlock ( const QDateTime & date ) {
HistoryBlock * dateBlock = new HistoryBlock ( this ) ; // date block
HistoryItem * dayItem = createDayServiceMsg ( this , dateBlock , date ) ;
2015-09-19 12:13:21 +03:00
dateBlock - > items . push_back ( dayItem ) ;
2014-05-30 12:53:19 +04:00
if ( width ) {
2015-12-23 17:18:42 +03:00
dateBlock - > height + = dayItem - > resize ( width ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-23 17:18:42 +03:00
2015-09-19 12:13:21 +03:00
blocks . push_front ( dateBlock ) ;
2015-12-23 17:18:42 +03:00
if ( width ) {
height + = dateBlock - > height ;
for ( int32 i = 1 , l = blocks . size ( ) ; i < l ; + + i ) {
blocks . at ( i ) - > y + = dateBlock - > height ;
}
}
2014-05-30 12:53:19 +04:00
}
2015-08-28 18:15:56 +03:00
void History : : addToOverview ( HistoryItem * item , MediaOverviewType type ) {
2015-09-19 12:13:21 +03:00
if ( overviewIds [ type ] . constFind ( item - > id ) = = overviewIds [ type ] . cend ( ) ) {
overview [ type ] . push_back ( item - > id ) ;
overviewIds [ type ] . insert ( item - > id , NullType ( ) ) ;
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ type ] > 0 ) {
+ + overviewCountData [ type ] ;
}
2015-08-28 18:15:56 +03:00
if ( App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , type ) ;
}
}
bool History : : addToOverviewFront ( HistoryItem * item , MediaOverviewType type ) {
2015-09-19 12:13:21 +03:00
if ( overviewIds [ type ] . constFind ( item - > id ) = = overviewIds [ type ] . cend ( ) ) {
overview [ type ] . push_front ( item - > id ) ;
overviewIds [ type ] . insert ( item - > id , NullType ( ) ) ;
2015-08-28 18:15:56 +03:00
return true ;
}
return false ;
}
2015-09-19 12:13:21 +03:00
HistoryItem * History : : addNewItem ( HistoryBlock * to , bool newBlock , HistoryItem * adding , bool newMsg ) {
2014-05-30 12:53:19 +04:00
if ( ! adding ) {
if ( newBlock ) delete to ;
2014-07-04 15:12:54 +04:00
return adding ;
2014-05-30 12:53:19 +04:00
}
if ( newBlock ) {
createInitialDateBlock ( adding - > date ) ;
to - > y = height ;
2015-09-19 12:13:21 +03:00
blocks . push_back ( to ) ;
} else if ( to - > items . back ( ) - > date . date ( ) ! = adding - > date . date ( ) ) {
2014-05-30 12:53:19 +04:00
HistoryItem * dayItem = createDayServiceMsg ( this , to , adding - > date ) ;
2015-09-19 12:13:21 +03:00
to - > items . push_back ( dayItem ) ;
2014-05-30 12:53:19 +04:00
if ( width ) {
2015-12-23 17:18:42 +03:00
dayItem - > y = to - > height ;
2014-05-30 12:53:19 +04:00
int32 dh = dayItem - > resize ( width ) ;
to - > height + = dh ;
height + = dh ;
}
}
2015-09-19 12:13:21 +03:00
to - > items . push_back ( adding ) ;
2015-08-07 15:11:50 +03:00
setLastMessage ( adding ) ;
2014-05-30 12:53:19 +04:00
adding - > y = to - > height ;
if ( width ) {
int32 dh = adding - > resize ( width ) ;
to - > height + = dh ;
height + = dh ;
}
if ( newMsg ) {
2015-10-27 20:29:39 -04:00
newItemAdded ( adding ) ;
2014-07-04 15:12:54 +04:00
}
2015-08-07 15:11:50 +03:00
2015-11-02 17:33:57 -05:00
if ( adding - > indexInOverview ( ) ) {
2015-09-21 23:57:42 +03:00
HistoryMedia * media = adding - > getMedia ( true ) ;
if ( media ) {
HistoryMediaType mt = media - > type ( ) ;
MediaOverviewType t = mediaToOverviewType ( mt ) ;
if ( t ! = OverviewCount ) {
2015-12-19 00:36:16 +03:00
if ( mt = = MediaTypeDocument & & static_cast < HistoryDocument * > ( media ) - > getDocument ( ) - > song ( ) ) {
2015-09-21 23:57:42 +03:00
addToOverview ( adding , OverviewAudioDocuments ) ;
} else {
addToOverview ( adding , t ) ;
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
}
2015-09-21 23:57:42 +03:00
if ( adding - > hasTextLinks ( ) ) {
addToOverview ( adding , OverviewLinks ) ;
}
2015-08-21 14:23:44 +03:00
}
2015-06-15 20:19:24 +03:00
if ( adding - > from ( ) - > id ) {
2015-11-09 12:51:22 +03:00
if ( adding - > from ( ) - > isUser ( ) ) {
QList < UserData * > * lastAuthors = 0 ;
if ( peer - > isChat ( ) ) {
lastAuthors = & peer - > asChat ( ) - > lastAuthors ;
2015-11-19 18:56:29 +03:00
} else if ( peer - > isMegagroup ( ) ) {
2015-11-09 12:51:22 +03:00
lastAuthors = & peer - > asChannel ( ) - > mgInfo - > lastParticipants ;
2015-11-20 16:34:37 +03:00
if ( adding - > from ( ) - > asUser ( ) - > botInfo ) {
peer - > asChannel ( ) - > mgInfo - > bots . insert ( adding - > from ( ) - > asUser ( ) , true ) ;
if ( peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 & & peer - > asChannel ( ) - > mgInfo - > botStatus < 2 ) {
peer - > asChannel ( ) - > mgInfo - > botStatus = 2 ;
}
}
2015-11-09 12:51:22 +03:00
}
if ( lastAuthors ) {
int prev = lastAuthors - > indexOf ( adding - > from ( ) - > asUser ( ) ) ;
if ( prev > 0 ) {
lastAuthors - > removeAt ( prev ) ;
2015-11-24 13:40:18 +03:00
} else if ( prev < 0 & & peer - > isMegagroup ( ) ) { // nothing is outdated if just reordering
peer - > asChannel ( ) - > mgInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsAdminsOutdated ;
2015-11-09 12:51:22 +03:00
}
if ( prev ) {
lastAuthors - > push_front ( adding - > from ( ) - > asUser ( ) ) ;
}
2015-06-15 20:19:24 +03:00
}
}
if ( adding - > hasReplyMarkup ( ) ) {
2015-09-03 13:48:40 +03:00
int32 markupFlags = App : : replyMarkup ( channelId ( ) , adding - > id ) . flags ;
2015-10-28 20:16:52 -04:00
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup : : flag_selective ) | | adding - > mentionsMe ( ) ) {
2015-11-09 12:51:22 +03:00
QMap < PeerData * , bool > * markupSenders = 0 ;
2015-09-21 23:57:42 +03:00
if ( peer - > isChat ( ) ) {
2015-11-09 12:51:22 +03:00
markupSenders = & peer - > asChat ( ) - > markupSenders ;
} else if ( peer - > isMegagroup ( ) ) {
markupSenders = & peer - > asChannel ( ) - > mgInfo - > markupSenders ;
}
if ( markupSenders ) {
markupSenders - > insert ( adding - > from ( ) , true ) ;
2015-06-22 11:51:39 +03:00
}
if ( markupFlags & MTPDreplyKeyboardMarkup_flag_ZERO ) { // zero markup means replyKeyboardHide
2015-11-09 12:51:22 +03:00
if ( lastKeyboardFrom = = adding - > from ( ) - > id | | ( ! lastKeyboardInited & & ! peer - > isChat ( ) & & ! peer - > isMegagroup ( ) & & ! adding - > out ( ) ) ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
}
} else {
2015-11-09 12:51:22 +03:00
bool botNotInChat = false ;
if ( peer - > isChat ( ) ) {
botNotInChat = adding - > from ( ) - > isUser ( ) & & ( ! peer - > canWrite ( ) | | ! peer - > asChat ( ) - > participants . isEmpty ( ) ) & & ! peer - > asChat ( ) - > participants . contains ( adding - > from ( ) - > asUser ( ) ) ;
} else if ( peer - > isMegagroup ( ) ) {
2015-11-24 19:19:18 +03:00
botNotInChat = adding - > from ( ) - > isUser ( ) & & ( ! peer - > canWrite ( ) | | peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 ) & & ! peer - > asChannel ( ) - > mgInfo - > bots . contains ( adding - > from ( ) - > asUser ( ) ) ;
2015-11-09 12:51:22 +03:00
}
if ( botNotInChat ) {
clearLastKeyboard ( ) ;
} else {
lastKeyboardInited = true ;
lastKeyboardId = adding - > id ;
lastKeyboardFrom = adding - > from ( ) - > id ;
lastKeyboardUsed = false ;
}
2015-06-17 22:43:03 +03:00
}
}
2015-03-19 12:18:19 +03:00
}
}
2015-09-21 23:57:42 +03:00
2014-07-04 15:12:54 +04:00
return adding ;
}
2014-10-22 22:39:03 +04:00
void History : : unregTyping ( UserData * from ) {
2015-08-01 11:33:00 +03:00
uint64 updateAtMs = 0 ;
2014-10-22 22:39:03 +04:00
TypingUsers : : iterator i = typing . find ( from ) ;
if ( i ! = typing . end ( ) ) {
2015-08-01 11:33:00 +03:00
updateAtMs = getms ( true ) ;
i . value ( ) = updateAtMs ;
}
SendActionUsers : : iterator j = sendActions . find ( from ) ;
if ( j ! = sendActions . end ( ) ) {
if ( ! updateAtMs ) updateAtMs = getms ( true ) ;
j . value ( ) . until = updateAtMs ;
}
if ( updateAtMs ) {
updateTyping ( updateAtMs , 0 , true ) ;
2014-10-22 22:39:03 +04:00
}
}
2014-07-04 15:12:54 +04:00
void History : : newItemAdded ( HistoryItem * item ) {
App : : checkImageCacheSize ( ) ;
2015-09-04 16:01:31 +03:00
if ( item - > from ( ) & & item - > from ( ) - > isUser ( ) ) {
unregTyping ( item - > from ( ) - > asUser ( ) ) ;
item - > from ( ) - > asUser ( ) - > madeAction ( ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
if ( item - > out ( ) ) {
if ( unreadBar ) unreadBar - > destroy ( ) ;
2015-10-27 20:29:39 -04:00
if ( ! item - > unread ( ) ) {
outboxRead ( item ) ;
}
2014-07-04 15:12:54 +04:00
} else if ( item - > unread ( ) ) {
2015-09-23 20:43:08 +03:00
bool skip = false ;
if ( ! isChannel ( ) | | peer - > asChannel ( ) - > amIn ( ) ) {
notifies . push_back ( item ) ;
App : : main ( ) - > newUnreadMsg ( this , item ) ;
}
2015-11-13 18:14:33 +03:00
} else if ( ! item - > isGroupMigrate ( ) | | ! peer - > isMegagroup ( ) ) {
2015-10-27 20:29:39 -04:00
inboxRead ( item ) ;
2014-07-04 15:12:54 +04:00
}
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
HistoryItem * History : : addItemAfterPrevToBlock ( HistoryItem * item , HistoryItem * prev , HistoryBlock * block ) {
if ( prev & & prev - > date . date ( ) ! = item - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , prev - > block ( ) , item - > date ) ;
prev - > block ( ) - > items . push_back ( dayItem ) ;
if ( width ) {
dayItem - > y = prev - > block ( ) - > height ;
prev - > block ( ) - > height + = dayItem - > resize ( width ) ;
if ( prev - > block ( ) ! = block ) {
height + = dayItem - > height ( ) ;
}
}
}
block - > items . push_back ( item ) ;
if ( width ) {
item - > y = block - > height ;
block - > height + = item - > resize ( width ) ;
}
return item ;
}
2015-09-20 11:55:41 +03:00
HistoryItem * History : : addMessageGroupAfterPrevToBlock ( const MTPDmessageGroup & group , HistoryItem * prev , HistoryBlock * block ) {
2015-09-19 12:13:21 +03:00
if ( prev & & prev - > type ( ) = = HistoryItemGroup ) {
static_cast < HistoryGroup * > ( prev ) - > uniteWith ( group . vmin_id . v , group . vmax_id . v , group . vcount . v ) ;
return prev ;
}
2015-09-20 11:55:41 +03:00
return addItemAfterPrevToBlock ( regItem ( new HistoryGroup ( this , block , group , prev ? prev - > date : date ( group . vdate ) ) ) , prev , block ) ;
}
HistoryItem * History : : addMessageGroupAfterPrev ( HistoryItem * newItem , HistoryItem * prev ) {
if ( prev & & prev - > type ( ) = = HistoryItemGroup ) {
static_cast < HistoryGroup * > ( prev ) - > uniteWith ( newItem ) ;
return prev ;
}
QDateTime date = prev ? prev - > date : newItem - > date ;
2015-09-21 23:57:42 +03:00
HistoryBlock * block = prev ? prev - > block ( ) : 0 ;
2015-09-20 11:55:41 +03:00
if ( ! block ) {
createInitialDateBlock ( date ) ;
block = new HistoryBlock ( this ) ;
2015-12-25 00:27:45 +03:00
blocks . push_back ( block ) ; // CHECK
2015-12-23 17:18:42 +03:00
if ( width ) {
block - > y = height ;
}
2015-09-20 11:55:41 +03:00
}
return addItemAfterPrevToBlock ( regItem ( new HistoryGroup ( this , block , newItem , date ) ) , prev , block ) ;
2015-09-19 12:13:21 +03:00
}
void History : : addOlderSlice ( const QVector < MTPMessage > & slice , const QVector < MTPMessageGroup > * collapsed ) {
2014-07-04 15:12:54 +04:00
if ( slice . isEmpty ( ) ) {
oldLoaded = true ;
2015-09-21 23:57:42 +03:00
if ( ! collapsed | | collapsed - > isEmpty ( ) | | ! isChannel ( ) ) {
if ( isChannel ( ) ) {
asChannelHistory ( ) - > checkJoinedMessage ( ) ;
asChannelHistory ( ) - > checkMaxReadMessageDate ( ) ;
}
return ;
}
2014-07-04 15:12:54 +04:00
}
2014-05-30 12:53:19 +04:00
2015-09-21 23:57:42 +03:00
const MTPMessageGroup * groupsBegin = ( isChannel ( ) & & collapsed ) ? collapsed - > constData ( ) : 0 , * groupsIt = groupsBegin , * groupsEnd = ( isChannel ( ) & & collapsed ) ? ( groupsBegin + collapsed - > size ( ) ) : 0 ;
2015-09-19 12:13:21 +03:00
2015-12-23 17:18:42 +03:00
HistoryItem * oldFirst = 0 , * last = 0 ;
if ( ! blocks . isEmpty ( ) ) {
t_assert ( blocks . size ( ) > 1 ) ;
oldFirst = blocks . at ( 1 ) - > items . front ( ) ;
2014-05-30 12:53:19 +04:00
}
HistoryBlock * block = new HistoryBlock ( this ) ;
2015-09-19 12:13:21 +03:00
block - > items . reserve ( slice . size ( ) + ( collapsed ? collapsed - > size ( ) : 0 ) ) ;
for ( QVector < MTPmessage > : : const_iterator i = slice . cend ( ) , e = slice . cbegin ( ) ; i ! = e ; ) {
- - i ;
2014-05-30 12:53:19 +04:00
HistoryItem * adding = createItem ( block , * i , false ) ;
2015-09-19 12:13:21 +03:00
if ( ! adding ) continue ;
for ( ; groupsIt ! = groupsEnd ; + + groupsIt ) {
if ( groupsIt - > type ( ) ! = mtpc_messageGroup ) continue ;
const MTPDmessageGroup & group ( groupsIt - > c_messageGroup ( ) ) ;
if ( group . vmin_id . v > = adding - > id ) break ;
2015-12-23 17:18:42 +03:00
last = addMessageGroupAfterPrevToBlock ( group , last , block ) ;
2015-09-19 12:13:21 +03:00
}
2015-12-23 17:18:42 +03:00
last = addItemAfterPrevToBlock ( adding , last , block ) ;
2015-09-19 12:13:21 +03:00
}
for ( ; groupsIt ! = groupsEnd ; + + groupsIt ) {
if ( groupsIt - > type ( ) ! = mtpc_messageGroup ) continue ;
const MTPDmessageGroup & group ( groupsIt - > c_messageGroup ( ) ) ;
2015-12-23 17:18:42 +03:00
last = addMessageGroupAfterPrevToBlock ( group , last , block ) ;
2015-09-19 12:13:21 +03:00
}
2015-12-23 17:18:42 +03:00
while ( oldFirst & & last & & oldFirst - > type ( ) = = HistoryItemGroup & & last - > type ( ) = = HistoryItemGroup ) {
static_cast < HistoryGroup * > ( last ) - > uniteWith ( static_cast < HistoryGroup * > ( oldFirst ) ) ;
oldFirst - > destroy ( ) ;
if ( blocks . isEmpty ( ) ) {
oldFirst = 0 ;
} else {
t_assert ( blocks . size ( ) > 1 ) ;
oldFirst = blocks . at ( 1 ) - > items . front ( ) ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-23 17:18:42 +03:00
if ( oldFirst & & last & & last - > date . date ( ) ! = oldFirst - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , block , oldFirst - > date ) ;
2015-09-19 12:13:21 +03:00
block - > items . push_back ( dayItem ) ;
2015-08-24 13:53:04 +03:00
if ( width ) {
dayItem - > y = block - > height ;
block - > height + = dayItem - > resize ( width ) ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-23 17:18:42 +03:00
if ( block - > items . isEmpty ( ) ) {
oldLoaded = true ;
delete block ;
} else {
if ( oldFirst ) {
HistoryBlock * initial = blocks . at ( 0 ) ;
blocks [ 0 ] = block ;
blocks . push_front ( initial ) ;
if ( width ) {
block - > y = initial - > height ;
for ( int32 i = 2 , l = blocks . size ( ) ; i < l ; + + i ) {
blocks . at ( i ) - > y + = block - > height ;
}
height + = block - > height ;
}
initial - > items . at ( 0 ) - > setDate ( block - > items . at ( 0 ) - > date ) ;
} else {
blocks . push_front ( block ) ;
if ( width ) {
height = block - > height ;
}
createInitialDateBlock ( block - > items . at ( 0 ) - > date ) ;
2015-08-24 13:53:04 +03:00
}
2014-08-11 13:03:45 +04:00
2015-11-09 12:51:22 +03:00
if ( loadedAtBottom ( ) ) { // add photos to overview and authors to lastAuthors / lastParticipants
2015-09-21 23:57:42 +03:00
bool channel = isChannel ( ) ;
2015-07-03 11:47:16 +03:00
int32 mask = 0 ;
2015-11-09 12:51:22 +03:00
QList < UserData * > * lastAuthors = 0 ;
QMap < PeerData * , bool > * markupSenders = 0 ;
if ( peer - > isChat ( ) ) {
lastAuthors = & peer - > asChat ( ) - > lastAuthors ;
markupSenders = & peer - > asChat ( ) - > markupSenders ;
} else if ( peer - > isMegagroup ( ) ) {
2015-11-19 18:56:29 +03:00
lastAuthors = & peer - > asChannel ( ) - > mgInfo - > lastParticipants ;
2015-11-09 12:51:22 +03:00
markupSenders = & peer - > asChannel ( ) - > mgInfo - > markupSenders ;
}
2015-09-19 12:13:21 +03:00
for ( int32 i = block - > items . size ( ) ; i > 0 ; - - i ) {
HistoryItem * item = block - > items [ i - 1 ] ;
2015-11-19 18:56:29 +03:00
if ( item - > indexInOverview ( ) ) {
HistoryMedia * media = item - > getMedia ( true ) ;
if ( media ) {
HistoryMediaType mt = media - > type ( ) ;
MediaOverviewType t = mediaToOverviewType ( mt ) ;
if ( t ! = OverviewCount ) {
2015-12-19 00:36:16 +03:00
if ( mt = = MediaTypeDocument & & static_cast < HistoryDocument * > ( media ) - > getDocument ( ) - > song ( ) ) {
2015-11-19 18:56:29 +03:00
if ( addToOverviewFront ( item , OverviewAudioDocuments ) ) mask | = ( 1 < < OverviewAudioDocuments ) ;
} else {
if ( addToOverviewFront ( item , t ) ) mask | = ( 1 < < t ) ;
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
}
2015-11-19 18:56:29 +03:00
if ( item - > hasTextLinks ( ) ) {
if ( addToOverviewFront ( item , OverviewLinks ) ) mask | = ( 1 < < OverviewLinks ) ;
}
2015-08-21 14:23:44 +03:00
}
2015-06-15 20:19:24 +03:00
if ( item - > from ( ) - > id ) {
2015-06-17 22:43:03 +03:00
if ( lastAuthors ) { // chats
2015-11-24 13:40:18 +03:00
if ( item - > from ( ) - > isUser ( ) ) {
if ( ! lastAuthors - > contains ( item - > from ( ) - > asUser ( ) ) ) {
lastAuthors - > push_back ( item - > from ( ) - > asUser ( ) ) ;
if ( peer - > isMegagroup ( ) ) {
peer - > asChannel ( ) - > mgInfo - > lastParticipantsStatus | = MegagroupInfo : : LastParticipantsAdminsOutdated ;
}
}
2015-06-17 22:43:03 +03:00
}
2015-11-09 12:51:22 +03:00
}
if ( markupSenders ) { // chats with bots
if ( ! lastKeyboardInited & & item - > hasReplyMarkup ( ) & & ! item - > out ( ) ) {
2015-09-03 13:48:40 +03:00
int32 markupFlags = App : : replyMarkup ( channelId ( ) , item - > id ) . flags ;
2015-10-28 20:16:52 -04:00
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup : : flag_selective ) | | item - > mentionsMe ( ) ) {
2015-11-09 12:51:22 +03:00
bool wasKeyboardHide = markupSenders - > contains ( item - > from ( ) ) ;
2015-06-22 11:51:39 +03:00
if ( ! wasKeyboardHide ) {
2015-11-09 12:51:22 +03:00
markupSenders - > insert ( item - > from ( ) , true ) ;
2015-06-22 11:51:39 +03:00
}
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup_flag_ZERO ) ) {
if ( ! lastKeyboardInited ) {
2015-11-09 12:51:22 +03:00
bool botNotInChat = false ;
if ( peer - > isChat ( ) ) {
botNotInChat = ( ! peer - > canWrite ( ) | | ! peer - > asChat ( ) - > participants . isEmpty ( ) ) & & item - > from ( ) - > isUser ( ) & & ! peer - > asChat ( ) - > participants . contains ( item - > from ( ) - > asUser ( ) ) ;
} else if ( peer - > isMegagroup ( ) ) {
2015-11-24 19:19:18 +03:00
botNotInChat = ( ! peer - > canWrite ( ) | | peer - > asChannel ( ) - > mgInfo - > botStatus ! = 0 ) & & item - > from ( ) - > isUser ( ) & & ! peer - > asChannel ( ) - > mgInfo - > bots . contains ( item - > from ( ) - > asUser ( ) ) ;
2015-11-09 12:51:22 +03:00
}
if ( wasKeyboardHide | | botNotInChat ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
} else {
2015-06-24 20:24:48 +03:00
lastKeyboardInited = true ;
2015-06-22 11:51:39 +03:00
lastKeyboardId = item - > id ;
lastKeyboardFrom = item - > from ( ) - > id ;
lastKeyboardUsed = false ;
}
2015-06-17 22:43:03 +03:00
}
}
}
}
} else if ( ! lastKeyboardInited & & item - > hasReplyMarkup ( ) & & ! item - > out ( ) ) { // conversations with bots
2015-09-03 13:48:40 +03:00
int32 markupFlags = App : : replyMarkup ( channelId ( ) , item - > id ) . flags ;
2015-10-28 20:16:52 -04:00
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup : : flag_selective ) | | item - > mentionsMe ( ) ) {
2015-06-22 11:51:39 +03:00
if ( markupFlags & MTPDreplyKeyboardMarkup_flag_ZERO ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
} else {
lastKeyboardInited = true ;
lastKeyboardId = item - > id ;
lastKeyboardFrom = item - > from ( ) - > id ;
lastKeyboardUsed = false ;
}
2015-06-15 20:19:24 +03:00
}
}
}
2014-08-11 13:03:45 +04:00
}
2015-07-03 11:47:16 +03:00
for ( int32 t = 0 ; t < OverviewCount ; + + t ) {
if ( ( mask & ( 1 < < t ) ) & & App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , MediaOverviewType ( t ) ) ;
}
2014-08-11 13:03:45 +04:00
}
2014-05-30 12:53:19 +04:00
}
2015-09-21 23:57:42 +03:00
if ( isChannel ( ) ) {
asChannelHistory ( ) - > checkJoinedMessage ( ) ;
asChannelHistory ( ) - > checkMaxReadMessageDate ( ) ;
}
if ( newLoaded & & ! lastMsg ) setLastMessage ( lastImportantMessage ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
void History : : addNewerSlice ( const QVector < MTPMessage > & slice , const QVector < MTPMessageGroup > * collapsed ) {
2015-09-24 19:05:06 +03:00
bool wasEmpty = isEmpty ( ) , wasLoadedAtBottom = loadedAtBottom ( ) ;
2014-07-04 15:12:54 +04:00
if ( slice . isEmpty ( ) ) {
newLoaded = true ;
2015-09-21 23:57:42 +03:00
if ( ! lastMsg ) setLastMessage ( lastImportantMessage ( ) ) ;
2014-07-04 15:12:54 +04:00
}
2015-09-24 19:05:06 +03:00
if ( ! slice . isEmpty ( ) | | ( isChannel ( ) & & collapsed & & ! collapsed - > isEmpty ( ) ) ) {
const MTPMessageGroup * groupsBegin = ( isChannel ( ) & & collapsed ) ? collapsed - > constData ( ) : 0 , * groupsIt = groupsBegin , * groupsEnd = ( isChannel ( ) & & collapsed ) ? ( groupsBegin + collapsed - > size ( ) ) : 0 ;
2015-09-19 12:13:21 +03:00
2015-09-24 19:05:06 +03:00
HistoryItem * prev = blocks . isEmpty ( ) ? 0 : blocks . back ( ) - > items . back ( ) ;
2014-07-04 15:12:54 +04:00
2015-09-24 19:05:06 +03:00
HistoryBlock * block = new HistoryBlock ( this ) ;
block - > items . reserve ( slice . size ( ) + ( collapsed ? collapsed - > size ( ) : 0 ) ) ;
for ( QVector < MTPmessage > : : const_iterator i = slice . cend ( ) , e = slice . cbegin ( ) ; i ! = e ; ) {
- - i ;
HistoryItem * adding = createItem ( block , * i , false ) ;
if ( ! adding ) continue ;
2014-07-04 15:12:54 +04:00
2015-09-24 19:05:06 +03:00
for ( ; groupsIt ! = groupsEnd ; + + groupsIt ) {
if ( groupsIt - > type ( ) ! = mtpc_messageGroup ) continue ;
const MTPDmessageGroup & group ( groupsIt - > c_messageGroup ( ) ) ;
if ( group . vmin_id . v > = adding - > id ) break ;
prev = addMessageGroupAfterPrevToBlock ( group , prev , block ) ;
}
2015-09-19 12:13:21 +03:00
2015-09-24 19:05:06 +03:00
prev = addItemAfterPrevToBlock ( adding , prev , block ) ;
}
2015-09-19 12:13:21 +03:00
for ( ; groupsIt ! = groupsEnd ; + + groupsIt ) {
if ( groupsIt - > type ( ) ! = mtpc_messageGroup ) continue ;
const MTPDmessageGroup & group ( groupsIt - > c_messageGroup ( ) ) ;
2015-09-20 11:55:41 +03:00
prev = addMessageGroupAfterPrevToBlock ( group , prev , block ) ;
2014-07-04 15:12:54 +04:00
}
2015-09-19 12:13:21 +03:00
2015-12-23 17:18:42 +03:00
if ( block - > items . isEmpty ( ) ) {
2015-09-24 19:05:06 +03:00
newLoaded = true ;
setLastMessage ( lastImportantMessage ( ) ) ;
delete block ;
2015-12-23 17:18:42 +03:00
} else {
blocks . push_back ( block ) ;
if ( width ) {
block - > y = height ;
height + = block - > height ;
}
if ( blocks . size ( ) = = 1 ) {
createInitialDateBlock ( block - > items . at ( 0 ) - > date ) ;
}
2015-09-24 19:05:06 +03:00
}
2014-07-04 15:12:54 +04:00
}
2015-12-23 17:18:42 +03:00
2014-08-11 13:03:45 +04:00
if ( ! wasLoadedAtBottom & & loadedAtBottom ( ) ) { // add all loaded photos to overview
2015-07-03 11:47:16 +03:00
int32 mask = 0 ;
2014-08-15 15:19:32 +04:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ i ] = = 0 ) continue ; // all loaded
2015-09-19 12:13:21 +03:00
if ( ! overview [ i ] . isEmpty ( ) | | ! overviewIds [ i ] . isEmpty ( ) ) {
overview [ i ] . clear ( ) ;
overviewIds [ i ] . clear ( ) ;
2015-07-03 11:47:16 +03:00
mask | = ( 1 < < i ) ;
}
2014-08-15 15:19:32 +04:00
}
2015-09-21 23:57:42 +03:00
bool channel = isChannel ( ) ;
2015-09-19 12:13:21 +03:00
for ( int32 i = 0 ; i < blocks . size ( ) ; + + i ) {
HistoryBlock * b = blocks [ i ] ;
for ( int32 j = 0 ; j < b - > items . size ( ) ; + + j ) {
HistoryItem * item = b - > items [ j ] ;
2015-11-02 17:33:57 -05:00
if ( ! item - > indexInOverview ( ) ) continue ;
2015-09-21 23:57:42 +03:00
2014-08-11 13:03:45 +04:00
HistoryMedia * media = item - > getMedia ( true ) ;
2014-08-15 15:19:32 +04:00
if ( media ) {
2015-07-03 11:47:16 +03:00
HistoryMediaType mt = media - > type ( ) ;
MediaOverviewType t = mediaToOverviewType ( mt ) ;
if ( t ! = OverviewCount ) {
2015-12-19 00:36:16 +03:00
if ( mt = = MediaTypeDocument & & static_cast < HistoryDocument * > ( media ) - > getDocument ( ) - > song ( ) ) {
2015-07-03 11:47:16 +03:00
t = OverviewAudioDocuments ;
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ t ] ! = 0 ) {
2015-09-19 12:13:21 +03:00
overview [ t ] . push_back ( item - > id ) ;
overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
2015-07-03 11:47:16 +03:00
mask | = ( 1 < < t ) ;
}
2015-09-13 20:27:29 +03:00
} else {
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ t ] ! = 0 ) {
2015-09-19 12:13:21 +03:00
overview [ t ] . push_back ( item - > id ) ;
overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
2015-09-13 20:27:29 +03:00
mask | = ( 1 < < t ) ;
}
2015-07-03 11:47:16 +03:00
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
}
2015-08-21 14:23:44 +03:00
if ( item - > hasTextLinks ( ) ) {
MediaOverviewType t = OverviewLinks ;
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ t ] ! = 0 ) {
2015-09-19 12:13:21 +03:00
overview [ t ] . push_back ( item - > id ) ;
overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
2015-08-21 14:23:44 +03:00
mask | = ( 1 < < t ) ;
}
}
2014-08-11 13:03:45 +04:00
}
}
2015-07-03 11:47:16 +03:00
for ( int32 t = 0 ; t < OverviewCount ; + + t ) {
if ( ( mask & ( 1 < < t ) ) & & App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , MediaOverviewType ( t ) ) ;
}
2014-08-11 13:03:45 +04:00
}
2015-09-21 23:57:42 +03:00
if ( isChannel ( ) ) asChannelHistory ( ) - > checkJoinedMessage ( ) ;
2014-07-04 15:12:54 +04:00
}
2015-09-06 13:17:09 +03:00
int32 History : : countUnread ( MsgId upTo ) {
int32 result = 0 ;
2015-09-19 12:13:21 +03:00
for ( Blocks : : const_iterator i = blocks . cend ( ) , e = blocks . cbegin ( ) ; i ! = e ; ) {
2015-09-06 13:17:09 +03:00
- - i ;
2015-09-19 12:13:21 +03:00
for ( HistoryBlock : : Items : : const_iterator j = ( * i ) - > items . cend ( ) , en = ( * i ) - > items . cbegin ( ) ; j ! = en ; ) {
2015-09-06 13:17:09 +03:00
- - j ;
if ( ( * j ) - > id > 0 & & ( * j ) - > id < = upTo ) {
break ;
} else if ( ! ( * j ) - > out ( ) & & ( * j ) - > unread ( ) & & ( * j ) - > id > upTo ) {
+ + result ;
}
}
}
return result ;
}
2015-09-19 12:13:21 +03:00
void History : : updateShowFrom ( ) {
if ( showFrom ) return ;
for ( Blocks : : const_iterator i = blocks . cend ( ) ; i ! = blocks . cbegin ( ) ; ) {
- - i ;
for ( HistoryBlock : : Items : : const_iterator j = ( * i ) - > items . cend ( ) ; j ! = ( * i ) - > items . cbegin ( ) ; ) {
- - j ;
2015-10-01 17:05:05 +03:00
if ( ( * j ) - > type ( ) = = HistoryItemMsg & & ( * j ) - > id > 0 & & ( ! ( * j ) - > out ( ) | | ! showFrom ) ) {
2015-09-19 12:13:21 +03:00
if ( ( * j ) - > id > = inboxReadBefore ) {
showFrom = * j ;
} else {
return ;
}
}
}
}
}
2015-09-06 13:17:09 +03:00
MsgId History : : inboxRead ( MsgId upTo ) {
2015-09-25 10:47:32 +03:00
if ( upTo < 0 ) return upTo ;
2014-05-30 12:53:19 +04:00
if ( unreadCount ) {
2015-03-13 16:01:25 +03:00
if ( upTo & & loadedAtBottom ( ) ) App : : main ( ) - > historyToDown ( this ) ;
2015-09-06 13:17:09 +03:00
setUnreadCount ( upTo ? countUnread ( upTo ) : 0 ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-06 13:17:09 +03:00
if ( ! upTo ) upTo = msgIdForRead ( ) ;
2015-09-07 10:52:37 +03:00
inboxReadBefore = qMax ( inboxReadBefore , upTo + 1 ) ;
2015-09-06 13:17:09 +03:00
2015-11-13 18:14:33 +03:00
if ( App : : main ( ) ) {
if ( ! dialogs . isEmpty ( ) ) {
App : : main ( ) - > dlgUpdated ( dialogs [ 0 ] ) ;
}
if ( peer - > migrateTo ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateTo ( ) - > id ) ) {
if ( ! h - > dialogs . isEmpty ( ) ) {
App : : main ( ) - > dlgUpdated ( h - > dialogs [ 0 ] ) ;
}
}
}
}
2015-10-03 13:09:09 +03:00
2015-07-17 22:17:37 +03:00
showFrom = 0 ;
2014-07-06 07:32:21 +04:00
App : : wnd ( ) - > notifyClear ( this ) ;
2014-07-04 15:12:54 +04:00
clearNotifications ( ) ;
2015-09-06 13:17:09 +03:00
return upTo ;
2014-05-30 12:53:19 +04:00
}
2015-09-06 13:17:09 +03:00
MsgId History : : inboxRead ( HistoryItem * wasRead ) {
2015-03-13 16:01:25 +03:00
return inboxRead ( wasRead ? wasRead - > id : 0 ) ;
}
2015-09-06 13:17:09 +03:00
MsgId History : : outboxRead ( int32 upTo ) {
2015-09-25 10:47:32 +03:00
if ( upTo < 0 ) return upTo ;
2015-09-06 13:17:09 +03:00
if ( ! upTo ) upTo = msgIdForRead ( ) ;
2015-09-07 10:52:37 +03:00
if ( outboxReadBefore < upTo + 1 ) outboxReadBefore = upTo + 1 ;
2015-09-06 13:17:09 +03:00
return upTo ;
2014-05-30 12:53:19 +04:00
}
2015-09-06 13:17:09 +03:00
MsgId History : : outboxRead ( HistoryItem * wasRead ) {
2015-03-13 16:01:25 +03:00
return outboxRead ( wasRead ? wasRead - > id : 0 ) ;
}
2015-09-20 11:55:41 +03:00
HistoryItem * History : : lastImportantMessage ( ) const {
if ( isEmpty ( ) ) return 0 ;
bool channel = isChannel ( ) ;
for ( int32 blockIndex = blocks . size ( ) ; blockIndex > 0 ; ) {
HistoryBlock * block = blocks . at ( - - blockIndex ) ;
for ( int32 itemIndex = block - > items . size ( ) ; itemIndex > 0 ; ) {
HistoryItem * item = block - > items . at ( - - itemIndex ) ;
2015-11-02 17:33:57 -05:00
if ( ( channel & & ! isMegagroup ( ) ) ? item - > isImportant ( ) : ( item - > type ( ) = = HistoryItemMsg ) ) {
2015-09-20 11:55:41 +03:00
return item ;
}
}
}
return 0 ;
}
2014-05-30 12:53:19 +04:00
void History : : setUnreadCount ( int32 newUnreadCount , bool psUpdate ) {
if ( unreadCount ! = newUnreadCount ) {
2015-09-07 10:52:37 +03:00
if ( newUnreadCount = = 1 ) {
2015-09-20 11:55:41 +03:00
if ( loadedAtBottom ( ) ) showFrom = lastImportantMessage ( ) ;
2015-09-07 10:52:37 +03:00
inboxReadBefore = qMax ( inboxReadBefore , msgIdForRead ( ) ) ;
2014-05-30 12:53:19 +04:00
} else if ( ! newUnreadCount ) {
showFrom = 0 ;
2015-09-07 10:52:37 +03:00
inboxReadBefore = qMax ( inboxReadBefore , msgIdForRead ( ) + 1 ) ;
2014-05-30 12:53:19 +04:00
}
App : : histories ( ) . unreadFull + = newUnreadCount - unreadCount ;
if ( mute ) App : : histories ( ) . unreadMuted + = newUnreadCount - unreadCount ;
unreadCount = newUnreadCount ;
2015-12-28 09:19:29 +03:00
if ( psUpdate & & ( ! mute | | cIncludeMuted ( ) ) & & App : : wnd ( ) ) App : : wnd ( ) - > updateCounter ( ) ;
2015-11-13 18:14:33 +03:00
if ( unreadBar ) {
int32 count = unreadCount ;
if ( peer - > migrateTo ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateTo ( ) - > id ) ) {
count + = h - > unreadCount ;
}
}
unreadBar - > setCount ( count ) ;
}
2014-05-30 12:53:19 +04:00
}
}
void History : : setMute ( bool newMute ) {
if ( mute ! = newMute ) {
App : : histories ( ) . unreadMuted + = newMute ? unreadCount : ( - unreadCount ) ;
mute = newMute ;
2015-04-30 16:53:36 +03:00
if ( App : : wnd ( ) ) App : : wnd ( ) - > updateCounter ( ) ;
2015-10-03 13:09:09 +03:00
if ( ! dialogs . isEmpty ( ) & & App : : main ( ) ) App : : main ( ) - > dlgUpdated ( dialogs [ 0 ] ) ;
2014-05-30 12:53:19 +04:00
}
}
void History : : getNextShowFrom ( HistoryBlock * block , int32 i ) {
if ( i > = 0 ) {
2015-09-19 12:13:21 +03:00
int32 l = block - > items . size ( ) ;
2014-05-30 12:53:19 +04:00
for ( + + i ; i < l ; + + i ) {
2015-09-19 12:13:21 +03:00
if ( block - > items [ i ] - > type ( ) = = HistoryItemMsg ) {
showFrom = block - > items [ i ] ;
2014-05-30 12:53:19 +04:00
return ;
}
}
}
2015-09-19 12:13:21 +03:00
int32 j = blocks . indexOf ( block ) , s = blocks . size ( ) ;
2014-05-30 12:53:19 +04:00
if ( j > = 0 ) {
for ( + + j ; j < s ; + + j ) {
2015-09-19 12:13:21 +03:00
block = blocks [ j ] ;
for ( int32 i = 0 , l = block - > items . size ( ) ; i < l ; + + i ) {
if ( block - > items [ i ] - > type ( ) = = HistoryItemMsg ) {
showFrom = block - > items [ i ] ;
2014-05-30 12:53:19 +04:00
return ;
}
}
}
}
showFrom = 0 ;
}
void History : : addUnreadBar ( ) {
2015-07-17 22:17:37 +03:00
if ( unreadBar | | ! showFrom | | showFrom - > detached ( ) | | ! unreadCount ) return ;
2015-09-19 12:13:21 +03:00
2015-11-13 18:14:33 +03:00
int32 count = unreadCount ;
if ( peer - > migrateTo ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateTo ( ) - > id ) ) {
count + = h - > unreadCount ;
}
}
2014-05-30 12:53:19 +04:00
HistoryBlock * block = showFrom - > block ( ) ;
2015-11-13 18:14:33 +03:00
unreadBar = new HistoryUnreadBar ( this , block , count , showFrom - > date ) ;
2015-12-23 15:55:32 +03:00
if ( ! addNewInTheMiddle ( regItem ( unreadBar ) , blocks . indexOf ( block ) , block - > items . indexOf ( showFrom ) ) ) {
2015-09-19 12:13:21 +03:00
unreadBar = 0 ;
}
}
2014-05-30 12:53:19 +04:00
2015-09-19 12:13:21 +03:00
HistoryItem * History : : addNewInTheMiddle ( HistoryItem * newItem , int32 blockIndex , int32 itemIndex ) {
2015-09-21 23:57:42 +03:00
if ( blockIndex < 0 | | itemIndex < 0 | | blockIndex > = blocks . size ( ) | | itemIndex > blocks . at ( blockIndex ) - > items . size ( ) ) {
2015-09-19 12:13:21 +03:00
delete newItem ;
return 0 ;
}
2014-05-30 12:53:19 +04:00
2015-09-19 12:13:21 +03:00
HistoryBlock * block = blocks . at ( blockIndex ) ;
2015-09-21 23:57:42 +03:00
newItem - > y = ( itemIndex < block - > items . size ( ) ) ? block - > items . at ( itemIndex ) - > y : block - > height ;
2015-09-19 12:13:21 +03:00
block - > items . insert ( itemIndex , newItem ) ;
2014-05-30 12:53:19 +04:00
2015-09-19 12:13:21 +03:00
if ( width ) {
int32 dh = newItem - > resize ( width ) , l = block - > items . size ( ) ;
for ( + + itemIndex ; itemIndex < l ; + + itemIndex ) {
block - > items [ itemIndex ] - > y + = dh ;
}
block - > height + = dh ;
for ( + + blockIndex , l = blocks . size ( ) ; blockIndex < l ; + + blockIndex ) {
blocks [ blockIndex ] - > y + = dh ;
}
height + = dh ;
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
return newItem ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
void History : : clearNotifications ( ) {
notifies . clear ( ) ;
}
bool History : : loadedAtBottom ( ) const {
return newLoaded ;
}
bool History : : loadedAtTop ( ) const {
return oldLoaded ;
}
2015-09-19 12:13:21 +03:00
bool History : : isReadyFor ( MsgId msgId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) {
2015-11-13 18:14:33 +03:00
if ( msgId < 0 & & - msgId < ServerMaxMsgId & & peer - > migrateFrom ( ) ) { // old group history
return App : : history ( peer - > migrateFrom ( ) - > id ) - > isReadyFor ( - msgId , fixInScrollMsgId , fixInScrollMsgTop ) ;
}
2015-09-20 11:55:41 +03:00
if ( msgId ! = ShowAtTheEndMsgId & & msgId ! = ShowAtUnreadMsgId & & isChannel ( ) ) {
2015-09-19 12:13:21 +03:00
return asChannelHistory ( ) - > isSwitchReadyFor ( msgId , fixInScrollMsgId , fixInScrollMsgTop ) ;
}
fixInScrollMsgId = 0 ;
fixInScrollMsgTop = 0 ;
2015-07-17 22:17:37 +03:00
if ( msgId = = ShowAtTheEndMsgId ) {
return loadedAtBottom ( ) ;
2015-09-19 12:13:21 +03:00
}
if ( msgId = = ShowAtUnreadMsgId ) {
2015-11-13 18:14:33 +03:00
if ( peer - > migrateFrom ( ) ) { // old group history
if ( History * h = App : : historyLoaded ( peer - > migrateFrom ( ) - > id ) ) {
if ( h - > unreadCount ) {
return h - > isReadyFor ( msgId , fixInScrollMsgId , fixInScrollMsgTop ) ;
}
}
}
2015-09-19 12:13:21 +03:00
if ( unreadCount ) {
if ( ! isEmpty ( ) ) {
return ( loadedAtTop ( ) | | minMsgId ( ) < = inboxReadBefore ) & & ( loadedAtBottom ( ) | | maxMsgId ( ) > = inboxReadBefore ) ;
2015-09-08 16:34:22 +03:00
}
2015-09-19 12:13:21 +03:00
return false ;
2015-09-08 16:34:22 +03:00
}
2015-09-19 12:13:21 +03:00
return loadedAtBottom ( ) ;
2015-07-17 22:17:37 +03:00
}
2015-09-19 12:13:21 +03:00
HistoryItem * item = App : : histItemById ( channelId ( ) , msgId ) ;
return item & & ( item - > history ( ) = = this ) & & ! item - > detached ( ) ;
2015-07-17 22:17:37 +03:00
}
2015-09-19 12:13:21 +03:00
void History : : getReadyFor ( MsgId msgId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) {
2015-11-13 18:14:33 +03:00
if ( msgId < 0 & & - msgId < ServerMaxMsgId & & peer - > migrateFrom ( ) ) {
History * h = App : : history ( peer - > migrateFrom ( ) - > id ) ;
h - > getReadyFor ( - msgId , fixInScrollMsgId , fixInScrollMsgTop ) ;
if ( h - > isEmpty ( ) ) {
clear ( true ) ;
newLoaded = oldLoaded = false ;
lastWidth = 0 ;
}
return ;
}
2015-09-20 11:55:41 +03:00
if ( msgId ! = ShowAtTheEndMsgId & & msgId ! = ShowAtUnreadMsgId & & isChannel ( ) ) {
2015-09-19 12:13:21 +03:00
return asChannelHistory ( ) - > getSwitchReadyFor ( msgId , fixInScrollMsgId , fixInScrollMsgTop ) ;
}
2015-11-13 18:14:33 +03:00
if ( msgId = = ShowAtUnreadMsgId & & peer - > migrateFrom ( ) ) {
if ( History * h = App : : historyLoaded ( peer - > migrateFrom ( ) - > id ) ) {
if ( h - > unreadCount ) {
clear ( true ) ;
newLoaded = oldLoaded = false ;
lastWidth = 0 ;
h - > getReadyFor ( msgId , fixInScrollMsgId , fixInScrollMsgTop ) ;
return ;
}
}
}
2015-09-19 12:13:21 +03:00
if ( ! isReadyFor ( msgId , fixInScrollMsgId , fixInScrollMsgTop ) ) {
2015-07-17 22:17:37 +03:00
clear ( true ) ;
2015-09-16 16:04:08 +03:00
newLoaded = ( msgId = = ShowAtTheEndMsgId ) ;
2015-07-17 22:17:37 +03:00
oldLoaded = false ;
lastWidth = 0 ;
}
}
2015-09-13 11:41:27 +03:00
void History : : setNotLoadedAtBottom ( ) {
newLoaded = false ;
}
2015-09-06 13:17:09 +03:00
namespace {
uint32 _dialogsPosToTopShift = 0x80000000UL ;
}
inline uint64 dialogPosFromDate ( const QDateTime & date ) {
return ( uint64 ( date . toTime_t ( ) ) < < 32 ) | ( + + _dialogsPosToTopShift ) ;
}
2015-09-21 23:57:42 +03:00
void History : : setLastMessage ( HistoryItem * msg ) {
2015-08-07 15:11:50 +03:00
if ( msg ) {
if ( ! lastMsg ) Local : : removeSavedPeer ( peer ) ;
lastMsg = msg ;
2015-09-21 23:57:42 +03:00
setPosInDialogsDate ( msg - > date ) ;
2015-08-07 15:11:50 +03:00
} else {
lastMsg = 0 ;
}
2015-10-14 13:51:37 +02:00
if ( ! dialogs . isEmpty ( ) & & App : : main ( ) ) App : : main ( ) - > dlgUpdated ( dialogs [ 0 ] ) ;
2015-08-07 15:11:50 +03:00
}
2015-09-06 13:17:09 +03:00
void History : : setPosInDialogsDate ( const QDateTime & date ) {
2015-10-23 18:06:56 +02:00
bool updateDialog = ( App : : main ( ) & & ( ! peer - > isChannel ( ) | | peer - > asChannel ( ) - > amIn ( ) | | ! dialogs . isEmpty ( ) ) ) ;
2015-11-13 18:14:33 +03:00
if ( peer - > migrateTo ( ) & & dialogs . isEmpty ( ) ) {
updateDialog = false ;
}
2015-09-21 23:57:42 +03:00
if ( ! lastMsgDate . isNull ( ) & & lastMsgDate > = date ) {
if ( ! updateDialog | | ! dialogs . isEmpty ( ) ) {
return ;
}
}
2015-09-06 13:17:09 +03:00
lastMsgDate = date ;
posInDialogs = dialogPosFromDate ( lastMsgDate ) ;
2015-09-21 23:57:42 +03:00
if ( updateDialog ) {
App : : main ( ) - > createDialog ( this ) ;
2015-09-06 13:17:09 +03:00
}
}
2014-07-04 15:12:54 +04:00
void History : : fixLastMessage ( bool wasAtBottom ) {
2015-09-21 23:57:42 +03:00
setLastMessage ( wasAtBottom ? lastImportantMessage ( ) : 0 ) ;
2014-07-04 15:12:54 +04:00
}
MsgId History : : minMsgId ( ) const {
2015-09-19 12:13:21 +03:00
for ( Blocks : : const_iterator i = blocks . cbegin ( ) , e = blocks . cend ( ) ; i ! = e ; + + i ) {
for ( HistoryBlock : : Items : : const_iterator j = ( * i ) - > items . cbegin ( ) , en = ( * i ) - > items . cend ( ) ; j ! = en ; + + j ) {
2014-07-04 15:12:54 +04:00
if ( ( * j ) - > id > 0 ) {
return ( * j ) - > id ;
2014-05-30 12:53:19 +04:00
}
}
}
2014-07-04 15:12:54 +04:00
return 0 ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
MsgId History : : maxMsgId ( ) const {
2015-09-19 12:13:21 +03:00
for ( Blocks : : const_iterator i = blocks . cend ( ) , e = blocks . cbegin ( ) ; i ! = e ; ) {
2014-07-04 15:12:54 +04:00
- - i ;
2015-09-19 12:13:21 +03:00
for ( HistoryBlock : : Items : : const_iterator j = ( * i ) - > items . cend ( ) , en = ( * i ) - > items . cbegin ( ) ; j ! = en ; ) {
2014-07-04 15:12:54 +04:00
- - j ;
if ( ( * j ) - > id > 0 ) {
return ( * j ) - > id ;
}
}
}
return 0 ;
2014-05-30 12:53:19 +04:00
}
2015-09-06 13:17:09 +03:00
MsgId History : : msgIdForRead ( ) const {
MsgId result = ( lastMsg & & lastMsg - > id > 0 ) ? lastMsg - > id : 0 ;
if ( loadedAtBottom ( ) ) result = qMax ( result , maxMsgId ( ) ) ;
return result ;
}
2015-12-22 11:01:02 +03:00
int32 History : : geomResize ( int32 newWidth , int32 * ytransform , const HistoryItem * resizedItem ) {
2015-09-10 13:30:59 +03:00
if ( width ! = newWidth ) resizedItem = 0 ; // recount all items
if ( width ! = newWidth | | resizedItem ) {
2014-05-30 12:53:19 +04:00
int32 y = 0 ;
2015-09-19 12:13:21 +03:00
for ( Blocks : : iterator i = blocks . begin ( ) , e = blocks . end ( ) ; i ! = e ; + + i ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * block = * i ;
bool updTransform = ytransform & & ( * ytransform > = block - > y ) & & ( * ytransform < block - > y + block - > height ) ;
if ( updTransform ) * ytransform - = block - > y ;
if ( block - > y ! = y ) {
block - > y = y ;
}
2015-09-10 13:30:59 +03:00
y + = block - > geomResize ( newWidth , ytransform , resizedItem ) ;
2014-05-30 12:53:19 +04:00
if ( updTransform ) {
* ytransform + = block - > y ;
ytransform = 0 ;
}
}
width = newWidth ;
height = y ;
}
return height ;
}
2015-09-19 12:13:21 +03:00
ChannelHistory * History : : asChannelHistory ( ) {
return isChannel ( ) ? static_cast < ChannelHistory * > ( this ) : 0 ;
}
const ChannelHistory * History : : asChannelHistory ( ) const {
return isChannel ( ) ? static_cast < const ChannelHistory * > ( this ) : 0 ;
}
2014-07-04 15:12:54 +04:00
void History : : clear ( bool leaveItems ) {
if ( unreadBar ) {
unreadBar - > destroy ( ) ;
}
if ( showFrom ) {
showFrom = 0 ;
}
2015-08-04 18:01:47 +03:00
if ( ! leaveItems ) {
2015-08-07 15:11:50 +03:00
setLastMessage ( 0 ) ;
2015-08-04 18:01:47 +03:00
}
2014-08-15 15:19:32 +04:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
2015-09-19 12:13:21 +03:00
if ( ! overview [ i ] . isEmpty ( ) | | ! overviewIds [ i ] . isEmpty ( ) ) {
2015-08-04 18:01:47 +03:00
if ( leaveItems ) {
2015-11-18 16:11:56 +03:00
if ( overviewCountData [ i ] = = 0 ) {
overviewCountData [ i ] = overview [ i ] . size ( ) ;
}
2015-08-04 18:01:47 +03:00
} else {
2015-11-18 16:11:56 +03:00
overviewCountData [ i ] = - 1 ; // not loaded yet
2015-08-04 18:01:47 +03:00
}
2015-09-19 12:13:21 +03:00
overview [ i ] . clear ( ) ;
overviewIds [ i ] . clear ( ) ;
2015-07-03 11:47:16 +03:00
if ( App : : wnd ( ) & & ! App : : quiting ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , MediaOverviewType ( i ) ) ;
}
2014-08-15 15:19:32 +04:00
}
2015-09-19 12:13:21 +03:00
for ( Blocks : : const_iterator i = blocks . cbegin ( ) , e = blocks . cend ( ) ; i ! = e ; + + i ) {
2014-07-04 15:12:54 +04:00
if ( leaveItems ) {
( * i ) - > clear ( true ) ;
}
2014-05-30 12:53:19 +04:00
delete * i ;
}
2015-09-19 12:13:21 +03:00
blocks . clear ( ) ;
2015-06-17 22:43:03 +03:00
if ( leaveItems ) {
lastKeyboardInited = false ;
} else {
2014-07-04 15:12:54 +04:00
setUnreadCount ( 0 ) ;
}
height = 0 ;
oldLoaded = false ;
2015-09-03 13:48:40 +03:00
if ( peer - > isChat ( ) ) {
2015-06-17 22:43:03 +03:00
peer - > asChat ( ) - > lastAuthors . clear ( ) ;
peer - > asChat ( ) - > markupSenders . clear ( ) ;
2015-09-21 23:57:42 +03:00
} else if ( isChannel ( ) ) {
asChannelHistory ( ) - > cleared ( ) ;
2015-11-09 12:51:22 +03:00
if ( isMegagroup ( ) ) {
peer - > asChannel ( ) - > mgInfo - > markupSenders . clear ( ) ;
}
2015-06-17 22:43:03 +03:00
}
if ( leaveItems & & App : : main ( ) ) App : : main ( ) - > historyCleared ( this ) ;
2014-05-30 12:53:19 +04:00
}
2015-11-18 16:11:56 +03:00
void History : : overviewSliceDone ( int32 overviewIndex , const MTPmessages_Messages & result , bool onlyCounts ) {
const QVector < MTPMessage > * v = 0 ;
switch ( result . type ( ) ) {
case mtpc_messages_messages : {
const MTPDmessages_messages & d ( result . c_messages_messages ( ) ) ;
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
v = & d . vmessages . c_vector ( ) . v ;
overviewCountData [ overviewIndex ] = 0 ;
} break ;
case mtpc_messages_messagesSlice : {
const MTPDmessages_messagesSlice & d ( result . c_messages_messagesSlice ( ) ) ;
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
overviewCountData [ overviewIndex ] = d . vcount . v ;
v = & d . vmessages . c_vector ( ) . v ;
} break ;
case mtpc_messages_channelMessages : {
const MTPDmessages_channelMessages & d ( result . c_messages_channelMessages ( ) ) ;
if ( peer - > isChannel ( ) ) {
peer - > asChannel ( ) - > ptsReceived ( d . vpts . v ) ;
} else {
LOG ( ( " API Error: received messages.channelMessages when no channel was passed! (History::overviewSliceDone, onlyCounts %1) " ) . arg ( logBool ( onlyCounts ) ) ) ;
}
if ( d . has_collapsed ( ) ) { // should not be returned
LOG ( ( " API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (History::overviewSliceDone, onlyCounts %1) " ) . arg ( logBool ( onlyCounts ) ) ) ;
}
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
overviewCountData [ overviewIndex ] = d . vcount . v ;
v = & d . vmessages . c_vector ( ) . v ;
} break ;
default : return ;
}
if ( ! onlyCounts & & v - > isEmpty ( ) ) {
overviewCountData [ overviewIndex ] = 0 ;
} else if ( overviewCountData [ overviewIndex ] > 0 ) {
for ( History : : MediaOverviewIds : : const_iterator i = overviewIds [ overviewIndex ] . cbegin ( ) , e = overviewIds [ overviewIndex ] . cend ( ) ; i ! = e ; + + i ) {
if ( i . key ( ) < 0 ) {
+ + overviewCountData [ overviewIndex ] ;
} else {
break ;
}
}
}
for ( QVector < MTPMessage > : : const_iterator i = v - > cbegin ( ) , e = v - > cend ( ) ; i ! = e ; + + i ) {
HistoryItem * item = App : : histories ( ) . addNewMessage ( * i , NewMessageExisting ) ;
if ( item & & overviewIds [ overviewIndex ] . constFind ( item - > id ) = = overviewIds [ overviewIndex ] . cend ( ) ) {
overviewIds [ overviewIndex ] . insert ( item - > id , NullType ( ) ) ;
overview [ overviewIndex ] . push_front ( item - > id ) ;
}
}
}
void History : : changeMsgId ( MsgId oldId , MsgId newId ) {
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
History : : MediaOverviewIds : : iterator j = overviewIds [ i ] . find ( oldId ) ;
if ( j ! = overviewIds [ i ] . cend ( ) ) {
overviewIds [ i ] . erase ( j ) ;
int32 index = overview [ i ] . indexOf ( oldId ) ;
if ( overviewIds [ i ] . constFind ( newId ) = = overviewIds [ i ] . cend ( ) ) {
overviewIds [ i ] . insert ( newId , NullType ( ) ) ;
if ( index > = 0 ) {
overview [ i ] [ index ] = newId ;
} else {
overview [ i ] . push_back ( newId ) ;
}
} else if ( index > = 0 ) {
overview [ i ] . removeAt ( index ) ;
}
}
}
}
2014-05-30 12:53:19 +04:00
void History : : blockResized ( HistoryBlock * block , int32 dh ) {
2015-09-19 12:13:21 +03:00
int32 i = blocks . indexOf ( block ) , l = blocks . size ( ) ;
2014-05-30 12:53:19 +04:00
if ( i > = 0 ) {
for ( + + i ; i < l ; + + i ) {
2015-09-19 12:13:21 +03:00
blocks [ i ] - > y - = dh ;
2014-05-30 12:53:19 +04:00
}
height - = dh ;
}
}
2015-11-13 18:14:33 +03:00
void History : : clearUpto ( MsgId msgId ) {
for ( HistoryItem * item = isEmpty ( ) ? 0 : blocks . back ( ) - > items . back ( ) ; item & & ( item - > id < 0 | | item - > id > = msgId ) ; item = isEmpty ( ) ? 0 : blocks . back ( ) - > items . back ( ) ) {
item - > destroy ( ) ;
}
}
2014-05-30 12:53:19 +04:00
void History : : removeBlock ( HistoryBlock * block ) {
2015-09-19 12:13:21 +03:00
int32 i = blocks . indexOf ( block ) , h = block - > height ;
2014-05-30 12:53:19 +04:00
if ( i > = 0 ) {
2015-09-19 12:13:21 +03:00
blocks . removeAt ( i ) ;
int32 l = blocks . size ( ) ;
2014-05-30 12:53:19 +04:00
if ( i > 0 & & l = = 1 ) { // only fake block with date left
2015-09-19 12:13:21 +03:00
removeBlock ( blocks [ 0 ] ) ;
2014-05-30 12:53:19 +04:00
height = 0 ;
} else if ( h ) {
for ( ; i < l ; + + i ) {
2015-09-19 12:13:21 +03:00
blocks [ i ] - > y - = h ;
2014-05-30 12:53:19 +04:00
}
height - = h ;
}
}
delete block ;
}
2015-12-22 11:01:02 +03:00
int32 HistoryBlock : : geomResize ( int32 newWidth , int32 * ytransform , const HistoryItem * resizedItem ) {
2014-05-30 12:53:19 +04:00
int32 y = 0 ;
2015-09-19 12:13:21 +03:00
for ( Items : : iterator i = items . begin ( ) , e = items . end ( ) ; i ! = e ; + + i ) {
2014-05-30 12:53:19 +04:00
HistoryItem * item = * i ;
bool updTransform = ytransform & & ( * ytransform > = item - > y ) & & ( * ytransform < item - > y + item - > height ( ) ) ;
if ( updTransform ) * ytransform - = item - > y ;
item - > y = y ;
2015-09-10 13:30:59 +03:00
if ( ! resizedItem | | resizedItem = = item ) {
y + = item - > resize ( newWidth ) ;
} else {
y + = item - > height ( ) ;
}
2014-05-30 12:53:19 +04:00
if ( updTransform ) {
* ytransform + = item - > y ;
ytransform = 0 ;
}
}
height = y ;
return height ;
}
2014-07-04 15:12:54 +04:00
void HistoryBlock : : clear ( bool leaveItems ) {
if ( leaveItems ) {
2015-09-19 12:13:21 +03:00
for ( Items : : const_iterator i = items . cbegin ( ) , e = items . cend ( ) ; i ! = e ; + + i ) {
2014-07-04 15:12:54 +04:00
( * i ) - > detachFast ( ) ;
}
} else {
2015-09-19 12:13:21 +03:00
for ( Items : : const_iterator i = items . cbegin ( ) , e = items . cend ( ) ; i ! = e ; + + i ) {
2014-07-04 15:12:54 +04:00
delete * i ;
}
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
items . clear ( ) ;
2014-05-30 12:53:19 +04:00
}
void HistoryBlock : : removeItem ( HistoryItem * item ) {
2015-09-19 12:13:21 +03:00
int32 i = items . indexOf ( item ) , dh = 0 ;
2014-05-30 12:53:19 +04:00
if ( history - > showFrom = = item ) {
history - > getNextShowFrom ( this , i ) ;
}
if ( i < 0 ) {
return ;
}
bool createInitialDate = false ;
QDateTime initialDateTime ;
2015-09-19 12:13:21 +03:00
int32 myIndex = history - > blocks . indexOf ( this ) ;
if ( myIndex > = 0 & & item - > type ( ) ! = HistoryItemDate ) { // fix message groups and date items
if ( item - > isImportant ( ) ) { // unite message groups around this important message
HistoryGroup * nextGroup = 0 , * prevGroup = 0 ;
HistoryCollapse * nextCollapse = 0 ;
HistoryItem * prevItem = 0 ;
for ( int32 nextBlock = myIndex , nextIndex = qMin ( items . size ( ) , i + 1 ) ; nextBlock < history - > blocks . size ( ) ; + + nextBlock ) {
HistoryBlock * block = history - > blocks . at ( nextBlock ) ;
for ( ; nextIndex < block - > items . size ( ) ; + + nextIndex ) {
HistoryItem * item = block - > items . at ( nextIndex ) ;
if ( item - > type ( ) = = HistoryItemMsg ) {
break ;
} else if ( item - > type ( ) = = HistoryItemGroup ) {
nextGroup = static_cast < HistoryGroup * > ( item ) ;
break ;
} else if ( item - > type ( ) = = HistoryItemCollapse ) {
nextCollapse = static_cast < HistoryCollapse * > ( item ) ;
break ;
}
}
if ( nextIndex = = block - > items . size ( ) ) {
nextIndex = 0 ;
} else {
break ;
}
}
for ( int32 prevBlock = myIndex + 1 , prevIndex = qMax ( 1 , i ) ; prevBlock > 0 ; ) {
- - prevBlock ;
HistoryBlock * block = history - > blocks . at ( prevBlock ) ;
if ( ! prevIndex ) prevIndex = block - > items . size ( ) ;
for ( ; prevIndex > 0 ; ) {
- - prevIndex ;
HistoryItem * item = block - > items . at ( prevIndex ) ;
if ( item - > type ( ) = = HistoryItemMsg | | item - > type ( ) = = HistoryItemCollapse ) {
prevItem = item ;
+ + prevIndex ;
break ;
} else if ( item - > type ( ) = = HistoryItemGroup ) {
prevGroup = static_cast < HistoryGroup * > ( item ) ;
+ + prevIndex ;
break ;
}
}
if ( prevIndex ! = 0 ) {
break ;
}
}
if ( nextGroup & & prevGroup ) {
prevGroup - > uniteWith ( nextGroup ) ;
nextGroup - > destroy ( ) ;
} else if ( nextCollapse & & ( ! prevItem | | ! prevItem - > isImportant ( ) ) ) {
nextCollapse - > destroy ( ) ;
}
}
// fix date items
HistoryItem * nextItem = ( i < items . size ( ) - 1 ) ? items [ i + 1 ] : ( ( myIndex < history - > blocks . size ( ) - 1 ) ? history - > blocks [ myIndex + 1 ] - > items [ 0 ] : 0 ) ;
2014-05-30 12:53:19 +04:00
if ( nextItem & & nextItem = = history - > unreadBar ) { // skip unread bar
2015-09-19 12:13:21 +03:00
if ( i < items . size ( ) - 2 ) {
nextItem = items [ i + 2 ] ;
} else if ( i < items . size ( ) - 1 ) {
nextItem = ( ( myIndex < history - > blocks . size ( ) - 1 ) ? history - > blocks [ myIndex + 1 ] - > items [ 0 ] : 0 ) ;
} else if ( myIndex < history - > blocks . size ( ) - 1 ) {
if ( 0 < history - > blocks [ myIndex + 1 ] - > items . size ( ) - 1 ) {
nextItem = history - > blocks [ myIndex + 1 ] - > items [ 1 ] ;
} else if ( myIndex < history - > blocks . size ( ) - 2 ) {
nextItem = history - > blocks [ myIndex + 2 ] - > items [ 0 ] ;
2014-05-30 12:53:19 +04:00
} else {
nextItem = 0 ;
}
} else {
nextItem = 0 ;
}
}
2015-09-19 12:13:21 +03:00
if ( ! nextItem | | nextItem - > type ( ) = = HistoryItemDate ) { // only if there is no next item or it is a date item
HistoryItem * prevItem = ( i > 0 ) ? items [ i - 1 ] : 0 ;
2014-05-30 12:53:19 +04:00
if ( prevItem & & prevItem = = history - > unreadBar ) { // skip unread bar
2015-09-19 12:13:21 +03:00
prevItem = ( i > 1 ) ? items [ i - 2 ] : 0 ;
2014-05-30 12:53:19 +04:00
}
if ( prevItem ) {
2015-09-19 12:13:21 +03:00
if ( prevItem - > type ( ) = = HistoryItemDate ) {
2014-05-30 12:53:19 +04:00
prevItem - > destroy ( ) ;
- - i ;
}
} else if ( myIndex > 0 ) {
2015-09-19 12:13:21 +03:00
HistoryBlock * prevBlock = history - > blocks [ myIndex - 1 ] ;
if ( prevBlock - > items . isEmpty ( ) | | ( ( myIndex = = 1 ) & & ( prevBlock - > items . size ( ) ! = 1 | | prevBlock - > items . front ( ) - > type ( ) ! = HistoryItemDate ) ) ) {
LOG ( ( " App Error: Found bad history, with no first date block: %1 " ) . arg ( history - > blocks [ 0 ] - > items . size ( ) ) ) ;
} else if ( prevBlock - > items [ prevBlock - > items . size ( ) - 1 ] - > type ( ) = = HistoryItemDate ) {
prevBlock - > items [ prevBlock - > items . size ( ) - 1 ] - > destroy ( ) ;
2014-05-30 12:53:19 +04:00
if ( nextItem & & myIndex = = 1 ) { // destroy next date (for creating initial then)
initialDateTime = nextItem - > date ;
createInitialDate = true ;
nextItem - > destroy ( ) ;
}
}
}
}
}
// myIndex can be invalid now, because of destroying previous blocks
dh = item - > height ( ) ;
2015-09-19 12:13:21 +03:00
items . remove ( i ) ;
int32 l = items . size ( ) ;
2015-09-13 20:27:29 +03:00
if ( ( ! item - > out ( ) | | item - > fromChannel ( ) ) & & item - > unread ( ) & & history - > unreadCount ) {
2014-05-30 12:53:19 +04:00
history - > setUnreadCount ( history - > unreadCount - 1 ) ;
}
2015-09-19 12:13:21 +03:00
int32 itemType = item - > type ( ) ;
2015-09-20 11:55:41 +03:00
if ( itemType = = HistoryItemUnreadBar ) {
2014-05-30 12:53:19 +04:00
if ( history - > unreadBar = = item ) {
history - > unreadBar = 0 ;
}
}
if ( createInitialDate ) {
history - > createInitialDateBlock ( initialDateTime ) ;
}
History * h = history ;
if ( l ) {
for ( ; i < l ; + + i ) {
2015-09-19 12:13:21 +03:00
items [ i ] - > y - = dh ;
2014-05-30 12:53:19 +04:00
}
height - = dh ;
history - > blockResized ( this , dh ) ;
} else {
history - > removeBlock ( this ) ;
}
}
2015-03-19 12:18:19 +03:00
HistoryItem : : HistoryItem ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime msgDate , int32 from ) : y ( 0 )
2014-06-16 13:31:10 +04:00
, id ( msgId )
, date ( msgDate )
2015-09-04 16:01:31 +03:00
, _from ( from ? App : : user ( from ) : history - > peer )
2014-06-16 13:31:10 +04:00
, _fromVersion ( _from - > nameVersion )
, _history ( history )
, _block ( block )
2015-03-19 12:18:19 +03:00
, _flags ( flags )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
}
2014-08-11 13:03:45 +04:00
void HistoryItem : : destroy ( ) {
bool wasAtBottom = history ( ) - > loadedAtBottom ( ) ;
_history - > removeNotification ( this ) ;
detach ( ) ;
2015-09-19 12:13:21 +03:00
if ( history ( ) - > isChannel ( ) ) {
history ( ) - > asChannelHistory ( ) - > messageDeleted ( this ) ;
}
2015-06-15 20:19:24 +03:00
if ( history ( ) - > lastMsg = = this ) {
2014-08-11 13:03:45 +04:00
history ( ) - > fixLastMessage ( wasAtBottom ) ;
}
2015-10-03 13:09:09 +03:00
if ( history ( ) - > lastKeyboardId = = id ) {
2015-11-24 19:19:18 +03:00
history ( ) - > clearLastKeyboard ( ) ;
if ( App : : main ( ) ) App : : main ( ) - > updateBotKeyboard ( history ( ) ) ;
2015-10-03 13:09:09 +03:00
}
2014-08-11 13:03:45 +04:00
HistoryMedia * m = getMedia ( true ) ;
2014-08-15 15:19:32 +04:00
MediaOverviewType t = m ? mediaToOverviewType ( m - > type ( ) ) : OverviewCount ;
2015-07-03 11:47:16 +03:00
if ( t ! = OverviewCount ) {
2015-12-19 00:36:16 +03:00
if ( m - > type ( ) = = MediaTypeDocument & & static_cast < HistoryDocument * > ( m ) - > getDocument ( ) - > song ( ) ) {
2015-07-03 11:47:16 +03:00
history ( ) - > eraseFromOverview ( OverviewAudioDocuments , id ) ;
2015-09-13 20:27:29 +03:00
} else {
history ( ) - > eraseFromOverview ( t , id ) ;
2014-08-11 13:03:45 +04:00
}
}
2015-08-21 14:23:44 +03:00
if ( hasTextLinks ( ) ) {
history ( ) - > eraseFromOverview ( OverviewLinks , id ) ;
}
2014-08-11 13:03:45 +04:00
delete this ;
}
2014-07-04 15:12:54 +04:00
void HistoryItem : : detach ( ) {
2015-09-19 12:13:21 +03:00
if ( _history ) {
if ( _history - > unreadBar = = this ) {
_history - > unreadBar = 0 ;
}
if ( _history - > isChannel ( ) ) {
_history - > asChannelHistory ( ) - > messageDetached ( this ) ;
}
2014-07-04 15:12:54 +04:00
}
if ( _block ) {
_block - > removeItem ( this ) ;
detachFast ( ) ;
App : : historyItemDetached ( this ) ;
} else {
if ( _history - > showFrom = = this ) {
_history - > showFrom = 0 ;
}
}
2015-09-19 12:13:21 +03:00
if ( _history & & _history - > unreadBar & & _history - > blocks . back ( ) - > items . back ( ) = = _history - > unreadBar ) {
2014-07-04 15:12:54 +04:00
_history - > unreadBar - > destroy ( ) ;
}
}
void HistoryItem : : detachFast ( ) {
_block = 0 ;
}
2015-11-18 16:11:56 +03:00
void HistoryItem : : setId ( MsgId newId ) {
history ( ) - > changeMsgId ( id , newId ) ;
id = newId ;
}
2014-05-30 12:53:19 +04:00
HistoryItem : : ~ HistoryItem ( ) {
App : : historyUnregItem ( this ) ;
2015-12-28 20:23:27 +03:00
if ( id < 0 & & App : : uploader ( ) ) {
App : : uploader ( ) - > cancel ( fullId ( ) ) ;
2014-05-30 12:53:19 +04:00
}
}
2015-12-23 15:55:32 +03:00
HistoryItem * regItem ( HistoryItem * item ) {
if ( item ) {
App : : historyRegItem ( item ) ;
item - > initDimensions ( ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
return item ;
2014-05-30 12:53:19 +04:00
}
2015-12-22 15:49:42 +03:00
RadialAnimation : : RadialAnimation ( AnimationCallbacks * callbacks )
: _firstStart ( 0 )
2015-12-11 21:11:38 +03:00
, _lastStart ( 0 )
, _lastTime ( 0 )
, _opacity ( 0 )
, a_arcEnd ( 0 , 0 )
2015-12-13 01:29:33 +03:00
, a_arcStart ( 0 , FullArcLength )
2015-12-11 21:11:38 +03:00
, _animation ( callbacks ) {
}
void RadialAnimation : : start ( float64 prg ) {
_firstStart = _lastStart = _lastTime = getms ( ) ;
2015-12-13 01:29:33 +03:00
int32 iprg = qRound ( qMax ( prg , 0.0001 ) * AlmostFullArcLength ) , iprgstrict = qRound ( prg * AlmostFullArcLength ) ;
a_arcEnd = anim : : ivalue ( iprgstrict , iprg ) ;
2015-12-11 21:11:38 +03:00
_animation . start ( ) ;
}
void RadialAnimation : : update ( float64 prg , bool finished , uint64 ms ) {
2015-12-13 01:29:33 +03:00
int32 iprg = qRound ( qMax ( prg , 0.0001 ) * AlmostFullArcLength ) ;
if ( iprg ! = a_arcEnd . to ( ) ) {
a_arcEnd . start ( iprg ) ;
2015-12-11 21:11:38 +03:00
_lastStart = _lastTime ;
}
_lastTime = ms ;
float64 dt = float64 ( ms - _lastStart ) , fulldt = float64 ( ms - _firstStart ) ;
_opacity = qMin ( fulldt / st : : radialDuration , 1. ) ;
if ( ! finished ) {
a_arcEnd . update ( 1. - ( st : : radialDuration / ( st : : radialDuration + dt ) ) , anim : : linear ) ;
} else if ( dt > = st : : radialDuration ) {
a_arcEnd . update ( 1 , anim : : linear ) ;
stop ( ) ;
} else {
float64 r = dt / st : : radialDuration ;
a_arcEnd . update ( r , anim : : linear ) ;
_opacity * = 1 - r ;
}
float64 fromstart = fulldt / st : : radialPeriod ;
a_arcStart . update ( fromstart - qFloor ( fromstart ) , anim : : linear ) ;
}
void RadialAnimation : : stop ( ) {
_firstStart = _lastStart = _lastTime = 0 ;
2015-12-13 01:29:33 +03:00
a_arcEnd = anim : : ivalue ( 0 , 0 ) ;
2015-12-11 21:11:38 +03:00
_animation . stop ( ) ;
}
2015-12-13 01:29:33 +03:00
void RadialAnimation : : step ( uint64 ms ) {
_animation . step ( ms ) ;
}
2015-12-11 21:11:38 +03:00
2015-12-22 15:49:42 +03:00
void RadialAnimation : : draw ( Painter & p , const QRect & inner , int32 thickness , const style : : color & color ) {
2015-12-11 21:11:38 +03:00
float64 o = p . opacity ( ) ;
p . setOpacity ( o * _opacity ) ;
QPen pen ( color - > p ) , was ( p . pen ( ) ) ;
2015-12-22 15:49:42 +03:00
pen . setWidth ( thickness ) ;
2015-12-11 21:11:38 +03:00
p . setPen ( pen ) ;
2015-12-13 01:29:33 +03:00
int32 len = MinArcLength + a_arcEnd . current ( ) ;
int32 from = QuarterArcLength - a_arcStart . current ( ) - len ;
if ( rtl ( ) ) {
from = QuarterArcLength - ( from - QuarterArcLength ) - len ;
if ( from < 0 ) from + = FullArcLength ;
}
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawArc ( inner , from , len ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
2015-12-11 21:11:38 +03:00
p . setPen ( was ) ;
p . setOpacity ( o ) ;
}
2015-12-25 16:09:14 +03:00
namespace {
int32 videoMaxStatusWidth ( VideoData * video ) {
int32 result = st : : normalFont - > width ( formatDownloadText ( video - > size , video - > size ) ) ;
result = qMax ( result , st : : normalFont - > width ( formatDurationAndSizeText ( video - > duration , video - > size ) ) ) ;
return result ;
}
int32 audioMaxStatusWidth ( AudioData * audio ) {
int32 result = st : : normalFont - > width ( formatDownloadText ( audio - > size , audio - > size ) ) ;
result = qMax ( result , st : : normalFont - > width ( formatPlayedText ( audio - > duration , audio - > duration ) ) ) ;
result = qMax ( result , st : : normalFont - > width ( formatDurationAndSizeText ( audio - > duration , audio - > size ) ) ) ;
return result ;
}
int32 documentMaxStatusWidth ( DocumentData * document ) {
int32 result = st : : normalFont - > width ( formatDownloadText ( document - > size , document - > size ) ) ;
if ( SongData * song = document - > song ( ) ) {
result = qMax ( result , st : : normalFont - > width ( formatPlayedText ( song - > duration , song - > duration ) ) ) ;
result = qMax ( result , st : : normalFont - > width ( formatDurationAndSizeText ( song - > duration , document - > size ) ) ) ;
} else {
result = qMax ( result , st : : normalFont - > width ( formatSizeText ( document - > size ) ) ) ;
}
return result ;
}
int32 gifMaxStatusWidth ( DocumentData * document ) {
int32 result = st : : normalFont - > width ( formatDownloadText ( document - > size , document - > size ) ) ;
result = qMax ( result , st : : normalFont - > width ( formatGifAndSizeText ( document - > size ) ) ) ;
return result ;
}
}
HistoryFileMedia : : HistoryFileMedia ( ) : HistoryMedia ( )
, _animation ( 0 ) {
}
void HistoryFileMedia : : linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) {
if ( ( lnk = = _savel | | lnk = = _cancell ) & & ! dataLoaded ( ) ) {
ensureAnimation ( parent ) ;
_animation - > a_thumbOver . start ( 1 ) ;
_animation - > _a_thumbOver . start ( ) ;
}
}
void HistoryFileMedia : : linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) {
if ( _animation & & ( lnk = = _savel | | lnk = = _cancell ) ) {
_animation - > a_thumbOver . start ( 0 ) ;
_animation - > _a_thumbOver . start ( ) ;
}
}
void HistoryFileMedia : : setLinks ( ITextLink * openl , ITextLink * savel , ITextLink * cancell ) {
_openl . reset ( openl ) ;
_savel . reset ( savel ) ;
_cancell . reset ( cancell ) ;
}
void HistoryFileMedia : : setStatusSize ( int32 newSize , int32 fullSize , int32 duration , qint64 realDuration ) const {
_statusSize = newSize ;
if ( _statusSize = = FileStatusSizeReady ) {
_statusText = ( duration > = 0 ) ? formatDurationAndSizeText ( duration , fullSize ) : ( duration < - 1 ? formatGifAndSizeText ( fullSize ) : formatSizeText ( fullSize ) ) ;
} else if ( _statusSize = = FileStatusSizeLoaded ) {
_statusText = ( duration > = 0 ) ? formatDurationText ( duration ) : ( duration < - 1 ? qsl ( " GIF " ) : formatSizeText ( fullSize ) ) ;
} else if ( _statusSize = = FileStatusSizeFailed ) {
_statusText = lang ( lng_attach_failed ) ;
} else if ( _statusSize > = 0 ) {
_statusText = formatDownloadText ( _statusSize , fullSize ) ;
} else {
_statusText = formatPlayedText ( - _statusSize - 1 , realDuration ) ;
}
}
void HistoryFileMedia : : step_thumbOver ( const HistoryItem * parent , float64 ms , bool timer ) {
float64 dt = ms / st : : msgFileOverDuration ;
if ( dt > = 1 ) {
_animation - > a_thumbOver . finish ( ) ;
_animation - > _a_thumbOver . stop ( ) ;
checkAnimationFinished ( ) ;
2015-12-28 00:37:48 +03:00
} else if ( ! timer ) {
2015-12-25 16:09:14 +03:00
_animation - > a_thumbOver . update ( dt , anim : : linear ) ;
}
if ( timer ) {
2015-12-28 00:37:48 +03:00
Ui : : repaintHistoryItem ( parent ) ;
2015-12-25 16:09:14 +03:00
}
}
void HistoryFileMedia : : step_radial ( const HistoryItem * parent , uint64 ms , bool timer ) {
if ( timer ) {
2015-12-28 00:37:48 +03:00
Ui : : repaintHistoryItem ( parent ) ;
} else {
_animation - > radial . update ( dataProgress ( ) , dataFinished ( ) , ms ) ;
if ( ! _animation - > radial . animating ( ) ) {
checkAnimationFinished ( ) ;
}
2015-12-25 16:09:14 +03:00
}
}
void HistoryFileMedia : : ensureAnimation ( const HistoryItem * parent ) const {
if ( ! _animation ) {
_animation = new AnimationData (
animation ( parent , const_cast < HistoryFileMedia * > ( this ) , & HistoryFileMedia : : step_thumbOver ) ,
animation ( parent , const_cast < HistoryFileMedia * > ( this ) , & HistoryFileMedia : : step_radial ) ) ;
}
}
void HistoryFileMedia : : checkAnimationFinished ( ) {
if ( _animation & & ! _animation - > _a_thumbOver . animating ( ) & & ! _animation - > radial . animating ( ) ) {
if ( dataLoaded ( ) ) {
delete _animation ;
_animation = 0 ;
}
}
}
HistoryFileMedia : : ~ HistoryFileMedia ( ) {
if ( _animation ) {
delete _animation ;
setBadPointer ( _animation ) ;
}
}
2015-12-24 22:26:28 +03:00
HistoryPhoto : : HistoryPhoto ( const MTPDphoto & photo , const QString & caption , HistoryItem * parent ) : HistoryFileMedia ( )
2015-12-09 21:06:20 +03:00
, _data ( App : : feedPhoto ( photo ) )
, _pixw ( 1 )
, _pixh ( 1 )
2015-12-13 18:21:20 +03:00
, _caption ( st : : minPhotoSize - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) {
2015-12-25 16:09:14 +03:00
setLinks ( new PhotoLink ( _data ) , new PhotoSaveLink ( _data ) , new PhotoCancelLink ( _data ) ) ;
2015-12-24 22:26:28 +03:00
2015-04-30 16:53:36 +03:00
if ( ! caption . isEmpty ( ) ) {
2015-10-23 18:06:56 +02:00
_caption . setText ( st : : msgFont , caption + parent - > skipBlock ( ) , itemTextNoMonoOptions ( parent ) ) ;
2015-04-30 16:53:36 +03:00
}
2014-08-11 13:03:45 +04:00
init ( ) ;
}
2015-12-24 22:26:28 +03:00
HistoryPhoto : : HistoryPhoto ( PhotoData * photo ) : HistoryFileMedia ( )
2015-12-19 00:36:16 +03:00
, _data ( photo )
, _pixw ( 1 )
, _pixh ( 1 ) {
2015-12-25 16:09:14 +03:00
setLinks ( new PhotoLink ( _data ) , new PhotoSaveLink ( _data ) , new PhotoCancelLink ( _data ) ) ;
2015-12-24 22:26:28 +03:00
2015-12-19 00:36:16 +03:00
init ( ) ;
}
2015-12-24 22:26:28 +03:00
HistoryPhoto : : HistoryPhoto ( PeerData * chat , const MTPDphoto & photo , int32 width ) : HistoryFileMedia ( )
2015-12-09 21:06:20 +03:00
, _data ( App : : feedPhoto ( photo ) )
, _pixw ( 1 )
2015-12-13 18:21:20 +03:00
, _pixh ( 1 ) {
2015-12-25 16:09:14 +03:00
setLinks ( new PhotoLink ( _data , chat ) , new PhotoSaveLink ( _data , chat ) , new PhotoCancelLink ( _data ) ) ;
2015-12-24 22:26:28 +03:00
2015-12-19 21:09:24 +03:00
_width = width ;
2014-08-11 13:03:45 +04:00
init ( ) ;
}
2015-12-24 22:26:28 +03:00
HistoryPhoto : : HistoryPhoto ( const HistoryPhoto & other ) : HistoryFileMedia ( )
, _data ( other . _data )
, _pixw ( other . _pixw )
2015-12-24 23:29:33 +03:00
, _pixh ( other . _pixh )
, _caption ( other . _caption ) {
2015-12-25 16:09:14 +03:00
setLinks ( new PhotoLink ( _data ) , new PhotoSaveLink ( _data ) , new PhotoCancelLink ( _data ) ) ;
2015-12-24 22:26:28 +03:00
init ( ) ;
}
2014-08-11 13:03:45 +04:00
void HistoryPhoto : : init ( ) {
2015-12-09 21:06:20 +03:00
_data - > thumb - > load ( ) ;
2014-10-10 16:46:20 +04:00
}
void HistoryPhoto : : initDimensions ( const HistoryItem * parent ) {
2015-12-09 21:06:20 +03:00
if ( _caption . hasSkipBlock ( ) ) {
_caption . setSkipBlock ( parent - > skipBlockWidth ( ) , parent - > skipBlockHeight ( ) ) ;
}
int32 tw = convertScale ( _data - > full - > width ( ) ) , th = convertScale ( _data - > full - > height ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
2015-12-09 21:06:20 +03:00
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
if ( th > st : : maxMediaSize ) {
tw = ( st : : maxMediaSize * tw ) / th ;
th = st : : maxMediaSize ;
}
if ( parent - > toHistoryMessage ( ) ) {
2015-12-19 15:27:03 +03:00
bool bubble = parent - > hasBubble ( ) ;
2015-12-19 21:09:24 +03:00
2015-12-13 18:21:20 +03:00
int32 minWidth = qMax ( st : : minPhotoSize , parent - > infoWidth ( ) + 2 * ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
2015-12-19 21:09:24 +03:00
int32 maxActualWidth = qMax ( tw , minWidth ) ;
2015-12-13 18:21:20 +03:00
_maxw = qMax ( maxActualWidth , th ) ;
_minh = qMax ( th , int32 ( st : : minPhotoSize ) ) ;
if ( bubble ) {
maxActualWidth + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_maxw + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_minh + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
if ( ! _caption . isEmpty ( ) ) {
_minh + = st : : mediaCaptionSkip + _caption . countHeight ( maxActualWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
}
}
2014-11-18 15:41:33 +03:00
} else {
2015-12-19 21:09:24 +03:00
_maxw = _minh = _width ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
}
2015-09-10 13:30:59 +03:00
int32 HistoryPhoto : : resize ( int32 width , const HistoryItem * parent ) {
2015-12-09 21:06:20 +03:00
bool bubble = parent - > hasBubble ( ) ;
2014-11-12 23:18:00 +03:00
2015-12-09 21:06:20 +03:00
int32 tw = convertScale ( _data - > full - > width ( ) ) , th = convertScale ( _data - > full - > height ( ) ) ;
2014-11-18 15:41:33 +03:00
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
2014-11-18 15:59:16 +03:00
if ( th > st : : maxMediaSize ) {
tw = ( st : : maxMediaSize * tw ) / th ;
th = st : : maxMediaSize ;
}
2015-12-09 21:06:20 +03:00
_pixw = qMin ( width , _maxw ) ;
if ( bubble ) {
_pixw - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
_pixh = th ;
if ( tw > _pixw ) {
_pixh = ( _pixw * _pixh / tw ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-12-09 21:06:20 +03:00
_pixw = tw ;
2014-11-12 23:18:00 +03:00
}
2015-12-09 21:06:20 +03:00
if ( _pixh > width ) {
_pixw = ( _pixw * width ) / _pixh ;
_pixh = width ;
2014-11-12 23:18:00 +03:00
}
2015-12-09 21:06:20 +03:00
if ( _pixw < 1 ) _pixw = 1 ;
if ( _pixh < 1 ) _pixh = 1 ;
2015-12-13 18:21:20 +03:00
int32 minWidth = qMax ( st : : minPhotoSize , parent - > infoWidth ( ) + 2 * ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
2015-12-19 21:09:24 +03:00
_width = qMax ( _pixw , int16 ( minWidth ) ) ;
2015-12-09 21:06:20 +03:00
_height = qMax ( _pixh , int16 ( st : : minPhotoSize ) ) ;
if ( bubble ) {
2015-12-19 21:09:24 +03:00
_width + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-12-09 21:06:20 +03:00
_height + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _caption . isEmpty ( ) ) {
2015-12-19 21:09:24 +03:00
int32 captionw = _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-12-09 21:06:20 +03:00
_height + = st : : mediaCaptionSkip + _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
2015-04-30 16:53:36 +03:00
}
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
return _height ;
}
2015-12-19 21:09:24 +03:00
void HistoryPhoto : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2015-12-24 22:26:28 +03:00
_data - > automaticLoad ( parent ) ;
bool loaded = _data - > loaded ( ) , displayLoading = _data - > displayLoading ( ) ;
bool notChild = ( parent - > getMedia ( ) = = this ) ;
2015-12-19 21:09:24 +03:00
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
bool bubble = parent - > hasBubble ( ) ;
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2014-05-30 12:53:19 +04:00
2015-12-19 21:09:24 +03:00
int32 captionw = width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-12-24 22:26:28 +03:00
if ( displayLoading ) {
ensureAnimation ( parent ) ;
if ( ! _animation - > radial . animating ( ) ) {
_animation - > radial . start ( _data - > progress ( ) ) ;
}
}
bool radial = isRadialAnimation ( ms ) ;
2015-12-19 21:09:24 +03:00
if ( bubble ) {
skipx = st : : mediaPadding . left ( ) ;
skipy = st : : mediaPadding . top ( ) ;
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
height - = skipy + st : : mediaPadding . bottom ( ) ;
if ( ! _caption . isEmpty ( ) ) {
height - = st : : mediaCaptionSkip + _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
}
} else {
App : : roundShadow ( p , 0 , 0 , width , height , selected ? st : : msgInShadowSelected : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
}
QPixmap pix ;
2015-12-24 22:26:28 +03:00
if ( loaded ) {
2015-12-19 21:09:24 +03:00
pix = _data - > full - > pixSingle ( _pixw , _pixh , width , height ) ;
} else {
pix = _data - > thumb - > pixBlurredSingle ( _pixw , _pixh , width , height ) ;
}
2015-12-24 22:26:28 +03:00
QRect rthumb ( rtlrect ( skipx , skipy , width , height , _width ) ) ;
p . drawPixmap ( rthumb . topLeft ( ) , pix ) ;
if ( selected ) {
App : : roundRect ( p , rthumb , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
2015-05-20 22:28:24 +03:00
2015-12-24 22:26:28 +03:00
if ( notChild & & ( radial | | ( ! loaded & & ! _data - > loading ( ) ) ) ) {
float64 radialOpacity = ( radial & & loaded & & ! _data - > uploading ( ) ) ? _animation - > radial . opacity ( ) : 1 ;
QRect inner ( rthumb . x ( ) + ( rthumb . width ( ) - st : : msgFileSize ) / 2 , rthumb . y ( ) + ( rthumb . height ( ) - st : : msgFileSize ) / 2 , st : : msgFileSize , st : : msgFileSize ) ;
p . setPen ( Qt : : NoPen ) ;
if ( selected ) {
p . setBrush ( st : : msgDateImgBgSelected ) ;
2015-12-28 00:37:48 +03:00
} else if ( isThumbAnimation ( ms ) ) {
2015-12-24 22:26:28 +03:00
float64 over = _animation - > a_thumbOver . current ( ) ;
p . setOpacity ( ( st : : msgDateImgBg - > c . alphaF ( ) * ( 1 - over ) ) + ( st : : msgDateImgBgOver - > c . alphaF ( ) * over ) ) ;
p . setBrush ( st : : black ) ;
} else {
bool over = textlnkDrawOver ( _data - > loading ( ) ? _cancell : _savel ) ;
p . setBrush ( over ? st : : msgDateImgBgOver : st : : msgDateImgBg ) ;
}
2015-12-19 21:09:24 +03:00
2015-12-24 22:26:28 +03:00
p . setOpacity ( radialOpacity * p . opacity ( ) ) ;
2015-12-19 21:09:24 +03:00
2015-12-24 22:26:28 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawEllipse ( inner ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
2015-12-19 21:09:24 +03:00
2015-12-24 22:26:28 +03:00
p . setOpacity ( radial ? _animation - > radial . opacity ( ) : 1 ) ;
p . setOpacity ( radialOpacity ) ;
style : : sprite icon ;
if ( radial | | _data - > loading ( ) ) {
icon = ( selected ? st : : msgFileInCancelSelected : st : : msgFileInCancel ) ;
} else {
icon = ( selected ? st : : msgFileInDownloadSelected : st : : msgFileInDownload ) ;
}
p . drawSpriteCenter ( inner , icon ) ;
if ( radial ) {
p . setOpacity ( 1 ) ;
QRect rinner ( inner . marginsRemoved ( QMargins ( st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine ) ) ) ;
_animation - > radial . draw ( p , rinner , st : : msgFileRadialLine , selected ? st : : msgInBgSelected : st : : msgInBg ) ;
}
2015-12-19 21:09:24 +03:00
}
// date
if ( _caption . isEmpty ( ) ) {
2015-12-24 22:26:28 +03:00
if ( notChild ) {
2015-12-19 21:09:24 +03:00
int32 fullRight = skipx + width , fullBottom = skipy + height ;
parent - > drawInfo ( p , fullRight , fullBottom , 2 * skipx + width , selected , InfoDisplayOverImage ) ;
}
} else {
p . setPen ( st : : black ) ;
_caption . draw ( p , st : : msgPadding . left ( ) , skipy + height + st : : mediaPadding . bottom ( ) + st : : mediaCaptionSkip , captionw ) ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
void HistoryPhoto : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
2015-12-09 21:06:20 +03:00
bool bubble = parent - > hasBubble ( ) ;
if ( bubble ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-12-09 21:06:20 +03:00
skipy = st : : mediaPadding . top ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _caption . isEmpty ( ) ) {
2015-12-09 21:06:20 +03:00
int32 captionw = width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
height - = _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
if ( x > = st : : msgPadding . left ( ) & & y > = height & & x < st : : msgPadding . left ( ) + captionw & & y < _height ) {
2015-06-27 16:02:00 +03:00
bool inText = false ;
2015-12-09 21:06:20 +03:00
_caption . getState ( lnk , inText , x - st : : msgPadding . left ( ) , y - height , captionw ) ;
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
2015-12-28 13:28:00 +03:00
return ;
2015-04-30 16:53:36 +03:00
}
2015-12-09 21:06:20 +03:00
height - = st : : mediaCaptionSkip ;
2015-04-30 16:53:36 +03:00
}
2015-12-09 21:06:20 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-08-31 17:27:20 +03:00
if ( x > = skipx & & y > = skipy & & x < skipx + width & & y < skipy + height ) {
2015-12-24 22:26:28 +03:00
if ( _data - > uploading ( ) ) {
lnk = _cancell ;
} else {
lnk = _data - > loaded ( ) ? _openl : ( _data - > loading ( ) ? _cancell : _savel ) ;
}
2015-12-19 00:36:16 +03:00
if ( _caption . isEmpty ( ) & & parent - > getMedia ( ) = = this ) {
2015-12-09 21:06:20 +03:00
int32 fullRight = skipx + width , fullBottom = skipy + height ;
2015-09-15 11:50:54 +03:00
bool inDate = parent - > pointInTime ( fullRight , fullBottom , x , y , InfoDisplayOverImage ) ;
2015-08-31 17:27:20 +03:00
if ( inDate ) {
state = HistoryInDateCursorState ;
}
}
2015-04-08 02:03:32 +03:00
return ;
2014-05-30 12:53:19 +04:00
}
}
2015-12-13 01:29:33 +03:00
void HistoryPhoto : : updateFrom ( const MTPMessageMedia & media , HistoryItem * parent , bool allowEmitResize ) {
2014-11-22 12:45:04 +03:00
if ( media . type ( ) = = mtpc_messageMediaPhoto ) {
const MTPPhoto & photo ( media . c_messageMediaPhoto ( ) . vphoto ) ;
2015-12-24 22:26:28 +03:00
App : : feedPhoto ( photo , _data ) ;
2014-11-22 12:45:04 +03:00
if ( photo . type ( ) = = mtpc_photo ) {
const QVector < MTPPhotoSize > & sizes ( photo . c_photo ( ) . vsizes . c_vector ( ) . v ) ;
2015-12-24 22:26:28 +03:00
int32 max = 0 ;
const MTPDfileLocation * maxLocation = 0 ;
for ( int32 i = 0 , l = sizes . size ( ) ; i < l ; + + i ) {
2014-11-22 12:45:04 +03:00
char size = 0 ;
const MTPFileLocation * loc = 0 ;
2015-12-24 22:26:28 +03:00
switch ( sizes . at ( i ) . type ( ) ) {
2014-11-22 12:45:04 +03:00
case mtpc_photoSize : {
2015-12-24 22:26:28 +03:00
const string & s ( sizes . at ( i ) . c_photoSize ( ) . vtype . c_string ( ) . v ) ;
loc = & sizes . at ( i ) . c_photoSize ( ) . vlocation ;
2014-11-22 12:45:04 +03:00
if ( s . size ( ) ) size = s [ 0 ] ;
} break ;
case mtpc_photoCachedSize : {
2015-12-24 22:26:28 +03:00
const string & s ( sizes . at ( i ) . c_photoCachedSize ( ) . vtype . c_string ( ) . v ) ;
loc = & sizes . at ( i ) . c_photoCachedSize ( ) . vlocation ;
2014-11-22 12:45:04 +03:00
if ( s . size ( ) ) size = s [ 0 ] ;
} break ;
}
if ( ! loc | | loc - > type ( ) ! = mtpc_fileLocation ) continue ;
if ( size = = ' s ' ) {
2015-12-09 21:06:20 +03:00
Local : : writeImage ( storageKey ( loc - > c_fileLocation ( ) ) , _data - > thumb ) ;
2014-11-22 12:45:04 +03:00
} else if ( size = = ' m ' ) {
2015-12-09 21:06:20 +03:00
Local : : writeImage ( storageKey ( loc - > c_fileLocation ( ) ) , _data - > medium ) ;
2015-12-24 22:26:28 +03:00
} else if ( size = = ' x ' & & max < 1 ) {
max = 1 ;
maxLocation = & loc - > c_fileLocation ( ) ;
} else if ( size = = ' y ' & & max < 2 ) {
max = 2 ;
maxLocation = & loc - > c_fileLocation ( ) ;
//} else if (size == 'w' && max < 3) {
// max = 3;
// maxLocation = &loc->c_fileLocation();
2014-11-22 12:45:04 +03:00
}
}
2015-12-24 22:26:28 +03:00
if ( maxLocation ) {
Local : : writeImage ( storageKey ( * maxLocation ) , _data - > full ) ;
}
2014-11-22 12:45:04 +03:00
}
}
}
2015-12-25 16:09:14 +03:00
void HistoryPhoto : : regItem ( HistoryItem * item ) {
App : : regPhotoItem ( _data , item ) ;
}
void HistoryPhoto : : unregItem ( HistoryItem * item ) {
App : : unregPhotoItem ( _data , item ) ;
}
2015-12-19 21:09:24 +03:00
const QString HistoryPhoto : : inDialogsText ( ) const {
return _caption . isEmpty ( ) ? lang ( lng_in_dlg_photo ) : _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksNone ) ;
}
2014-05-30 12:53:19 +04:00
2015-12-19 21:09:24 +03:00
const QString HistoryPhoto : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_photo ) + ( _caption . isEmpty ( ) ? QString ( ) : ( qsl ( " , " ) + _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksAll ) ) ) + qsl ( " ] " ) ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
ImagePtr HistoryPhoto : : replyPreview ( ) {
2015-12-09 21:06:20 +03:00
return _data - > makeReplyPreview ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-12-13 18:21:20 +03:00
HistoryVideo : : HistoryVideo ( const MTPDvideo & video , const QString & caption , HistoryItem * parent ) : HistoryFileMedia ( )
, _data ( App : : feedVideo ( video ) )
2015-12-24 23:29:33 +03:00
, _thumbw ( 1 )
, _caption ( st : : minPhotoSize - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) {
2015-12-13 18:21:20 +03:00
if ( ! caption . isEmpty ( ) ) {
_caption . setText ( st : : msgFont , caption + parent - > skipBlock ( ) , itemTextNoMonoOptions ( parent ) ) ;
}
2015-12-13 01:29:33 +03:00
2015-12-13 18:21:20 +03:00
setLinks ( new VideoOpenLink ( _data ) , new VideoSaveLink ( _data ) , new VideoCancelLink ( _data ) ) ;
2015-12-13 01:29:33 +03:00
2015-12-13 18:21:20 +03:00
setStatusSize ( FileStatusSizeReady ) ;
_data - > thumb - > load ( ) ;
}
2015-12-17 20:31:28 +03:00
HistoryVideo : : HistoryVideo ( const HistoryVideo & other ) : HistoryFileMedia ( )
, _data ( other . _data )
2015-12-24 23:29:33 +03:00
, _thumbw ( other . _thumbw )
, _caption ( other . _caption ) {
2015-12-17 20:31:28 +03:00
setLinks ( new VideoOpenLink ( _data ) , new VideoSaveLink ( _data ) , new VideoCancelLink ( _data ) ) ;
setStatusSize ( other . _statusSize ) ;
}
2015-12-13 18:21:20 +03:00
void HistoryVideo : : initDimensions ( const HistoryItem * parent ) {
bool bubble = parent - > hasBubble ( ) ;
if ( _caption . hasSkipBlock ( ) ) {
_caption . setSkipBlock ( parent - > skipBlockWidth ( ) , parent - > skipBlockHeight ( ) ) ;
2015-12-13 01:29:33 +03:00
}
2015-12-13 18:21:20 +03:00
int32 tw = convertScale ( _data - > thumb - > width ( ) ) , th = convertScale ( _data - > thumb - > height ( ) ) ;
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
if ( tw * st : : msgVideoSize . height ( ) > th * st : : msgVideoSize . width ( ) ) {
th = qRound ( ( st : : msgVideoSize . width ( ) / float64 ( tw ) ) * th ) ;
tw = st : : msgVideoSize . width ( ) ;
} else {
tw = qRound ( ( st : : msgVideoSize . height ( ) / float64 ( th ) ) * tw ) ;
th = st : : msgVideoSize . height ( ) ;
}
2015-12-19 21:09:24 +03:00
_thumbw = qMax ( tw , 1 ) ;
2015-12-13 18:21:20 +03:00
int32 minWidth = qMax ( st : : minPhotoSize , parent - > infoWidth ( ) + 2 * ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
minWidth = qMax ( minWidth , videoMaxStatusWidth ( _data ) + 2 * int32 ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
2015-12-24 22:26:28 +03:00
_maxw = qMax ( _thumbw , int16 ( minWidth ) ) ;
2015-12-13 18:21:20 +03:00
_minh = qMax ( th , int32 ( st : : minPhotoSize ) ) ;
if ( bubble ) {
_maxw + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_minh + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
if ( ! _caption . isEmpty ( ) ) {
_minh + = st : : mediaCaptionSkip + _caption . countHeight ( _maxw - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
2015-12-13 01:29:33 +03:00
}
}
2015-12-13 18:21:20 +03:00
}
2015-12-13 01:29:33 +03:00
2015-12-19 21:09:24 +03:00
int32 HistoryVideo : : resize ( int32 width , const HistoryItem * parent ) {
2015-12-13 18:21:20 +03:00
bool bubble = parent - > hasBubble ( ) ;
int32 tw = convertScale ( _data - > thumb - > width ( ) ) , th = convertScale ( _data - > thumb - > height ( ) ) ;
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
if ( tw * st : : msgVideoSize . height ( ) > th * st : : msgVideoSize . width ( ) ) {
th = qRound ( ( st : : msgVideoSize . width ( ) / float64 ( tw ) ) * th ) ;
tw = st : : msgVideoSize . width ( ) ;
} else {
tw = qRound ( ( st : : msgVideoSize . height ( ) / float64 ( th ) ) * tw ) ;
th = st : : msgVideoSize . height ( ) ;
}
if ( bubble ) {
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
if ( width < tw ) {
th = qRound ( ( width / float64 ( tw ) ) * th ) ;
tw = width ;
}
2015-12-19 21:09:24 +03:00
int32 minWidth = qMax ( st : : minPhotoSize , parent - > infoWidth ( ) + 2 * ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
minWidth = qMax ( minWidth , videoMaxStatusWidth ( _data ) + 2 * int32 ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
2015-12-24 22:26:28 +03:00
_width = qMax ( _thumbw , int16 ( minWidth ) ) ;
2015-12-19 21:09:24 +03:00
_height = qMax ( th , int32 ( st : : minPhotoSize ) ) ;
2015-12-13 18:21:20 +03:00
if ( bubble ) {
2015-12-19 21:09:24 +03:00
_width + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_height + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
2015-12-13 18:21:20 +03:00
if ( ! _caption . isEmpty ( ) ) {
2015-12-19 21:09:24 +03:00
int32 captionw = _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
_height + = st : : mediaCaptionSkip + _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
2015-12-13 18:21:20 +03:00
}
}
2015-12-19 21:09:24 +03:00
return _height ;
2015-12-13 18:21:20 +03:00
}
void HistoryVideo : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
2015-12-19 21:09:24 +03:00
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2015-12-24 22:26:28 +03:00
_data - > automaticLoad ( parent ) ;
bool loaded = _data - > loaded ( ) , displayLoading = _data - > displayLoading ( ) ;
2015-12-19 21:09:24 +03:00
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
2015-12-13 18:21:20 +03:00
bool bubble = parent - > hasBubble ( ) ;
2015-12-19 21:09:24 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
int32 captionw = width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-12-13 18:21:20 +03:00
2015-12-24 22:26:28 +03:00
if ( displayLoading ) {
2015-12-13 18:21:20 +03:00
ensureAnimation ( parent ) ;
if ( ! _animation - > radial . animating ( ) ) {
_animation - > radial . start ( _data - > progress ( ) ) ;
}
}
updateStatusText ( parent ) ;
bool radial = isRadialAnimation ( ms ) ;
if ( bubble ) {
skipx = st : : mediaPadding . left ( ) ;
skipy = st : : mediaPadding . top ( ) ;
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
height - = skipy + st : : mediaPadding . bottom ( ) ;
if ( ! _caption . isEmpty ( ) ) {
height - = st : : mediaCaptionSkip + _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
}
} else {
2015-12-19 21:09:24 +03:00
App : : roundShadow ( p , 0 , 0 , width , height , selected ? st : : msgInShadowSelected : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
2015-12-13 18:21:20 +03:00
}
2015-12-19 21:09:24 +03:00
QRect rthumb ( rtlrect ( skipx , skipy , width , height , _width ) ) ;
2015-12-13 18:21:20 +03:00
QPixmap pix = _data - > thumb - > pixBlurredSingle ( _thumbw , 0 , width , height ) ;
p . drawPixmap ( rthumb . topLeft ( ) , pix ) ;
if ( selected ) {
App : : roundRect ( p , rthumb , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
QRect inner ( rthumb . x ( ) + ( rthumb . width ( ) - st : : msgFileSize ) / 2 , rthumb . y ( ) + ( rthumb . height ( ) - st : : msgFileSize ) / 2 , st : : msgFileSize , st : : msgFileSize ) ;
p . setPen ( Qt : : NoPen ) ;
if ( selected ) {
p . setBrush ( st : : msgDateImgBgSelected ) ;
2015-12-28 00:37:48 +03:00
} else if ( isThumbAnimation ( ms ) ) {
2015-12-13 18:21:20 +03:00
float64 over = _animation - > a_thumbOver . current ( ) ;
p . setOpacity ( ( st : : msgDateImgBg - > c . alphaF ( ) * ( 1 - over ) ) + ( st : : msgDateImgBgOver - > c . alphaF ( ) * over ) ) ;
p . setBrush ( st : : black ) ;
} else {
2015-12-24 22:26:28 +03:00
bool over = textlnkDrawOver ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-13 18:21:20 +03:00
p . setBrush ( over ? st : : msgDateImgBgOver : st : : msgDateImgBg ) ;
}
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawEllipse ( inner ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
if ( ! selected & & _animation ) {
p . setOpacity ( 1 ) ;
}
style : : sprite icon ;
2015-12-24 22:26:28 +03:00
if ( loaded ) {
2015-12-13 18:21:20 +03:00
icon = ( selected ? st : : msgFileInPlaySelected : st : : msgFileInPlay ) ;
2015-12-24 22:26:28 +03:00
} else if ( radial | | _data - > loading ( ) ) {
2015-12-13 18:21:20 +03:00
icon = ( selected ? st : : msgFileInCancelSelected : st : : msgFileInCancel ) ;
} else {
icon = ( selected ? st : : msgFileInDownloadSelected : st : : msgFileInDownload ) ;
}
p . drawSpriteCenter ( inner , icon ) ;
if ( radial ) {
QRect rinner ( inner . marginsRemoved ( QMargins ( st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine ) ) ) ;
2015-12-22 15:49:42 +03:00
_animation - > radial . draw ( p , rinner , st : : msgFileRadialLine , selected ? st : : msgInBgSelected : st : : msgInBg ) ;
2015-12-13 18:21:20 +03:00
}
int32 statusX = skipx + st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) , statusY = skipy + st : : msgDateImgDelta + st : : msgDateImgPadding . y ( ) ;
int32 statusW = st : : normalFont - > width ( _statusText ) + 2 * st : : msgDateImgPadding . x ( ) ;
int32 statusH = st : : normalFont - > height + 2 * st : : msgDateImgPadding . y ( ) ;
2015-12-19 21:09:24 +03:00
App : : roundRect ( p , rtlrect ( statusX - st : : msgDateImgPadding . x ( ) , statusY - st : : msgDateImgPadding . y ( ) , statusW , statusH , _width ) , selected ? st : : msgDateImgBgSelected : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2015-12-13 18:21:20 +03:00
p . setFont ( st : : normalFont ) ;
p . setPen ( st : : white ) ;
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( statusX , statusY , _width , _statusText , statusW - 2 * st : : msgDateImgPadding . x ( ) ) ;
2015-12-13 18:21:20 +03:00
// date
if ( _caption . isEmpty ( ) ) {
2015-12-19 00:36:16 +03:00
if ( parent - > getMedia ( ) = = this ) {
int32 fullRight = skipx + width , fullBottom = skipy + height ;
parent - > drawInfo ( p , fullRight , fullBottom , 2 * skipx + width , selected , InfoDisplayOverImage ) ;
}
2015-12-13 18:21:20 +03:00
} else {
p . setPen ( st : : black ) ;
_caption . draw ( p , st : : msgPadding . left ( ) , skipy + height + st : : mediaPadding . bottom ( ) + st : : mediaCaptionSkip , captionw ) ;
}
}
2015-12-19 21:09:24 +03:00
void HistoryVideo : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2015-12-24 22:26:28 +03:00
bool loaded = _data - > loaded ( ) ;
2015-12-19 21:09:24 +03:00
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
2015-12-13 18:21:20 +03:00
bool bubble = parent - > hasBubble ( ) ;
if ( bubble ) {
2015-12-19 21:09:24 +03:00
skipx = st : : mediaPadding . left ( ) ;
skipy = st : : mediaPadding . top ( ) ;
if ( ! _caption . isEmpty ( ) ) {
int32 captionw = width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
height - = _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
if ( x > = st : : msgPadding . left ( ) & & y > = height & & x < st : : msgPadding . left ( ) + captionw & & y < _height ) {
bool inText = false ;
_caption . getState ( lnk , inText , x - st : : msgPadding . left ( ) , y - height , captionw ) ;
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
}
height - = st : : mediaCaptionSkip ;
}
2015-12-13 18:21:20 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-12-19 21:09:24 +03:00
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-12-13 18:21:20 +03:00
}
2015-12-19 21:09:24 +03:00
if ( x > = skipx & & y > = skipy & & x < skipx + width & & y < skipy + height ) {
2015-12-24 22:26:28 +03:00
lnk = loaded ? _openl : ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-19 21:09:24 +03:00
if ( _caption . isEmpty ( ) & & parent - > getMedia ( ) = = this ) {
int32 fullRight = skipx + width , fullBottom = skipy + height ;
bool inDate = parent - > pointInTime ( fullRight , fullBottom , x , y , InfoDisplayOverImage ) ;
if ( inDate ) {
state = HistoryInDateCursorState ;
}
2015-12-13 18:21:20 +03:00
}
2015-12-19 21:09:24 +03:00
return ;
2015-12-13 18:21:20 +03:00
}
2015-12-19 21:09:24 +03:00
}
void HistoryVideo : : setStatusSize ( int32 newSize ) const {
HistoryFileMedia : : setStatusSize ( newSize , _data - > size , _data - > duration , 0 ) ;
}
const QString HistoryVideo : : inDialogsText ( ) const {
return _caption . isEmpty ( ) ? lang ( lng_in_dlg_video ) : _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksNone ) ;
}
const QString HistoryVideo : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_video ) + ( _caption . isEmpty ( ) ? QString ( ) : ( qsl ( " , " ) + _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksAll ) ) ) + qsl ( " ] " ) ;
}
void HistoryVideo : : updateStatusText ( const HistoryItem * parent ) const {
bool showPause = false ;
int32 statusSize = 0 , realDuration = 0 ;
if ( _data - > status = = FileDownloadFailed | | _data - > status = = FileUploadFailed ) {
statusSize = FileStatusSizeFailed ;
} else if ( _data - > status = = FileUploading ) {
statusSize = _data - > uploadOffset ;
2015-12-24 22:26:28 +03:00
} else if ( _data - > loading ( ) ) {
statusSize = _data - > progress ( ) ;
2015-12-19 21:09:24 +03:00
} else if ( ! _data - > already ( ) . isEmpty ( ) ) {
statusSize = FileStatusSizeLoaded ;
} else {
statusSize = FileStatusSizeReady ;
}
if ( statusSize ! = _statusSize ) {
setStatusSize ( statusSize ) ;
}
}
void HistoryVideo : : regItem ( HistoryItem * item ) {
App : : regVideoItem ( _data , item ) ;
}
void HistoryVideo : : unregItem ( HistoryItem * item ) {
App : : unregVideoItem ( _data , item ) ;
2015-12-13 18:21:20 +03:00
}
ImagePtr HistoryVideo : : replyPreview ( ) {
if ( _data - > replyPreview - > isNull ( ) & & ! _data - > thumb - > isNull ( ) ) {
if ( _data - > thumb - > loaded ( ) ) {
int w = _data - > thumb - > width ( ) , h = _data - > thumb - > height ( ) ;
if ( w < = 0 ) w = 1 ;
if ( h < = 0 ) h = 1 ;
_data - > replyPreview = ImagePtr ( w > h ? _data - > thumb - > pix ( w * st : : msgReplyBarSize . height ( ) / h , st : : msgReplyBarSize . height ( ) ) : _data - > thumb - > pix ( st : : msgReplyBarSize . height ( ) ) , " PNG " ) ;
} else {
_data - > thumb - > load ( ) ;
}
2015-12-13 01:29:33 +03:00
}
2015-12-13 18:21:20 +03:00
return _data - > replyPreview ;
2015-12-13 01:29:33 +03:00
}
HistoryAudio : : HistoryAudio ( const MTPDaudio & audio ) : HistoryFileMedia ( )
, _data ( App : : feedAudio ( audio ) ) {
2015-12-24 00:19:57 +03:00
setLinks ( new AudioOpenLink ( _data ) , new AudioOpenLink ( _data ) , new AudioCancelLink ( _data ) ) ;
2015-12-13 01:29:33 +03:00
setStatusSize ( FileStatusSizeReady ) ;
}
2015-12-17 20:31:28 +03:00
HistoryAudio : : HistoryAudio ( const HistoryAudio & other ) : HistoryFileMedia ( )
, _data ( other . _data ) {
2015-12-24 00:19:57 +03:00
setLinks ( new AudioOpenLink ( _data ) , new AudioOpenLink ( _data ) , new AudioCancelLink ( _data ) ) ;
2015-12-17 20:31:28 +03:00
setStatusSize ( other . _statusSize ) ;
}
2015-12-13 01:29:33 +03:00
void HistoryAudio : : initDimensions ( const HistoryItem * parent ) {
_maxw = st : : msgFileMinWidth ;
int32 tleft = 0 , tright = 0 ;
tleft = st : : msgFilePadding . left ( ) + st : : msgFileSize + st : : msgFilePadding . right ( ) ;
tright = st : : msgFileThumbPadding . left ( ) ;
_maxw = qMax ( _maxw , tleft + audioMaxStatusWidth ( _data ) + int ( st : : mediaUnreadSkip + st : : mediaUnreadSize ) + parent - > skipBlockWidth ( ) + st : : msgPadding . right ( ) ) ;
_maxw = qMax ( tleft + st : : semiboldFont - > width ( lang ( lng_media_audio ) ) + tright , _maxw ) ;
_maxw = qMin ( _maxw , int ( st : : msgMaxWidth ) ) ;
_height = _minh = st : : msgFilePadding . top ( ) + st : : msgFileSize + st : : msgFilePadding . bottom ( ) ;
}
void HistoryAudio : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
2015-12-19 21:09:24 +03:00
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2015-12-13 01:29:33 +03:00
2015-12-24 22:26:28 +03:00
_data - > automaticLoad ( parent ) ;
bool loaded = _data - > loaded ( ) , displayLoading = _data - > displayLoading ( ) ;
2015-12-13 01:29:33 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-12-24 22:26:28 +03:00
if ( displayLoading ) {
2015-12-13 01:29:33 +03:00
ensureAnimation ( parent ) ;
if ( ! _animation - > radial . animating ( ) ) {
_animation - > radial . start ( _data - > progress ( ) ) ;
2015-06-02 14:22:00 +03:00
}
2014-09-04 11:33:44 +04:00
}
2015-12-13 01:29:33 +03:00
bool showPause = updateStatusText ( parent ) ;
bool radial = isRadialAnimation ( ms ) ;
int32 nameleft = 0 , nametop = 0 , nameright = 0 , statustop = 0 , linktop = 0 ;
nameleft = st : : msgFilePadding . left ( ) + st : : msgFileSize + st : : msgFilePadding . right ( ) ;
nametop = st : : msgFileNameTop ;
nameright = st : : msgFilePadding . left ( ) ;
statustop = st : : msgFileStatusTop ;
2015-06-02 14:22:00 +03:00
2015-12-19 21:09:24 +03:00
QRect inner ( rtlrect ( st : : msgFilePadding . left ( ) , st : : msgFilePadding . top ( ) , st : : msgFileSize , st : : msgFileSize , _width ) ) ;
2015-12-13 01:29:33 +03:00
p . setPen ( Qt : : NoPen ) ;
2014-05-30 12:53:19 +04:00
if ( selected ) {
2015-12-13 01:29:33 +03:00
p . setBrush ( outbg ? st : : msgFileOutBgSelected : st : : msgFileInBgSelected ) ;
2015-12-28 00:37:48 +03:00
} else if ( isThumbAnimation ( ms ) ) {
2015-12-13 01:29:33 +03:00
float64 over = _animation - > a_thumbOver . current ( ) ;
p . setBrush ( style : : interpolate ( outbg ? st : : msgFileOutBg : st : : msgFileInBg , outbg ? st : : msgFileOutBgOver : st : : msgFileInBgOver , over ) ) ;
} else {
2015-12-24 22:26:28 +03:00
bool over = textlnkDrawOver ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-13 01:29:33 +03:00
p . setBrush ( outbg ? ( over ? st : : msgFileOutBgOver : st : : msgFileOutBg ) : ( over ? st : : msgFileInBgOver : st : : msgFileInBg ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-13 01:29:33 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawEllipse ( inner ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
if ( radial ) {
QRect rinner ( inner . marginsRemoved ( QMargins ( st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine ) ) ) ;
style : : color bg ( outbg ? ( selected ? st : : msgOutBgSelected : st : : msgOutBg ) : ( selected ? st : : msgInBgSelected : st : : msgInBg ) ) ;
2015-12-22 15:49:42 +03:00
_animation - > radial . draw ( p , rinner , st : : msgFileRadialLine , bg ) ;
2015-12-13 01:29:33 +03:00
}
style : : sprite icon ;
if ( showPause ) {
icon = outbg ? ( selected ? st : : msgFileOutPauseSelected : st : : msgFileOutPause ) : ( selected ? st : : msgFileInPauseSelected : st : : msgFileInPause ) ;
2015-12-24 22:26:28 +03:00
} else if ( radial | | _data - > loading ( ) ) {
2015-12-13 01:29:33 +03:00
icon = outbg ? ( selected ? st : : msgFileOutCancelSelected : st : : msgFileOutCancel ) : ( selected ? st : : msgFileInCancelSelected : st : : msgFileInCancel ) ;
2015-12-24 22:26:28 +03:00
} else if ( loaded ) {
icon = outbg ? ( selected ? st : : msgFileOutPlaySelected : st : : msgFileOutPlay ) : ( selected ? st : : msgFileInPlaySelected : st : : msgFileInPlay ) ;
2015-12-13 01:29:33 +03:00
} else {
icon = outbg ? ( selected ? st : : msgFileOutDownloadSelected : st : : msgFileOutDownload ) : ( selected ? st : : msgFileInDownloadSelected : st : : msgFileInDownload ) ;
}
p . drawSpriteCenter ( inner , icon ) ;
2015-12-19 21:09:24 +03:00
int32 namewidth = _width - nameleft - nameright ;
2015-12-13 01:29:33 +03:00
p . setFont ( st : : semiboldFont ) ;
p . setPen ( st : : black ) ;
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( nameleft , nametop , _width , lang ( lng_media_audio ) ) ;
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
style : : color status ( outbg ? ( selected ? st : : mediaOutFgSelected : st : : mediaOutFg ) : ( selected ? st : : mediaInFgSelected : st : : mediaInFg ) ) ;
2015-12-13 01:29:33 +03:00
p . setFont ( st : : normalFont ) ;
p . setPen ( status ) ;
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( nameleft , statustop , _width , _statusText ) ;
2015-12-13 01:29:33 +03:00
2015-04-30 16:53:36 +03:00
if ( parent - > isMediaUnread ( ) ) {
2015-12-13 01:29:33 +03:00
int32 w = st : : normalFont - > width ( _statusText ) ;
if ( w + st : : mediaUnreadSkip + st : : mediaUnreadSize < = namewidth ) {
2015-04-30 16:53:36 +03:00
p . setPen ( Qt : : NoPen ) ;
2015-12-13 01:29:33 +03:00
p . setBrush ( outbg ? ( selected ? st : : msgFileOutBgSelected : st : : msgFileOutBg ) : ( selected ? st : : msgFileInBgSelected : st : : msgFileInBg ) ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , true ) ;
2015-12-19 21:09:24 +03:00
p . drawEllipse ( rtlrect ( nameleft + w + st : : mediaUnreadSkip , statustop + st : : mediaUnreadTop , st : : mediaUnreadSize , st : : mediaUnreadSize , _width ) ) ;
2015-04-30 16:53:36 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
}
}
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
void HistoryAudio : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-12-23 22:23:14 +03:00
bool loaded = _data - > loaded ( ) ;
2015-12-19 21:09:24 +03:00
bool showPause = updateStatusText ( parent ) ;
int32 nameleft = 0 , nametop = 0 , nameright = 0 , statustop = 0 , linktop = 0 ;
QRect inner ( rtlrect ( st : : msgFilePadding . left ( ) , st : : msgFilePadding . top ( ) , st : : msgFileSize , st : : msgFileSize , _width ) ) ;
2015-12-24 22:26:28 +03:00
if ( ( _data - > loading ( ) | | _data - > status = = FileUploading | | ! loaded ) & & inner . contains ( x , y ) ) {
lnk = ( _data - > loading ( ) | | _data - > status = = FileUploading ) ? _cancell : _savel ;
2015-12-19 21:09:24 +03:00
return ;
}
2015-12-24 22:26:28 +03:00
if ( x > = 0 & & y > = 0 & & x < _width & & y < _height & & _data - > access & & ! _data - > loading ( ) ) {
2015-12-19 21:09:24 +03:00
lnk = _openl ;
return ;
}
2014-05-30 12:53:19 +04:00
}
const QString HistoryAudio : : inDialogsText ( ) const {
return lang ( lng_in_dlg_audio ) ;
}
2014-11-22 12:45:04 +03:00
const QString HistoryAudio : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_audio ) + qsl ( " ] " ) ;
}
2015-12-19 21:09:24 +03:00
void HistoryAudio : : regItem ( HistoryItem * item ) {
App : : regAudioItem ( _data , item ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
void HistoryAudio : : unregItem ( HistoryItem * item ) {
App : : unregAudioItem ( _data , item ) ;
}
2015-03-19 12:18:19 +03:00
2015-12-19 21:09:24 +03:00
void HistoryAudio : : updateFrom ( const MTPMessageMedia & media , HistoryItem * parent , bool allowEmitResize ) {
if ( media . type ( ) = = mtpc_messageMediaAudio ) {
App : : feedAudio ( media . c_messageMediaAudio ( ) . vaudio , _data ) ;
2015-12-24 22:26:28 +03:00
if ( ! _data - > data ( ) . isEmpty ( ) ) {
Local : : writeAudio ( mediaKey ( AudioFileLocation , _data - > dc , _data - > id ) , _data - > data ( ) ) ;
2015-12-19 21:09:24 +03:00
}
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
}
2014-05-30 12:53:19 +04:00
2015-12-19 21:09:24 +03:00
void HistoryAudio : : setStatusSize ( int32 newSize , qint64 realDuration ) const {
HistoryFileMedia : : setStatusSize ( newSize , _data - > size , _data - > duration , realDuration ) ;
}
2015-08-31 17:27:20 +03:00
2015-12-19 21:09:24 +03:00
bool HistoryAudio : : updateStatusText ( const HistoryItem * parent ) const {
bool showPause = false ;
int32 statusSize = 0 , realDuration = 0 ;
if ( _data - > status = = FileDownloadFailed | | _data - > status = = FileUploadFailed ) {
statusSize = FileStatusSizeFailed ;
} else if ( _data - > status = = FileUploading ) {
statusSize = _data - > uploadOffset ;
2015-12-24 22:26:28 +03:00
} else if ( _data - > loading ( ) ) {
statusSize = _data - > loadOffset ( ) ;
2015-12-23 22:23:14 +03:00
} else if ( _data - > loaded ( ) ) {
2015-12-19 21:09:24 +03:00
AudioMsgId playing ;
AudioPlayerState playingState = AudioPlayerStopped ;
int64 playingPosition = 0 , playingDuration = 0 ;
int32 playingFrequency = 0 ;
if ( audioPlayer ( ) ) {
audioPlayer ( ) - > currentState ( & playing , & playingState , & playingPosition , & playingDuration , & playingFrequency ) ;
}
2015-08-31 17:27:20 +03:00
2015-12-19 21:09:24 +03:00
if ( playing . msgId = = parent - > fullId ( ) & & ! ( playingState & AudioPlayerStoppedMask ) & & playingState ! = AudioPlayerFinishing ) {
statusSize = - 1 - ( playingPosition / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) ;
realDuration = playingDuration / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ;
showPause = ( playingState = = AudioPlayerPlaying | | playingState = = AudioPlayerResuming | | playingState = = AudioPlayerStarting ) ;
} else {
statusSize = FileStatusSizeLoaded ;
}
} else {
statusSize = FileStatusSizeReady ;
2015-12-13 01:29:33 +03:00
}
2015-12-19 21:09:24 +03:00
if ( statusSize ! = _statusSize ) {
setStatusSize ( statusSize , realDuration ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
return showPause ;
2014-05-30 12:53:19 +04:00
}
2015-12-28 13:28:00 +03:00
HistoryDocument : : HistoryDocument ( DocumentData * document , const QString & caption , const HistoryItem * parent ) : HistoryFileMedia ( )
2015-12-08 22:07:50 +03:00
, _data ( document )
2015-12-13 01:29:33 +03:00
, _linksavel ( new DocumentSaveLink ( _data ) )
, _linkcancell ( new DocumentCancelLink ( _data ) )
2015-12-21 16:14:29 +03:00
, _name ( documentName ( _data ) )
2015-12-28 13:28:00 +03:00
, _namew ( st : : semiboldFont - > width ( _name ) )
, _caption ( st : : msgFileMinWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) {
2015-12-13 01:29:33 +03:00
setLinks ( new DocumentOpenLink ( _data ) , new DocumentSaveLink ( _data ) , new DocumentCancelLink ( _data ) ) ;
2015-12-09 21:06:20 +03:00
2015-12-10 16:37:45 +03:00
setStatusSize ( FileStatusSizeReady ) ;
2015-12-08 22:07:50 +03:00
2015-12-28 13:28:00 +03:00
if ( ! caption . isEmpty ( ) ) {
_caption . setText ( st : : msgFont , caption + parent - > skipBlock ( ) , itemTextNoMonoOptions ( parent ) ) ;
}
2015-12-08 22:07:50 +03:00
if ( withThumb ( ) ) {
_data - > thumb - > load ( ) ;
int32 tw = _data - > thumb - > width ( ) , th = _data - > thumb - > height ( ) ;
if ( tw > th ) {
_thumbw = ( tw * st : : msgFileThumbSize ) / th ;
} else {
_thumbw = st : : msgFileThumbSize ;
}
2014-05-30 12:53:19 +04:00
} else {
2015-12-08 22:07:50 +03:00
_thumbw = 0 ;
2014-05-30 12:53:19 +04:00
}
}
2015-12-17 20:31:28 +03:00
HistoryDocument : : HistoryDocument ( const HistoryDocument & other ) : HistoryFileMedia ( )
, _data ( other . _data )
, _linksavel ( new DocumentSaveLink ( _data ) )
, _linkcancell ( new DocumentCancelLink ( _data ) )
, _name ( other . _name )
2015-12-24 23:29:33 +03:00
, _namew ( other . _namew )
2015-12-17 20:31:28 +03:00
, _thumbw ( other . _thumbw ) {
setLinks ( new DocumentOpenLink ( _data ) , new DocumentSaveLink ( _data ) , new DocumentCancelLink ( _data ) ) ;
setStatusSize ( other . _statusSize ) ;
}
2014-08-15 15:19:32 +04:00
void HistoryDocument : : initDimensions ( const HistoryItem * parent ) {
2015-12-28 13:28:00 +03:00
if ( _caption . hasSkipBlock ( ) ) {
_caption . setSkipBlock ( parent - > skipBlockWidth ( ) , parent - > skipBlockHeight ( ) ) ;
}
2015-12-08 22:07:50 +03:00
_maxw = st : : msgFileMinWidth ;
int32 tleft = 0 , tright = 0 ;
bool wthumb = withThumb ( ) ;
if ( wthumb ) {
tleft = st : : msgFileThumbPadding . left ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . right ( ) ;
tright = st : : msgFileThumbPadding . left ( ) ;
_maxw = qMax ( _maxw , tleft + documentMaxStatusWidth ( _data ) + tright ) ;
2014-10-10 16:46:20 +04:00
} else {
2015-12-08 22:07:50 +03:00
tleft = st : : msgFilePadding . left ( ) + st : : msgFileSize + st : : msgFilePadding . right ( ) ;
tright = st : : msgFileThumbPadding . left ( ) ;
_maxw = qMax ( _maxw , tleft + documentMaxStatusWidth ( _data ) + parent - > skipBlockWidth ( ) + st : : msgPadding . right ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-08 22:07:50 +03:00
_maxw = qMax ( tleft + _namew + tright , _maxw ) ;
_maxw = qMin ( _maxw , int ( st : : msgMaxWidth ) ) ;
2015-12-11 21:11:38 +03:00
2015-12-13 01:29:33 +03:00
if ( wthumb ) {
2015-12-19 21:09:24 +03:00
_minh = st : : msgFileThumbPadding . top ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . bottom ( ) ;
2015-12-11 21:11:38 +03:00
} else {
2015-12-19 21:09:24 +03:00
_minh = st : : msgFilePadding . top ( ) + st : : msgFileSize + st : : msgFilePadding . bottom ( ) ;
2015-12-11 21:11:38 +03:00
}
2015-12-28 13:28:00 +03:00
if ( _caption . isEmpty ( ) ) {
_height = _minh ;
} else {
_minh + = _caption . countHeight ( _maxw - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
}
}
int32 HistoryDocument : : resize ( int32 width , const HistoryItem * parent ) {
if ( _caption . isEmpty ( ) ) {
return HistoryFileMedia : : resize ( width , parent ) ;
}
_width = qMin ( width , _maxw ) ;
bool wthumb = withThumb ( ) ;
if ( wthumb ) {
_height = st : : msgFileThumbPadding . top ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . bottom ( ) ;
} else {
_height = st : : msgFilePadding . top ( ) + st : : msgFileSize + st : : msgFilePadding . bottom ( ) ;
}
_height + = _caption . countHeight ( _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
return _height ;
2014-05-30 12:53:19 +04:00
}
2015-12-11 21:11:38 +03:00
void HistoryDocument : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
2015-12-19 21:09:24 +03:00
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2014-05-30 12:53:19 +04:00
2015-12-24 22:26:28 +03:00
_data - > automaticLoad ( parent ) ;
bool loaded = _data - > loaded ( ) , displayLoading = _data - > displayLoading ( ) ;
2015-12-28 13:28:00 +03:00
int32 captionw = _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-12-10 16:37:45 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-03-19 12:18:19 +03:00
2015-12-24 22:26:28 +03:00
if ( displayLoading ) {
2015-12-11 21:11:38 +03:00
ensureAnimation ( parent ) ;
if ( ! _animation - > radial . animating ( ) ) {
_animation - > radial . start ( _data - > progress ( ) ) ;
}
}
2015-12-13 01:29:33 +03:00
bool showPause = updateStatusText ( parent ) ;
bool radial = isRadialAnimation ( ms ) ;
2014-05-30 12:53:19 +04:00
2015-12-28 13:28:00 +03:00
int32 nameleft = 0 , nametop = 0 , nameright = 0 , statustop = 0 , linktop = 0 , bottom = 0 ;
2015-12-10 16:37:45 +03:00
bool wthumb = withThumb ( ) ;
if ( wthumb ) {
nameleft = st : : msgFileThumbPadding . left ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . right ( ) ;
nametop = st : : msgFileThumbNameTop ;
nameright = st : : msgFileThumbPadding . left ( ) ;
statustop = st : : msgFileThumbStatusTop ;
linktop = st : : msgFileThumbLinkTop ;
2015-12-28 13:28:00 +03:00
bottom = st : : msgFileThumbPadding . top ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . bottom ( ) ;
2015-12-19 21:09:24 +03:00
QRect rthumb ( rtlrect ( st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . top ( ) , st : : msgFileThumbSize , st : : msgFileThumbSize , _width ) ) ;
2015-12-10 16:37:45 +03:00
if ( _data - > thumb - > loaded ( ) ) {
2015-12-23 22:23:14 +03:00
QPixmap thumb = loaded ? _data - > thumb - > pixSingle ( _thumbw , 0 , st : : msgFileThumbSize , st : : msgFileThumbSize ) : _data - > thumb - > pixBlurredSingle ( _thumbw , 0 , st : : msgFileThumbSize , st : : msgFileThumbSize ) ;
2015-12-10 16:37:45 +03:00
p . drawPixmap ( rthumb . topLeft ( ) , thumb ) ;
} else {
App : : roundRect ( p , rthumb , st : : black , BlackCorners ) ;
}
if ( selected ) {
App : : roundRect ( p , rthumb , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
2014-05-30 12:53:19 +04:00
2015-12-24 22:26:28 +03:00
if ( radial | | ( ! loaded & & ! _data - > loading ( ) ) ) {
2015-12-25 18:21:18 +03:00
float64 radialOpacity = ( radial & & loaded & & ! _data - > uploading ( ) ) ? _animation - > radial . opacity ( ) : 1 ;
2015-12-10 16:37:45 +03:00
QRect inner ( rthumb . x ( ) + ( rthumb . width ( ) - st : : msgFileSize ) / 2 , rthumb . y ( ) + ( rthumb . height ( ) - st : : msgFileSize ) / 2 , st : : msgFileSize , st : : msgFileSize ) ;
p . setPen ( Qt : : NoPen ) ;
2015-12-11 21:11:38 +03:00
if ( selected ) {
p . setBrush ( st : : msgDateImgBgSelected ) ;
2015-12-28 00:37:48 +03:00
} else if ( isThumbAnimation ( ms ) ) {
2015-12-11 21:11:38 +03:00
float64 over = _animation - > a_thumbOver . current ( ) ;
p . setOpacity ( ( st : : msgDateImgBg - > c . alphaF ( ) * ( 1 - over ) ) + ( st : : msgDateImgBgOver - > c . alphaF ( ) * over ) ) ;
p . setBrush ( st : : black ) ;
} else {
2015-12-24 22:26:28 +03:00
bool over = textlnkDrawOver ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-11 21:11:38 +03:00
p . setBrush ( over ? st : : msgDateImgBgOver : st : : msgDateImgBg ) ;
}
2015-12-24 22:26:28 +03:00
p . setOpacity ( radialOpacity * p . opacity ( ) ) ;
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawEllipse ( inner ) ;
2015-12-10 16:37:45 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
2014-05-30 12:53:19 +04:00
2015-12-24 22:26:28 +03:00
p . setOpacity ( radialOpacity ) ;
2015-12-10 16:37:45 +03:00
style : : sprite icon ;
2015-12-24 22:26:28 +03:00
if ( radial | | _data - > loading ( ) ) {
2015-12-10 16:37:45 +03:00
icon = ( selected ? st : : msgFileInCancelSelected : st : : msgFileInCancel ) ;
} else {
icon = ( selected ? st : : msgFileInDownloadSelected : st : : msgFileInDownload ) ;
}
2015-12-24 22:26:28 +03:00
p . setOpacity ( ( radial & & loaded ) ? _animation - > radial . opacity ( ) : 1 ) ;
2015-12-10 16:37:45 +03:00
p . drawSpriteCenter ( inner , icon ) ;
2015-12-11 21:11:38 +03:00
if ( radial ) {
p . setOpacity ( 1 ) ;
QRect rinner ( inner . marginsRemoved ( QMargins ( st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine ) ) ) ;
2015-12-22 15:49:42 +03:00
_animation - > radial . draw ( p , rinner , st : : msgFileRadialLine , selected ? st : : msgInBgSelected : st : : msgInBg ) ;
2015-12-11 21:11:38 +03:00
}
2015-12-10 16:37:45 +03:00
}
2014-05-30 12:53:19 +04:00
2015-12-11 10:44:53 +03:00
if ( _data - > status ! = FileUploadFailed ) {
2015-12-24 22:26:28 +03:00
const TextLinkPtr & lnk ( ( _data - > loading ( ) | | _data - > status = = FileUploading ) ? _linkcancell : _linksavel ) ;
2015-12-11 21:11:38 +03:00
bool over = textlnkDrawOver ( lnk ) ;
2015-12-11 10:44:53 +03:00
p . setFont ( over ? st : : semiboldFont - > underline ( ) : st : : semiboldFont ) ;
p . setPen ( outbg ? ( selected ? st : : msgFileThumbLinkOutFgSelected : st : : msgFileThumbLinkOutFg ) : ( selected ? st : : msgFileThumbLinkInFgSelected : st : : msgFileThumbLinkInFg ) ) ;
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( nameleft , linktop , _width , _link , _linkw ) ;
2015-12-11 10:44:53 +03:00
}
2015-12-10 16:37:45 +03:00
} else {
nameleft = st : : msgFilePadding . left ( ) + st : : msgFileSize + st : : msgFilePadding . right ( ) ;
nametop = st : : msgFileNameTop ;
nameright = st : : msgFilePadding . left ( ) ;
statustop = st : : msgFileStatusTop ;
2015-12-28 13:28:00 +03:00
bottom = st : : msgFilePadding . top ( ) + st : : msgFileSize + st : : msgFilePadding . bottom ( ) ;
2015-12-10 16:37:45 +03:00
2015-12-19 21:09:24 +03:00
QRect inner ( rtlrect ( st : : msgFilePadding . left ( ) , st : : msgFilePadding . top ( ) , st : : msgFileSize , st : : msgFileSize , _width ) ) ;
2015-12-10 16:37:45 +03:00
p . setPen ( Qt : : NoPen ) ;
2015-12-11 21:11:38 +03:00
if ( selected ) {
p . setBrush ( outbg ? st : : msgFileOutBgSelected : st : : msgFileInBgSelected ) ;
2015-12-28 00:37:48 +03:00
} else if ( isThumbAnimation ( ms ) ) {
2015-12-11 21:11:38 +03:00
float64 over = _animation - > a_thumbOver . current ( ) ;
p . setBrush ( style : : interpolate ( outbg ? st : : msgFileOutBg : st : : msgFileInBg , outbg ? st : : msgFileOutBgOver : st : : msgFileInBgOver , over ) ) ;
} else {
2015-12-24 22:26:28 +03:00
bool over = textlnkDrawOver ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-11 21:11:38 +03:00
p . setBrush ( outbg ? ( over ? st : : msgFileOutBgOver : st : : msgFileOutBg ) : ( over ? st : : msgFileInBgOver : st : : msgFileInBg ) ) ;
}
2015-12-10 16:37:45 +03:00
2015-12-11 21:11:38 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawEllipse ( inner ) ;
2015-12-10 16:37:45 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
2015-12-11 21:11:38 +03:00
if ( radial ) {
QRect rinner ( inner . marginsRemoved ( QMargins ( st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine ) ) ) ;
style : : color bg ( outbg ? ( selected ? st : : msgOutBgSelected : st : : msgOutBg ) : ( selected ? st : : msgInBgSelected : st : : msgInBg ) ) ;
2015-12-22 15:49:42 +03:00
_animation - > radial . draw ( p , rinner , st : : msgFileRadialLine , bg ) ;
2015-12-11 21:11:38 +03:00
}
2015-12-10 16:37:45 +03:00
style : : sprite icon ;
if ( showPause ) {
icon = outbg ? ( selected ? st : : msgFileOutPauseSelected : st : : msgFileOutPause ) : ( selected ? st : : msgFileInPauseSelected : st : : msgFileInPause ) ;
2015-12-24 22:26:28 +03:00
} else if ( radial | | _data - > loading ( ) ) {
icon = outbg ? ( selected ? st : : msgFileOutCancelSelected : st : : msgFileOutCancel ) : ( selected ? st : : msgFileInCancelSelected : st : : msgFileInCancel ) ;
} else if ( loaded ) {
2015-12-10 16:37:45 +03:00
if ( _data - > song ( ) ) {
icon = outbg ? ( selected ? st : : msgFileOutPlaySelected : st : : msgFileOutPlay ) : ( selected ? st : : msgFileInPlaySelected : st : : msgFileInPlay ) ;
} else if ( _data - > isImage ( ) ) {
icon = outbg ? ( selected ? st : : msgFileOutImageSelected : st : : msgFileOutImage ) : ( selected ? st : : msgFileInImageSelected : st : : msgFileInImage ) ;
} else {
icon = outbg ? ( selected ? st : : msgFileOutFileSelected : st : : msgFileOutFile ) : ( selected ? st : : msgFileInFileSelected : st : : msgFileInFile ) ;
}
} else {
icon = outbg ? ( selected ? st : : msgFileOutDownloadSelected : st : : msgFileOutDownload ) : ( selected ? st : : msgFileInDownloadSelected : st : : msgFileInDownload ) ;
}
p . drawSpriteCenter ( inner , icon ) ;
}
2015-12-19 21:09:24 +03:00
int32 namewidth = _width - nameleft - nameright ;
2015-12-10 16:37:45 +03:00
p . setFont ( st : : semiboldFont ) ;
p . setPen ( st : : black ) ;
if ( namewidth < _namew ) {
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( nameleft , nametop , _width , st : : semiboldFont - > elided ( _name , namewidth ) ) ;
2015-12-10 16:37:45 +03:00
} else {
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( nameleft , nametop , _width , _name , _namew ) ;
2015-12-10 16:37:45 +03:00
}
2015-12-11 21:11:38 +03:00
style : : color status ( outbg ? ( selected ? st : : mediaOutFgSelected : st : : mediaOutFg ) : ( selected ? st : : mediaInFgSelected : st : : mediaInFg ) ) ;
2015-12-10 16:37:45 +03:00
p . setFont ( st : : normalFont ) ;
p . setPen ( status ) ;
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( nameleft , statustop , _width , _statusText ) ;
2015-12-28 13:28:00 +03:00
if ( ! _caption . isEmpty ( ) ) {
p . setPen ( st : : black ) ;
_caption . draw ( p , st : : msgPadding . left ( ) , bottom , captionw ) ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
void HistoryDocument : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2015-09-13 20:27:29 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-12-23 22:23:14 +03:00
bool loaded = _data - > loaded ( ) ;
2015-07-03 13:48:28 +03:00
2015-12-09 21:06:20 +03:00
bool showPause = updateStatusText ( parent ) ;
2015-07-03 13:48:28 +03:00
2015-12-28 13:28:00 +03:00
int32 nameleft = 0 , nametop = 0 , nameright = 0 , statustop = 0 , linktop = 0 , bottom = 0 ;
2015-12-19 21:09:24 +03:00
bool wthumb = withThumb ( ) ;
if ( wthumb ) {
nameleft = st : : msgFileThumbPadding . left ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . right ( ) ;
linktop = st : : msgFileThumbLinkTop ;
2015-12-28 13:28:00 +03:00
bottom = st : : msgFileThumbPadding . top ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . bottom ( ) ;
2015-12-10 16:37:45 +03:00
2015-12-19 21:09:24 +03:00
QRect rthumb ( rtlrect ( st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . top ( ) , st : : msgFileThumbSize , st : : msgFileThumbSize , _width ) ) ;
2015-07-03 13:48:28 +03:00
2015-12-24 22:26:28 +03:00
if ( ( _data - > loading ( ) | | _data - > uploading ( ) | | ! loaded ) & & rthumb . contains ( x , y ) ) {
lnk = ( _data - > loading ( ) | | _data - > uploading ( ) ) ? _cancell : _savel ;
return ;
2015-12-19 21:09:24 +03:00
}
2015-07-03 13:48:28 +03:00
2015-12-19 21:09:24 +03:00
if ( _data - > status ! = FileUploadFailed ) {
if ( rtlrect ( nameleft , linktop , _linkw , st : : semiboldFont - > height , _width ) . contains ( x , y ) ) {
2015-12-24 22:26:28 +03:00
lnk = ( _data - > loading ( ) | | _data - > uploading ( ) ) ? _linkcancell : _linksavel ;
2015-12-19 21:09:24 +03:00
return ;
}
}
2015-07-03 13:48:28 +03:00
} else {
2015-12-28 13:28:00 +03:00
bottom = st : : msgFilePadding . top ( ) + st : : msgFileSize + st : : msgFilePadding . bottom ( ) ;
2015-12-19 21:09:24 +03:00
QRect inner ( rtlrect ( st : : msgFilePadding . left ( ) , st : : msgFilePadding . top ( ) , st : : msgFileSize , st : : msgFileSize , _width ) ) ;
2015-12-24 22:26:28 +03:00
if ( ( _data - > loading ( ) | | _data - > uploading ( ) | | ! loaded ) & & inner . contains ( x , y ) ) {
lnk = ( _data - > loading ( ) | | _data - > uploading ( ) ) ? _cancell : _savel ;
2015-12-19 21:09:24 +03:00
return ;
}
2015-07-03 13:48:28 +03:00
}
2015-12-28 13:28:00 +03:00
int32 height = _height ;
if ( ! _caption . isEmpty ( ) ) {
if ( y > = bottom ) {
bool inText = false ;
2015-12-28 16:03:16 +03:00
_caption . getState ( lnk , inText , x - st : : msgPadding . left ( ) , y - bottom , _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) ;
2015-12-28 13:28:00 +03:00
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
return ;
}
height - = _caption . countHeight ( _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
}
if ( x > = 0 & & y > = 0 & & x < _width & & y < height & & ! _data - > loading ( ) & & ! _data - > uploading ( ) & & _data - > access ) {
2015-12-19 21:09:24 +03:00
lnk = _openl ;
return ;
2015-07-03 13:48:28 +03:00
}
}
2014-05-30 12:53:19 +04:00
const QString HistoryDocument : : inDialogsText ( ) const {
2015-12-28 16:03:16 +03:00
return ( _name . isEmpty ( ) ? lang ( lng_in_dlg_file ) : _name ) + ( _caption . isEmpty ( ) ? QString ( ) : ( ' ' + _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksNone ) ) ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-22 12:45:04 +03:00
const QString HistoryDocument : : inHistoryText ( ) const {
2015-12-28 16:03:16 +03:00
return qsl ( " [ " ) + lang ( lng_in_dlg_file ) + ( _name . isEmpty ( ) ? QString ( ) : ( qsl ( " : " ) + _name ) ) + ( _caption . isEmpty ( ) ? QString ( ) : ( qsl ( " , " ) + _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksAll ) ) ) + qsl ( " ] " ) ;
2014-11-22 12:45:04 +03:00
}
2015-12-19 21:09:24 +03:00
void HistoryDocument : : setStatusSize ( int32 newSize , qint64 realDuration ) const {
HistoryFileMedia : : setStatusSize ( newSize , _data - > size , _data - > song ( ) ? _data - > song ( ) - > duration : - 1 , realDuration ) ;
2014-05-30 12:53:19 +04:00
2015-12-19 21:09:24 +03:00
if ( _statusSize = = FileStatusSizeReady ) {
_link = lang ( lng_media_download ) . toUpper ( ) ;
} else if ( _statusSize = = FileStatusSizeLoaded ) {
_link = lang ( lng_media_open_with ) . toUpper ( ) ;
} else if ( _statusSize = = FileStatusSizeFailed ) {
_link = lang ( lng_media_download ) . toUpper ( ) ;
} else if ( _statusSize > = 0 ) {
_link = lang ( lng_media_cancel ) . toUpper ( ) ;
} else {
_link = lang ( lng_media_open_with ) . toUpper ( ) ;
2014-10-10 16:46:20 +04:00
}
2015-12-19 21:09:24 +03:00
_linkw = st : : semiboldFont - > width ( _link ) ;
2014-10-10 16:46:20 +04:00
}
2015-12-19 21:09:24 +03:00
bool HistoryDocument : : updateStatusText ( const HistoryItem * parent ) const {
bool showPause = false ;
int32 statusSize = 0 , realDuration = 0 ;
if ( _data - > status = = FileDownloadFailed | | _data - > status = = FileUploadFailed ) {
statusSize = FileStatusSizeFailed ;
} else if ( _data - > status = = FileUploading ) {
statusSize = _data - > uploadOffset ;
2015-12-24 22:26:28 +03:00
} else if ( _data - > loading ( ) ) {
statusSize = _data - > loadOffset ( ) ;
2015-12-23 22:23:14 +03:00
} else if ( _data - > loaded ( ) ) {
if ( _data - > song ( ) ) {
SongMsgId playing ;
AudioPlayerState playingState = AudioPlayerStopped ;
int64 playingPosition = 0 , playingDuration = 0 ;
int32 playingFrequency = 0 ;
if ( audioPlayer ( ) ) {
audioPlayer ( ) - > currentState ( & playing , & playingState , & playingPosition , & playingDuration , & playingFrequency ) ;
}
2015-12-11 10:44:53 +03:00
2015-12-23 22:23:14 +03:00
if ( playing . msgId = = parent - > fullId ( ) & & ! ( playingState & AudioPlayerStoppedMask ) & & playingState ! = AudioPlayerFinishing ) {
statusSize = - 1 - ( playingPosition / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) ;
realDuration = playingDuration / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ;
showPause = ( playingState = = AudioPlayerPlaying | | playingState = = AudioPlayerResuming | | playingState = = AudioPlayerStarting ) ;
} else {
statusSize = FileStatusSizeLoaded ;
}
if ( ! showPause & & playing . msgId = = parent - > fullId ( ) & & App : : main ( ) & & App : : main ( ) - > player ( ) - > seekingSong ( playing ) ) {
showPause = true ;
}
2015-12-11 10:44:53 +03:00
} else {
2015-12-19 21:09:24 +03:00
statusSize = FileStatusSizeLoaded ;
2015-08-31 17:27:20 +03:00
}
2015-12-11 10:44:53 +03:00
} else {
2015-12-19 21:09:24 +03:00
statusSize = FileStatusSizeReady ;
2015-12-11 10:44:53 +03:00
}
2015-12-19 21:09:24 +03:00
if ( statusSize ! = _statusSize ) {
setStatusSize ( statusSize , realDuration ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
return showPause ;
}
void HistoryDocument : : regItem ( HistoryItem * item ) {
App : : regDocumentItem ( _data , item ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
void HistoryDocument : : unregItem ( HistoryItem * item ) {
App : : unregDocumentItem ( _data , item ) ;
}
void HistoryDocument : : updateFrom ( const MTPMessageMedia & media , HistoryItem * parent , bool allowEmitResize ) {
if ( media . type ( ) = = mtpc_messageMediaDocument ) {
App : : feedDocument ( media . c_messageMediaDocument ( ) . vdocument , _data ) ;
}
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
ImagePtr HistoryDocument : : replyPreview ( ) {
2015-12-08 22:07:50 +03:00
return _data - > makeReplyPreview ( ) ;
}
2015-12-28 13:28:00 +03:00
HistoryGif : : HistoryGif ( DocumentData * document , const QString & caption , const HistoryItem * parent ) : HistoryFileMedia ( )
2015-12-08 22:07:50 +03:00
, _data ( document )
2015-12-13 20:05:32 +03:00
, _thumbw ( 1 )
2015-12-15 17:50:51 +03:00
, _thumbh ( 1 )
2015-12-28 13:28:00 +03:00
, _caption ( st : : minPhotoSize - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) )
2015-12-15 17:50:51 +03:00
, _gif ( 0 ) {
2015-12-25 16:10:13 +03:00
setLinks ( new GifOpenLink ( _data ) , new GifOpenLink ( _data ) , new DocumentCancelLink ( _data ) ) ;
2015-12-13 20:05:32 +03:00
setStatusSize ( FileStatusSizeReady ) ;
2015-12-28 13:28:00 +03:00
if ( ! caption . isEmpty ( ) ) {
_caption . setText ( st : : msgFont , caption + parent - > skipBlock ( ) , itemTextNoMonoOptions ( parent ) ) ;
}
2015-12-08 22:07:50 +03:00
_data - > thumb - > load ( ) ;
}
2015-12-17 20:31:28 +03:00
HistoryGif : : HistoryGif ( const HistoryGif & other ) : HistoryFileMedia ( )
, _data ( other . _data )
, _thumbw ( other . _thumbw )
, _thumbh ( other . _thumbh )
, _gif ( 0 ) {
2015-12-25 16:10:13 +03:00
setLinks ( new GifOpenLink ( _data ) , new GifOpenLink ( _data ) , new DocumentCancelLink ( _data ) ) ;
2015-12-17 20:31:28 +03:00
setStatusSize ( other . _statusSize ) ;
}
2015-12-08 22:07:50 +03:00
void HistoryGif : : initDimensions ( const HistoryItem * parent ) {
2015-12-28 13:28:00 +03:00
if ( _caption . hasSkipBlock ( ) ) {
_caption . setSkipBlock ( parent - > skipBlockWidth ( ) , parent - > skipBlockHeight ( ) ) ;
}
2015-12-13 20:05:32 +03:00
bool bubble = parent - > hasBubble ( ) ;
int32 tw = 0 , th = 0 ;
2015-12-25 16:10:13 +03:00
if ( gif ( ) & & _gif - > state ( ) = = ClipError ) {
if ( ! _gif - > autoplay ( ) ) {
Ui : : showLayer ( new InformBox ( lang ( lng_gif_error ) ) ) ;
}
2015-12-16 18:04:02 +03:00
App : : unregGifItem ( _gif ) ;
delete _gif ;
2015-12-25 16:10:13 +03:00
_gif = BadClipReader ;
2015-12-16 18:04:02 +03:00
}
2015-12-25 16:10:13 +03:00
if ( gif ( ) & & _gif - > ready ( ) ) {
2015-12-15 17:50:51 +03:00
tw = convertScale ( _gif - > width ( ) ) ;
th = convertScale ( _gif - > height ( ) ) ;
2015-12-08 22:07:50 +03:00
} else {
2015-12-13 20:05:32 +03:00
tw = convertScale ( _data - > dimensions . width ( ) ) , th = convertScale ( _data - > dimensions . height ( ) ) ;
if ( ! tw | | ! th ) {
tw = convertScale ( _data - > thumb - > width ( ) ) ;
th = convertScale ( _data - > thumb - > height ( ) ) ;
}
}
2015-12-16 18:04:02 +03:00
if ( tw > st : : maxGifSize ) {
th = ( st : : maxGifSize * th ) / tw ;
tw = st : : maxGifSize ;
2015-12-13 20:05:32 +03:00
}
2015-12-16 18:04:02 +03:00
if ( th > st : : maxGifSize ) {
tw = ( st : : maxGifSize * tw ) / th ;
th = st : : maxGifSize ;
2015-12-13 20:05:32 +03:00
}
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
_thumbw = tw ;
_thumbh = th ;
2015-12-15 17:50:51 +03:00
_maxw = qMax ( tw , int32 ( st : : minPhotoSize ) ) ;
_minh = qMax ( th , int32 ( st : : minPhotoSize ) ) ;
2015-12-25 16:10:13 +03:00
if ( ! gif ( ) | | ! _gif - > ready ( ) ) {
2015-12-15 17:50:51 +03:00
_maxw = qMax ( _maxw , parent - > infoWidth ( ) + 2 * int32 ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
_maxw = qMax ( _maxw , gifMaxStatusWidth ( _data ) + 2 * int32 ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
2015-12-13 20:05:32 +03:00
}
if ( bubble ) {
_maxw + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_minh + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
2015-12-28 13:28:00 +03:00
if ( ! _caption . isEmpty ( ) ) {
_minh + = st : : mediaCaptionSkip + _caption . countHeight ( _maxw - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
}
2015-12-08 22:07:50 +03:00
}
2015-12-19 21:09:24 +03:00
}
int32 HistoryGif : : resize ( int32 width , const HistoryItem * parent ) {
bool bubble = parent - > hasBubble ( ) ;
int32 tw = 0 , th = 0 ;
2015-12-25 16:10:13 +03:00
if ( gif ( ) & & _gif - > ready ( ) ) {
2015-12-19 21:09:24 +03:00
tw = convertScale ( _gif - > width ( ) ) ;
th = convertScale ( _gif - > height ( ) ) ;
} else {
tw = convertScale ( _data - > dimensions . width ( ) ) , th = convertScale ( _data - > dimensions . height ( ) ) ;
if ( ! tw | | ! th ) {
tw = convertScale ( _data - > thumb - > width ( ) ) ;
th = convertScale ( _data - > thumb - > height ( ) ) ;
}
}
if ( tw > st : : maxGifSize ) {
th = ( st : : maxGifSize * th ) / tw ;
tw = st : : maxGifSize ;
}
if ( th > st : : maxGifSize ) {
tw = ( st : : maxGifSize * tw ) / th ;
th = st : : maxGifSize ;
}
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
if ( bubble ) {
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
if ( width < tw ) {
th = qRound ( ( width / float64 ( tw ) ) * th ) ;
tw = width ;
}
_thumbw = tw ;
_thumbh = th ;
_width = qMax ( tw , int32 ( st : : minPhotoSize ) ) ;
_height = qMax ( th , int32 ( st : : minPhotoSize ) ) ;
2015-12-25 16:10:13 +03:00
if ( gif ( ) & & _gif - > ready ( ) ) {
2015-12-19 21:09:24 +03:00
if ( ! _gif - > started ( ) ) {
_gif - > start ( _thumbw , _thumbh , _width , _height , true ) ;
}
} else {
_width = qMax ( _width , parent - > infoWidth ( ) + 2 * int32 ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
_width = qMax ( _width , gifMaxStatusWidth ( _data ) + 2 * int32 ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
}
if ( bubble ) {
_width + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_height + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
2015-12-28 13:28:00 +03:00
if ( ! _caption . isEmpty ( ) ) {
_height + = st : : mediaCaptionSkip + _caption . countHeight ( _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) + st : : msgPadding . bottom ( ) ;
}
2015-12-19 21:09:24 +03:00
}
return _height ;
2015-12-08 22:07:50 +03:00
}
2015-12-11 21:11:38 +03:00
void HistoryGif : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
2015-12-19 21:09:24 +03:00
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2015-12-08 22:07:50 +03:00
2015-12-24 22:26:28 +03:00
_data - > automaticLoad ( parent ) ;
bool loaded = _data - > loaded ( ) , displayLoading = _data - > displayLoading ( ) ;
2015-12-28 00:37:48 +03:00
if ( loaded & & ! gif ( ) & & _gif ! = BadClipReader & & cAutoPlayGif ( ) ) {
2015-12-23 19:48:44 +03:00
const_cast < HistoryGif * > ( this ) - > playInline ( const_cast < HistoryItem * > ( parent ) ) ;
2015-12-25 16:10:13 +03:00
if ( gif ( ) ) _gif - > setAutoplay ( ) ;
2015-12-23 19:48:44 +03:00
}
2015-12-24 22:26:28 +03:00
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
bool bubble = parent - > hasBubble ( ) ;
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-12-28 13:28:00 +03:00
int32 captionw = width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-12-25 16:10:13 +03:00
bool animating = ( gif ( ) & & _gif - > started ( ) ) ;
2015-12-13 20:05:32 +03:00
2015-12-24 22:26:28 +03:00
if ( ! animating | | _data - > uploading ( ) ) {
if ( displayLoading ) {
2015-12-13 20:05:32 +03:00
ensureAnimation ( parent ) ;
if ( ! _animation - > radial . animating ( ) ) {
_animation - > radial . start ( _data - > progress ( ) ) ;
}
2015-12-08 22:07:50 +03:00
}
2015-12-13 20:05:32 +03:00
updateStatusText ( parent ) ;
}
2015-12-19 00:36:16 +03:00
bool radial = isRadialAnimation ( ms ) ;
2015-12-13 20:05:32 +03:00
if ( bubble ) {
skipx = st : : mediaPadding . left ( ) ;
skipy = st : : mediaPadding . top ( ) ;
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-12-28 13:28:00 +03:00
if ( ! _caption . isEmpty ( ) ) {
height - = st : : mediaCaptionSkip + _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
}
2015-12-13 20:05:32 +03:00
} else {
App : : roundShadow ( p , 0 , 0 , width , _height , selected ? st : : msgInShadowSelected : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
}
2015-12-19 21:09:24 +03:00
QRect rthumb ( rtlrect ( skipx , skipy , width , height , _width ) ) ;
2015-12-08 22:07:50 +03:00
2015-12-13 20:05:32 +03:00
if ( animating ) {
2015-12-28 00:37:48 +03:00
p . drawPixmap ( rthumb . topLeft ( ) , _gif - > current ( _thumbw , _thumbh , width , height , ( Ui : : isLayerShown ( ) | | Ui : : isMediaViewShown ( ) | | Ui : : isGifBeingChosen ( ) ) ? 0 : ms ) ) ;
2015-12-13 20:05:32 +03:00
} else {
p . drawPixmap ( rthumb . topLeft ( ) , _data - > thumb - > pixBlurredSingle ( _thumbw , _thumbh , width , height ) ) ;
}
if ( selected ) {
App : : roundRect ( p , rthumb , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
2015-12-08 22:07:50 +03:00
2015-12-28 00:37:48 +03:00
if ( radial | | ( ! _gif & & ( ( ! loaded & & ! _data - > loading ( ) ) | | ! cAutoPlayGif ( ) ) ) | | ( _gif = = BadClipReader ) ) {
2015-12-25 18:21:18 +03:00
float64 radialOpacity = ( radial & & loaded & & ! _data - > uploading ( ) ) ? _animation - > radial . opacity ( ) : 1 ;
2015-12-13 20:05:32 +03:00
QRect inner ( rthumb . x ( ) + ( rthumb . width ( ) - st : : msgFileSize ) / 2 , rthumb . y ( ) + ( rthumb . height ( ) - st : : msgFileSize ) / 2 , st : : msgFileSize , st : : msgFileSize ) ;
p . setPen ( Qt : : NoPen ) ;
2015-12-08 22:07:50 +03:00
if ( selected ) {
2015-12-13 20:05:32 +03:00
p . setBrush ( st : : msgDateImgBgSelected ) ;
2015-12-28 00:37:48 +03:00
} else if ( isThumbAnimation ( ms ) ) {
2015-12-13 20:05:32 +03:00
float64 over = _animation - > a_thumbOver . current ( ) ;
p . setOpacity ( ( st : : msgDateImgBg - > c . alphaF ( ) * ( 1 - over ) ) + ( st : : msgDateImgBgOver - > c . alphaF ( ) * over ) ) ;
p . setBrush ( st : : black ) ;
} else {
2015-12-24 22:26:28 +03:00
bool over = textlnkDrawOver ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-13 20:05:32 +03:00
p . setBrush ( over ? st : : msgDateImgBgOver : st : : msgDateImgBg ) ;
2015-12-08 22:07:50 +03:00
}
2015-12-24 22:26:28 +03:00
p . setOpacity ( radialOpacity * p . opacity ( ) ) ;
2015-12-13 20:05:32 +03:00
p . setRenderHint ( QPainter : : HighQualityAntialiasing ) ;
p . drawEllipse ( inner ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
2015-12-24 22:26:28 +03:00
p . setOpacity ( radialOpacity ) ;
2015-12-13 20:05:32 +03:00
style : : sprite icon ;
2015-12-23 19:48:44 +03:00
if ( _data - > loaded ( ) & & ! radial ) {
2015-12-13 20:05:32 +03:00
icon = ( selected ? st : : msgFileInPlaySelected : st : : msgFileInPlay ) ;
2015-12-24 22:26:28 +03:00
} else if ( radial | | _data - > loading ( ) ) {
2015-12-13 20:05:32 +03:00
icon = ( selected ? st : : msgFileInCancelSelected : st : : msgFileInCancel ) ;
} else {
icon = ( selected ? st : : msgFileInDownloadSelected : st : : msgFileInDownload ) ;
}
p . drawSpriteCenter ( inner , icon ) ;
if ( radial ) {
2015-12-24 22:26:28 +03:00
p . setOpacity ( 1 ) ;
2015-12-13 20:05:32 +03:00
QRect rinner ( inner . marginsRemoved ( QMargins ( st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine , st : : msgFileRadialLine ) ) ) ;
2015-12-22 15:49:42 +03:00
_animation - > radial . draw ( p , rinner , st : : msgFileRadialLine , selected ? st : : msgInBgSelected : st : : msgInBg ) ;
2015-12-13 20:05:32 +03:00
}
2015-12-24 22:26:28 +03:00
if ( ! animating | | _data - > uploading ( ) ) {
2015-12-19 00:36:16 +03:00
int32 statusX = skipx + st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) , statusY = skipy + st : : msgDateImgDelta + st : : msgDateImgPadding . y ( ) ;
int32 statusW = st : : normalFont - > width ( _statusText ) + 2 * st : : msgDateImgPadding . x ( ) ;
int32 statusH = st : : normalFont - > height + 2 * st : : msgDateImgPadding . y ( ) ;
2015-12-19 21:09:24 +03:00
App : : roundRect ( p , rtlrect ( statusX - st : : msgDateImgPadding . x ( ) , statusY - st : : msgDateImgPadding . y ( ) , statusW , statusH , _width ) , selected ? st : : msgDateImgBgSelected : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2015-12-19 00:36:16 +03:00
p . setFont ( st : : normalFont ) ;
p . setPen ( st : : white ) ;
2015-12-19 21:09:24 +03:00
p . drawTextLeft ( statusX , statusY , _width , _statusText , statusW - 2 * st : : msgDateImgPadding . x ( ) ) ;
2015-12-13 20:05:32 +03:00
2015-12-19 00:36:16 +03:00
// date
2015-12-28 13:28:00 +03:00
if ( _caption . isEmpty ( ) & & parent - > getMedia ( ) = = this ) {
2015-12-19 00:36:16 +03:00
int32 fullRight = skipx + width , fullBottom = skipy + height ;
parent - > drawInfo ( p , fullRight , fullBottom , 2 * skipx + width , selected , InfoDisplayOverImage ) ;
}
}
2015-12-08 22:07:50 +03:00
}
2015-12-28 13:28:00 +03:00
if ( ! _caption . isEmpty ( ) ) {
p . setPen ( st : : black ) ;
_caption . draw ( p , st : : msgPadding . left ( ) , skipy + height + st : : mediaPadding . bottom ( ) + st : : mediaCaptionSkip , captionw ) ;
}
2015-12-13 20:05:32 +03:00
}
2015-12-08 22:07:50 +03:00
2015-12-19 21:09:24 +03:00
void HistoryGif : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
bool bubble = parent - > hasBubble ( ) ;
if ( bubble ) {
skipx = st : : mediaPadding . left ( ) ;
skipy = st : : mediaPadding . top ( ) ;
2015-12-28 13:28:00 +03:00
if ( ! _caption . isEmpty ( ) ) {
int32 captionw = width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
height - = _caption . countHeight ( captionw ) + st : : msgPadding . bottom ( ) ;
if ( x > = st : : msgPadding . left ( ) & & y > = height & & x < st : : msgPadding . left ( ) + captionw & & y < _height ) {
bool inText = false ;
_caption . getState ( lnk , inText , x - st : : msgPadding . left ( ) , y - height , captionw ) ;
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
return ;
}
height - = st : : mediaCaptionSkip ;
}
2015-12-19 21:09:24 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
height - = skipy + st : : mediaPadding . bottom ( ) ;
}
if ( x > = skipx & & y > = skipy & & x < skipx + width & & y < skipy + height ) {
2015-12-24 22:26:28 +03:00
if ( _data - > uploading ( ) ) {
lnk = _cancell ;
2015-12-28 00:37:48 +03:00
} else if ( ! gif ( ) | | ! cAutoPlayGif ( ) ) {
2015-12-24 22:26:28 +03:00
lnk = _data - > loaded ( ) ? _openl : ( _data - > loading ( ) ? _cancell : _savel ) ;
2015-12-19 21:09:24 +03:00
}
if ( parent - > getMedia ( ) = = this ) {
int32 fullRight = skipx + width , fullBottom = skipy + height ;
bool inDate = parent - > pointInTime ( fullRight , fullBottom , x , y , InfoDisplayOverImage ) ;
if ( inDate ) {
state = HistoryInDateCursorState ;
}
}
return ;
}
}
const QString HistoryGif : : inDialogsText ( ) const {
2015-12-28 16:03:16 +03:00
return qsl ( " GIF " ) + ( _caption . isEmpty ( ) ? QString ( ) : ( ' ' + _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksNone ) ) ) ;
2015-12-19 21:09:24 +03:00
}
const QString HistoryGif : : inHistoryText ( ) const {
2015-12-28 16:03:16 +03:00
return qsl ( " [ GIF " ) + ( _caption . isEmpty ( ) ? QString ( ) : ( _caption . original ( 0 , 0xFFFF , Text : : ExpandLinksAll ) + ' ' ) ) + qsl ( " ] " ) ;
2015-12-19 21:09:24 +03:00
}
2015-12-13 20:05:32 +03:00
void HistoryGif : : setStatusSize ( int32 newSize ) const {
HistoryFileMedia : : setStatusSize ( newSize , _data - > size , - 2 , 0 ) ;
}
void HistoryGif : : updateStatusText ( const HistoryItem * parent ) const {
bool showPause = false ;
int32 statusSize = 0 , realDuration = 0 ;
if ( _data - > status = = FileDownloadFailed | | _data - > status = = FileUploadFailed ) {
statusSize = FileStatusSizeFailed ;
} else if ( _data - > status = = FileUploading ) {
statusSize = _data - > uploadOffset ;
2015-12-24 22:26:28 +03:00
} else if ( _data - > loading ( ) ) {
statusSize = _data - > loadOffset ( ) ;
2015-12-23 19:48:44 +03:00
} else if ( _data - > loaded ( ) ) {
2015-12-13 20:05:32 +03:00
statusSize = FileStatusSizeLoaded ;
} else {
statusSize = FileStatusSizeReady ;
}
if ( statusSize ! = _statusSize ) {
setStatusSize ( statusSize ) ;
}
2015-12-08 22:07:50 +03:00
}
void HistoryGif : : regItem ( HistoryItem * item ) {
App : : regDocumentItem ( _data , item ) ;
}
void HistoryGif : : unregItem ( HistoryItem * item ) {
App : : unregDocumentItem ( _data , item ) ;
}
2015-12-13 01:29:33 +03:00
void HistoryGif : : updateFrom ( const MTPMessageMedia & media , HistoryItem * parent , bool allowEmitResize ) {
2015-12-08 22:07:50 +03:00
if ( media . type ( ) = = mtpc_messageMediaDocument ) {
App : : feedDocument ( media . c_messageMediaDocument ( ) . vdocument , _data ) ;
}
}
ImagePtr HistoryGif : : replyPreview ( ) {
return _data - > makeReplyPreview ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-12-19 00:36:16 +03:00
bool HistoryGif : : playInline ( HistoryItem * parent ) {
2015-12-25 16:10:13 +03:00
if ( gif ( ) ) {
2015-12-19 00:36:16 +03:00
stopInline ( parent ) ;
2015-12-15 17:50:51 +03:00
} else {
2015-12-28 00:37:48 +03:00
if ( ! cAutoPlayGif ( ) ) {
App : : stopGifItems ( ) ;
}
2015-12-24 22:26:28 +03:00
_gif = new ClipReader ( _data - > location ( ) , _data - > data ( ) ) ;
2015-12-15 17:50:51 +03:00
App : : regGifItem ( _gif , parent ) ;
}
2015-12-19 00:36:16 +03:00
return true ;
2015-12-15 17:50:51 +03:00
}
2015-12-19 00:36:16 +03:00
void HistoryGif : : stopInline ( HistoryItem * parent ) {
2015-12-25 16:10:13 +03:00
if ( gif ( ) ) {
App : : unregGifItem ( _gif ) ;
delete _gif ;
_gif = 0 ;
}
2015-12-16 16:35:15 +03:00
parent - > initDimensions ( ) ;
2015-12-22 11:01:02 +03:00
Notify : : historyItemResized ( parent ) ;
2015-12-16 16:35:15 +03:00
Notify : : historyItemLayoutChanged ( parent ) ;
}
2015-12-15 17:50:51 +03:00
HistoryGif : : ~ HistoryGif ( ) {
2015-12-25 16:10:13 +03:00
if ( gif ( ) ) {
2015-12-15 17:50:51 +03:00
App : : unregGifItem ( _gif ) ;
delete _gif ;
setBadPointer ( _gif ) ;
}
}
2015-04-04 23:01:34 +03:00
HistorySticker : : HistorySticker ( DocumentData * document ) : HistoryMedia ( )
2015-12-23 15:19:32 +03:00
, _pixw ( 1 )
, _pixh ( 1 )
, _data ( document ) {
_data - > thumb - > load ( ) ;
if ( ! _data - > sticker ( ) - > alt . isEmpty ( ) ) {
_emoji = _data - > sticker ( ) - > alt ;
2015-10-27 23:47:55 -04:00
int32 elen = 0 ;
if ( EmojiPtr e = emojiFromText ( _emoji . constData ( ) , _emoji . constEnd ( ) , elen ) ) {
_emoji = emojiString ( e ) ;
}
2015-07-01 00:27:56 +03:00
}
2015-01-05 23:17:33 +03:00
}
void HistorySticker : : initDimensions ( const HistoryItem * parent ) {
2015-12-23 15:19:32 +03:00
_pixw = _data - > dimensions . width ( ) ;
_pixh = _data - > dimensions . height ( ) ;
if ( _pixw > st : : maxStickerSize ) {
_pixh = ( st : : maxStickerSize * _pixh ) / _pixw ;
_pixw = st : : maxStickerSize ;
}
if ( _pixh > st : : maxStickerSize ) {
_pixw = ( st : : maxStickerSize * _pixw ) / _pixh ;
_pixh = st : : maxStickerSize ;
}
if ( _pixw < 1 ) _pixw = 1 ;
if ( _pixh < 1 ) _pixh = 1 ;
_maxw = qMax ( _pixw , int16 ( st : : minPhotoSize ) ) ;
_minh = qMax ( _pixh , int16 ( st : : minPhotoSize ) ) ;
2015-03-19 12:18:19 +03:00
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
2015-06-02 14:22:00 +03:00
_maxw + = st : : msgReplyPadding . left ( ) + reply - > replyToWidth ( ) ;
2015-03-19 12:18:19 +03:00
}
_height = _minh ;
2014-12-23 02:11:37 +03:00
}
2015-12-11 21:11:38 +03:00
void HistorySticker : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
2015-12-19 21:09:24 +03:00
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2014-12-23 02:11:37 +03:00
2015-12-24 22:26:28 +03:00
_data - > checkSticker ( ) ;
2015-12-23 19:48:44 +03:00
bool loaded = _data - > loaded ( ) ;
2015-12-24 22:26:28 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel , hovered , pressed ;
2015-09-13 20:27:29 +03:00
2015-03-19 12:18:19 +03:00
int32 usew = _maxw , usex = 0 ;
const HistoryReply * reply = toHistoryReply ( parent ) ;
if ( reply ) {
2015-06-02 14:22:00 +03:00
usew - = st : : msgReplyPadding . left ( ) + reply - > replyToWidth ( ) ;
2015-09-13 20:27:29 +03:00
if ( fromChannel ) {
} else if ( out ) {
2015-12-19 21:09:24 +03:00
usex = _width - usew ;
2015-03-19 12:18:19 +03:00
}
}
2015-12-19 21:09:24 +03:00
if ( rtl ( ) ) usex = _width - usex - usew ;
2015-03-19 12:18:19 +03:00
2014-12-23 02:11:37 +03:00
if ( selected ) {
2015-12-23 15:19:32 +03:00
if ( _data - > sticker ( ) - > img - > isNull ( ) ) {
p . drawPixmap ( QPoint ( usex + ( usew - _pixw ) / 2 , ( _minh - _pixh ) / 2 ) , _data - > thumb - > pixBlurredColored ( st : : msgStickerOverlay , _pixw , _pixh ) ) ;
2015-01-05 23:17:33 +03:00
} else {
2015-12-23 15:19:32 +03:00
p . drawPixmap ( QPoint ( usex + ( usew - _pixw ) / 2 , ( _minh - _pixh ) / 2 ) , _data - > sticker ( ) - > img - > pixColored ( st : : msgStickerOverlay , _pixw , _pixh ) ) ;
2015-01-05 23:17:33 +03:00
}
} else {
2015-12-23 15:19:32 +03:00
if ( _data - > sticker ( ) - > img - > isNull ( ) ) {
p . drawPixmap ( QPoint ( usex + ( usew - _pixw ) / 2 , ( _minh - _pixh ) / 2 ) , _data - > thumb - > pixBlurred ( _pixw , _pixh ) ) ;
2015-01-05 23:17:33 +03:00
} else {
2015-12-23 15:19:32 +03:00
p . drawPixmap ( QPoint ( usex + ( usew - _pixw ) / 2 , ( _minh - _pixh ) / 2 ) , _data - > sticker ( ) - > img - > pix ( _pixw , _pixh ) ) ;
2015-01-05 23:17:33 +03:00
}
2014-12-23 02:11:37 +03:00
}
2015-12-19 00:36:16 +03:00
if ( parent - > getMedia ( ) = = this ) {
parent - > drawInfo ( p , usex + usew , _height , usex * 2 + usew , selected , InfoDisplayOverImage ) ;
2015-03-19 12:18:19 +03:00
2015-12-19 00:36:16 +03:00
if ( reply ) {
2015-12-19 21:09:24 +03:00
int32 rw = _width - usew - st : : msgReplyPadding . left ( ) , rh = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-12-19 00:36:16 +03:00
int32 rx = fromChannel ? ( usew + st : : msgReplyPadding . left ( ) ) : ( out ? 0 : ( usew + st : : msgReplyPadding . left ( ) ) ) , ry = _height - rh ;
2015-12-19 21:09:24 +03:00
if ( rtl ( ) ) rx = _width - rx - rw ;
2015-12-19 00:36:16 +03:00
App : : roundRect ( p , rx , ry , rw , rh , selected ? App : : msgServiceSelectBg ( ) : App : : msgServiceBg ( ) , selected ? ServiceSelectedCorners : ServiceCorners ) ;
2015-03-19 12:18:19 +03:00
2015-12-19 00:36:16 +03:00
reply - > drawReplyTo ( p , rx + st : : msgReplyPadding . left ( ) , ry , rw - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected , true ) ;
}
2015-03-19 12:18:19 +03:00
}
}
2015-12-19 21:09:24 +03:00
void HistorySticker : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
2014-12-23 02:11:37 +03:00
2015-12-19 21:09:24 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2014-12-23 02:11:37 +03:00
2015-12-19 21:09:24 +03:00
int32 usew = _maxw , usex = 0 ;
const HistoryReply * reply = toHistoryReply ( parent ) ;
if ( reply ) {
usew - = reply - > replyToWidth ( ) ;
if ( fromChannel ) {
} else if ( out ) {
usex = _width - usew ;
}
}
if ( rtl ( ) ) usex = _width - usex - usew ;
if ( reply ) {
int32 rw = _width - usew , rh = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
int32 rx = fromChannel ? ( usew + st : : msgReplyPadding . left ( ) ) : ( out ? 0 : ( usew + st : : msgReplyPadding . left ( ) ) ) , ry = _height - rh ;
if ( rtl ( ) ) rx = _width - rx - rw ;
if ( x > = rx & & y > = ry & & x < rx + rw & & y < ry + rh ) {
lnk = reply - > replyToLink ( ) ;
return ;
}
}
if ( parent - > getMedia ( ) = = this ) {
bool inDate = parent - > pointInTime ( usex + usew , _height , x , y , InfoDisplayOverImage ) ;
if ( inDate ) {
state = HistoryInDateCursorState ;
2015-05-29 21:52:43 +03:00
}
2014-12-23 02:11:37 +03:00
}
}
const QString HistorySticker : : inDialogsText ( ) const {
2015-01-05 23:17:33 +03:00
return _emoji . isEmpty ( ) ? lang ( lng_in_dlg_sticker ) : lng_in_dlg_sticker_emoji ( lt_emoji , _emoji ) ;
2014-12-23 02:11:37 +03:00
}
const QString HistorySticker : : inHistoryText ( ) const {
2015-01-05 23:17:33 +03:00
return qsl ( " [ " ) + inDialogsText ( ) + qsl ( " ] " ) ;
2014-12-23 02:11:37 +03:00
}
2015-12-19 21:09:24 +03:00
void HistorySticker : : regItem ( HistoryItem * item ) {
2015-12-23 15:19:32 +03:00
App : : regDocumentItem ( _data , item ) ;
2014-12-23 02:11:37 +03:00
}
2015-12-19 21:09:24 +03:00
void HistorySticker : : unregItem ( HistoryItem * item ) {
2015-12-23 15:19:32 +03:00
App : : unregDocumentItem ( _data , item ) ;
2015-12-19 21:09:24 +03:00
}
2015-08-31 17:27:20 +03:00
2015-12-19 21:09:24 +03:00
void HistorySticker : : updateFrom ( const MTPMessageMedia & media , HistoryItem * parent , bool allowEmitResize ) {
if ( media . type ( ) = = mtpc_messageMediaDocument ) {
2015-12-23 15:19:32 +03:00
App : : feedDocument ( media . c_messageMediaDocument ( ) . vdocument , _data ) ;
2015-12-24 22:26:28 +03:00
if ( ! _data - > data ( ) . isEmpty ( ) ) {
Local : : writeStickerImage ( mediaKey ( DocumentFileLocation , _data - > dc , _data - > id ) , _data - > data ( ) ) ;
2015-12-19 00:36:16 +03:00
}
2015-08-31 17:27:20 +03:00
}
2014-12-23 02:11:37 +03:00
}
2015-12-13 01:29:33 +03:00
void SendMessageLink : : onClick ( Qt : : MouseButton button ) const {
if ( button = = Qt : : LeftButton ) {
Ui : : showPeerHistory ( peer ( ) - > id , ShowAtUnreadMsgId ) ;
}
}
2015-09-23 20:43:08 +03:00
2015-12-13 01:29:33 +03:00
void AddContactLink : : onClick ( Qt : : MouseButton button ) const {
if ( button = = Qt : : LeftButton ) {
if ( HistoryItem * item = App : : histItemById ( peerToChannel ( peer ( ) ) , msgid ( ) ) ) {
if ( HistoryMedia * media = item - > getMedia ( ) ) {
if ( media - > type ( ) = = MediaTypeContact ) {
QString fname = static_cast < HistoryContact * > ( media ) - > fname ( ) ;
QString lname = static_cast < HistoryContact * > ( media ) - > lname ( ) ;
QString phone = static_cast < HistoryContact * > ( media ) - > phone ( ) ;
Ui : : showLayer ( new AddContactBox ( fname , lname , phone ) ) ;
}
}
}
2015-09-23 20:43:08 +03:00
}
}
2015-12-13 01:29:33 +03:00
HistoryContact : : HistoryContact ( int32 userId , const QString & first , const QString & last , const QString & phone ) : HistoryMedia ( )
, _userId ( userId )
, _contact ( 0 )
, _phonew ( 0 )
, _fname ( first )
, _lname ( last )
, _phone ( App : : formatPhone ( phone ) )
, _linkw ( 0 ) {
_name . setText ( st : : semiboldFont , lng_full_name ( lt_first_name , first , lt_last_name , last ) . trimmed ( ) , _textNameOptions ) ;
2015-09-23 20:43:08 +03:00
2015-12-13 01:29:33 +03:00
_phonew = st : : normalFont - > width ( _phone ) ;
}
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
void HistoryContact : : initDimensions ( const HistoryItem * parent ) {
_maxw = st : : msgFileMinWidth ;
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
_contact = _userId ? App : : userLoaded ( _userId ) : 0 ;
if ( _contact ) {
_contact - > photo - > load ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-13 01:29:33 +03:00
if ( _contact & & _contact - > contact > 0 ) {
_linkl . reset ( new SendMessageLink ( _contact ) ) ;
_link = lang ( lng_profile_send_message ) . toUpper ( ) ;
} else if ( _userId ) {
_linkl . reset ( new AddContactLink ( parent - > history ( ) - > peer - > id , parent - > id ) ) ;
_link = lang ( lng_profile_add_contact ) . toUpper ( ) ;
}
_linkw = _link . isEmpty ( ) ? 0 : st : : semiboldFont - > width ( _link ) ;
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
int32 tleft = 0 , tright = 0 ;
if ( _userId ) {
tleft = st : : msgFileThumbPadding . left ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . right ( ) ;
tright = st : : msgFileThumbPadding . left ( ) ;
_maxw = qMax ( _maxw , tleft + _phonew + tright ) ;
} else {
tleft = st : : msgFilePadding . left ( ) + st : : msgFileSize + st : : msgFilePadding . right ( ) ;
tright = st : : msgFileThumbPadding . left ( ) ;
_maxw = qMax ( _maxw , tleft + _phonew + parent - > skipBlockWidth ( ) + st : : msgPadding . right ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-13 01:29:33 +03:00
_maxw = qMax ( tleft + _name . maxWidth ( ) + tright , _maxw ) ;
_maxw = qMin ( _maxw , int ( st : : msgMaxWidth ) ) ;
if ( _userId ) {
2015-12-19 21:09:24 +03:00
_minh = st : : msgFileThumbPadding . top ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . bottom ( ) ;
2015-12-13 01:29:33 +03:00
} else {
2015-12-19 21:09:24 +03:00
_minh = st : : msgFilePadding . top ( ) + st : : msgFileSize + st : : msgFilePadding . bottom ( ) ;
2015-12-13 01:29:33 +03:00
}
2015-12-19 21:09:24 +03:00
_height = _minh ;
2014-05-30 12:53:19 +04:00
}
2015-12-11 21:11:38 +03:00
void HistoryContact : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
2015-12-19 21:09:24 +03:00
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
2015-03-19 12:18:19 +03:00
2015-09-13 20:27:29 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-12-13 01:29:33 +03:00
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
width = _maxw ;
}
2015-12-13 01:29:33 +03:00
int32 nameleft = 0 , nametop = 0 , nameright = 0 , statustop = 0 , linktop = 0 ;
if ( _userId ) {
nameleft = st : : msgFileThumbPadding . left ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . right ( ) ;
nametop = st : : msgFileThumbNameTop ;
nameright = st : : msgFileThumbPadding . left ( ) ;
statustop = st : : msgFileThumbStatusTop ;
linktop = st : : msgFileThumbLinkTop ;
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
QRect rthumb ( rtlrect ( st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . top ( ) , st : : msgFileThumbSize , st : : msgFileThumbSize , width ) ) ;
if ( _contact & & _contact - > photo - > loaded ( ) ) {
QPixmap thumb = _contact - > photo - > pixRounded ( st : : msgFileThumbSize , st : : msgFileThumbSize ) ;
p . drawPixmap ( rthumb . topLeft ( ) , thumb ) ;
} else {
2015-12-13 14:17:15 +03:00
p . drawPixmap ( rthumb . topLeft ( ) , userDefPhoto ( _contact ? _contact - > colorIndex : ( qAbs ( _userId ) % UserColorsCount ) ) - > pixRounded ( st : : msgFileThumbSize , st : : msgFileThumbSize ) ) ;
2015-12-13 01:29:33 +03:00
}
if ( selected ) {
App : : roundRect ( p , rthumb , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
bool over = textlnkDrawOver ( _linkl ) ;
p . setFont ( over ? st : : semiboldFont - > underline ( ) : st : : semiboldFont ) ;
p . setPen ( outbg ? ( selected ? st : : msgFileThumbLinkOutFgSelected : st : : msgFileThumbLinkOutFg ) : ( selected ? st : : msgFileThumbLinkInFgSelected : st : : msgFileThumbLinkInFg ) ) ;
p . drawTextLeft ( nameleft , linktop , width , _link , _linkw ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-12-13 01:29:33 +03:00
nameleft = st : : msgFilePadding . left ( ) + st : : msgFileSize + st : : msgFilePadding . right ( ) ;
nametop = st : : msgFileNameTop ;
nameright = st : : msgFilePadding . left ( ) ;
statustop = st : : msgFileStatusTop ;
QRect inner ( rtlrect ( st : : msgFilePadding . left ( ) , st : : msgFilePadding . top ( ) , st : : msgFileSize , st : : msgFileSize , width ) ) ;
2015-12-13 14:17:15 +03:00
p . drawPixmap ( inner . topLeft ( ) , userDefPhoto ( qAbs ( parent - > id ) % UserColorsCount ) - > pixRounded ( st : : msgFileSize , st : : msgFileSize ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-13 01:29:33 +03:00
int32 namewidth = width - nameleft - nameright ;
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
p . setFont ( st : : semiboldFont ) ;
p . setPen ( st : : black ) ;
_name . drawLeftElided ( p , nameleft , nametop , namewidth , width ) ;
2015-12-19 21:09:24 +03:00
2015-12-11 21:11:38 +03:00
style : : color status ( outbg ? ( selected ? st : : mediaOutFgSelected : st : : mediaOutFg ) : ( selected ? st : : mediaInFgSelected : st : : mediaInFg ) ) ;
2015-12-13 01:29:33 +03:00
p . setFont ( st : : normalFont ) ;
p . setPen ( status ) ;
p . drawTextLeft ( nameleft , statustop , width , _phone ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
void HistoryContact : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
int32 nameleft = 0 , nametop = 0 , nameright = 0 , statustop = 0 , linktop = 0 ;
if ( _userId ) {
nameleft = st : : msgFileThumbPadding . left ( ) + st : : msgFileThumbSize + st : : msgFileThumbPadding . right ( ) ;
linktop = st : : msgFileThumbLinkTop ;
if ( rtlrect ( nameleft , linktop , _linkw , st : : semiboldFont - > height , _width ) . contains ( x , y ) ) {
lnk = _linkl ;
return ;
}
}
if ( x > = 0 & & y > = 0 & & x < _width & & y < _height & & _contact ) {
lnk = _contact - > lnk ;
return ;
}
}
const QString HistoryContact : : inDialogsText ( ) const {
return lang ( lng_in_dlg_contact ) ;
}
const QString HistoryContact : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_contact ) + qsl ( " : " ) + _name . original ( ) + qsl ( " , " ) + _phone + qsl ( " ] " ) ;
}
void HistoryContact : : regItem ( HistoryItem * item ) {
if ( _userId ) {
App : : regSharedContactItem ( _userId , item ) ;
}
}
void HistoryContact : : unregItem ( HistoryItem * item ) {
if ( _userId ) {
App : : unregSharedContactItem ( _userId , item ) ;
}
}
2015-12-13 01:29:33 +03:00
void HistoryContact : : updateFrom ( const MTPMessageMedia & media , HistoryItem * parent , bool allowEmitResize ) {
2014-08-22 18:55:23 +04:00
if ( media . type ( ) = = mtpc_messageMediaContact ) {
2015-12-13 01:29:33 +03:00
if ( _userId ! = media . c_messageMediaContact ( ) . vuser_id . v ) {
unregItem ( parent ) ;
_userId = media . c_messageMediaContact ( ) . vuser_id . v ;
regItem ( parent ) ;
parent - > initDimensions ( ) ;
2015-12-22 11:01:02 +03:00
if ( allowEmitResize ) Notify : : historyItemResized ( parent ) ;
2014-08-22 18:55:23 +04:00
}
}
}
2015-12-19 00:36:16 +03:00
namespace {
QString siteNameFromUrl ( const QString & url ) {
QUrl u ( url ) ;
QString pretty = u . isValid ( ) ? u . toDisplayString ( ) : url ;
QRegularExpressionMatch m = QRegularExpression ( qsl ( " ^[a-zA-Z0-9]+:// " ) ) . match ( pretty ) ;
if ( m . hasMatch ( ) ) pretty = pretty . mid ( m . capturedLength ( ) ) ;
int32 slash = pretty . indexOf ( ' / ' ) ;
if ( slash > 0 ) pretty = pretty . mid ( 0 , slash ) ;
QStringList components = pretty . split ( ' . ' , QString : : SkipEmptyParts ) ;
if ( components . size ( ) > = 2 ) {
components = components . mid ( components . size ( ) - 2 ) ;
return components . at ( 0 ) . at ( 0 ) . toUpper ( ) + components . at ( 0 ) . mid ( 1 ) + ' . ' + components . at ( 1 ) ;
}
return QString ( ) ;
}
int32 articleThumbWidth ( PhotoData * thumb , int32 height ) {
int32 w = thumb - > medium - > width ( ) , h = thumb - > medium - > height ( ) ;
return qMax ( qMin ( height * w / h , height ) , 1 ) ;
}
int32 articleThumbHeight ( PhotoData * thumb , int32 width ) {
return qMax ( thumb - > medium - > height ( ) * width / thumb - > medium - > width ( ) , 1 ) ;
}
int32 _lineHeight = 0 ;
}
2015-04-04 23:01:34 +03:00
HistoryWebPage : : HistoryWebPage ( WebPageData * data ) : HistoryMedia ( )
2015-12-19 00:36:16 +03:00
, _data ( data )
2015-09-01 16:50:56 +03:00
, _openl ( 0 )
2015-12-19 00:36:16 +03:00
, _attach ( 0 )
2015-04-04 23:01:34 +03:00
, _asArticle ( false )
, _title ( st : : msgMinWidth - st : : webPageLeft )
, _description ( st : : msgMinWidth - st : : webPageLeft )
, _siteNameWidth ( 0 )
, _durationWidth ( 0 )
2015-12-19 00:36:16 +03:00
, _pixw ( 0 )
, _pixh ( 0 ) {
}
HistoryWebPage : : HistoryWebPage ( const HistoryWebPage & other ) : HistoryMedia ( )
, _data ( other . _data )
, _openl ( 0 )
, _attach ( other . _attach ? other . _attach - > clone ( ) : 0 )
, _asArticle ( other . _asArticle )
, _title ( other . _title )
, _description ( other . _description )
, _siteNameWidth ( other . _siteNameWidth )
, _durationWidth ( other . _durationWidth )
, _pixw ( other . _pixw )
, _pixh ( other . _pixh ) {
2015-04-04 23:01:34 +03:00
}
void HistoryWebPage : : initDimensions ( const HistoryItem * parent ) {
2015-12-19 00:36:16 +03:00
if ( _data - > pendingTill ) {
2015-05-20 22:28:24 +03:00
_maxw = _minh = _height = 0 ;
2015-04-04 23:01:34 +03:00
return ;
}
2015-09-01 16:50:56 +03:00
2015-12-19 00:36:16 +03:00
if ( ! _lineHeight ) _lineHeight = qMax ( st : : webPageTitleFont - > height , st : : webPageDescriptionFont - > height ) ;
if ( ! _openl & & ! _data - > url . isEmpty ( ) ) _openl = TextLinkPtr ( new TextLink ( _data - > url ) ) ;
// init layout
QString title ( _data - > title . isEmpty ( ) ? _data - > author : _data - > title ) ;
if ( ! _data - > description . isEmpty ( ) & & title . isEmpty ( ) & & _data - > siteName . isEmpty ( ) & & ! _data - > url . isEmpty ( ) ) {
_data - > siteName = siteNameFromUrl ( _data - > url ) ;
}
if ( ! _data - > doc & & _data - > photo & & _data - > type ! = WebPagePhoto & & _data - > type ! = WebPageVideo ) {
if ( _data - > type = = WebPageProfile ) {
2015-04-04 23:01:34 +03:00
_asArticle = true ;
2015-12-19 00:36:16 +03:00
} else if ( _data - > siteName = = qstr ( " Twitter " ) | | _data - > siteName = = qstr ( " Facebook " ) ) {
2015-04-04 23:01:34 +03:00
_asArticle = false ;
} else {
_asArticle = true ;
}
2015-12-19 00:36:16 +03:00
if ( _asArticle & & ( _data - > description . isEmpty ( ) | | ( title . isEmpty ( ) & & _data - > siteName . isEmpty ( ) ) ) ) {
_asArticle = false ;
}
2015-04-04 23:01:34 +03:00
} else {
_asArticle = false ;
}
2015-09-01 16:50:56 +03:00
2015-12-19 00:36:16 +03:00
// init attach
if ( ! _asArticle & & ! _attach ) {
if ( _data - > doc ) {
if ( _data - > doc - > sticker ( ) ) {
_attach = new HistorySticker ( _data - > doc ) ;
} else if ( _data - > doc - > isAnimation ( ) ) {
2015-12-28 13:28:00 +03:00
_attach = new HistoryGif ( _data - > doc , QString ( ) , parent ) ;
2015-09-01 16:50:56 +03:00
} else {
2015-12-28 13:28:00 +03:00
_attach = new HistoryDocument ( _data - > doc , QString ( ) , parent ) ;
2015-09-01 16:50:56 +03:00
}
2015-12-19 00:36:16 +03:00
} else if ( _data - > photo ) {
_attach = new HistoryPhoto ( _data - > photo ) ;
2015-09-01 16:50:56 +03:00
}
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
// init strings
if ( _description . isEmpty ( ) & & ! _data - > description . isEmpty ( ) ) {
QString text = textClean ( _data - > description ) ;
if ( text . isEmpty ( ) ) {
_data - > description = QString ( ) ;
2015-04-04 23:01:34 +03:00
} else {
2015-12-19 00:36:16 +03:00
if ( ! _asArticle & & ! _attach ) {
text + = parent - > skipBlock ( ) ;
}
const TextParseOptions * opts = & _webpageDescriptionOptions ;
if ( _data - > siteName = = qstr ( " Twitter " ) ) {
opts = & _twitterDescriptionOptions ;
} else if ( _data - > siteName = = qstr ( " Instagram " ) ) {
opts = & _instagramDescriptionOptions ;
}
_description . setText ( st : : webPageDescriptionFont , text , * opts ) ;
2015-04-04 23:01:34 +03:00
}
}
2015-12-19 00:36:16 +03:00
if ( _title . isEmpty ( ) & & ! title . isEmpty ( ) ) {
title = textOneLine ( textClean ( title ) ) ;
if ( title . isEmpty ( ) ) {
if ( _data - > title . isEmpty ( ) ) {
_data - > author = QString ( ) ;
} else {
_data - > title = QString ( ) ;
}
2015-04-04 23:01:34 +03:00
} else {
2015-12-19 00:36:16 +03:00
if ( ! _asArticle & & ! _attach & & _description . isEmpty ( ) ) {
title + = parent - > skipBlock ( ) ;
}
_title . setText ( st : : webPageTitleFont , title , _webpageTitleOptions ) ;
2015-04-04 23:01:34 +03:00
}
}
2015-12-19 00:36:16 +03:00
if ( ! _siteNameWidth & & ! _data - > siteName . isEmpty ( ) ) {
_siteNameWidth = st : : webPageTitleFont - > width ( _data - > siteName ) ;
}
// init dimensions
int32 l = st : : msgPadding . left ( ) + st : : webPageLeft , r = st : : msgPadding . right ( ) ;
int32 skipBlockWidth = parent - > skipBlockWidth ( ) ;
_maxw = skipBlockWidth ;
_minh = 0 ;
int32 siteNameHeight = _data - > siteName . isEmpty ( ) ? 0 : _lineHeight ;
int32 titleMinHeight = _title . isEmpty ( ) ? 0 : _lineHeight ;
int32 descMaxLines = ( 3 + ( siteNameHeight ? 0 : 1 ) + ( titleMinHeight ? 0 : 1 ) ) ;
int32 descriptionMinHeight = _description . isEmpty ( ) ? 0 : qMin ( _description . minHeight ( ) , descMaxLines * _lineHeight ) ;
int32 articleMinHeight = siteNameHeight + titleMinHeight + descriptionMinHeight ;
int32 articlePhotoMaxWidth = 0 ;
if ( _asArticle ) {
articlePhotoMaxWidth = st : : webPagePhotoDelta + qMax ( articleThumbWidth ( _data - > photo , articleMinHeight ) , _lineHeight ) ;
}
if ( _siteNameWidth ) {
if ( _title . isEmpty ( ) & & _description . isEmpty ( ) ) {
_maxw = qMax ( _maxw , int32 ( _siteNameWidth + parent - > skipBlockWidth ( ) ) ) ;
2015-04-04 23:01:34 +03:00
} else {
2015-12-19 00:36:16 +03:00
_maxw = qMax ( _maxw , int32 ( _siteNameWidth + articlePhotoMaxWidth ) ) ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
_minh + = _lineHeight ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
if ( ! _title . isEmpty ( ) ) {
_maxw = qMax ( _maxw , int32 ( _title . maxWidth ( ) + articlePhotoMaxWidth ) ) ;
_minh + = titleMinHeight ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
if ( ! _description . isEmpty ( ) ) {
_maxw = qMax ( _maxw , int32 ( _description . maxWidth ( ) + articlePhotoMaxWidth ) ) ;
_minh + = descriptionMinHeight ;
}
if ( _attach ) {
if ( _minh ) _minh + = st : : webPagePhotoSkip ;
_attach - > initDimensions ( parent ) ;
QMargins bubble ( _attach - > bubbleMargins ( ) ) ;
_maxw = qMax ( _maxw , int32 ( _attach - > maxWidth ( ) - bubble . left ( ) - bubble . top ( ) + ( _attach - > customInfoLayout ( ) ? skipBlockWidth : 0 ) ) ) ;
_minh + = _attach - > minHeight ( ) - bubble . top ( ) - bubble . bottom ( ) ;
}
if ( _data - > type = = WebPageVideo & & _data - > duration ) {
_duration = formatDurationText ( _data - > duration ) ;
2015-10-03 13:09:09 +03:00
_durationWidth = st : : msgDateFont - > width ( _duration ) ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
_maxw + = st : : msgPadding . left ( ) + st : : webPageLeft + st : : msgPadding . right ( ) ;
_minh + = st : : msgPadding . bottom ( ) ;
if ( _asArticle ) {
2015-12-28 00:37:48 +03:00
_minh = resize ( _maxw , parent ) ; // hack
// _minh += st::msgDateFont->height;
2015-12-19 00:36:16 +03:00
}
}
2015-08-30 17:57:21 +03:00
2015-12-19 00:36:16 +03:00
int32 HistoryWebPage : : resize ( int32 width , const HistoryItem * parent ) {
if ( _data - > pendingTill ) {
2015-12-19 21:09:24 +03:00
_width = width ;
2015-12-19 00:36:16 +03:00
_height = _minh ;
return _height ;
}
2015-08-30 17:57:21 +03:00
2015-12-19 21:09:24 +03:00
_width = qMin ( width , _maxw ) ;
2015-12-19 00:36:16 +03:00
width - = st : : msgPadding . left ( ) + st : : webPageLeft + st : : msgPadding . right ( ) ;
2015-08-30 17:57:21 +03:00
2015-12-19 00:36:16 +03:00
int32 linesMax = 5 ;
int32 siteNameLines = _siteNameWidth ? 1 : 0 , siteNameHeight = _siteNameWidth ? _lineHeight : 0 ;
if ( _asArticle ) {
_pixh = linesMax * _lineHeight ;
do {
_pixw = articleThumbWidth ( _data - > photo , _pixh ) ;
int32 wleft = width - st : : webPagePhotoDelta - qMax ( _pixw , int16 ( _lineHeight ) ) ;
_height = siteNameHeight ;
2015-08-30 17:57:21 +03:00
2015-12-19 00:36:16 +03:00
if ( _title . isEmpty ( ) ) {
_titleLines = 0 ;
} else {
if ( _title . countHeight ( wleft ) < 2 * st : : webPageTitleFont - > height ) {
_titleLines = 1 ;
2015-08-30 17:57:21 +03:00
} else {
2015-12-19 00:36:16 +03:00
_titleLines = 2 ;
2015-08-30 17:57:21 +03:00
}
2015-12-19 00:36:16 +03:00
_height + = _titleLines * _lineHeight ;
2015-08-30 17:57:21 +03:00
}
2015-12-19 00:36:16 +03:00
int32 descriptionHeight = _description . countHeight ( wleft ) ;
if ( descriptionHeight < ( linesMax - siteNameLines - _titleLines ) * st : : webPageDescriptionFont - > height ) {
_descriptionLines = ( descriptionHeight / st : : webPageDescriptionFont - > height ) ;
2015-08-30 17:57:21 +03:00
} else {
2015-12-19 00:36:16 +03:00
_descriptionLines = ( linesMax - siteNameLines - _titleLines ) ;
2015-08-30 17:57:21 +03:00
}
2015-12-19 00:36:16 +03:00
_height + = _descriptionLines * _lineHeight ;
2015-08-30 17:57:21 +03:00
2015-12-19 00:36:16 +03:00
if ( _height > = _pixh ) {
break ;
}
2015-04-04 23:01:34 +03:00
2015-12-19 00:36:16 +03:00
_pixh - = _lineHeight ;
} while ( _pixh > _lineHeight ) ;
_height + = st : : msgDateFont - > height ;
} else {
_height = siteNameHeight ;
2015-04-04 23:01:34 +03:00
2015-12-19 00:36:16 +03:00
if ( _title . isEmpty ( ) ) {
_titleLines = 0 ;
} else {
if ( _title . countHeight ( width ) < 2 * st : : webPageTitleFont - > height ) {
_titleLines = 1 ;
} else {
_titleLines = 2 ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
_height + = _titleLines * _lineHeight ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
if ( _description . isEmpty ( ) ) {
_descriptionLines = 0 ;
2015-04-04 23:01:34 +03:00
} else {
2015-12-19 21:09:24 +03:00
int32 descriptionHeight = _description . countHeight ( width ) ;
if ( descriptionHeight < ( linesMax - siteNameLines - _titleLines ) * st : : webPageDescriptionFont - > height ) {
_descriptionLines = ( descriptionHeight / st : : webPageDescriptionFont - > height ) ;
} else {
_descriptionLines = ( linesMax - siteNameLines - _titleLines ) ;
}
_height + = _descriptionLines * _lineHeight ;
}
if ( _attach ) {
if ( _height ) _height + = st : : webPagePhotoSkip ;
QMargins bubble ( _attach - > bubbleMargins ( ) ) ;
_attach - > resize ( width + bubble . left ( ) + bubble . right ( ) , parent ) ;
_height + = _attach - > height ( ) - bubble . top ( ) - bubble . bottom ( ) ;
if ( _attach - > customInfoLayout ( ) & & _attach - > currentWidth ( ) + parent - > skipBlockWidth ( ) > width + bubble . left ( ) + bubble . right ( ) ) {
_height + = st : : msgDateFont - > height ;
}
}
}
_height + = st : : msgPadding . bottom ( ) ;
return _height ;
}
void HistoryWebPage : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
style : : color barfg = ( selected ? ( outbg ? st : : msgOutReplyBarSelColor : st : : msgInReplyBarSelColor ) : ( outbg ? st : : msgOutReplyBarColor : st : : msgInReplyBarColor ) ) ;
style : : color semibold = ( selected ? ( outbg ? st : : msgOutServiceFgSelected : st : : msgInServiceFgSelected ) : ( outbg ? st : : msgOutServiceFg : st : : msgInServiceFg ) ) ;
style : : color regular = ( selected ? ( outbg ? st : : msgOutDateFgSelected : st : : msgInDateFgSelected ) : ( outbg ? st : : msgOutDateFg : st : : msgInDateFg ) ) ;
int32 lshift = st : : msgPadding . left ( ) + st : : webPageLeft , rshift = st : : msgPadding . right ( ) , bshift = st : : msgPadding . bottom ( ) ;
width - = lshift + rshift ;
QMargins bubble ( _attach ? _attach - > bubbleMargins ( ) : QMargins ( ) ) ;
if ( _asArticle | | ( _attach & & _attach - > customInfoLayout ( ) & & _attach - > currentWidth ( ) + parent - > skipBlockWidth ( ) > width + bubble . left ( ) + bubble . right ( ) ) ) {
bshift + = st : : msgDateFont - > height ;
}
QRect bar ( rtlrect ( st : : msgPadding . left ( ) , 0 , st : : webPageBar , _height - bshift , _width ) ) ;
p . fillRect ( bar , barfg ) ;
if ( _asArticle ) {
_data - > photo - > medium - > load ( false , false ) ;
bool full = _data - > photo - > medium - > loaded ( ) ;
QPixmap pix ;
int32 pw = qMax ( _pixw , int16 ( _lineHeight ) ) ;
if ( full ) {
pix = _data - > photo - > medium - > pixSingle ( _pixw , articleThumbHeight ( _data - > photo , _pixw ) , pw , _pixh ) ;
} else {
pix = _data - > photo - > thumb - > pixBlurredSingle ( _pixw , articleThumbHeight ( _data - > photo , _pixw ) , pw , _pixh ) ;
2015-08-30 17:57:21 +03:00
}
2015-12-19 21:09:24 +03:00
p . drawPixmapLeft ( lshift + width - pw , 0 , _width , pix ) ;
if ( selected ) {
App : : roundRect ( p , rtlrect ( lshift + width - pw , 0 , pw , _pixh , _width ) , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 21:09:24 +03:00
width - = pw + st : : webPagePhotoDelta ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 21:09:24 +03:00
int32 tshift = 0 ;
if ( _siteNameWidth ) {
p . setFont ( st : : webPageTitleFont ) ;
p . setPen ( semibold ) ;
p . drawTextLeft ( lshift , tshift , _width , ( width > = _siteNameWidth ) ? _data - > siteName : st : : webPageTitleFont - > elided ( _data - > siteName , width ) ) ;
tshift + = _lineHeight ;
}
if ( _titleLines ) {
p . setPen ( st : : black ) ;
int32 endskip = 0 ;
if ( _title . hasSkipBlock ( ) ) {
endskip = parent - > skipBlockWidth ( ) ;
}
_title . drawLeftElided ( p , lshift , tshift , width , _width , _titleLines , style : : al_left , 0 , - 1 , endskip ) ;
tshift + = _titleLines * _lineHeight ;
}
if ( _descriptionLines ) {
p . setPen ( st : : black ) ;
int32 endskip = 0 ;
if ( _description . hasSkipBlock ( ) ) {
endskip = parent - > skipBlockWidth ( ) ;
}
_description . drawLeftElided ( p , lshift , tshift , width , _width , _descriptionLines , style : : al_left , 0 , - 1 , endskip ) ;
tshift + = _descriptionLines * _lineHeight ;
}
if ( _attach ) {
if ( tshift ) tshift + = st : : webPagePhotoSkip ;
2015-04-04 23:01:34 +03:00
2015-12-19 21:09:24 +03:00
int32 attachLeft = lshift - bubble . left ( ) , attachTop = tshift - bubble . top ( ) ;
if ( rtl ( ) ) attachLeft = _width - attachLeft - _attach - > currentWidth ( ) ;
2015-04-04 23:01:34 +03:00
2015-12-19 21:09:24 +03:00
p . save ( ) ;
p . translate ( attachLeft , attachTop ) ;
2015-04-04 23:01:34 +03:00
2015-12-19 21:09:24 +03:00
_attach - > draw ( p , parent , r . translated ( - attachLeft , - attachTop ) , selected , ms ) ;
int32 pixwidth = _attach - > currentWidth ( ) , pixheight = _attach - > height ( ) ;
if ( _data - > type = = WebPageVideo ) {
if ( _data - > siteName = = qstr ( " YouTube " ) ) {
p . drawPixmap ( QPoint ( ( pixwidth - st : : youtubeIcon . pxWidth ( ) ) / 2 , ( pixheight - st : : youtubeIcon . pxHeight ( ) ) / 2 ) , App : : sprite ( ) , st : : youtubeIcon ) ;
} else {
p . drawPixmap ( QPoint ( ( pixwidth - st : : videoIcon . pxWidth ( ) ) / 2 , ( pixheight - st : : videoIcon . pxHeight ( ) ) / 2 ) , App : : sprite ( ) , st : : videoIcon ) ;
}
if ( _durationWidth ) {
int32 dateX = pixwidth - _durationWidth - st : : msgDateImgDelta - 2 * st : : msgDateImgPadding . x ( ) ;
int32 dateY = pixheight - st : : msgDateFont - > height - 2 * st : : msgDateImgPadding . y ( ) - st : : msgDateImgDelta ;
int32 dateW = pixwidth - dateX - st : : msgDateImgDelta ;
int32 dateH = pixheight - dateY - st : : msgDateImgDelta ;
2015-04-04 23:01:34 +03:00
2015-12-19 21:09:24 +03:00
App : : roundRect ( p , dateX , dateY , dateW , dateH , selected ? st : : msgDateImgBgSelected : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2015-04-04 23:01:34 +03:00
2015-12-19 21:09:24 +03:00
p . setFont ( st : : msgDateFont ) ;
p . setPen ( st : : msgDateImgColor ) ;
p . drawTextLeft ( dateX + st : : msgDateImgPadding . x ( ) , dateY + st : : msgDateImgPadding . y ( ) , pixwidth , _duration ) ;
}
}
2015-04-04 23:01:34 +03:00
2015-12-19 21:09:24 +03:00
p . restore ( ) ;
}
2015-04-04 23:01:34 +03:00
}
2015-12-19 21:09:24 +03:00
void HistoryWebPage : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
2015-04-04 23:01:34 +03:00
2015-12-19 00:36:16 +03:00
int32 lshift = st : : msgPadding . left ( ) + st : : webPageLeft , rshift = st : : msgPadding . right ( ) , bshift = st : : msgPadding . bottom ( ) ;
width - = lshift + rshift ;
QMargins bubble ( _attach ? _attach - > bubbleMargins ( ) : QMargins ( ) ) ;
if ( _asArticle | | ( _attach & & _attach - > customInfoLayout ( ) & & _attach - > currentWidth ( ) + parent - > skipBlockWidth ( ) > width + bubble . left ( ) + bubble . right ( ) ) ) {
bshift + = st : : msgDateFont - > height ;
}
2015-04-04 23:01:34 +03:00
2015-04-08 02:03:32 +03:00
if ( _asArticle ) {
2015-12-19 00:36:16 +03:00
int32 pw = qMax ( _pixw , int16 ( _lineHeight ) ) ;
2015-12-19 21:09:24 +03:00
if ( rtlrect ( lshift + width - pw , 0 , pw , _pixh , _width ) . contains ( x , y ) ) {
2015-04-08 02:03:32 +03:00
lnk = _openl ;
return ;
2015-04-04 23:01:34 +03:00
}
2015-12-19 00:36:16 +03:00
width - = pw + st : : webPagePhotoDelta ;
2015-04-08 02:03:32 +03:00
}
2015-12-19 00:36:16 +03:00
int32 tshift = 0 ;
2015-04-08 02:03:32 +03:00
if ( _siteNameWidth ) {
2015-12-19 00:36:16 +03:00
tshift + = _lineHeight ;
2015-04-08 02:03:32 +03:00
}
2015-12-19 00:36:16 +03:00
if ( _titleLines ) {
tshift + = _titleLines * _lineHeight ;
2015-04-08 02:03:32 +03:00
}
2015-12-19 00:36:16 +03:00
if ( _descriptionLines ) {
if ( y > = tshift & & y < tshift + _descriptionLines * _lineHeight ) {
2015-06-27 16:02:00 +03:00
bool inText = false ;
2015-12-19 21:09:24 +03:00
_description . getStateLeft ( lnk , inText , x - lshift , y - tshift , width , _width ) ;
2015-06-27 16:02:00 +03:00
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
2015-04-08 02:03:32 +03:00
return ;
}
2015-12-19 00:36:16 +03:00
tshift + = _descriptionLines * _lineHeight ;
2015-04-08 02:03:32 +03:00
}
2015-12-19 00:36:16 +03:00
if ( _attach ) {
if ( tshift ) tshift + = st : : webPagePhotoSkip ;
if ( x > = lshift & & x < lshift + width & & y > = tshift & & y < _height - st : : msgPadding . bottom ( ) ) {
2015-12-19 15:27:03 +03:00
int32 attachLeft = lshift - bubble . left ( ) , attachTop = tshift - bubble . top ( ) ;
2015-12-19 21:09:24 +03:00
if ( rtl ( ) ) attachLeft = _width - attachLeft - _attach - > currentWidth ( ) ;
2015-12-19 15:27:03 +03:00
_attach - > getState ( lnk , state , x - attachLeft , y - attachTop , parent ) ;
2015-12-24 22:26:28 +03:00
if ( lnk & & ! _data - > doc & & _data - > photo ) {
2015-12-23 14:13:08 +03:00
if ( _data - > type = = WebPageProfile | | _data - > type = = WebPageVideo ) {
lnk = _openl ;
} else if ( _data - > type = = WebPagePhoto | | _data - > siteName = = qstr ( " Twitter " ) | | _data - > siteName = = qstr ( " Facebook " ) ) {
// leave photo link
} else {
lnk = _openl ;
}
}
2015-04-04 23:01:34 +03:00
}
}
}
2015-12-19 21:09:24 +03:00
void HistoryWebPage : : linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) {
if ( _attach ) {
_attach - > linkOver ( parent , lnk ) ;
}
}
void HistoryWebPage : : linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) {
if ( _attach ) {
_attach - > linkOut ( parent , lnk ) ;
}
}
void HistoryWebPage : : regItem ( HistoryItem * item ) {
App : : regWebPageItem ( _data , item ) ;
if ( _attach ) _attach - > regItem ( item ) ;
}
void HistoryWebPage : : unregItem ( HistoryItem * item ) {
App : : unregWebPageItem ( _data , item ) ;
if ( _attach ) _attach - > unregItem ( item ) ;
}
const QString HistoryWebPage : : inDialogsText ( ) const {
return QString ( ) ;
}
const QString HistoryWebPage : : inHistoryText ( ) const {
return QString ( ) ;
2015-04-04 23:01:34 +03:00
}
ImagePtr HistoryWebPage : : replyPreview ( ) {
2015-12-28 00:37:48 +03:00
return _attach ? _attach - > replyPreview ( ) : ( _data - > photo ? _data - > photo - > makeReplyPreview ( ) : ImagePtr ( ) ) ;
}
HistoryWebPage : : ~ HistoryWebPage ( ) {
delete _attach ;
setBadPointer ( _attach ) ;
2015-04-04 23:01:34 +03:00
}
2014-11-12 23:18:00 +03:00
namespace {
ImageLinkManager manager ;
}
void ImageLinkManager : : init ( ) {
if ( manager ) delete manager ;
manager = new QNetworkAccessManager ( ) ;
App : : setProxySettings ( * manager ) ;
2014-11-13 01:35:00 +03:00
2014-11-12 23:18:00 +03:00
connect ( manager , SIGNAL ( authenticationRequired ( QNetworkReply * , QAuthenticator * ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
2014-11-15 02:23:35 +03:00
connect ( manager , SIGNAL ( sslErrors ( QNetworkReply * , const QList < QSslError > & ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
2014-11-12 23:18:00 +03:00
connect ( manager , SIGNAL ( finished ( QNetworkReply * ) ) , this , SLOT ( onFinished ( QNetworkReply * ) ) ) ;
if ( black ) delete black ;
QImage b ( cIntRetinaFactor ( ) , cIntRetinaFactor ( ) , QImage : : Format_ARGB32_Premultiplied ) ;
{
QPainter p ( & b ) ;
p . fillRect ( QRect ( 0 , 0 , cIntRetinaFactor ( ) , cIntRetinaFactor ( ) ) , st : : white - > b ) ;
}
2014-12-23 02:11:37 +03:00
QPixmap p = QPixmap : : fromImage ( b , Qt : : ColorOnly ) ;
2014-11-12 23:18:00 +03:00
p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
black = new ImagePtr ( p , " PNG " ) ;
}
void ImageLinkManager : : reinit ( ) {
if ( manager ) App : : setProxySettings ( * manager ) ;
}
void ImageLinkManager : : deinit ( ) {
if ( manager ) {
delete manager ;
manager = 0 ;
}
if ( black ) {
delete black ;
black = 0 ;
}
dataLoadings . clear ( ) ;
imageLoadings . clear ( ) ;
}
void initImageLinkManager ( ) {
manager . init ( ) ;
}
void reinitImageLinkManager ( ) {
manager . reinit ( ) ;
}
void deinitImageLinkManager ( ) {
manager . deinit ( ) ;
}
void ImageLinkManager : : getData ( ImageLinkData * data ) {
if ( ! manager ) {
DEBUG_LOG ( ( " App Error: getting image link data without manager init! " ) ) ;
return failed ( data ) ;
}
QString url ;
switch ( data - > type ) {
2014-11-13 14:27:10 +03:00
case GoogleMapsLink : {
int32 w = st : : locationSize . width ( ) , h = st : : locationSize . height ( ) ;
int32 zoom = 13 , scale = 1 ;
if ( cScale ( ) = = dbisTwo | | cRetina ( ) ) {
scale = 2 ;
} else {
w = convertScale ( w ) ;
h = convertScale ( h ) ;
}
url = qsl ( " https://maps.googleapis.com/maps/api/staticmap?center= " ) + data - > id . mid ( 9 ) + qsl ( " &zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big| " ) . arg ( zoom ) . arg ( w ) . arg ( h ) . arg ( scale ) + data - > id . mid ( 9 ) + qsl ( " &sensor=false " ) ;
QNetworkReply * reply = manager - > get ( QNetworkRequest ( QUrl ( url ) ) ) ;
imageLoadings [ reply ] = data ;
} break ;
2014-11-12 23:18:00 +03:00
default : {
2014-11-13 01:35:00 +03:00
failed ( data ) ;
2014-11-12 23:18:00 +03:00
} break ;
}
}
void ImageLinkManager : : onFinished ( QNetworkReply * reply ) {
if ( ! manager ) return ;
if ( reply - > error ( ) ! = QNetworkReply : : NoError ) return onFailed ( reply ) ;
QVariant statusCode = reply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) ;
if ( statusCode . isValid ( ) ) {
int status = statusCode . toInt ( ) ;
if ( status = = 301 | | status = = 302 ) {
QString loc = reply - > header ( QNetworkRequest : : LocationHeader ) . toString ( ) ;
if ( ! loc . isEmpty ( ) ) {
QMap < QNetworkReply * , ImageLinkData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
ImageLinkData * d = i . value ( ) ;
if ( serverRedirects . constFind ( d ) = = serverRedirects . cend ( ) ) {
serverRedirects . insert ( d , 1 ) ;
} else if ( + + serverRedirects [ d ] > MaxHttpRedirects ) {
DEBUG_LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for image link: %1 " ) . arg ( loc ) ) ;
return onFailed ( reply ) ;
}
dataLoadings . erase ( i ) ;
dataLoadings . insert ( manager - > get ( QNetworkRequest ( loc ) ) , d ) ;
return ;
} else if ( ( i = imageLoadings . find ( reply ) ) ! = imageLoadings . cend ( ) ) {
ImageLinkData * d = i . value ( ) ;
if ( serverRedirects . constFind ( d ) = = serverRedirects . cend ( ) ) {
serverRedirects . insert ( d , 1 ) ;
} else if ( + + serverRedirects [ d ] > MaxHttpRedirects ) {
DEBUG_LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for image link: %1 " ) . arg ( loc ) ) ;
return onFailed ( reply ) ;
}
imageLoadings . erase ( i ) ;
imageLoadings . insert ( manager - > get ( QNetworkRequest ( loc ) ) , d ) ;
return ;
}
}
}
if ( status ! = 200 ) {
DEBUG_LOG ( ( " Network Error: Bad HTTP status received in onFinished() for image link: %1 " ) . arg ( status ) ) ;
return onFailed ( reply ) ;
}
}
ImageLinkData * d = 0 ;
QMap < QNetworkReply * , ImageLinkData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
d = i . value ( ) ;
dataLoadings . erase ( i ) ;
QJsonParseError e ;
QJsonDocument doc = QJsonDocument : : fromJson ( reply - > readAll ( ) , & e ) ;
if ( e . error ! = QJsonParseError : : NoError ) {
DEBUG_LOG ( ( " JSON Error: Bad json received in onFinished() for image link " ) ) ;
return onFailed ( reply ) ;
}
switch ( d - > type ) {
2014-11-13 14:27:10 +03:00
case GoogleMapsLink : failed ( d ) ; break ;
2014-11-12 23:18:00 +03:00
}
if ( App : : main ( ) ) App : : main ( ) - > update ( ) ;
} else {
i = imageLoadings . find ( reply ) ;
if ( i ! = imageLoadings . cend ( ) ) {
d = i . value ( ) ;
imageLoadings . erase ( i ) ;
QPixmap thumb ;
QByteArray format ;
QByteArray data ( reply - > readAll ( ) ) ;
{
QBuffer buffer ( & data ) ;
QImageReader reader ( & buffer ) ;
2015-12-23 14:13:08 +03:00
# if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
reader . setAutoTransform ( true ) ;
# endif
2014-11-12 23:18:00 +03:00
thumb = QPixmap : : fromImageReader ( & reader , Qt : : ColorOnly ) ;
format = reader . format ( ) ;
2014-11-13 14:27:10 +03:00
thumb . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2014-11-12 23:18:00 +03:00
if ( format . isEmpty ( ) ) format = QByteArray ( " JPG " ) ;
}
d - > loading = false ;
d - > thumb = thumb . isNull ( ) ? ( * black ) : ImagePtr ( thumb , format ) ;
serverRedirects . remove ( d ) ;
if ( App : : main ( ) ) App : : main ( ) - > update ( ) ;
}
}
}
void ImageLinkManager : : onFailed ( QNetworkReply * reply ) {
if ( ! manager ) return ;
ImageLinkData * d = 0 ;
QMap < QNetworkReply * , ImageLinkData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
d = i . value ( ) ;
dataLoadings . erase ( i ) ;
} else {
i = imageLoadings . find ( reply ) ;
if ( i ! = imageLoadings . cend ( ) ) {
d = i . value ( ) ;
imageLoadings . erase ( i ) ;
}
}
DEBUG_LOG ( ( " Network Error: failed to get data for image link %1, error %2 " ) . arg ( d ? d - > id : 0 ) . arg ( reply - > errorString ( ) ) ) ;
if ( d ) {
2014-11-13 01:35:00 +03:00
failed ( d ) ;
2014-11-12 23:18:00 +03:00
}
}
void ImageLinkManager : : failed ( ImageLinkData * data ) {
2014-11-13 01:35:00 +03:00
data - > loading = false ;
data - > thumb = * black ;
serverRedirects . remove ( data ) ;
2014-11-12 23:18:00 +03:00
}
void ImageLinkData : : load ( ) {
if ( ! thumb - > isNull ( ) ) return thumb - > load ( false , false ) ;
if ( loading ) return ;
loading = true ;
manager . getData ( this ) ;
}
2015-04-30 16:53:36 +03:00
HistoryImageLink : : HistoryImageLink ( const QString & url , const QString & title , const QString & description ) : HistoryMedia ( ) ,
_title ( st : : msgMinWidth ) ,
_description ( st : : msgMinWidth ) {
if ( ! title . isEmpty ( ) ) {
_title . setText ( st : : webPageTitleFont , textClean ( title ) , _webpageTitleOptions ) ;
}
if ( ! description . isEmpty ( ) ) {
_description . setText ( st : : webPageDescriptionFont , textClean ( description ) , _webpageDescriptionOptions ) ;
}
2014-11-13 14:27:10 +03:00
if ( url . startsWith ( qsl ( " location: " ) ) ) {
2014-11-22 12:45:04 +03:00
QString lnk = qsl ( " https://maps.google.com/maps?q= " ) + url . mid ( 9 ) + qsl ( " &ll= " ) + url . mid ( 9 ) + qsl ( " &z=17 " ) ;
2015-12-19 15:27:03 +03:00
_link . reset ( new TextLink ( lnk ) ) ;
2014-11-23 14:20:40 +03:00
2015-12-19 15:27:03 +03:00
_data = App : : imageLinkSet ( url , GoogleMapsLink , lnk ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-12-19 15:27:03 +03:00
_link . reset ( new TextLink ( url ) ) ;
2014-11-12 23:18:00 +03:00
}
}
void HistoryImageLink : : initDimensions ( const HistoryItem * parent ) {
2015-12-19 15:27:03 +03:00
bool bubble = parent - > hasBubble ( ) ;
int32 tw = fullWidth ( ) , th = fullHeight ( ) ;
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
2014-11-12 23:18:00 +03:00
}
2015-12-19 15:27:03 +03:00
int32 minWidth = qMax ( st : : minPhotoSize , parent - > infoWidth ( ) + 2 * ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
2015-12-19 21:09:24 +03:00
_maxw = qMax ( tw , int32 ( minWidth ) ) ;
2015-12-19 15:27:03 +03:00
_minh = qMax ( th , int32 ( st : : minPhotoSize ) ) ;
if ( bubble ) {
2015-03-19 12:18:19 +03:00
_maxw + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _title . isEmpty ( ) ) {
2015-12-19 15:27:03 +03:00
_minh + = qMin ( _title . countHeight ( _maxw - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) , 2 * st : : webPageTitleFont - > height ) ;
2015-04-30 16:53:36 +03:00
}
if ( ! _description . isEmpty ( ) ) {
2015-12-19 15:27:03 +03:00
_maxw = qMax ( _maxw , int32 ( st : : msgPadding . left ( ) + _description . maxWidth ( ) + st : : msgPadding . right ( ) ) ) ;
_minh + = qMin ( _description . countHeight ( _maxw - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) , 3 * st : : webPageDescriptionFont - > height ) ;
2015-04-30 16:53:36 +03:00
}
2015-12-19 15:27:03 +03:00
_minh + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
_minh + = st : : webPagePhotoSkip ;
2015-12-19 15:27:03 +03:00
if ( ! parent - > toHistoryForwarded ( ) & & ! parent - > toHistoryReply ( ) ) {
_minh + = st : : msgPadding . top ( ) ;
}
2015-04-30 16:53:36 +03:00
}
2015-03-19 12:18:19 +03:00
}
2014-11-12 23:18:00 +03:00
}
2015-12-19 21:09:24 +03:00
int32 HistoryImageLink : : resize ( int32 width , const HistoryItem * parent ) {
2015-12-19 15:27:03 +03:00
bool bubble = parent - > hasBubble ( ) ;
2015-12-19 21:09:24 +03:00
_width = qMin ( width , _maxw ) ;
if ( bubble ) {
_width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
int32 tw = fullWidth ( ) , th = fullHeight ( ) ;
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
_height = th ;
if ( tw > _width ) {
_height = ( _width * _height / tw ) ;
} else {
_width = tw ;
}
int32 minWidth = qMax ( st : : minPhotoSize , parent - > infoWidth ( ) + 2 * ( st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ) ) ;
_width = qMax ( _width , int32 ( minWidth ) ) ;
_height = qMax ( _height , int32 ( st : : minPhotoSize ) ) ;
if ( bubble ) {
_width + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
_height + = st : : mediaPadding . top ( ) + st : : mediaPadding . bottom ( ) ;
if ( ! _title . isEmpty ( ) ) {
_height + = qMin ( _title . countHeight ( _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) , st : : webPageTitleFont - > height * 2 ) ;
}
if ( ! _description . isEmpty ( ) ) {
_height + = qMin ( _description . countHeight ( _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) , st : : webPageDescriptionFont - > height * 3 ) ;
}
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
_height + = st : : webPagePhotoSkip ;
if ( ! parent - > toHistoryForwarded ( ) & & ! parent - > toHistoryReply ( ) ) {
_height + = st : : msgPadding . top ( ) ;
}
}
}
return _height ;
}
2015-12-11 21:11:38 +03:00
2015-12-19 21:09:24 +03:00
void HistoryImageLink : : draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
bool bubble = parent - > hasBubble ( ) ;
2015-09-13 20:27:29 +03:00
bool out = parent - > out ( ) , fromChannel = parent - > fromChannel ( ) , outbg = out & & ! fromChannel ;
2015-05-20 22:28:24 +03:00
2015-12-19 15:27:03 +03:00
if ( bubble ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-12-19 15:27:03 +03:00
skipy = st : : mediaPadding . top ( ) ;
2015-03-19 12:18:19 +03:00
2015-12-19 15:27:03 +03:00
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
if ( ! parent - > toHistoryForwarded ( ) & & ! parent - > toHistoryReply ( ) ) {
skipy + = st : : msgPadding . top ( ) ;
}
}
2015-12-09 22:09:29 +03:00
2015-03-19 12:18:19 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-12-19 21:09:24 +03:00
int32 textw = _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
2015-12-19 15:27:03 +03:00
p . setPen ( st : : black ) ;
2015-04-30 16:53:36 +03:00
if ( ! _title . isEmpty ( ) ) {
2015-12-19 21:09:24 +03:00
_title . drawLeftElided ( p , skipx + st : : msgPadding . left ( ) , skipy , textw , _width , 2 ) ;
2015-12-19 15:27:03 +03:00
skipy + = qMin ( _title . countHeight ( textw ) , 2 * st : : webPageTitleFont - > height ) ;
2015-04-30 16:53:36 +03:00
}
if ( ! _description . isEmpty ( ) ) {
2015-12-19 21:09:24 +03:00
_description . drawLeftElided ( p , skipx + st : : msgPadding . left ( ) , skipy , textw , _width , 3 ) ;
2015-12-19 15:27:03 +03:00
skipy + = qMin ( _description . countHeight ( textw ) , 3 * st : : webPageDescriptionFont - > height ) ;
2015-04-30 16:53:36 +03:00
}
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
skipy + = st : : webPagePhotoSkip ;
}
2015-03-19 12:18:19 +03:00
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-05-20 22:28:24 +03:00
} else {
2015-12-19 21:09:24 +03:00
App : : roundShadow ( p , 0 , 0 , width , height , selected ? st : : msgInShadowSelected : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
2015-03-19 12:18:19 +03:00
}
2014-11-12 23:18:00 +03:00
2015-12-19 15:27:03 +03:00
_data - > load ( ) ;
2014-11-12 23:18:00 +03:00
QPixmap toDraw ;
2015-12-19 15:27:03 +03:00
if ( _data & & ! _data - > thumb - > isNull ( ) ) {
int32 w = _data - > thumb - > width ( ) , h = _data - > thumb - > height ( ) ;
2015-05-20 22:28:24 +03:00
QPixmap pix ;
2015-12-19 15:27:03 +03:00
if ( width * h = = height * w | | ( w = = fullWidth ( ) & & h = = fullHeight ( ) ) ) {
pix = _data - > thumb - > pixSingle ( width , height , width , height ) ;
2015-05-20 22:50:05 +03:00
} else if ( width * h > height * w ) {
int32 nw = height * w / h ;
2015-12-19 15:27:03 +03:00
pix = _data - > thumb - > pixSingle ( nw , height , width , height ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-05-20 22:50:05 +03:00
int32 nh = width * h / w ;
2015-12-19 15:27:03 +03:00
pix = _data - > thumb - > pixSingle ( width , nh , width , height ) ;
2014-11-12 23:18:00 +03:00
}
2015-05-20 22:28:24 +03:00
p . drawPixmap ( QPoint ( skipx , skipy ) , pix ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , skipx , skipy , width , height , st : : black , BlackCorners ) ;
2014-11-12 23:18:00 +03:00
}
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , skipx , skipy , width , height , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-11-12 23:18:00 +03:00
}
2015-12-19 00:36:16 +03:00
if ( parent - > getMedia ( ) = = this ) {
int32 fullRight = skipx + width , fullBottom = _height - ( skipx ? st : : mediaPadding . bottom ( ) : 0 ) ;
parent - > drawInfo ( p , fullRight , fullBottom , skipx * 2 + width , selected , InfoDisplayOverImage ) ;
}
2014-11-12 23:18:00 +03:00
}
2015-12-19 21:09:24 +03:00
void HistoryImageLink : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const {
if ( _width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) return ;
int32 skipx = 0 , skipy = 0 , width = _width , height = _height ;
2015-12-19 15:27:03 +03:00
bool bubble = parent - > hasBubble ( ) ;
2015-09-13 20:27:29 +03:00
2015-12-19 15:27:03 +03:00
if ( bubble ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-12-19 15:27:03 +03:00
skipy = st : : mediaPadding . top ( ) ;
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
if ( ! parent - > toHistoryForwarded ( ) & & ! parent - > toHistoryReply ( ) ) {
skipy + = st : : msgPadding . top ( ) ;
}
}
2015-03-19 12:18:19 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-12-19 21:09:24 +03:00
int32 textw = _width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ;
2015-12-19 15:27:03 +03:00
if ( ! _title . isEmpty ( ) ) {
skipy + = qMin ( _title . countHeight ( textw ) , 2 * st : : webPageTitleFont - > height ) ;
}
if ( ! _description . isEmpty ( ) ) {
skipy + = qMin ( _description . countHeight ( textw ) , 3 * st : : webPageDescriptionFont - > height ) ;
}
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
skipy + = st : : webPagePhotoSkip ;
}
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-12-19 15:27:03 +03:00
if ( x > = skipx & & y > = skipy & & x < skipx + width & & y < skipy + height & & _data ) {
lnk = _link ;
2015-08-31 17:27:20 +03:00
2015-10-23 21:24:05 +02:00
int32 fullRight = skipx + width , fullBottom = _height - ( skipx ? st : : mediaPadding . bottom ( ) : 0 ) ;
bool inDate = parent - > pointInTime ( fullRight , fullBottom , x , y , InfoDisplayOverImage ) ;
2015-08-31 17:27:20 +03:00
if ( inDate ) {
state = HistoryInDateCursorState ;
}
2015-04-08 02:03:32 +03:00
return ;
2014-11-12 23:18:00 +03:00
}
}
2015-12-19 21:09:24 +03:00
const QString HistoryImageLink : : inDialogsText ( ) const {
if ( _data ) {
switch ( _data - > type ) {
case GoogleMapsLink : return lang ( lng_maps_point ) ;
}
}
return QString ( ) ;
}
const QString HistoryImageLink : : inHistoryText ( ) const {
if ( _data ) {
switch ( _data - > type ) {
case GoogleMapsLink : return qsl ( " [ " ) + lang ( lng_maps_point ) + qsl ( " : " ) + _link - > text ( ) + qsl ( " ] " ) ;
}
}
return qsl ( " [ Link : " ) + _link - > text ( ) + qsl ( " ] " ) ;
}
int32 HistoryImageLink : : fullWidth ( ) const {
if ( _data ) {
switch ( _data - > type ) {
case GoogleMapsLink : return st : : locationSize . width ( ) ;
}
}
return st : : minPhotoSize ;
}
int32 HistoryImageLink : : fullHeight ( ) const {
if ( _data ) {
switch ( _data - > type ) {
case GoogleMapsLink : return st : : locationSize . height ( ) ;
}
}
return st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
2014-05-30 12:53:19 +04:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , const MTPDmessage & msg ) :
2015-09-08 20:59:36 +03:00
HistoryItem ( history , block , msg . vid . v , msg . vflags . v , : : date ( msg . vdate ) , msg . has_from_id ( ) ? msg . vfrom_id . v : 0 )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2015-09-15 11:50:54 +03:00
, _views ( msg . has_views ( ) ? msg . vviews . v : - 1 )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
QString text ( textClean ( qs ( msg . vmessage ) ) ) ;
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2015-08-30 17:57:21 +03:00
initMedia ( msg . has_media ( ) ? ( & msg . vmedia ) : 0 , text ) ;
2015-10-23 18:06:56 +02:00
setText ( text , msg . has_entities ( ) ? entitiesFromMTP ( msg . ventities . c_vector ( ) . v ) : EntitiesInText ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-10-23 18:06:56 +02:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime date , int32 from , const QString & msg , const EntitiesInText & entities , HistoryMedia * fromMedia ) :
2015-03-19 12:18:19 +03:00
HistoryItem ( history , block , msgId , flags , date , from )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2015-09-15 11:50:54 +03:00
, _views ( fromChannel ( ) ? 1 : - 1 )
2014-06-16 13:31:10 +04:00
{
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2014-05-30 12:53:19 +04:00
if ( fromMedia ) {
2014-08-15 15:19:32 +04:00
_media = fromMedia - > clone ( ) ;
_media - > regItem ( this ) ;
2014-05-30 12:53:19 +04:00
}
2015-10-23 18:06:56 +02:00
setText ( msg , entities ) ;
2015-01-02 17:55:24 +03:00
}
2015-12-28 13:28:00 +03:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) :
2015-03-19 12:18:19 +03:00
HistoryItem ( history , block , msgId , flags , date , from )
2015-01-02 17:55:24 +03:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
, _media ( 0 )
2015-09-15 11:50:54 +03:00
, _views ( fromChannel ( ) ? 1 : - 1 )
2015-01-02 17:55:24 +03:00
{
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2015-12-28 13:28:00 +03:00
initMediaFromDocument ( doc , caption ) ;
2015-10-23 18:06:56 +02:00
setText ( QString ( ) , EntitiesInText ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-21 23:57:42 +03:00
QString formatViewsCount ( int32 views ) {
if ( views > 999999 ) {
views / = 100000 ;
if ( views % 10 ) {
return QString : : number ( views / 10 ) + ' . ' + QString : : number ( views % 10 ) + ' M ' ;
}
return QString : : number ( views / 10 ) + ' M ' ;
} else if ( views > 9999 ) {
views / = 100 ;
if ( views % 10 ) {
return QString : : number ( views / 10 ) + ' . ' + QString : : number ( views % 10 ) + ' K ' ;
}
return QString : : number ( views / 10 ) + ' K ' ;
} else if ( views > 0 ) {
return QString : : number ( views ) ;
}
return qsl ( " 1 " ) ;
}
2015-04-30 16:53:36 +03:00
void HistoryMessage : : initTime ( ) {
2015-09-21 23:57:42 +03:00
_timeText = date . toString ( cTimeFormat ( ) ) ;
2015-10-03 13:09:09 +03:00
_timeWidth = st : : msgDateFont - > width ( _timeText ) ;
2015-09-15 11:50:54 +03:00
2015-09-21 23:57:42 +03:00
_viewsText = ( _views > = 0 ) ? formatViewsCount ( _views ) : QString ( ) ;
2015-10-03 13:09:09 +03:00
_viewsWidth = _viewsText . isEmpty ( ) ? 0 : st : : msgDateFont - > width ( _viewsText ) ;
2015-04-30 16:53:36 +03:00
}
2015-08-30 17:57:21 +03:00
void HistoryMessage : : initMedia ( const MTPMessageMedia * media , QString & currentText ) {
switch ( media ? media - > type ( ) : mtpc_messageMediaEmpty ) {
2014-05-30 12:53:19 +04:00
case mtpc_messageMediaContact : {
2015-08-30 17:57:21 +03:00
const MTPDmessageMediaContact & d ( media - > c_messageMediaContact ( ) ) ;
2014-08-15 15:19:32 +04:00
_media = new HistoryContact ( d . vuser_id . v , qs ( d . vfirst_name ) , qs ( d . vlast_name ) , qs ( d . vphone_number ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageMediaGeo : {
2015-08-30 17:57:21 +03:00
const MTPGeoPoint & point ( media - > c_messageMediaGeo ( ) . vgeo ) ;
2014-05-30 12:53:19 +04:00
if ( point . type ( ) = = mtpc_geoPoint ) {
const MTPDgeoPoint & d ( point . c_geoPoint ( ) ) ;
2014-11-13 14:27:10 +03:00
_media = new HistoryImageLink ( qsl ( " location:%1,%2 " ) . arg ( d . vlat . v ) . arg ( d . vlong . v ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
2015-04-30 16:53:36 +03:00
case mtpc_messageMediaVenue : {
2015-08-30 17:57:21 +03:00
const MTPDmessageMediaVenue & d ( media - > c_messageMediaVenue ( ) ) ;
2015-04-30 16:53:36 +03:00
if ( d . vgeo . type ( ) = = mtpc_geoPoint ) {
const MTPDgeoPoint & g ( d . vgeo . c_geoPoint ( ) ) ;
_media = new HistoryImageLink ( qsl ( " location:%1,%2 " ) . arg ( g . vlat . v ) . arg ( g . vlong . v ) , qs ( d . vtitle ) , qs ( d . vaddress ) ) ;
}
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageMediaPhoto : {
2015-08-30 17:57:21 +03:00
const MTPDmessageMediaPhoto & photo ( media - > c_messageMediaPhoto ( ) ) ;
2015-04-30 16:53:36 +03:00
if ( photo . vphoto . type ( ) = = mtpc_photo ) {
_media = new HistoryPhoto ( photo . vphoto . c_photo ( ) , qs ( photo . vcaption ) , this ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageMediaVideo : {
2015-08-30 17:57:21 +03:00
const MTPDmessageMediaVideo & video ( media - > c_messageMediaVideo ( ) ) ;
2015-04-30 16:53:36 +03:00
if ( video . vvideo . type ( ) = = mtpc_video ) {
_media = new HistoryVideo ( video . vvideo . c_video ( ) , qs ( video . vcaption ) , this ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageMediaAudio : {
2015-08-30 17:57:21 +03:00
const MTPAudio & audio ( media - > c_messageMediaAudio ( ) . vaudio ) ;
2014-05-30 12:53:19 +04:00
if ( audio . type ( ) = = mtpc_audio ) {
2014-08-15 15:19:32 +04:00
_media = new HistoryAudio ( audio . c_audio ( ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageMediaDocument : {
2015-08-30 17:57:21 +03:00
const MTPDocument & document ( media - > c_messageMediaDocument ( ) . vdocument ) ;
2014-05-30 12:53:19 +04:00
if ( document . type ( ) = = mtpc_document ) {
2015-12-28 13:28:00 +03:00
return initMediaFromDocument ( App : : feedDocument ( document ) , qs ( media - > c_messageMediaDocument ( ) . vcaption ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
2015-04-04 23:01:34 +03:00
case mtpc_messageMediaWebPage : {
2015-08-30 17:57:21 +03:00
const MTPWebPage & d ( media - > c_messageMediaWebPage ( ) . vwebpage ) ;
2015-04-04 23:01:34 +03:00
switch ( d . type ( ) ) {
2015-12-19 15:27:03 +03:00
case mtpc_webPageEmpty : break ;
2015-04-04 23:01:34 +03:00
case mtpc_webPagePending : {
2015-12-28 13:28:00 +03:00
_media = new HistoryWebPage ( App : : feedWebPage ( d . c_webPagePending ( ) ) ) ;
2015-04-04 23:01:34 +03:00
} break ;
case mtpc_webPage : {
_media = new HistoryWebPage ( App : : feedWebPage ( d . c_webPage ( ) ) ) ;
} break ;
2015-12-16 18:31:56 +03:00
case mtpc_webPageExternal : LOG ( ( " API Error: should not get webPageExternal in HistoryMessage::initMedia " ) ) ; break ;
2015-04-04 23:01:34 +03:00
}
} break ;
2014-05-30 12:53:19 +04:00
} ;
2014-08-15 15:19:32 +04:00
if ( _media ) _media - > regItem ( this ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-28 13:28:00 +03:00
void HistoryMessage : : initMediaFromDocument ( DocumentData * doc , const QString & caption ) {
2015-07-01 00:07:05 +03:00
if ( doc - > sticker ( ) ) {
2015-01-02 17:55:24 +03:00
_media = new HistorySticker ( doc ) ;
2015-12-21 16:14:29 +03:00
} else if ( doc - > isAnimation ( ) ) {
2015-12-28 13:28:00 +03:00
_media = new HistoryGif ( doc , caption , this ) ;
2015-01-02 17:55:24 +03:00
} else {
2015-12-28 13:28:00 +03:00
_media = new HistoryDocument ( doc , caption , this ) ;
2015-01-02 17:55:24 +03:00
}
_media - > regItem ( this ) ;
}
2015-12-09 21:06:20 +03:00
int32 HistoryMessage : : plainMaxWidth ( ) const {
return st : : msgPadding . left ( ) + _text . maxWidth ( ) + st : : msgPadding . right ( ) ;
}
2015-09-10 13:30:59 +03:00
void HistoryMessage : : initDimensions ( ) {
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2015-04-04 23:01:34 +03:00
if ( _media ) {
_media - > initDimensions ( this ) ;
2015-12-09 21:06:20 +03:00
if ( _media - > isDisplayed ( ) ) {
if ( _text . hasSkipBlock ( ) ) {
_text . removeSkipBlock ( ) ;
_textWidth = 0 ;
_textHeight = 0 ;
}
} else if ( ! _text . hasSkipBlock ( ) ) {
2015-09-15 11:50:54 +03:00
_text . setSkipBlock ( skipBlockWidth ( ) , skipBlockHeight ( ) ) ;
2015-08-24 13:53:04 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
2015-05-20 22:28:24 +03:00
}
2015-04-04 23:01:34 +03:00
}
2015-12-28 00:37:48 +03:00
_maxw = plainMaxWidth ( ) ;
if ( _text . isEmpty ( ) ) {
_minh = 0 ;
} else {
_minh = st : : msgPadding . top ( ) + _text . minHeight ( ) + st : : msgPadding . bottom ( ) ;
}
if ( _media & & _media - > isDisplayed ( ) ) {
int32 maxw = _media - > maxWidth ( ) ;
if ( maxw > _maxw ) _maxw = maxw ;
_minh + = _media - > minHeight ( ) ;
}
2015-12-08 22:07:50 +03:00
} else {
_media - > initDimensions ( this ) ;
_maxw = _media - > maxWidth ( ) ;
_minh = _media - > minHeight ( ) ;
2014-05-30 12:53:19 +04:00
}
fromNameUpdated ( ) ;
}
2015-12-09 21:06:20 +03:00
void HistoryMessage : : countPositionAndSize ( int32 & left , int32 & width ) const {
int32 mwidth = qMin ( int ( st : : msgMaxWidth ) , _maxw ) ;
if ( _media & & _media - > currentWidth ( ) < mwidth ) {
mwidth = qMax ( _media - > currentWidth ( ) , qMin ( mwidth , plainMaxWidth ( ) ) ) ;
}
left = ( ! fromChannel ( ) & & out ( ) ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) ;
if ( displayFromPhoto ( ) ) {
left + = st : : msgPhotoSkip ;
}
width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
if ( width > mwidth ) {
if ( ! fromChannel ( ) & & out ( ) ) {
left + = width - mwidth ;
}
width = mwidth ;
}
}
2014-05-30 12:53:19 +04:00
void HistoryMessage : : fromNameUpdated ( ) const {
2015-12-09 21:06:20 +03:00
if ( ! _media & & displayFromName ( ) ) {
int32 _namew = st : : msgPadding . left ( ) + _from - > nameText . maxWidth ( ) + st : : msgPadding . right ( ) ;
if ( _namew > _maxw ) _maxw = _namew ;
}
2014-05-30 12:53:19 +04:00
}
QString HistoryMessage : : selectedText ( uint32 selection ) const {
2015-12-20 17:05:07 +03:00
if ( _media & & selection = = FullSelection ) {
2015-10-25 18:08:45 +01:00
QString text = _text . original ( 0 , 0xFFFF , Text : : ExpandLinksAll ) , mediaText = _media - > inHistoryText ( ) ;
2015-04-04 23:01:34 +03:00
return text . isEmpty ( ) ? mediaText : ( mediaText . isEmpty ( ) ? text : ( text + ' ' + mediaText ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-20 17:05:07 +03:00
uint16 selectedFrom = ( selection = = FullSelection ) ? 0 : ( ( selection > > 16 ) & 0xFFFF ) ;
uint16 selectedTo = ( selection = = FullSelection ) ? 0xFFFF : ( selection & 0xFFFF ) ;
2015-10-25 18:08:45 +01:00
return _text . original ( selectedFrom , selectedTo , Text : : ExpandLinksAll ) ;
2015-08-24 13:53:04 +03:00
}
2015-03-19 12:18:19 +03:00
QString HistoryMessage : : inDialogsText ( ) const {
2015-12-09 22:09:29 +03:00
return emptyText ( ) ? ( _media ? _media - > inDialogsText ( ) : QString ( ) ) : _text . original ( 0 , 0xFFFF , Text : : ExpandLinksNone ) ;
2015-03-19 12:18:19 +03:00
}
2014-08-11 13:03:45 +04:00
HistoryMedia * HistoryMessage : : getMedia ( bool inOverview ) const {
2014-08-15 15:19:32 +04:00
return _media ;
2014-05-30 12:53:19 +04:00
}
2015-10-14 21:15:46 +02:00
void HistoryMessage : : setMedia ( const MTPMessageMedia * media , bool allowEmitResize ) {
2015-08-30 17:57:21 +03:00
if ( ( ! _media | | _media - > isImageLink ( ) ) & & ( ! media | | media - > type ( ) = = mtpc_messageMediaEmpty ) ) return ;
2015-08-24 13:53:04 +03:00
2015-05-20 22:28:24 +03:00
bool mediaWasDisplayed = false ;
2015-04-08 02:03:32 +03:00
if ( _media ) {
2015-05-20 22:28:24 +03:00
mediaWasDisplayed = _media - > isDisplayed ( ) ;
2015-04-08 02:03:32 +03:00
delete _media ;
_media = 0 ;
}
2015-04-05 11:40:56 +03:00
QString t ;
initMedia ( media , t ) ;
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) & & ! mediaWasDisplayed ) {
2015-08-24 13:53:04 +03:00
_text . removeSkipBlock ( ) ;
_textWidth = 0 ;
_textHeight = 0 ;
2015-05-20 22:28:24 +03:00
} else if ( mediaWasDisplayed & & ( ! _media | | ! _media - > isDisplayed ( ) ) ) {
2015-09-15 11:50:54 +03:00
_text . setSkipBlock ( skipBlockWidth ( ) , skipBlockHeight ( ) ) ;
2015-08-24 13:53:04 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
2015-04-04 23:01:34 +03:00
}
2015-09-10 13:30:59 +03:00
initDimensions ( ) ;
2015-12-22 11:01:02 +03:00
if ( allowEmitResize ) Notify : : historyItemResized ( this ) ;
2015-04-04 23:01:34 +03:00
}
2015-10-23 18:06:56 +02:00
void HistoryMessage : : setText ( const QString & text , const EntitiesInText & entities ) {
2015-12-08 22:07:50 +03:00
textstyleSet ( & ( ( out ( ) & & ! fromChannel ( ) ) ? st : : outTextStyle : st : : inTextStyle ) ) ;
if ( _media & & _media - > isDisplayed ( ) ) {
_text . setMarkedText ( st : : msgFont , text , entities , itemTextOptions ( this ) ) ;
} else {
_text . setMarkedText ( st : : msgFont , text + skipBlock ( ) , entities , itemTextOptions ( this ) ) ;
}
textstyleRestore ( ) ;
if ( id > 0 ) {
for ( int32 i = 0 , l = entities . size ( ) ; i ! = l ; + + i ) {
if ( entities . at ( i ) . type = = EntityInTextUrl | | entities . at ( i ) . type = = EntityInTextCustomUrl | | entities . at ( i ) . type = = EntityInTextEmail ) {
_flags | = MTPDmessage_flag_HAS_TEXT_LINKS ;
break ;
2015-08-24 13:53:04 +03:00
}
}
}
2015-12-08 22:07:50 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
2015-08-24 13:53:04 +03:00
}
2015-10-25 18:08:45 +01:00
QString HistoryMessage : : originalText ( ) const {
2015-12-09 22:09:29 +03:00
return emptyText ( ) ? QString ( ) : _text . original ( ) ;
2015-10-25 18:08:45 +01:00
}
EntitiesInText HistoryMessage : : originalEntities ( ) const {
2015-12-09 22:09:29 +03:00
return emptyText ( ) ? EntitiesInText ( ) : _text . originalEntities ( ) ;
2015-08-28 18:15:56 +03:00
}
2015-09-02 00:33:44 +03:00
bool HistoryMessage : : textHasLinks ( ) {
2015-12-09 22:09:29 +03:00
return emptyText ( ) ? false : _text . hasLinks ( ) ;
2015-09-02 00:33:44 +03:00
}
2015-12-11 21:11:38 +03:00
void HistoryMessage : : drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const {
p . setFont ( st : : msgDateFont ) ;
2015-09-15 11:50:54 +03:00
bool outbg = out ( ) & & ! fromChannel ( ) , overimg = ( type = = InfoDisplayOverImage ) ;
int32 infoRight = right , infoBottom = bottom ;
switch ( type ) {
case InfoDisplayDefault :
infoRight - = st : : msgPadding . right ( ) - st : : msgDateDelta . x ( ) ;
infoBottom - = st : : msgPadding . bottom ( ) - st : : msgDateDelta . y ( ) ;
2015-12-11 21:11:38 +03:00
p . setPen ( ( selected ? ( outbg ? st : : msgOutDateFgSelected : st : : msgInDateFgSelected ) : ( outbg ? st : : msgOutDateFg : st : : msgInDateFg ) ) - > p ) ;
2015-09-15 11:50:54 +03:00
break ;
case InfoDisplayOverImage :
infoRight - = st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ;
infoBottom - = st : : msgDateImgDelta + st : : msgDateImgPadding . y ( ) ;
p . setPen ( st : : msgDateImgColor - > p ) ;
break ;
}
int32 infoW = HistoryMessage : : infoWidth ( ) ;
2015-12-11 21:11:38 +03:00
if ( rtl ( ) ) infoRight = width - infoRight + infoW ;
2015-09-15 11:50:54 +03:00
int32 dateX = infoRight - infoW ;
int32 dateY = infoBottom - st : : msgDateFont - > height ;
if ( type = = InfoDisplayOverImage ) {
int32 dateW = infoW + 2 * st : : msgDateImgPadding . x ( ) , dateH = st : : msgDateFont - > height + 2 * st : : msgDateImgPadding . y ( ) ;
2015-12-11 21:11:38 +03:00
App : : roundRect ( p , dateX - st : : msgDateImgPadding . x ( ) , dateY - st : : msgDateImgPadding . y ( ) , dateW , dateH , selected ? st : : msgDateImgBgSelected : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2015-09-15 11:50:54 +03:00
}
dateX + = HistoryMessage : : timeLeft ( ) ;
p . drawText ( dateX , dateY + st : : msgDateFont - > ascent , _timeText ) ;
QPoint iconPos ;
const QRect * iconRect = 0 ;
if ( ! _viewsText . isEmpty ( ) ) {
iconPos = QPoint ( infoRight - infoW + st : : msgViewsPos . x ( ) , infoBottom - st : : msgViewsImg . pxHeight ( ) + st : : msgViewsPos . y ( ) ) ;
if ( id > 0 ) {
if ( out ( ) & & ! fromChannel ( ) ) {
iconRect = & ( overimg ? st : : msgInvViewsImg : ( selected ? st : : msgSelectOutViewsImg : st : : msgOutViewsImg ) ) ;
} else {
iconRect = & ( overimg ? st : : msgInvViewsImg : ( selected ? st : : msgSelectViewsImg : st : : msgViewsImg ) ) ;
}
p . drawText ( iconPos . x ( ) + st : : msgViewsImg . pxWidth ( ) + st : : msgDateCheckSpace , infoBottom - st : : msgDateFont - > descent , _viewsText ) ;
} else {
iconPos . setX ( iconPos . x ( ) + st : : msgDateViewsSpace + _viewsWidth ) ;
if ( out ( ) & & ! fromChannel ( ) ) {
iconRect = & ( overimg ? st : : msgInvSendingViewsImg : st : : msgSendingOutViewsImg ) ;
} else {
iconRect = & ( overimg ? st : : msgInvSendingViewsImg : st : : msgSendingViewsImg ) ;
}
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
2015-10-27 20:29:39 -04:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
iconPos = QPoint ( infoRight - infoW , infoBottom - st : : msgViewsImg . pxHeight ( ) + st : : msgViewsPos . y ( ) ) ;
iconRect = & ( overimg ? st : : msgInvSendingViewsImg : st : : msgSendingViewsImg ) ;
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
2015-09-15 11:50:54 +03:00
}
if ( out ( ) & & ! fromChannel ( ) ) {
iconPos = QPoint ( infoRight - st : : msgCheckImg . pxWidth ( ) + st : : msgCheckPos . x ( ) , infoBottom - st : : msgCheckImg . pxHeight ( ) + st : : msgCheckPos . y ( ) ) ;
if ( id > 0 ) {
if ( unread ( ) ) {
iconRect = & ( overimg ? st : : msgInvCheckImg : ( selected ? st : : msgSelectCheckImg : st : : msgCheckImg ) ) ;
} else {
iconRect = & ( overimg ? st : : msgInvDblCheckImg : ( selected ? st : : msgSelectDblCheckImg : st : : msgDblCheckImg ) ) ;
}
} else {
iconRect = & ( overimg ? st : : msgInvSendingImg : st : : msgSendingImg ) ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
void HistoryMessage : : setViewsCount ( int32 count ) {
2015-11-13 18:14:33 +03:00
if ( _views = = count | | ( count > = 0 & & _views > count ) ) return ;
2015-09-15 11:50:54 +03:00
int32 was = _viewsWidth ;
_views = count ;
2015-09-21 23:57:42 +03:00
_viewsText = ( _views > = 0 ) ? formatViewsCount ( _views ) : QString ( ) ;
2015-10-03 13:09:09 +03:00
_viewsWidth = _viewsText . isEmpty ( ) ? 0 : st : : msgDateFont - > width ( _viewsText ) ;
2015-09-15 11:50:54 +03:00
if ( was = = _viewsWidth ) {
2015-12-28 00:37:48 +03:00
Ui : : repaintHistoryItem ( this ) ;
2015-09-15 11:50:54 +03:00
} else {
if ( _text . hasSkipBlock ( ) ) {
_text . setSkipBlock ( HistoryMessage : : skipBlockWidth ( ) , HistoryMessage : : skipBlockHeight ( ) ) ;
_textWidth = 0 ;
_textHeight = 0 ;
}
initDimensions ( ) ;
2015-12-22 11:01:02 +03:00
Notify : : historyItemResized ( this ) ;
2015-09-15 11:50:54 +03:00
}
}
2015-10-27 20:29:39 -04:00
void HistoryMessage : : setId ( MsgId newId ) {
bool wasPositive = ( id > 0 ) , positive = ( newId > 0 ) ;
2015-11-18 16:11:56 +03:00
HistoryItem : : setId ( newId ) ;
2015-10-27 20:29:39 -04:00
if ( wasPositive = = positive ) {
2015-12-28 00:37:48 +03:00
Ui : : repaintHistoryItem ( this ) ;
2015-10-27 20:29:39 -04:00
} else {
if ( _text . hasSkipBlock ( ) ) {
_text . setSkipBlock ( HistoryMessage : : skipBlockWidth ( ) , HistoryMessage : : skipBlockHeight ( ) ) ;
_textWidth = 0 ;
_textHeight = 0 ;
}
initDimensions ( ) ;
2015-12-22 11:01:02 +03:00
Notify : : historyItemResized ( this ) ;
2015-10-27 20:29:39 -04:00
}
}
2015-12-11 21:11:38 +03:00
void HistoryMessage : : draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const {
2015-12-20 17:05:07 +03:00
bool outbg = out ( ) & & ! fromChannel ( ) , bubble = drawBubble ( ) , selected = ( selection = = FullSelection ) ;
2015-09-13 20:27:29 +03:00
textstyleSet ( & ( outbg ? st : : outTextStyle : st : : inTextStyle ) ) ;
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
uint64 animms = App : : main ( ) ? App : : main ( ) - > animActiveTimeStart ( this ) : 0 ;
if ( animms > 0 & & animms < = ms ) {
animms = ms - animms ;
if ( animms > st : : activeFadeInDuration + st : : activeFadeOutDuration ) {
2015-07-17 22:17:37 +03:00
App : : main ( ) - > stopAnimActive ( ) ;
} else {
2015-12-11 21:11:38 +03:00
float64 dt = ( animms > st : : activeFadeInDuration ) ? ( 1 - ( animms - st : : activeFadeInDuration ) / float64 ( st : : activeFadeOutDuration ) ) : ( animms / float64 ( st : : activeFadeInDuration ) ) ;
2015-07-17 22:17:37 +03:00
float64 o = p . opacity ( ) ;
p . setOpacity ( o * dt ) ;
p . fillRect ( 0 , 0 , _history - > width , _height , textstyleCurrent ( ) - > selectOverlay - > b ) ;
p . setOpacity ( o ) ;
2014-07-04 15:12:54 +04:00
}
}
2014-05-30 12:53:19 +04:00
if ( _from - > nameVersion > _fromVersion ) {
fromNameUpdated ( ) ;
_fromVersion = _from - > nameVersion ;
}
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2015-09-13 20:27:29 +03:00
if ( displayFromPhoto ( ) ) {
2015-12-09 21:06:20 +03:00
p . drawPixmap ( left - st : : msgPhotoSkip , _height - st : : msgMargin . bottom ( ) - st : : msgPhotoSize , _from - > photo - > pixRounded ( st : : msgPhotoSize ) ) ;
2014-05-30 12:53:19 +04:00
}
if ( width < 1 ) return ;
2015-12-09 21:06:20 +03:00
if ( bubble ) {
2014-05-30 12:53:19 +04:00
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-12-11 21:11:38 +03:00
style : : color bg ( selected ? ( outbg ? st : : msgOutBgSelected : st : : msgInBgSelected ) : ( outbg ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( outbg ? st : : msgOutShadowSelected : st : : msgInShadowSelected ) : ( outbg ? st : : msgOutShadow : st : : msgInShadow ) ) ;
2015-09-13 20:27:29 +03:00
RoundCorners cors ( selected ? ( outbg ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( outbg ? MessageOutCorners : MessageInCorners ) ) ;
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , r , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
2015-09-03 13:48:40 +03:00
if ( displayFromName ( ) ) {
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgNameFont - > f ) ;
2015-09-19 12:13:21 +03:00
if ( fromChannel ( ) ) {
2015-12-11 21:11:38 +03:00
p . setPen ( selected ? st : : msgInServiceFgSelected : st : : msgInServiceFg ) ;
2015-09-19 12:13:21 +03:00
} else {
p . setPen ( _from - > color ) ;
}
2014-05-30 12:53:19 +04:00
_from - > nameText . drawElided ( p , r . left ( ) + st : : msgPadding . left ( ) , r . top ( ) + st : : msgPadding . top ( ) , width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) ;
r . setTop ( r . top ( ) + st : : msgNameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
drawMessageText ( p , trect , selection ) ;
2015-12-09 21:06:20 +03:00
if ( _media & & _media - > isDisplayed ( ) ) {
2015-04-04 23:01:34 +03:00
p . save ( ) ;
2015-12-11 21:11:38 +03:00
int32 top = _height - st : : msgMargin . bottom ( ) - _media - > height ( ) ;
p . translate ( left , top ) ;
_media - > draw ( p , this , r . translated ( - left , - top ) , selected , ms ) ;
2015-04-04 23:01:34 +03:00
p . restore ( ) ;
2015-12-09 21:06:20 +03:00
if ( ! _media - > customInfoLayout ( ) ) {
2015-12-11 21:11:38 +03:00
HistoryMessage : : drawInfo ( p , r . x ( ) + r . width ( ) , r . y ( ) + r . height ( ) , 2 * r . x ( ) + r . width ( ) , selected , InfoDisplayDefault ) ;
2015-12-09 21:06:20 +03:00
}
} else {
2015-12-11 21:11:38 +03:00
HistoryMessage : : drawInfo ( p , r . x ( ) + r . width ( ) , r . y ( ) + r . height ( ) , 2 * r . x ( ) + r . width ( ) , selected , InfoDisplayDefault ) ;
2015-04-04 23:01:34 +03:00
}
2015-12-08 22:07:50 +03:00
} else {
p . save ( ) ;
2015-12-11 21:11:38 +03:00
int32 top = st : : msgMargin . top ( ) ;
p . translate ( left , top ) ;
_media - > draw ( p , this , r . translated ( - left , - top ) , selected , ms ) ;
2015-12-08 22:07:50 +03:00
p . restore ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-15 11:50:54 +03:00
void HistoryMessage : : drawMessageText ( Painter & p , const QRect & trect , uint32 selection ) const {
2014-05-30 12:53:19 +04:00
p . setPen ( st : : msgColor - > p ) ;
p . setFont ( st : : msgFont - > f ) ;
2015-12-20 17:05:07 +03:00
uint16 selectedFrom = ( selection = = FullSelection ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullSelection ) ? 0 : selection & 0xFFFF ;
2014-05-30 12:53:19 +04:00
_text . draw ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , Qt : : AlignLeft , 0 , - 1 , selectedFrom , selectedTo ) ;
}
2015-09-10 13:30:59 +03:00
int32 HistoryMessage : : resize ( int32 width ) {
2015-08-24 13:53:04 +03:00
if ( width < st : : msgMinWidth ) return _height ;
2014-05-30 12:53:19 +04:00
width - = st : : msgMargin . left ( ) + st : : msgMargin . right ( ) ;
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2014-05-30 12:53:19 +04:00
if ( width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) {
width = st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ;
} else if ( width > st : : msgMaxWidth ) {
width = st : : msgMaxWidth ;
}
2015-12-09 21:06:20 +03:00
bool media = ( _media & & _media - > isDisplayed ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
_height = _minh ;
2015-12-09 21:06:20 +03:00
if ( media ) _media - > resize ( _maxw , this ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-12-09 21:06:20 +03:00
if ( _text . isEmpty ( ) ) {
_height = 0 ;
} else {
int32 textWidth = qMax ( width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , 1 ) ;
if ( textWidth ! = _textWidth ) {
textstyleSet ( & ( ( out ( ) & & ! fromChannel ( ) ) ? st : : outTextStyle : st : : inTextStyle ) ) ;
_textWidth = textWidth ;
_textHeight = _text . countHeight ( textWidth ) ;
textstyleRestore ( ) ;
}
_height = st : : msgPadding . top ( ) + _textHeight + st : : msgPadding . bottom ( ) ;
}
if ( media ) _height + = _media - > resize ( width , this ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-03 13:48:40 +03:00
if ( displayFromName ( ) ) {
2015-12-09 22:09:29 +03:00
if ( emptyText ( ) ) {
2015-12-09 21:06:20 +03:00
_height + = st : : msgPadding . top ( ) + st : : msgNameFont - > height + st : : mediaHeaderSkip ;
} else {
_height + = st : : msgNameFont - > height ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-08 22:07:50 +03:00
} else {
_height = _media - > resize ( width , this ) ;
2014-05-30 12:53:19 +04:00
}
_height + = st : : msgMargin . top ( ) + st : : msgMargin . bottom ( ) ;
return _height ;
}
bool HistoryMessage : : hasPoint ( int32 x , int32 y ) const {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return false ;
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
return r . contains ( x , y ) ;
} else {
2014-10-10 16:46:20 +04:00
return _media - > hasPoint ( x - left , y - st : : msgMargin . top ( ) , this ) ;
2014-05-30 12:53:19 +04:00
}
}
2015-09-15 11:50:54 +03:00
bool HistoryMessage : : pointInTime ( int32 right , int32 bottom , int32 x , int32 y , InfoDisplayType type ) const {
int32 infoRight = right , infoBottom = bottom ;
switch ( type ) {
case InfoDisplayDefault :
infoRight - = st : : msgPadding . right ( ) - st : : msgDateDelta . x ( ) ;
infoBottom - = st : : msgPadding . bottom ( ) - st : : msgDateDelta . y ( ) ;
break ;
case InfoDisplayOverImage :
infoRight - = st : : msgDateImgDelta + st : : msgDateImgPadding . x ( ) ;
infoBottom - = st : : msgDateImgDelta + st : : msgDateImgPadding . y ( ) ;
break ;
}
int32 dateX = infoRight - HistoryMessage : : infoWidth ( ) + HistoryMessage : : timeLeft ( ) ;
int32 dateY = infoBottom - st : : msgDateFont - > height ;
return QRect ( dateX , dateY , HistoryMessage : : timeWidth ( ) , st : : msgDateFont - > height ) . contains ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryMessage : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
state = HistoryDefaultCursorState ;
2014-05-30 12:53:19 +04:00
lnk = TextLinkPtr ( ) ;
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
if ( displayFromPhoto ( ) ) {
if ( x > = left - st : : msgPhotoSkip & & x < left - st : : msgPhotoSkip + st : : msgPhotoSize & & y > = _height - st : : msgMargin . bottom ( ) - st : : msgPhotoSize & & y < _height - st : : msgMargin . bottom ( ) ) {
2014-05-30 12:53:19 +04:00
lnk = _from - > lnk ;
return ;
}
}
if ( width < 1 ) return ;
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
if ( displayFromName ( ) ) { // from user left name
if ( x > = r . left ( ) + st : : msgPadding . left ( ) & & y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + st : : msgNameFont - > height & & x < r . left ( ) + r . width ( ) - st : : msgPadding . right ( ) & & x < r . left ( ) + st : : msgPadding . left ( ) + _from - > nameText . maxWidth ( ) ) {
lnk = _from - > lnk ;
return ;
}
r . setTop ( r . top ( ) + st : : msgNameFont - > height ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
2015-12-08 22:07:50 +03:00
getStateFromMessageText ( lnk , state , x , y , r ) ;
} else {
_media - > getState ( lnk , state , x - left , y - st : : msgMargin . top ( ) , this ) ;
}
2015-05-14 19:50:04 +03:00
}
2015-06-27 16:02:00 +03:00
void HistoryMessage : : getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const {
2015-12-09 21:06:20 +03:00
bool inDate = false ;
2015-06-27 16:02:00 +03:00
2014-05-30 12:53:19 +04:00
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-04-04 23:01:34 +03:00
TextLinkPtr medialnk ;
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) ) {
2015-12-09 21:06:20 +03:00
if ( ! _media - > customInfoLayout ( ) ) {
inDate = HistoryMessage : : pointInTime ( r . x ( ) + r . width ( ) , r . y ( ) + r . height ( ) , x , y , InfoDisplayDefault ) ;
}
if ( y > = r . bottom ( ) - _media - > height ( ) & & y < r . bottom ( ) ) {
_media - > getState ( lnk , state , x - r . left ( ) , y - ( r . bottom ( ) - _media - > height ( ) ) , this ) ;
2015-06-27 16:02:00 +03:00
if ( inDate ) state = HistoryInDateCursorState ;
2015-04-08 02:03:32 +03:00
return ;
2015-04-04 23:01:34 +03:00
}
2015-12-09 21:06:20 +03:00
trect . setBottom ( trect . bottom ( ) - _media - > height ( ) ) ;
} else {
inDate = HistoryMessage : : pointInTime ( r . x ( ) + r . width ( ) , r . y ( ) + r . height ( ) , x , y , InfoDisplayDefault ) ;
2015-04-04 23:01:34 +03:00
}
2015-12-09 21:06:20 +03:00
2015-11-23 18:34:38 +03:00
textstyleSet ( & ( ( out ( ) & & ! fromChannel ( ) ) ? st : : outTextStyle : st : : inTextStyle ) ) ;
2015-06-27 16:02:00 +03:00
bool inText = false ;
2014-05-30 12:53:19 +04:00
_text . getState ( lnk , inText , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) ) ;
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2015-06-27 16:02:00 +03:00
if ( inDate ) {
state = HistoryInDateCursorState ;
} else if ( inText ) {
state = HistoryInTextCursorState ;
} else {
state = HistoryDefaultCursorState ;
}
2014-05-30 12:53:19 +04:00
}
void HistoryMessage : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2015-12-08 22:07:50 +03:00
if ( width < 1 ) return ;
2014-05-30 12:53:19 +04:00
2015-12-08 22:07:50 +03:00
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
if ( displayFromName ( ) ) { // from user left name
r . setTop ( r . top ( ) + st : : msgNameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
if ( _media & & _media - > isDisplayed ( ) ) {
2015-12-09 21:06:20 +03:00
trect . setBottom ( trect . bottom ( ) - _media - > height ( ) ) ;
2015-12-08 22:07:50 +03:00
}
textstyleSet ( & ( ( out ( ) & & ! fromChannel ( ) ) ? st : : outTextStyle : st : : inTextStyle ) ) ;
_text . getSymbol ( symbol , after , upon , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) ) ;
textstyleRestore ( ) ;
2015-04-04 23:01:34 +03:00
}
2014-05-30 12:53:19 +04:00
}
2015-09-15 11:50:54 +03:00
void HistoryMessage : : drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const {
2014-05-30 12:53:19 +04:00
if ( cacheFor ! = this ) {
cacheFor = this ;
2015-03-19 12:18:19 +03:00
QString msg ( inDialogsText ( ) ) ;
2015-09-13 20:27:29 +03:00
if ( ( ! _history - > peer - > isUser ( ) | | out ( ) ) & & ! fromChannel ( ) ) {
2014-10-07 21:57:57 +04:00
TextCustomTagsMap custom ;
2014-05-30 12:53:19 +04:00
custom . insert ( QChar ( ' c ' ) , qMakePair ( textcmdStartLink ( 1 ) , textcmdStopLink ( ) ) ) ;
2015-09-04 16:01:31 +03:00
msg = lng_message_with_from ( lt_from , textRichPrepare ( ( _from = = App : : self ( ) ) ? lang ( lng_from_you ) : _from - > shortName ( ) ) , lt_message , textRichPrepare ( msg ) ) ;
2014-10-07 21:57:57 +04:00
cache . setRichText ( st : : dlgHistFont , msg , _textDlgOptions , custom ) ;
} else {
cache . setText ( st : : dlgHistFont , msg , _textDlgOptions ) ;
2014-05-30 12:53:19 +04:00
}
}
if ( r . width ( ) ) {
textstyleSet ( & ( act ? st : : dlgActiveTextStyle : st : : dlgTextStyle ) ) ;
p . setFont ( st : : dlgHistFont - > f ) ;
2015-12-09 22:09:29 +03:00
p . setPen ( ( act ? st : : dlgActiveColor : ( emptyText ( ) ? st : : dlgSystemColor : st : : dlgTextColor ) ) - > p ) ;
2014-05-30 12:53:19 +04:00
cache . drawElided ( p , r . left ( ) , r . top ( ) , r . width ( ) , r . height ( ) / st : : dlgHistFont - > height ) ;
2014-12-05 16:44:27 +03:00
textstyleRestore ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2014-06-14 23:32:11 +04:00
QString HistoryMessage : : notificationHeader ( ) const {
2015-09-13 20:27:29 +03:00
return ( ! _history - > peer - > isUser ( ) & & ! fromChannel ( ) ) ? from ( ) - > name : QString ( ) ;
2014-06-14 23:32:11 +04:00
}
QString HistoryMessage : : notificationText ( ) const {
2015-03-19 12:18:19 +03:00
QString msg ( inDialogsText ( ) ) ;
2014-06-14 23:32:11 +04:00
if ( msg . size ( ) > 0xFF ) msg = msg . mid ( 0 , 0xFF ) + qsl ( " .. " ) ;
return msg ;
}
2014-05-30 12:53:19 +04:00
HistoryMessage : : ~ HistoryMessage ( ) {
2014-08-15 15:19:32 +04:00
if ( _media ) {
_media - > unregItem ( this ) ;
2015-04-04 23:01:34 +03:00
delete _media ;
2014-08-11 13:03:45 +04:00
}
2015-06-15 20:19:24 +03:00
if ( _flags & MTPDmessage : : flag_reply_markup ) {
2015-09-03 13:48:40 +03:00
App : : clearReplyMarkup ( channelId ( ) , id ) ;
2015-06-15 20:19:24 +03:00
}
2014-05-30 12:53:19 +04:00
}
2015-09-15 11:50:54 +03:00
HistoryForwarded : : HistoryForwarded ( History * history , HistoryBlock * block , const MTPDmessage & msg ) : HistoryMessage ( history , block , msg )
2014-06-16 13:31:10 +04:00
, fwdDate ( : : date ( msg . vfwd_date ) )
2015-09-12 14:59:50 +03:00
, fwdFrom ( App : : peer ( peerFromMTP ( msg . vfwd_from_id ) ) )
2014-06-16 13:31:10 +04:00
, fwdFromVersion ( fwdFrom - > nameVersion )
2015-12-11 21:11:38 +03:00
, fromWidth ( st : : msgServiceFont - > width ( lang ( lng_forwarded_from ) ) + st : : msgServiceFont - > spacew ) {
2014-05-30 12:53:19 +04:00
fwdNameUpdated ( ) ;
}
2015-10-28 20:16:52 -04:00
HistoryForwarded : : HistoryForwarded ( History * history , HistoryBlock * block , MsgId id , QDateTime date , int32 from , HistoryMessage * msg ) : HistoryMessage ( history , block , id , newMessageFlags ( history - > peer ) | ( ! history - > peer - > isChannel ( ) & & msg - > getMedia ( ) & & ( msg - > getMedia ( ) - > type ( ) = = MediaTypeAudio /* || msg->getMedia()->type() == MediaTypeVideo*/ ) ? MTPDmessage : : flag_media_unread : 0 ) , date , from , msg - > HistoryMessage : : originalText ( ) , msg - > HistoryMessage : : originalEntities ( ) , msg - > getMedia ( ) )
2015-03-19 12:18:19 +03:00
, fwdDate ( msg - > dateForwarded ( ) )
, fwdFrom ( msg - > fromForwarded ( ) )
2014-06-16 13:31:10 +04:00
, fwdFromVersion ( fwdFrom - > nameVersion )
2015-12-11 21:11:38 +03:00
, fromWidth ( st : : msgServiceFont - > width ( lang ( lng_forwarded_from ) ) + st : : msgServiceFont - > spacew ) {
2014-05-30 12:53:19 +04:00
fwdNameUpdated ( ) ;
}
QString HistoryForwarded : : selectedText ( uint32 selection ) const {
2015-12-20 17:05:07 +03:00
if ( selection ! = FullSelection ) return HistoryMessage : : selectedText ( selection ) ;
2014-05-30 12:53:19 +04:00
QString result , original = HistoryMessage : : selectedText ( selection ) ;
2015-03-19 12:18:19 +03:00
result . reserve ( lang ( lng_forwarded_from ) . size ( ) + fwdFrom - > name . size ( ) + 4 + original . size ( ) ) ;
result . append ( ' [ ' ) . append ( lang ( lng_forwarded_from ) ) . append ( ' ' ) . append ( fwdFrom - > name ) . append ( qsl ( " ] \n " ) ) . append ( original ) ;
2014-05-30 12:53:19 +04:00
return result ;
}
2015-09-10 13:30:59 +03:00
void HistoryForwarded : : initDimensions ( ) {
HistoryMessage : : initDimensions ( ) ;
2015-03-19 12:18:19 +03:00
fwdNameUpdated ( ) ;
}
2014-05-30 12:53:19 +04:00
void HistoryForwarded : : fwdNameUpdated ( ) const {
fwdFromName . setText ( st : : msgServiceNameFont , App : : peerName ( fwdFrom ) , _textNameOptions ) ;
2015-12-09 21:06:20 +03:00
if ( ! _media ) {
int32 _namew = st : : msgPadding . left ( ) + fromWidth + fwdFromName . maxWidth ( ) + st : : msgPadding . right ( ) ;
2015-12-08 22:07:50 +03:00
if ( _namew > _maxw ) _maxw = _namew ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-11 21:11:38 +03:00
void HistoryForwarded : : draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const {
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) & & fwdFrom - > nameVersion > fwdFromVersion ) {
2014-05-30 12:53:19 +04:00
fwdNameUpdated ( ) ;
fwdFromVersion = fwdFrom - > nameVersion ;
}
2015-12-11 21:11:38 +03:00
HistoryMessage : : draw ( p , r , selection , ms ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-15 11:50:54 +03:00
void HistoryForwarded : : drawForwardedFrom ( Painter & p , int32 x , int32 y , int32 w , bool selected ) const {
2014-05-30 12:53:19 +04:00
style : : font serviceFont ( st : : msgServiceFont ) , serviceName ( st : : msgServiceNameFont ) ;
2015-04-23 18:50:11 +03:00
2015-09-13 20:27:29 +03:00
bool outbg = out ( ) & & ! fromChannel ( ) ;
2015-12-11 21:11:38 +03:00
p . setPen ( ( selected ? ( outbg ? st : : msgOutServiceFgSelected : st : : msgInServiceFgSelected ) : ( outbg ? st : : msgOutServiceFg : st : : msgInServiceFg ) ) - > p ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( serviceFont - > f ) ;
2015-04-23 18:50:11 +03:00
if ( w > = fromWidth ) {
p . drawText ( x , y + serviceFont - > ascent , lang ( lng_forwarded_from ) ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( serviceName - > f ) ;
2015-04-23 18:50:11 +03:00
fwdFromName . drawElided ( p , x + fromWidth , y , w - fromWidth ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-10-03 13:09:09 +03:00
p . drawText ( x , y + serviceFont - > ascent , serviceFont - > elided ( lang ( lng_forwarded_from ) , w ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-04-23 18:50:11 +03:00
}
2015-09-15 11:50:54 +03:00
void HistoryForwarded : : drawMessageText ( Painter & p , const QRect & trect , uint32 selection ) const {
2014-05-30 12:53:19 +04:00
QRect realtrect ( trect ) ;
2015-12-09 22:09:29 +03:00
if ( displayForwardedFrom ( ) ) {
2015-12-20 17:05:07 +03:00
drawForwardedFrom ( p , realtrect . x ( ) , realtrect . y ( ) , realtrect . width ( ) , ( selection = = FullSelection ) ) ;
2015-12-09 22:09:29 +03:00
realtrect . setY ( trect . y ( ) + st : : msgServiceNameFont - > height ) ;
}
2014-05-30 12:53:19 +04:00
HistoryMessage : : drawMessageText ( p , realtrect , selection ) ;
}
2015-09-10 13:30:59 +03:00
int32 HistoryForwarded : : resize ( int32 width ) {
HistoryMessage : : resize ( width ) ;
2015-12-09 22:09:29 +03:00
if ( drawBubble ( ) & & displayForwardedFrom ( ) ) {
if ( emptyText ( ) & & ! displayFromName ( ) ) {
2015-12-09 21:06:20 +03:00
_height + = st : : msgPadding . top ( ) + st : : msgServiceNameFont - > height + st : : mediaHeaderSkip ;
} else {
_height + = st : : msgServiceNameFont - > height ;
}
2015-12-08 22:07:50 +03:00
}
2014-05-30 12:53:19 +04:00
return _height ;
}
bool HistoryForwarded : : hasPoint ( int32 x , int32 y ) const {
2015-12-09 22:09:29 +03:00
if ( drawBubble ( ) & & displayForwardedFrom ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return false ;
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
return r . contains ( x , y ) ;
}
return HistoryMessage : : hasPoint ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryForwarded : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2014-05-30 12:53:19 +04:00
lnk = TextLinkPtr ( ) ;
2015-06-27 16:02:00 +03:00
state = HistoryDefaultCursorState ;
2014-05-30 12:53:19 +04:00
2015-12-09 22:09:29 +03:00
if ( drawBubble ( ) & & displayForwardedFrom ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
if ( displayFromPhoto ( ) ) {
if ( x > = left - st : : msgPhotoSkip & & x < left - st : : msgPhotoSkip + st : : msgPhotoSize ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2014-05-30 12:53:19 +04:00
}
}
if ( width < 1 ) return ;
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-09-03 13:48:40 +03:00
if ( displayFromName ( ) ) {
2014-05-30 12:53:19 +04:00
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2014-05-30 12:53:19 +04:00
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-04-04 23:01:34 +03:00
if ( y > = trect . top ( ) & & y < trect . top ( ) + st : : msgServiceNameFont - > height ) {
2015-06-27 16:02:00 +03:00
return getForwardedState ( lnk , state , x - trect . left ( ) , trect . right ( ) - trect . left ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-04-04 23:01:34 +03:00
y - = st : : msgServiceNameFont - > height ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
void HistoryForwarded : : getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const {
2015-05-14 19:50:04 +03:00
QRect realr ( r ) ;
2015-12-09 22:09:29 +03:00
if ( drawBubble ( ) & & displayForwardedFrom ( ) ) {
realr . setHeight ( r . height ( ) - st : : msgServiceNameFont - > height ) ;
}
2015-06-27 16:02:00 +03:00
HistoryMessage : : getStateFromMessageText ( lnk , state , x , y , realr ) ;
2015-05-14 19:50:04 +03:00
}
2015-06-27 16:02:00 +03:00
void HistoryForwarded : : getForwardedState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 w ) const {
state = HistoryDefaultCursorState ;
2015-04-23 18:50:11 +03:00
if ( x > = fromWidth & & x < w & & x < fromWidth + fwdFromName . maxWidth ( ) ) {
lnk = fwdFrom - > lnk ;
} else {
lnk = TextLinkPtr ( ) ;
}
}
2014-05-30 12:53:19 +04:00
void HistoryForwarded : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
2015-12-09 22:09:29 +03:00
if ( drawBubble ( ) & & displayForwardedFrom ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return ;
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-09-03 13:48:40 +03:00
if ( displayFromName ( ) ) {
2014-05-30 12:53:19 +04:00
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-04-04 23:01:34 +03:00
y - = st : : msgServiceNameFont - > height ;
2014-05-30 12:53:19 +04:00
}
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
2015-09-15 11:50:54 +03:00
HistoryReply : : HistoryReply ( History * history , HistoryBlock * block , const MTPDmessage & msg ) : HistoryMessage ( history , block , msg )
2015-03-19 12:18:19 +03:00
, replyToMsgId ( msg . vreply_to_msg_id . v )
, replyToMsg ( 0 )
, replyToVersion ( 0 )
2015-12-09 22:09:29 +03:00
, _maxReplyWidth ( 0 ) {
2015-10-03 14:33:51 +03:00
if ( ! updateReplyTo ( ) & & App : : api ( ) ) {
2015-09-12 14:59:50 +03:00
App : : api ( ) - > requestReplyTo ( this , history - > peer - > asChannel ( ) , replyToMsgId ) ;
2015-03-19 12:18:19 +03:00
}
}
2015-12-28 13:28:00 +03:00
HistoryReply : : HistoryReply ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption )
: HistoryMessage ( history , block , msgId , flags , date , from , doc , caption )
2015-03-19 12:18:19 +03:00
, replyToMsgId ( replyTo )
, replyToMsg ( 0 )
, replyToVersion ( 0 )
2015-12-09 22:09:29 +03:00
, _maxReplyWidth ( 0 ) {
2015-10-03 14:33:51 +03:00
if ( ! updateReplyTo ( ) & & App : : api ( ) ) {
2015-09-12 14:59:50 +03:00
App : : api ( ) - > requestReplyTo ( this , history - > peer - > asChannel ( ) , replyToMsgId ) ;
2015-03-19 12:18:19 +03:00
}
}
QString HistoryReply : : selectedText ( uint32 selection ) const {
2015-12-20 17:05:07 +03:00
if ( selection ! = FullSelection | | ! replyToMsg ) return HistoryMessage : : selectedText ( selection ) ;
2015-03-19 12:18:19 +03:00
QString result , original = HistoryMessage : : selectedText ( selection ) ;
result . reserve ( lang ( lng_in_reply_to ) . size ( ) + replyToMsg - > from ( ) - > name . size ( ) + 4 + original . size ( ) ) ;
result . append ( ' [ ' ) . append ( lang ( lng_in_reply_to ) ) . append ( ' ' ) . append ( replyToMsg - > from ( ) - > name ) . append ( qsl ( " ] \n " ) ) . append ( original ) ;
return result ;
}
2015-09-10 13:30:59 +03:00
void HistoryReply : : initDimensions ( ) {
HistoryMessage : : initDimensions ( ) ;
2015-12-09 21:06:20 +03:00
replyToNameUpdated ( ) ;
2015-03-19 12:18:19 +03:00
}
bool HistoryReply : : updateReplyTo ( bool force ) {
if ( replyToMsg | | ! replyToMsgId ) return true ;
2015-09-03 13:48:40 +03:00
replyToMsg = App : : histItemById ( channelId ( ) , replyToMsgId ) ;
2015-03-19 12:18:19 +03:00
if ( replyToMsg ) {
App : : historyRegReply ( this , replyToMsg ) ;
replyToText . setText ( st : : msgFont , replyToMsg - > inReplyText ( ) , _textDlgOptions ) ;
replyToNameUpdated ( ) ;
replyToLnk = TextLinkPtr ( new MessageLink ( replyToMsg - > history ( ) - > peer - > id , replyToMsg - > id ) ) ;
} else if ( force ) {
replyToMsgId = 0 ;
}
if ( force ) {
initDimensions ( ) ;
2015-12-22 11:01:02 +03:00
Notify : : historyItemResized ( this ) ;
2015-03-19 12:18:19 +03:00
}
return ( replyToMsg | | ! replyToMsgId ) ;
}
void HistoryReply : : replyToNameUpdated ( ) const {
2015-12-09 21:06:20 +03:00
if ( replyToMsg ) {
replyToName . setText ( st : : msgServiceNameFont , App : : peerName ( replyToMsg - > from ( ) ) , _textNameOptions ) ;
replyToVersion = replyToMsg - > from ( ) - > nameVersion ;
bool hasPreview = replyToMsg - > getMedia ( ) ? replyToMsg - > getMedia ( ) - > hasReplyPreview ( ) : false ;
int32 previewSkip = hasPreview ? ( st : : msgReplyBarSize . height ( ) + st : : msgReplyBarSkip - st : : msgReplyBarSize . width ( ) - st : : msgReplyBarPos . x ( ) ) : 0 ;
_maxReplyWidth = previewSkip + qMax ( replyToName . maxWidth ( ) , qMin ( replyToText . maxWidth ( ) , 4 * replyToName . maxWidth ( ) ) ) ;
} else {
_maxReplyWidth = st : : msgDateFont - > width ( lang ( replyToMsgId ? lng_profile_loading : lng_deleted_message ) ) ;
}
_maxReplyWidth = st : : msgReplyPadding . left ( ) + st : : msgReplyBarSkip + _maxReplyWidth + st : : msgReplyPadding . right ( ) ;
if ( ! _media ) {
int32 replyw = st : : msgPadding . left ( ) + _maxReplyWidth - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) + st : : msgPadding . right ( ) ;
if ( replyw > _maxw ) _maxw = replyw ;
2015-03-19 12:18:19 +03:00
}
}
int32 HistoryReply : : replyToWidth ( ) const {
return _maxReplyWidth ;
}
TextLinkPtr HistoryReply : : replyToLink ( ) const {
return replyToLnk ;
}
MsgId HistoryReply : : replyToId ( ) const {
return replyToMsgId ;
}
HistoryItem * HistoryReply : : replyToMessage ( ) const {
return replyToMsg ;
}
void HistoryReply : : replyToReplaced ( HistoryItem * oldItem , HistoryItem * newItem ) {
if ( replyToMsg = = oldItem ) {
replyToMsg = newItem ;
if ( ! newItem ) {
replyToMsgId = 0 ;
initDimensions ( ) ;
}
}
}
2015-12-11 21:11:38 +03:00
void HistoryReply : : draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const {
2015-03-19 12:18:19 +03:00
if ( replyToMsg & & replyToMsg - > from ( ) - > nameVersion > replyToVersion ) {
replyToNameUpdated ( ) ;
}
2015-12-11 21:11:38 +03:00
HistoryMessage : : draw ( p , r , selection , ms ) ;
2015-03-19 12:18:19 +03:00
}
2015-09-15 11:50:54 +03:00
void HistoryReply : : drawReplyTo ( Painter & p , int32 x , int32 y , int32 w , bool selected , bool likeService ) const {
2015-03-19 12:18:19 +03:00
style : : color bar ;
2015-09-13 20:27:29 +03:00
bool outbg = out ( ) & & ! fromChannel ( ) ;
2015-03-19 12:18:19 +03:00
if ( likeService ) {
bar = st : : white ;
} else {
2015-09-13 20:27:29 +03:00
bar = ( selected ? ( outbg ? st : : msgOutReplyBarSelColor : st : : msgInReplyBarSelColor ) : ( outbg ? st : : msgOutReplyBarColor : st : : msgInReplyBarColor ) ) ;
2015-03-19 12:18:19 +03:00
}
2015-12-19 15:27:03 +03:00
QRect rbar ( rtlrect ( x + st : : msgReplyBarPos . x ( ) , y + st : : msgReplyPadding . top ( ) + st : : msgReplyBarPos . y ( ) , st : : msgReplyBarSize . width ( ) , st : : msgReplyBarSize . height ( ) , w + 2 * x ) ) ;
p . fillRect ( rbar , bar ) ;
2015-03-19 12:18:19 +03:00
if ( w > st : : msgReplyBarSkip ) {
if ( replyToMsg ) {
bool hasPreview = replyToMsg - > getMedia ( ) ? replyToMsg - > getMedia ( ) - > hasReplyPreview ( ) : false ;
int previewSkip = hasPreview ? ( st : : msgReplyBarSize . height ( ) + st : : msgReplyBarSkip - st : : msgReplyBarSize . width ( ) - st : : msgReplyBarPos . x ( ) ) : 0 ;
if ( hasPreview ) {
ImagePtr replyPreview = replyToMsg - > getMedia ( ) - > replyPreview ( ) ;
if ( ! replyPreview - > isNull ( ) ) {
2015-12-19 15:27:03 +03:00
QRect to ( rtlrect ( x + st : : msgReplyBarSkip , y + st : : msgReplyPadding . top ( ) + st : : msgReplyBarPos . y ( ) , st : : msgReplyBarSize . height ( ) , st : : msgReplyBarSize . height ( ) , w + 2 * x ) ) ;
2015-05-20 22:28:24 +03:00
p . drawPixmap ( to . x ( ) , to . y ( ) , replyPreview - > pixSingle ( replyPreview - > width ( ) / cIntRetinaFactor ( ) , replyPreview - > height ( ) / cIntRetinaFactor ( ) , to . width ( ) , to . height ( ) ) ) ;
2015-03-19 12:18:19 +03:00
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , to , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2015-03-19 12:18:19 +03:00
}
}
}
if ( w > st : : msgReplyBarSkip + previewSkip ) {
if ( likeService ) {
2015-12-19 15:27:03 +03:00
p . setPen ( st : : white ) ;
2015-03-19 12:18:19 +03:00
} else {
2015-12-19 15:27:03 +03:00
p . setPen ( selected ? ( outbg ? st : : msgOutServiceFgSelected : st : : msgInServiceFgSelected ) : ( outbg ? st : : msgOutServiceFg : st : : msgInServiceFg ) ) ;
2015-03-19 12:18:19 +03:00
}
2015-12-19 15:27:03 +03:00
replyToName . drawLeftElided ( p , x + st : : msgReplyBarSkip + previewSkip , y + st : : msgReplyPadding . top ( ) , w - st : : msgReplyBarSkip - previewSkip , w + 2 * x ) ;
2015-03-19 12:18:19 +03:00
2015-04-13 09:58:13 +01:00
HistoryMessage * replyToAsMsg = replyToMsg - > toHistoryMessage ( ) ;
2015-03-19 12:18:19 +03:00
if ( likeService ) {
2015-12-09 22:09:29 +03:00
} else if ( ( replyToAsMsg & & replyToAsMsg - > emptyText ( ) ) | | replyToMsg - > serviceMsg ( ) ) {
2015-12-11 21:11:38 +03:00
style : : color date ( outbg ? ( selected ? st : : msgOutDateFgSelected : st : : msgOutDateFg ) : ( selected ? st : : msgInDateFgSelected : st : : msgInDateFg ) ) ;
2015-12-19 15:27:03 +03:00
p . setPen ( date ) ;
2015-03-19 12:18:19 +03:00
} else {
2015-12-19 15:27:03 +03:00
p . setPen ( st : : msgColor ) ;
2015-03-19 12:18:19 +03:00
}
2015-12-19 15:27:03 +03:00
replyToText . drawLeftElided ( p , x + st : : msgReplyBarSkip + previewSkip , y + st : : msgReplyPadding . top ( ) + st : : msgServiceNameFont - > height , w - st : : msgReplyBarSkip - previewSkip , w + 2 * x ) ;
2015-03-19 12:18:19 +03:00
}
} else {
2015-12-19 15:27:03 +03:00
p . setFont ( st : : msgDateFont ) ;
2015-12-11 21:11:38 +03:00
style : : color date ( outbg ? ( selected ? st : : msgOutDateFgSelected : st : : msgOutDateFg ) : ( selected ? st : : msgInDateFgSelected : st : : msgInDateFg ) ) ;
2015-12-19 15:27:03 +03:00
p . setPen ( likeService ? st : : white : date ) ;
p . drawTextLeft ( x + st : : msgReplyBarSkip , y + st : : msgReplyPadding . top ( ) + ( st : : msgReplyBarSize . height ( ) - st : : msgDateFont - > height ) / 2 , w + 2 * x , st : : msgDateFont - > elided ( lang ( replyToMsgId ? lng_profile_loading : lng_deleted_message ) , w - st : : msgReplyBarSkip ) ) ;
2015-03-19 12:18:19 +03:00
}
}
}
2015-09-15 11:50:54 +03:00
void HistoryReply : : drawMessageText ( Painter & p , const QRect & trect , uint32 selection ) const {
2015-03-19 12:18:19 +03:00
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-12-20 17:05:07 +03:00
drawReplyTo ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , ( selection = = FullSelection ) ) ;
2015-03-19 12:18:19 +03:00
QRect realtrect ( trect ) ;
realtrect . setY ( trect . y ( ) + h ) ;
HistoryMessage : : drawMessageText ( p , realtrect , selection ) ;
}
2015-09-10 13:30:59 +03:00
int32 HistoryReply : : resize ( int32 width ) {
HistoryMessage : : resize ( width ) ;
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2015-12-09 22:09:29 +03:00
if ( emptyText ( ) & & ! displayFromName ( ) ) {
_height + = st : : msgPadding . top ( ) + st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) + st : : mediaHeaderSkip ;
2015-12-09 21:06:20 +03:00
} else {
_height + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
}
2015-12-08 22:07:50 +03:00
}
2015-03-19 12:18:19 +03:00
return _height ;
}
bool HistoryReply : : hasPoint ( int32 x , int32 y ) const {
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2015-03-19 12:18:19 +03:00
if ( width < 1 ) return false ;
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
return r . contains ( x , y ) ;
}
return HistoryMessage : : hasPoint ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryReply : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2015-03-19 12:18:19 +03:00
lnk = TextLinkPtr ( ) ;
2015-06-27 16:02:00 +03:00
state = HistoryDefaultCursorState ;
2015-03-19 12:18:19 +03:00
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2015-09-13 20:27:29 +03:00
if ( displayFromPhoto ( ) ) { // from user left photo
2015-12-09 21:06:20 +03:00
if ( x > = left - st : : msgPhotoSkip & & x < left - st : : msgPhotoSkip + st : : msgPhotoSize ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2015-03-19 12:18:19 +03:00
}
}
if ( width < 1 ) return ;
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-09-03 13:48:40 +03:00
if ( displayFromName ( ) ) {
2015-03-19 12:18:19 +03:00
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2015-03-19 12:18:19 +03:00
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
if ( y > = trect . top ( ) & & y < trect . top ( ) + h ) {
if ( replyToMsg & & y > = trect . top ( ) + st : : msgReplyPadding . top ( ) & & y < trect . top ( ) + st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) & & x > = trect . left ( ) & & x < trect . right ( ) ) {
lnk = replyToLnk ;
}
return ;
}
y - = h ;
}
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2015-03-19 12:18:19 +03:00
}
2015-06-27 16:02:00 +03:00
void HistoryReply : : getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const {
2015-05-14 19:50:04 +03:00
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
QRect realr ( r ) ;
realr . setHeight ( r . height ( ) - h ) ;
2015-06-27 16:02:00 +03:00
HistoryMessage : : getStateFromMessageText ( lnk , state , x , y , realr ) ;
2015-05-14 19:50:04 +03:00
}
2015-03-19 12:18:19 +03:00
void HistoryReply : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
2015-12-08 22:07:50 +03:00
if ( drawBubble ( ) ) {
2015-12-09 21:06:20 +03:00
int32 left = 0 , width = 0 ;
countPositionAndSize ( left , width ) ;
2015-03-19 12:18:19 +03:00
if ( width < 1 ) return ;
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-09-03 13:48:40 +03:00
if ( displayFromName ( ) ) {
2015-03-19 12:18:19 +03:00
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
y - = h ;
}
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
HistoryReply : : ~ HistoryReply ( ) {
if ( replyToMsg ) {
App : : historyUnregReply ( this , replyToMsg ) ;
2015-10-03 14:33:51 +03:00
} else if ( replyToMsgId & & App : : api ( ) ) {
2015-03-19 12:18:19 +03:00
App : : api ( ) - > itemRemoved ( this ) ;
}
}
2014-12-18 21:40:49 +03:00
void HistoryServiceMsg : : setMessageByAction ( const MTPmessageAction & action ) {
2015-11-24 20:37:55 +03:00
QList < TextLinkPtr > links ;
2014-12-18 21:40:49 +03:00
LangString text = lang ( lng_message_empty ) ;
QString from = textcmdLink ( 1 , _from - > name ) ;
2014-05-30 12:53:19 +04:00
switch ( action . type ( ) ) {
case mtpc_messageActionChatAddUser : {
const MTPDmessageActionChatAddUser & d ( action . c_messageActionChatAddUser ( ) ) ;
2015-11-13 18:14:33 +03:00
const QVector < MTPint > & v ( d . vusers . c_vector ( ) . v ) ;
bool foundSelf = false ;
for ( int32 i = 0 , l = v . size ( ) ; i < l ; + + i ) {
if ( v . at ( i ) . v = = MTP : : authedId ( ) ) {
foundSelf = true ;
break ;
}
}
if ( v . size ( ) = = 1 ) {
UserData * u = App : : user ( peerFromUser ( v . at ( 0 ) ) ) ;
if ( u = = _from ) {
text = lng_action_user_joined ( lt_from , from ) ;
} else {
2015-11-24 20:37:55 +03:00
links . push_back ( TextLinkPtr ( new PeerLink ( u ) ) ) ;
2015-11-13 18:14:33 +03:00
text = lng_action_add_user ( lt_from , from , lt_user , textcmdLink ( 2 , u - > name ) ) ;
}
2015-11-16 19:04:37 +03:00
} else if ( v . isEmpty ( ) ) {
text = lng_action_add_user ( lt_from , from , lt_user , " somebody " ) ;
2014-12-18 21:40:49 +03:00
} else {
2015-11-24 20:37:55 +03:00
for ( int32 i = 0 , l = v . size ( ) ; i < l ; + + i ) {
UserData * u = App : : user ( peerFromUser ( v . at ( i ) ) ) ;
QString linkText = textcmdLink ( i + 2 , u - > name ) ;
if ( i = = 0 ) {
text = linkText ;
} else if ( i + 1 < l ) {
text = lng_action_add_users_and_one ( lt_accumulated , text , lt_user , linkText ) ;
} else {
text = lng_action_add_users_and_last ( lt_accumulated , text , lt_user , linkText ) ;
}
links . push_back ( TextLinkPtr ( new PeerLink ( u ) ) ) ;
}
text = lng_action_add_users_many ( lt_from , from , lt_users , text ) ;
2015-11-13 18:14:33 +03:00
}
2015-11-20 21:24:44 +03:00
if ( foundSelf ) {
if ( unread ( ) & & history ( ) - > peer - > isChat ( ) & & ! history ( ) - > peer - > asChat ( ) - > inviterForSpamReport & & _from - > isUser ( ) ) {
2015-11-13 18:14:33 +03:00
history ( ) - > peer - > asChat ( ) - > inviterForSpamReport = peerToUser ( _from - > id ) ;
2015-09-08 20:22:29 +03:00
}
2015-11-20 21:24:44 +03:00
if ( history ( ) - > peer - > isMegagroup ( ) ) {
history ( ) - > peer - > asChannel ( ) - > mgInfo - > joinedMessageFound = true ;
}
2014-05-30 12:53:19 +04:00
}
} break ;
2015-04-30 16:53:36 +03:00
case mtpc_messageActionChatJoinedByLink : {
const MTPDmessageActionChatJoinedByLink & d ( action . c_messageActionChatJoinedByLink ( ) ) ;
2015-09-03 13:48:40 +03:00
if ( true | | peerFromUser ( d . vinviter_id ) = = _from - > id ) {
2015-09-23 13:39:37 +03:00
text = lng_action_user_joined_by_link ( lt_from , from ) ;
2015-04-30 16:53:36 +03:00
//} else {
//UserData *u = App::user(App::peerFromUser(d.vinviter_id));
//second = TextLinkPtr(new PeerLink(u));
//text = lng_action_user_joined_by_link_from(lt_from, from, lt_inviter, textcmdLink(2, u->name));
}
2015-11-20 21:24:44 +03:00
if ( _from - > isSelf ( ) & & history ( ) - > peer - > isMegagroup ( ) ) {
history ( ) - > peer - > asChannel ( ) - > mgInfo - > joinedMessageFound = true ;
}
2015-04-30 16:53:36 +03:00
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageActionChatCreate : {
const MTPDmessageActionChatCreate & d ( action . c_messageActionChatCreate ( ) ) ;
2014-12-18 21:40:49 +03:00
text = lng_action_created_chat ( lt_from , from , lt_title , textClean ( qs ( d . vtitle ) ) ) ;
2015-09-08 20:22:29 +03:00
if ( unread ( ) ) {
2015-09-12 14:59:50 +03:00
if ( history ( ) - > peer - > isChat ( ) & & ! history ( ) - > peer - > asChat ( ) - > inviterForSpamReport & & _from - > isUser ( ) & & peerToUser ( _from - > id ) ! = MTP : : authedId ( ) ) {
history ( ) - > peer - > asChat ( ) - > inviterForSpamReport = peerToUser ( _from - > id ) ;
2015-09-08 20:22:29 +03:00
}
}
2014-05-30 12:53:19 +04:00
} break ;
2015-09-04 16:01:31 +03:00
case mtpc_messageActionChannelCreate : {
const MTPDmessageActionChannelCreate & d ( action . c_messageActionChannelCreate ( ) ) ;
2015-11-02 17:33:57 -05:00
if ( fromChannel ( ) ) {
text = lng_action_created_channel ( lt_title , textClean ( qs ( d . vtitle ) ) ) ;
} else {
text = lng_action_created_chat ( lt_from , from , lt_title , textClean ( qs ( d . vtitle ) ) ) ;
}
2015-09-04 16:01:31 +03:00
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageActionChatDeletePhoto : {
2015-09-13 20:27:29 +03:00
text = fromChannel ( ) ? lang ( lng_action_removed_photo_channel ) : lng_action_removed_photo ( lt_from , from ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageActionChatDeleteUser : {
const MTPDmessageActionChatDeleteUser & d ( action . c_messageActionChatDeleteUser ( ) ) ;
2015-09-03 13:48:40 +03:00
if ( peerFromUser ( d . vuser_id ) = = _from - > id ) {
2015-09-23 13:39:37 +03:00
text = lng_action_user_left ( lt_from , from ) ;
2014-12-18 21:40:49 +03:00
} else {
2015-09-03 13:48:40 +03:00
UserData * u = App : : user ( peerFromUser ( d . vuser_id ) ) ;
2015-11-24 20:37:55 +03:00
links . push_back ( TextLinkPtr ( new PeerLink ( u ) ) ) ;
2014-12-18 21:40:49 +03:00
text = lng_action_kick_user ( lt_from , from , lt_user , textcmdLink ( 2 , u - > name ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageActionChatEditPhoto : {
const MTPDmessageActionChatEditPhoto & d ( action . c_messageActionChatEditPhoto ( ) ) ;
if ( d . vphoto . type ( ) = = mtpc_photo ) {
2014-10-07 21:57:57 +04:00
_media = new HistoryPhoto ( history ( ) - > peer , d . vphoto . c_photo ( ) , st : : msgServicePhotoWidth ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-13 20:27:29 +03:00
text = fromChannel ( ) ? lang ( lng_action_changed_photo_channel ) : lng_action_changed_photo ( lt_from , from ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageActionChatEditTitle : {
const MTPDmessageActionChatEditTitle & d ( action . c_messageActionChatEditTitle ( ) ) ;
2015-09-13 20:27:29 +03:00
text = fromChannel ( ) ? lng_action_changed_title_channel ( lt_title , textClean ( qs ( d . vtitle ) ) ) : lng_action_changed_title ( lt_from , from , lt_title , textClean ( qs ( d . vtitle ) ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
2015-11-06 12:48:49 -05:00
case mtpc_messageActionChatMigrateTo : {
2015-11-13 18:14:33 +03:00
_flags | = MTPDmessage_flag_IS_GROUP_MIGRATE ;
2015-11-06 12:48:49 -05:00
const MTPDmessageActionChatMigrateTo & d ( action . c_messageActionChatMigrateTo ( ) ) ;
if ( true /*PeerData *channel = App::peerLoaded(peerFromChannel(d.vchannel_id))*/ ) {
text = lang ( lng_action_group_migrate ) ;
} else {
text = lang ( lng_contacts_loading ) ;
}
} break ;
case mtpc_messageActionChannelMigrateFrom : {
2015-11-13 18:14:33 +03:00
_flags | = MTPDmessage_flag_IS_GROUP_MIGRATE ;
2015-11-06 12:48:49 -05:00
const MTPDmessageActionChannelMigrateFrom & d ( action . c_messageActionChannelMigrateFrom ( ) ) ;
if ( true /*PeerData *chat = App::peerLoaded(peerFromChannel(d.vchat_id))*/ ) {
text = lang ( lng_action_group_migrate ) ;
} else {
text = lang ( lng_contacts_loading ) ;
}
} break ;
2014-12-18 21:40:49 +03:00
default : from = QString ( ) ; break ;
2014-05-30 12:53:19 +04:00
}
2015-11-23 18:34:38 +03:00
textstyleSet ( & st : : serviceTextStyle ) ;
2014-12-18 21:40:49 +03:00
_text . setText ( st : : msgServiceFont , text , _historySrvOptions ) ;
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2014-12-18 21:40:49 +03:00
if ( ! from . isEmpty ( ) ) {
_text . setLink ( 1 , TextLinkPtr ( new PeerLink ( _from ) ) ) ;
}
2015-11-24 20:37:55 +03:00
for ( int32 i = 0 , l = links . size ( ) ; i < l ; + + i ) {
_text . setLink ( i + 2 , links . at ( i ) ) ;
2015-11-13 18:14:33 +03:00
}
2014-05-30 12:53:19 +04:00
}
HistoryServiceMsg : : HistoryServiceMsg ( History * history , HistoryBlock * block , const MTPDmessageService & msg ) :
2015-09-04 16:01:31 +03:00
HistoryItem ( history , block , msg . vid . v , msg . vflags . v , : : date ( msg . vdate ) , msg . has_from_id ( ) ? msg . vfrom_id . v : 0 )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2014-06-16 13:31:10 +04:00
{
2014-12-18 21:40:49 +03:00
setMessageByAction ( msg . vaction ) ;
2014-05-30 12:53:19 +04:00
}
2015-07-15 14:23:59 +03:00
HistoryServiceMsg : : HistoryServiceMsg ( History * history , HistoryBlock * block , MsgId msgId , QDateTime date , const QString & msg , int32 flags , HistoryMedia * media , int32 from ) :
HistoryItem ( history , block , msgId , flags , date , from )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgServiceFont , msg , _historySrvOptions , st : : dlgMinWidth )
2014-08-15 15:19:32 +04:00
, _media ( media )
2014-06-16 13:31:10 +04:00
{
2014-10-10 16:46:20 +04:00
}
2015-09-10 13:30:59 +03:00
void HistoryServiceMsg : : initDimensions ( ) {
2014-05-30 12:53:19 +04:00
_maxw = _text . maxWidth ( ) + st : : msgServicePadding . left ( ) + st : : msgServicePadding . right ( ) ;
_minh = _text . minHeight ( ) ;
2015-09-10 13:30:59 +03:00
if ( _media ) _media - > initDimensions ( this ) ;
2014-05-30 12:53:19 +04:00
}
QString HistoryServiceMsg : : selectedText ( uint32 selection ) const {
2015-12-20 17:05:07 +03:00
uint16 selectedFrom = ( selection = = FullSelection ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullSelection ) ? 0xFFFF : ( selection & 0xFFFF ) ;
2014-05-30 12:53:19 +04:00
return _text . original ( selectedFrom , selectedTo ) ;
}
2015-03-19 12:18:19 +03:00
QString HistoryServiceMsg : : inDialogsText ( ) const {
2015-10-25 18:08:45 +01:00
return _text . original ( 0 , 0xFFFF , Text : : ExpandLinksNone ) ;
2015-03-19 12:18:19 +03:00
}
QString HistoryServiceMsg : : inReplyText ( ) const {
QString result = HistoryServiceMsg : : inDialogsText ( ) ;
return result . trimmed ( ) . startsWith ( from ( ) - > name ) ? result . trimmed ( ) . mid ( from ( ) - > name . size ( ) ) . trimmed ( ) : result ;
}
2015-09-22 13:19:57 +03:00
void HistoryServiceMsg : : setServiceText ( const QString & text ) {
2015-11-23 18:34:38 +03:00
textstyleSet ( & st : : serviceTextStyle ) ;
2015-09-19 12:13:21 +03:00
_text . setText ( st : : msgServiceFont , text , _historySrvOptions ) ;
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2015-09-19 12:13:21 +03:00
initDimensions ( ) ;
}
2015-12-11 21:11:38 +03:00
void HistoryServiceMsg : : draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const {
uint64 animms = App : : main ( ) ? App : : main ( ) - > animActiveTimeStart ( this ) : 0 ;
if ( animms > 0 & & animms < = ms ) {
animms = ms - animms ;
if ( animms > st : : activeFadeInDuration + st : : activeFadeOutDuration ) {
2015-07-17 22:17:37 +03:00
App : : main ( ) - > stopAnimActive ( ) ;
} else {
textstyleSet ( & st : : inTextStyle ) ;
2015-12-11 21:11:38 +03:00
float64 dt = ( animms > st : : activeFadeInDuration ) ? ( 1 - ( animms - st : : activeFadeInDuration ) / float64 ( st : : activeFadeOutDuration ) ) : ( animms / float64 ( st : : activeFadeInDuration ) ) ;
2015-07-17 22:17:37 +03:00
float64 o = p . opacity ( ) ;
p . setOpacity ( o * dt ) ;
p . fillRect ( 0 , 0 , _history - > width , _height , textstyleCurrent ( ) - > selectOverlay - > b ) ;
p . setOpacity ( o ) ;
2015-03-19 12:18:19 +03:00
}
}
2014-05-30 12:53:19 +04:00
textstyleSet ( & st : : serviceTextStyle ) ;
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
p . save ( ) ;
2015-12-11 21:11:38 +03:00
int32 left = st : : msgServiceMargin . left ( ) + ( width - _media - > maxWidth ( ) ) / 2 , top = st : : msgServiceMargin . top ( ) + height + st : : msgServiceMargin . top ( ) ;
p . translate ( left , top ) ;
2015-12-20 17:05:07 +03:00
_media - > draw ( p , this , r . translated ( - left , - top ) , selection = = FullSelection , ms ) ;
2014-05-30 12:53:19 +04:00
p . restore ( ) ;
}
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
if ( width > _maxw ) {
left + = ( width - _maxw ) / 2 ;
width = _maxw ;
}
2015-12-20 17:05:07 +03:00
App : : roundRect ( p , left , st : : msgServiceMargin . top ( ) , width , height , App : : msgServiceBg ( ) , ( selection = = FullSelection ) ? ServiceSelectedCorners : ServiceCorners ) ;
2015-05-20 22:28:24 +03:00
2014-05-30 12:53:19 +04:00
p . setBrush ( Qt : : NoBrush ) ;
p . setPen ( st : : msgServiceColor - > p ) ;
p . setFont ( st : : msgServiceFont - > f ) ;
2015-12-20 17:05:07 +03:00
uint16 selectedFrom = ( selection = = FullSelection ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullSelection ) ? 0 : selection & 0xFFFF ;
2014-05-30 12:53:19 +04:00
_text . draw ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , Qt : : AlignCenter , 0 , - 1 , selectedFrom , selectedTo ) ;
textstyleRestore ( ) ;
}
2015-09-10 13:30:59 +03:00
int32 HistoryServiceMsg : : resize ( int32 width ) {
2014-05-30 12:53:19 +04:00
width - = st : : msgServiceMargin . left ( ) + st : : msgServiceMargin . left ( ) ; // two small margins
if ( width < st : : msgServicePadding . left ( ) + st : : msgServicePadding . right ( ) + 1 ) width = st : : msgServicePadding . left ( ) + st : : msgServicePadding . right ( ) + 1 ;
int32 nwidth = qMax ( width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , 0 ) ;
if ( nwidth ! = _textWidth ) {
_textWidth = nwidth ;
2015-11-23 18:34:38 +03:00
textstyleSet ( & st : : serviceTextStyle ) ;
2014-05-30 12:53:19 +04:00
_textHeight = _text . countHeight ( nwidth ) ;
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2014-05-30 12:53:19 +04:00
}
if ( width > = _maxw ) {
_height = _minh ;
} else {
_height = _textHeight ;
}
_height + = st : : msgServicePadding . top ( ) + st : : msgServicePadding . bottom ( ) + st : : msgServiceMargin . top ( ) + st : : msgServiceMargin . bottom ( ) ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
2015-09-10 13:30:59 +03:00
_height + = st : : msgServiceMargin . top ( ) + _media - > resize ( _media - > currentWidth ( ) , this ) ;
2014-05-30 12:53:19 +04:00
}
return _height ;
}
bool HistoryServiceMsg : : hasPoint ( int32 x , int32 y ) const {
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return false ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
}
return QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . contains ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryServiceMsg : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2014-05-30 12:53:19 +04:00
lnk = TextLinkPtr ( ) ;
2015-06-27 16:02:00 +03:00
state = HistoryDefaultCursorState ;
2014-05-30 12:53:19 +04:00
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
}
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
if ( trect . contains ( x , y ) ) {
2015-11-23 18:34:38 +03:00
textstyleSet ( & st : : serviceTextStyle ) ;
2015-06-27 16:02:00 +03:00
bool inText = false ;
_text . getState ( lnk , inText , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) , Qt : : AlignCenter ) ;
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2015-06-27 16:02:00 +03:00
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
} else if ( _media ) {
_media - > getState ( lnk , state , x - st : : msgServiceMargin . left ( ) - ( width - _media - > maxWidth ( ) ) / 2 , y - st : : msgServiceMargin . top ( ) - height - st : : msgServiceMargin . top ( ) , this ) ;
2014-05-30 12:53:19 +04:00
}
}
void HistoryServiceMsg : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
}
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
2015-11-23 18:34:38 +03:00
textstyleSet ( & st : : serviceTextStyle ) ;
_text . getSymbol ( symbol , after , upon , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) , Qt : : AlignCenter ) ;
textstyleRestore ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-15 11:50:54 +03:00
void HistoryServiceMsg : : drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const {
2014-05-30 12:53:19 +04:00
if ( cacheFor ! = this ) {
cacheFor = this ;
2015-03-19 12:18:19 +03:00
cache . setText ( st : : dlgHistFont , inDialogsText ( ) , _textDlgOptions ) ;
2014-05-30 12:53:19 +04:00
}
QRect tr ( r ) ;
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgSystemColor ) - > p ) ;
cache . drawElided ( p , tr . left ( ) , tr . top ( ) , tr . width ( ) , tr . height ( ) / st : : dlgHistFont - > height ) ;
}
2014-06-14 23:32:11 +04:00
QString HistoryServiceMsg : : notificationText ( ) const {
2015-10-25 18:08:45 +01:00
QString msg = _text . original ( ) ;
2014-06-14 23:32:11 +04:00
if ( msg . size ( ) > 0xFF ) msg = msg . mid ( 0 , 0xFF ) + qsl ( " .. " ) ;
return msg ;
}
2014-08-11 13:03:45 +04:00
HistoryMedia * HistoryServiceMsg : : getMedia ( bool inOverview ) const {
2014-08-15 15:19:32 +04:00
return inOverview ? 0 : _media ;
2014-08-11 13:03:45 +04:00
}
2014-05-30 12:53:19 +04:00
HistoryServiceMsg : : ~ HistoryServiceMsg ( ) {
2014-08-15 15:19:32 +04:00
delete _media ;
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
HistoryDateMsg : : HistoryDateMsg ( History * history , HistoryBlock * block , const QDate & date ) :
2015-12-21 16:14:29 +03:00
HistoryServiceMsg ( history , block , clientMsgId ( ) , QDateTime ( date ) , langDayOfMonthFull ( date ) ) {
2014-05-30 12:53:19 +04:00
}
2015-12-23 17:18:42 +03:00
void HistoryDateMsg : : setDate ( const QDateTime & date ) {
if ( this - > date . date ( ) ! = date . date ( ) ) {
setServiceText ( langDayOfMonthFull ( date . date ( ) ) ) ;
}
HistoryServiceMsg : : setDate ( date ) ;
}
2014-05-30 12:53:19 +04:00
HistoryItem * createDayServiceMsg ( History * history , HistoryBlock * block , QDateTime date ) {
return regItem ( new HistoryDateMsg ( history , block , date . date ( ) ) ) ;
}
2015-09-19 12:13:21 +03:00
HistoryGroup : : HistoryGroup ( History * history , HistoryBlock * block , const MTPDmessageGroup & group , const QDateTime & date ) :
2015-09-20 11:55:41 +03:00
HistoryServiceMsg ( history , block , clientMsgId ( ) , date , lng_channel_comments_count ( lt_count , group . vcount . v ) /* + qsl(" (%1 .. %2)").arg(group.vmin_id.v).arg(group.vmax_id.v)*/ ) ,
2015-09-19 12:13:21 +03:00
_minId ( group . vmin_id . v ) , _maxId ( group . vmax_id . v ) , _count ( group . vcount . v ) , _lnk ( new CommentsLink ( this ) ) {
}
2015-09-20 11:55:41 +03:00
HistoryGroup : : HistoryGroup ( History * history , HistoryBlock * block , HistoryItem * newItem , const QDateTime & date ) :
HistoryServiceMsg ( history , block , clientMsgId ( ) , date , lng_channel_comments_count ( lt_count , 1 ) /* + qsl(" (%1 .. %2)").arg(newItem->id - 1).arg(newItem->id + 1)*/ ) ,
_minId ( newItem - > id - 1 ) , _maxId ( newItem - > id + 1 ) , _count ( 1 ) , _lnk ( new CommentsLink ( this ) ) {
}
2015-09-19 12:13:21 +03:00
void HistoryGroup : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
lnk = TextLinkPtr ( ) ;
state = HistoryDefaultCursorState ;
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
if ( width > _maxw ) {
left + = ( width - _maxw ) / 2 ;
width = _maxw ;
}
if ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . contains ( x , y ) ) {
lnk = _lnk ;
}
}
void HistoryGroup : : uniteWith ( MsgId minId , MsgId maxId , int32 count ) {
2015-09-21 23:57:42 +03:00
if ( minId < 0 | | maxId < 0 ) return ;
2015-09-19 12:13:21 +03:00
if ( minId = = _minId & & maxId = = _maxId & & count = = _count ) return ;
if ( minId < _minId ) {
2015-09-20 11:55:41 +03:00
if ( maxId < = _minId + 1 ) {
2015-09-19 12:13:21 +03:00
_count + = count ;
} else if ( maxId < = _maxId ) { // :( smth not precise
2015-09-20 11:55:41 +03:00
_count + = qMax ( 0 , count - ( maxId - _minId - 1 ) ) ;
2015-09-19 12:13:21 +03:00
} else { // :( smth not precise
_count = qMax ( count , _count ) ;
_maxId = maxId ;
}
_minId = minId ;
} else if ( maxId > _maxId ) {
2015-09-20 11:55:41 +03:00
if ( minId + 1 > = _maxId ) {
2015-09-19 12:13:21 +03:00
_count + = count ;
} else if ( minId > = _minId ) { // :( smth not precise
2015-09-20 11:55:41 +03:00
_count + = qMax ( 0 , count - ( _maxId - minId - 1 ) ) ;
2015-09-19 12:13:21 +03:00
} else { // :( smth not precise
_count = qMax ( count , _count ) ;
_minId = minId ;
}
_maxId = maxId ;
} else if ( count > _count ) { // :( smth not precise
_count = count ;
}
updateText ( ) ;
}
bool HistoryGroup : : decrementCount ( ) {
if ( _count > 1 ) {
- - _count ;
updateText ( ) ;
return true ;
}
return false ;
}
void HistoryGroup : : updateText ( ) {
2015-09-22 13:19:57 +03:00
setServiceText ( lng_channel_comments_count ( lt_count , _count ) /* + qsl(" (%1 .. %2)").arg(_minId).arg(_maxId)*/ ) ;
2015-09-19 12:13:21 +03:00
}
HistoryCollapse : : HistoryCollapse ( History * history , HistoryBlock * block , MsgId wasMinId , const QDateTime & date ) :
HistoryServiceMsg ( history , block , clientMsgId ( ) , date , qsl ( " - " ) ) ,
_wasMinId ( wasMinId ) {
}
2015-12-11 21:11:38 +03:00
void HistoryCollapse : : draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const {
2015-09-19 12:13:21 +03:00
}
void HistoryCollapse : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
lnk = TextLinkPtr ( ) ;
state = HistoryDefaultCursorState ;
}
2015-09-21 23:57:42 +03:00
HistoryJoined : : HistoryJoined ( History * history , HistoryBlock * block , const QDateTime & inviteDate , UserData * inviter , int32 flags ) :
HistoryServiceMsg ( history , block , clientMsgId ( ) , inviteDate , QString ( ) , flags ) {
2015-11-23 18:34:38 +03:00
textstyleSet ( & st : : serviceTextStyle ) ;
2015-09-22 13:19:57 +03:00
if ( peerToUser ( inviter - > id ) = = MTP : : authedId ( ) ) {
2015-11-02 17:33:57 -05:00
_text . setText ( st : : msgServiceFont , lang ( history - > isMegagroup ( ) ? lng_action_you_joined_group : lng_action_you_joined ) , _historySrvOptions ) ;
2015-09-21 23:57:42 +03:00
} else {
2015-11-02 17:33:57 -05:00
_text . setText ( st : : msgServiceFont , history - > isMegagroup ( ) ? lng_action_add_you_group ( lt_from , textcmdLink ( 1 , inviter - > name ) ) : lng_action_add_you ( lt_from , textcmdLink ( 1 , inviter - > name ) ) , _historySrvOptions ) ;
2015-09-21 23:57:42 +03:00
_text . setLink ( 1 , TextLinkPtr ( new PeerLink ( inviter ) ) ) ;
}
2015-11-23 18:34:38 +03:00
textstyleRestore ( ) ;
2015-09-21 23:57:42 +03:00
}
2015-03-19 12:18:19 +03:00
HistoryUnreadBar : : HistoryUnreadBar ( History * history , HistoryBlock * block , int32 count , const QDateTime & date ) : HistoryItem ( history , block , clientMsgId ( ) , 0 , date , 0 ) , freezed ( false ) {
2014-05-30 12:53:19 +04:00
setCount ( count ) ;
2014-10-10 16:46:20 +04:00
initDimensions ( ) ;
}
2015-09-10 13:30:59 +03:00
void HistoryUnreadBar : : initDimensions ( ) {
2014-05-30 12:53:19 +04:00
_maxw = st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ;
_minh = st : : unreadBarHeight ;
}
void HistoryUnreadBar : : setCount ( int32 count ) {
if ( ! count ) freezed = true ;
if ( freezed ) return ;
2014-12-18 21:40:49 +03:00
text = lng_unread_bar ( lt_count , count ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-11 21:11:38 +03:00
void HistoryUnreadBar : : draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const {
2014-07-13 13:50:38 +04:00
p . fillRect ( 0 , st : : lineWidth , _history - > width , st : : unreadBarHeight - 2 * st : : lineWidth , st : : unreadBarBG - > b ) ;
2014-07-06 07:32:21 +04:00
p . fillRect ( 0 , st : : unreadBarHeight - st : : lineWidth , _history - > width , st : : lineWidth , st : : unreadBarBorder - > b ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( st : : unreadBarFont - > f ) ;
p . setPen ( st : : unreadBarColor - > p ) ;
2014-07-13 13:50:38 +04:00
p . drawText ( QRect ( 0 , 0 , _history - > width , st : : unreadBarHeight - st : : lineWidth ) , text , style : : al_center ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-10 13:30:59 +03:00
int32 HistoryUnreadBar : : resize ( int32 width ) {
2014-05-30 12:53:19 +04:00
_height = st : : unreadBarHeight ;
return _height ;
}
2015-09-15 11:50:54 +03:00
void HistoryUnreadBar : : drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const {
2014-05-30 12:53:19 +04:00
}
2014-06-14 23:32:11 +04:00
QString HistoryUnreadBar : : notificationText ( ) const {
return QString ( ) ;
}