saved gifs done

This commit is contained in:
John Preston 2015-12-28 00:37:48 +03:00
parent dcbdd0b0a5
commit 9a1798f043
49 changed files with 2456 additions and 592 deletions

View file

@ -582,6 +582,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_media_auto_gif" = "Automatic GIF download";
"lng_media_auto_private_chats" = "Private chats";
"lng_media_auto_groups" = "Groups and channels";
"lng_media_auto_play" = "Autoplay";
"lng_emoji_category0" = "Frequently used";
"lng_emoji_category1" = "People";
@ -596,6 +597,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_switch_stickers_gifs" = "GIFs & Stickers";
"lng_switch_emoji" = "Emoji";
"lng_saved_gifs" = "Saved GIFs";
"lng_box_remove" = "Remove";
"lng_custom_stickers" = "Custom stickers";
@ -724,6 +727,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_context_delete_file" = "Delete File";
"lng_context_close_file" = "Close File";
"lng_context_copy_text" = "Copy Text";
"lng_context_save_gif" = "Save GIF";
"lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply";
"lng_context_forward_msg" = "Forward Message";

View file

@ -1865,6 +1865,8 @@ emojiObjectsActive: sprite(308px, 264px, 21px, 22px);
emojiSymbolsOver: sprite(84px, 196px, 21px, 22px);
emojiSymbolsActive: sprite(287px, 286px, 21px, 22px);
stickersSettings: sprite(140px, 124px, 21px, 22px);
savedGifsOver: sprite(329px, 286px, 21px, 22px);
savedGifsActive: sprite(350px, 286px, 21px, 22px);
emojiPanCategories: #f7f7f7;
@ -1989,6 +1991,11 @@ stickerPreviewDuration: 150;
stickerPreviewBg: #FFFFFFB0;
stickerPreviewMin: 0.1;
savedGifsLeft: 15px;
savedGifsSkip: 3px;
savedGifHeight: 96px;
savedGifMinWidth: 64px;
verifiedCheckProfile: sprite(285px, 235px, 18px, 18px);
verifiedCheckProfilePos: point(7px, 6px);
verifiedCheck: sprite(285px, 221px, 14px, 14px);
@ -2020,7 +2027,7 @@ botKbScroll: flatScroll(solidScroll) {
width: 10px;
}
minPhotoSize: 104px;
minPhotoSize: 100px;
maxMediaSize: 420px;
maxStickerSize: 256px;
maxGifSize: 320px;

View file

@ -915,5 +915,5 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
}
ApiWrap::~ApiWrap() {
App::deinitMedia(false);
App::clearHistories();
}

View file

@ -45,21 +45,14 @@ namespace {
typedef QMap<PeerData*, bool> UpdatedPeers;
UpdatedPeers updatedPeers;
typedef QHash<PhotoId, PhotoData*> PhotosData;
PhotosData photosData;
typedef QHash<VideoId, VideoData*> VideosData;
VideosData videosData;
typedef QHash<AudioId, AudioData*> AudiosData;
AudiosData audiosData;
DocumentsData documentsData;
typedef QHash<QString, ImageLinkData*> ImageLinksData;
ImageLinksData imageLinksData;
typedef QHash<DocumentId, DocumentData*> DocumentsData;
DocumentsData documentsData;
typedef QHash<WebPageId, WebPageData*> WebPagesData;
WebPagesData webPagesData;
@ -918,11 +911,41 @@ namespace App {
existing->setViewsCount(m.has_views() ? m.vviews.v : -1);
return !existing->detached();
if (!existing->detached()) {
App::checkSavedGif(existing);
return true;
}
return false;
}
return false;
}
void addSavedGif(DocumentData *doc) {
SavedGifs &saved(cRefSavedGifs());
int32 index = saved.indexOf(doc);
if (index) {
if (index > 0) saved.remove(index);
saved.push_front(doc);
if (saved.size() > cSavedGifsLimit()) saved.pop_back();
Local::writeSavedGifs();
if (App::main()) emit App::main()->savedGifsUpdated();
}
}
void checkSavedGif(HistoryItem *item) {
if (!item->toHistoryForwarded() && item->out()) {
if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) {
if (doc->type == AnimatedDocument && doc->mime.toLower() == qstr("video/mp4")) {
addSavedGif(doc);
}
}
}
}
}
void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type) {
QMap<uint64, int32> msgsIds;
for (int32 i = 0, l = msgs.size(); i < l; ++i) {
@ -1417,9 +1440,9 @@ namespace App {
}
PhotoData *photo(const PhotoId &photo) {
PhotosData::const_iterator i = photosData.constFind(photo);
if (i == photosData.cend()) {
i = photosData.insert(photo, new PhotoData(photo));
PhotosData::const_iterator i = ::photosData.constFind(photo);
if (i == ::photosData.cend()) {
i = ::photosData.insert(photo, new PhotoData(photo));
}
return i.value();
}
@ -1427,9 +1450,9 @@ namespace App {
PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full) {
if (convert) {
if (convert->id != photo) {
PhotosData::iterator i = photosData.find(convert->id);
if (i != photosData.cend() && i.value() == convert) {
photosData.erase(i);
PhotosData::iterator i = ::photosData.find(convert->id);
if (i != ::photosData.cend() && i.value() == convert) {
::photosData.erase(i);
}
convert->id = photo;
delete convert->uploadingData;
@ -1443,16 +1466,16 @@ namespace App {
convert->full = full;
}
}
PhotosData::const_iterator i = photosData.constFind(photo);
PhotosData::const_iterator i = ::photosData.constFind(photo);
PhotoData *result;
LastPhotosMap::iterator inLastIter = lastPhotosMap.end();
if (i == photosData.cend()) {
if (i == ::photosData.cend()) {
if (convert) {
result = convert;
} else {
result = new PhotoData(photo, access, date, thumb, medium, full);
}
photosData.insert(photo, result);
::photosData.insert(photo, result);
} else {
result = i.value();
if (result != convert && !result->date && date) {
@ -1479,9 +1502,9 @@ namespace App {
}
VideoData *video(const VideoId &video) {
VideosData::const_iterator i = videosData.constFind(video);
if (i == videosData.cend()) {
i = videosData.insert(video, new VideoData(video));
VideosData::const_iterator i = ::videosData.constFind(video);
if (i == ::videosData.cend()) {
i = ::videosData.insert(video, new VideoData(video));
}
return i.value();
}
@ -1489,9 +1512,9 @@ namespace App {
VideoData *videoSet(const VideoId &video, VideoData *convert, const uint64 &access, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size) {
if (convert) {
if (convert->id != video) {
VideosData::iterator i = videosData.find(convert->id);
if (i != videosData.cend() && i.value() == convert) {
videosData.erase(i);
VideosData::iterator i = ::videosData.find(convert->id);
if (i != ::videosData.cend() && i.value() == convert) {
::videosData.erase(i);
}
convert->id = video;
convert->status = FileReady;
@ -1507,15 +1530,15 @@ namespace App {
convert->size = size;
}
}
VideosData::const_iterator i = videosData.constFind(video);
VideosData::const_iterator i = ::videosData.constFind(video);
VideoData *result;
if (i == videosData.cend()) {
if (i == ::videosData.cend()) {
if (convert) {
result = convert;
} else {
result = new VideoData(video, access, date, duration, w, h, thumb, dc, size);
}
videosData.insert(video, result);
::videosData.insert(video, result);
} else {
result = i.value();
if (result != convert && !result->date && date) {
@ -1533,9 +1556,9 @@ namespace App {
}
AudioData *audio(const AudioId &audio) {
AudiosData::const_iterator i = audiosData.constFind(audio);
if (i == audiosData.cend()) {
i = audiosData.insert(audio, new AudioData(audio));
AudiosData::const_iterator i = ::audiosData.constFind(audio);
if (i == ::audiosData.cend()) {
i = ::audiosData.insert(audio, new AudioData(audio));
}
return i.value();
}
@ -1543,9 +1566,9 @@ namespace App {
AudioData *audioSet(const AudioId &audio, AudioData *convert, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size) {
if (convert) {
if (convert->id != audio) {
AudiosData::iterator i = audiosData.find(convert->id);
if (i != audiosData.cend() && i.value() == convert) {
audiosData.erase(i);
AudiosData::iterator i = ::audiosData.find(convert->id);
if (i != ::audiosData.cend() && i.value() == convert) {
::audiosData.erase(i);
}
convert->id = audio;
convert->status = FileReady;
@ -1559,15 +1582,15 @@ namespace App {
convert->size = size;
}
}
AudiosData::const_iterator i = audiosData.constFind(audio);
AudiosData::const_iterator i = ::audiosData.constFind(audio);
AudioData *result;
if (i == audiosData.cend()) {
if (i == ::audiosData.cend()) {
if (convert) {
result = convert;
} else {
result = new AudioData(audio, access, date, mime, duration, dc, size);
}
audiosData.insert(audio, result);
::audiosData.insert(audio, result);
} else {
result = i.value();
if (result != convert && !result->date && date) {
@ -1583,9 +1606,9 @@ namespace App {
}
DocumentData *document(const DocumentId &document) {
DocumentsData::const_iterator i = documentsData.constFind(document);
if (i == documentsData.cend()) {
i = documentsData.insert(document, new DocumentData(document));
DocumentsData::const_iterator i = ::documentsData.constFind(document);
if (i == ::documentsData.cend()) {
i = ::documentsData.insert(document, new DocumentData(document));
}
return i.value();
}
@ -1594,9 +1617,9 @@ namespace App {
bool sentSticker = false;
if (convert) {
if (convert->id != document) {
DocumentsData::iterator i = documentsData.find(convert->id);
if (i != documentsData.cend() && i.value() == convert) {
documentsData.erase(i);
DocumentsData::iterator i = ::documentsData.find(convert->id);
if (i != ::documentsData.cend() && i.value() == convert) {
::documentsData.erase(i);
}
convert->id = document;
convert->status = FileReady;
@ -1636,9 +1659,9 @@ namespace App {
Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), loc);
}
}
DocumentsData::const_iterator i = documentsData.constFind(document);
DocumentsData::const_iterator i = ::documentsData.constFind(document);
DocumentData *result;
if (i == documentsData.cend()) {
if (i == ::documentsData.cend()) {
if (convert) {
result = convert;
} else {
@ -1646,7 +1669,7 @@ namespace App {
result->recountIsImage();
if (result->sticker()) result->sticker()->loc = thumbLocation;
}
documentsData.insert(document, result);
::documentsData.insert(document, result);
} else {
result = i.value();
if (result != convert) {
@ -1776,16 +1799,16 @@ namespace App {
void forgetMedia() {
lastPhotos.clear();
lastPhotosMap.clear();
for (PhotosData::const_iterator i = photosData.cbegin(), e = photosData.cend(); i != e; ++i) {
for (PhotosData::const_iterator i = ::photosData.cbegin(), e = ::photosData.cend(); i != e; ++i) {
i.value()->forget();
}
for (VideosData::const_iterator i = videosData.cbegin(), e = videosData.cend(); i != e; ++i) {
for (VideosData::const_iterator i = ::videosData.cbegin(), e = ::videosData.cend(); i != e; ++i) {
i.value()->forget();
}
for (AudiosData::const_iterator i = audiosData.cbegin(), e = audiosData.cend(); i != e; ++i) {
for (AudiosData::const_iterator i = ::audiosData.cbegin(), e = ::audiosData.cend(); i != e; ++i) {
i.value()->forget();
}
for (DocumentsData::const_iterator i = documentsData.cbegin(), e = documentsData.cend(); i != e; ++i) {
for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) {
i.value()->forget();
}
for (ImageLinksData::const_iterator i = imageLinksData.cbegin(), e = imageLinksData.cend(); i != e; ++i) {
@ -1933,32 +1956,33 @@ namespace App {
delete *i;
}
peersData.clear();
for (PhotosData::const_iterator i = photosData.cbegin(), e = photosData.cend(); i != e; ++i) {
for (PhotosData::const_iterator i = ::photosData.cbegin(), e = ::photosData.cend(); i != e; ++i) {
delete *i;
}
photosData.clear();
for (VideosData::const_iterator i = videosData.cbegin(), e = videosData.cend(); i != e; ++i) {
::photosData.clear();
for (VideosData::const_iterator i = ::videosData.cbegin(), e = ::videosData.cend(); i != e; ++i) {
delete *i;
}
videosData.clear();
for (AudiosData::const_iterator i = audiosData.cbegin(), e = audiosData.cend(); i != e; ++i) {
::videosData.clear();
for (AudiosData::const_iterator i = ::audiosData.cbegin(), e = ::audiosData.cend(); i != e; ++i) {
delete *i;
}
audiosData.clear();
for (DocumentsData::const_iterator i = documentsData.cbegin(), e = documentsData.cend(); i != e; ++i) {
::audiosData.clear();
for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) {
delete *i;
}
documentsData.clear();
::documentsData.clear();
for (WebPagesData::const_iterator i = webPagesData.cbegin(), e = webPagesData.cend(); i != e; ++i) {
delete *i;
}
webPagesData.clear();
if (api()) api()->clearWebPageRequests();
cSetRecentStickers(RecentStickerPack());
cSetStickersHash(0);
cSetStickerSets(StickerSets());
cSetStickerSetsOrder(StickerSetsOrder());
cSetLastStickersUpdate(0);
cSetSavedGifs(SavedGifs());
cSetLastSavedGifsUpdate(0);
cSetReportSpamStatuses(ReportSpamStatuses());
::photoItems.clear();
::videoItems.clear();
@ -2057,7 +2081,6 @@ namespace App {
}
void initMedia() {
deinitMedia(false);
audioInit();
if (!::monofont) {
@ -2119,48 +2142,47 @@ namespace App {
prepareCorners(MessageInSelectedCorners, st::msgRadius, st::msgInBgSelected, &st::msgInShadowSelected);
prepareCorners(MessageOutCorners, st::msgRadius, st::msgOutBg, &st::msgOutShadow);
prepareCorners(MessageOutSelectedCorners, st::msgRadius, st::msgOutBgSelected, &st::msgOutShadowSelected);
}
void deinitMedia(bool completely) {
void clearHistories() {
textlnkOver(TextLinkPtr());
textlnkDown(TextLinkPtr());
histories().clear();
if (completely) {
audioFinish();
delete ::sprite;
::sprite = 0;
delete ::emoji;
::emoji = 0;
delete ::emojiLarge;
::emojiLarge = 0;
for (int32 j = 0; j < 4; ++j) {
for (int32 i = 0; i < RoundCornersCount; ++i) {
delete ::corners[i].p[j]; ::corners[i].p[j] = 0;
}
delete ::cornersMask[j]; ::cornersMask[j] = 0;
}
for (CornersMap::const_iterator i = ::cornersMap.cbegin(), e = ::cornersMap.cend(); i != e; ++i) {
for (int32 j = 0; j < 4; ++j) {
delete i->p[j];
}
}
::cornersMap.clear();
mainEmojiMap.clear();
otherEmojiMap.clear();
clearAllImages();
} else {
clearStorageImages();
cSetServerBackgrounds(WallPapers());
}
clearStorageImages();
cSetServerBackgrounds(WallPapers());
serviceImageCacheSize = imageCacheSize();
}
void deinitMedia() {
audioFinish();
delete ::sprite;
::sprite = 0;
delete ::emoji;
::emoji = 0;
delete ::emojiLarge;
::emojiLarge = 0;
for (int32 j = 0; j < 4; ++j) {
for (int32 i = 0; i < RoundCornersCount; ++i) {
delete ::corners[i].p[j]; ::corners[i].p[j] = 0;
}
delete ::cornersMask[j]; ::cornersMask[j] = 0;
}
for (CornersMap::const_iterator i = ::cornersMap.cbegin(), e = ::cornersMap.cend(); i != e; ++i) {
for (int32 j = 0; j < 4; ++j) {
delete i->p[j];
}
}
::cornersMap.clear();
mainEmojiMap.clear();
otherEmojiMap.clear();
clearAllImages();
}
void hoveredItem(HistoryItem *item) {
::hoveredItem = item;
}
@ -2362,6 +2384,10 @@ namespace App {
return ::photoItems;
}
const PhotosData &photosData() {
return ::photosData;
}
void regVideoItem(VideoData *data, HistoryItem *item) {
::videoItems[data].insert(item, NullType());
}
@ -2374,6 +2400,10 @@ namespace App {
return ::videoItems;
}
const VideosData &videosData() {
return ::videosData;
}
void regAudioItem(AudioData *data, HistoryItem *item) {
::audioItems[data].insert(item, NullType());
}
@ -2386,6 +2416,10 @@ namespace App {
return ::audioItems;
}
const AudiosData &audiosData() {
return ::audiosData;
}
void regDocumentItem(DocumentData *data, HistoryItem *item) {
::documentItems[data].insert(item, NullType());
}
@ -2398,6 +2432,10 @@ namespace App {
return ::documentItems;
}
const DocumentsData &documentsData() {
return ::documentsData;
}
void regWebPageItem(WebPageData *data, HistoryItem *item) {
::webPageItems[data].insert(item, NullType());
}
@ -2436,9 +2474,10 @@ namespace App {
void stopGifItems() {
if (!::gifItems.isEmpty()) {
if (HistoryItem *playing = ::gifItems.begin().value()) {
if (playing->getMedia()) {
playing->getMedia()->stopInline(playing);
GifItems gifs = ::gifItems;
for (GifItems::const_iterator i = gifs.cbegin(), e = gifs.cend(); i != e; ++i) {
if (HistoryMedia *media = i.value()->getMedia()) {
media->stopInline(i.value());
}
}
}

View file

@ -35,13 +35,19 @@ class FileUploader;
#include "layout.h"
typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
typedef QMap<PhotoData*, HistoryItemsMap> PhotoItems;
typedef QMap<VideoData*, HistoryItemsMap> VideoItems;
typedef QMap<AudioData*, HistoryItemsMap> AudioItems;
typedef QMap<DocumentData*, HistoryItemsMap> DocumentItems;
typedef QMap<WebPageData*, HistoryItemsMap> WebPageItems;
typedef QMap<int32, HistoryItemsMap> SharedContactItems;
typedef QMap<ClipReader*, HistoryItem*> GifItems;
typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
typedef QHash<VideoData*, HistoryItemsMap> VideoItems;
typedef QHash<AudioData*, HistoryItemsMap> AudioItems;
typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
typedef QHash<int32, HistoryItemsMap> SharedContactItems;
typedef QHash<ClipReader*, HistoryItem*> GifItems;
typedef QHash<PhotoId, PhotoData*> PhotosData;
typedef QHash<VideoId, VideoData*> VideosData;
typedef QHash<AudioId, AudioData*> AudiosData;
typedef QHash<DocumentId, DocumentData*> DocumentsData;
struct ReplyMarkup {
ReplyMarkup(int32 flags = 0) : flags(flags) {
}
@ -79,6 +85,8 @@ namespace App {
void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true);
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d, bool emitPeerUpdated = true);
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
void addSavedGif(DocumentData *doc);
void checkSavedGif(HistoryItem *item);
void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type);
void feedMsgs(const MTPVector<MTPMessage> &msgs, NewMessageType type);
void feedInboxRead(const PeerId &peer, MsgId upTo);
@ -184,8 +192,10 @@ namespace App {
const QPixmap &emojiLarge();
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight);
void clearHistories();
void initMedia();
void deinitMedia(bool completely = true);
void deinitMedia();
void playSound();
void checkImageCacheSize();
@ -202,18 +212,22 @@ namespace App {
void regPhotoItem(PhotoData *data, HistoryItem *item);
void unregPhotoItem(PhotoData *data, HistoryItem *item);
const PhotoItems &photoItems();
const PhotosData &photosData();
void regVideoItem(VideoData *data, HistoryItem *item);
void unregVideoItem(VideoData *data, HistoryItem *item);
const VideoItems &videoItems();
const VideosData &videosData();
void regAudioItem(AudioData *data, HistoryItem *item);
void unregAudioItem(AudioData*data, HistoryItem *item);
const AudioItems &audioItems();
const AudiosData &audiosData();
void regDocumentItem(DocumentData *data, HistoryItem *item);
void unregDocumentItem(DocumentData *data, HistoryItem *item);
const DocumentItems &documentItems();
const DocumentsData &documentsData();
void regWebPageItem(WebPageData *data, HistoryItem *item);
void unregWebPageItem(WebPageData *data, HistoryItem *item);
@ -276,25 +290,4 @@ namespace App {
};
inline int32 stickersCountHash(bool checkOfficial = false) {
uint32 acc = 0;
bool foundOfficial = false, foundBad = false;;
const StickerSets &sets(cStickerSets());
const StickerSetsOrder &order(cStickerSetsOrder());
for (StickerSetsOrder::const_iterator i = order.cbegin(), e = order.cend(); i != e; ++i) {
StickerSets::const_iterator j = sets.constFind(*i);
if (j != sets.cend()) {
if (j->id == 0) {
foundBad = true;
} else if (j->flags & MTPDstickerSet::flag_official) {
foundOfficial = true;
}
if (!(j->flags & MTPDstickerSet::flag_disabled)) {
acc = (acc * 20261) + j->hash;
}
}
}
return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0;
}
#include "facades.h"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 240 KiB

View file

@ -226,11 +226,12 @@ AutoDownloadBox::AutoDownloadBox() : AbstractBox(st::boxWidth)
, _audioGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadAudio() & dbiadNoGroups))
, _gifPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadGif() & dbiadNoPrivate))
, _gifGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadGif() & dbiadNoGroups))
, _gifPlay(this, lang(lng_media_auto_play), cAutoPlayGif())
, _sectionHeight(st::boxTitleHeight + 2 * (st::defaultCheckbox.height + st::setLittleSkip))
, _save(this, lang(lng_connection_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
setMaxHeight(3 * _sectionHeight + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom());
setMaxHeight(3 * _sectionHeight + st::setLittleSkip + _gifPlay.height() + st::setLittleSkip + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom());
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
@ -245,6 +246,7 @@ void AutoDownloadBox::hideAll() {
_audioGroups.hide();
_gifPrivate.hide();
_gifGroups.hide();
_gifPlay.hide();
_save.hide();
_cancel.hide();
@ -257,6 +259,7 @@ void AutoDownloadBox::showAll() {
_audioGroups.show();
_gifPrivate.show();
_gifGroups.show();
_gifPlay.show();
_save.show();
_cancel.show();
@ -282,15 +285,60 @@ void AutoDownloadBox::resizeEvent(QResizeEvent *e) {
_gifPrivate.moveToLeft(st::boxTitlePosition.x(), 2 * _sectionHeight + st::boxTitleHeight + st::setLittleSkip);
_gifGroups.moveToLeft(st::boxTitlePosition.x(), _gifPrivate.y() + _gifPrivate.height() + st::setLittleSkip);
_gifPlay.moveToLeft(st::boxTitlePosition.x(), _gifGroups.y() + _gifGroups.height() + st::setLittleSkip);
_save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
}
void AutoDownloadBox::onSave() {
cSetAutoDownloadPhoto((_photoPrivate.checked() ? 0 : dbiadNoPrivate) | (_photoGroups.checked() ? 0 : dbiadNoGroups));
cSetAutoDownloadAudio((_audioPrivate.checked() ? 0 : dbiadNoPrivate) | (_audioGroups.checked() ? 0 : dbiadNoGroups));
cSetAutoDownloadGif((_gifPrivate.checked() ? 0 : dbiadNoPrivate) | (_gifGroups.checked() ? 0 : dbiadNoGroups));
Local::writeUserSettings();
bool changed = false;
int32 autoDownloadPhoto = (_photoPrivate.checked() ? 0 : dbiadNoPrivate) | (_photoGroups.checked() ? 0 : dbiadNoGroups);
if (cAutoDownloadPhoto() != autoDownloadPhoto) {
bool enabledPrivate = ((cAutoDownloadPhoto() & dbiadNoPrivate) && !(autoDownloadPhoto & dbiadNoPrivate));
bool enabledGroups = ((cAutoDownloadPhoto() & dbiadNoGroups) && !(autoDownloadPhoto & dbiadNoGroups));
cSetAutoDownloadPhoto(autoDownloadPhoto);
if (enabledPrivate || enabledGroups) {
const PhotosData &data(App::photosData());
for (PhotosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
}
}
changed = true;
}
int32 autoDownloadAudio = (_audioPrivate.checked() ? 0 : dbiadNoPrivate) | (_audioGroups.checked() ? 0 : dbiadNoGroups);
if (cAutoDownloadAudio() != autoDownloadAudio) {
bool enabledPrivate = ((cAutoDownloadAudio() & dbiadNoPrivate) && !(autoDownloadAudio & dbiadNoPrivate));
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
cSetAutoDownloadAudio(autoDownloadAudio);
if (enabledPrivate || enabledGroups) {
const AudiosData &data(App::audiosData());
for (AudiosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
}
}
changed = true;
}
int32 autoDownloadGif = (_gifPrivate.checked() ? 0 : dbiadNoPrivate) | (_gifGroups.checked() ? 0 : dbiadNoGroups);
if (cAutoDownloadGif() != autoDownloadGif) {
bool enabledPrivate = ((cAutoDownloadGif() & dbiadNoPrivate) && !(autoDownloadGif & dbiadNoPrivate));
bool enabledGroups = ((cAutoDownloadGif() & dbiadNoGroups) && !(autoDownloadGif & dbiadNoGroups));
cSetAutoDownloadGif(autoDownloadGif);
if (enabledPrivate || enabledGroups) {
const DocumentsData &data(App::documentsData());
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
}
}
changed = true;
}
if (cAutoPlayGif() != _gifPlay.checked()) {
cSetAutoPlayGif(_gifPlay.checked());
if (!cAutoPlayGif()) {
App::stopGifItems();
}
changed = true;
}
if (changed) Local::writeUserSettings();
onClose();
}

View file

@ -77,7 +77,7 @@ private:
Checkbox _photoPrivate, _photoGroups;
Checkbox _audioPrivate, _audioGroups;
Checkbox _gifPrivate, _gifGroups;
Checkbox _gifPrivate, _gifGroups, _gifPlay;
int32 _sectionHeight;

View file

@ -112,7 +112,6 @@ void StickerSetInner::installDone(const MTPBool &result) {
sets.erase(custom);
}
}
cSetStickersHash(stickersCountHash());
Local::writeStickers();
emit installed(_setId);
Ui::hideLayer();
@ -892,7 +891,6 @@ void StickersBox::onSave() {
}
}
cSetStickersHash(stickersCountHash());
Local::writeStickers();
if (writeRecent) Local::writeUserSettings();
emit App::main()->stickersUpdated();

View file

@ -130,6 +130,7 @@ enum {
EmojiPanRowsPerPage = 6,
StickerPanPerRow = 5,
StickerPanRowsPerPage = 4,
SavedGifsMaxPerRow = 4,
StickersUpdateTimeout = 3600000, // update not more than once in an hour
SearchPeopleLimit = 5,

View file

@ -28,6 +28,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "window.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "boxes/confirmbox.h"
#include "boxes/stickersetbox.h"
@ -732,9 +733,6 @@ EmojiPanInner::EmojiPanInner() : TWidget()
_hovers[i] = QVector<float64>(_counts[i], 0);
}
_saveConfigTimer.setSingleShot(true);
connect(&_saveConfigTimer, SIGNAL(timeout()), this, SLOT(onSaveConfig()));
_showPickerTimer.setSingleShot(true);
connect(&_showPickerTimer, SIGNAL(timeout()), this, SLOT(onShowPicker()));
connect(&_picker, SIGNAL(emojiSelected(EmojiPtr)), this, SLOT(onColorSelected(EmojiPtr)));
@ -937,15 +935,11 @@ void EmojiPanInner::selectEmoji(EmojiPtr emoji) {
qSwap(*i, *(i - 1));
}
}
_saveConfigTimer.start(SaveRecentEmojisTimeout);
emit saveConfigDelayed(SaveRecentEmojisTimeout);
emit selected(emoji);
}
void EmojiPanInner::onSaveConfig() {
Local::writeUserSettings();
}
void EmojiPanInner::onShowPicker() {
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
@ -1219,6 +1213,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
StickerPanInner::StickerPanInner() : TWidget()
, _a_selected(animation(this, &StickerPanInner::step_selected))
, _top(0)
, _showingGifs(cShowingSavedGifs())
, _selected(-1)
, _pressedSel(-1)
, _settings(this, lang(lng_stickers_you_have))
@ -1234,8 +1229,6 @@ StickerPanInner::StickerPanInner() : TWidget()
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
refreshStickers();
}
void StickerPanInner::setMaxHeight(int32 h) {
@ -1253,11 +1246,15 @@ void StickerPanInner::setScrollTop(int top) {
int StickerPanInner::countHeight() {
int result = 0, minLastH = _maxHeight - st::rbEmoji.height - st::stickerPanPadding;
for (int i = 0; i < _sets.size(); ++i) {
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
int h = st::emojiPanHeader + rows * st::stickerPanSize.height();
if (i == _sets.size() - 1 && h < minLastH) h = minLastH;
result += h;
if (_showingGifs) {
result = st::emojiPanHeader + _gifRows.count() * (st::savedGifHeight + st::savedGifsSkip) - st::savedGifsSkip;
} else {
for (int i = 0; i < _sets.size(); ++i) {
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
int h = st::emojiPanHeader + rows * st::stickerPanSize.height();
if (i == _sets.size() - 1 && h < minLastH) h = minLastH;
result += h;
}
}
return qMax(minLastH, result) + st::stickerPanPadding;
}
@ -1285,8 +1282,39 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
if (r != rect()) {
p.setClipRect(r);
}
p.fillRect(r, st::white->b);
p.fillRect(r, st::white);
if (_showingGifs) {
paintSavedGifs(p, r);
} else {
paintStickers(p, r);
}
}
void StickerPanInner::paintSavedGifs(Painter &p, const QRect &r) {
uint64 ms = getms();
int32 fromrow = floorclamp(r.y() - st::emojiPanHeader, st::savedGifHeight + st::savedGifsSkip, 0, _gifRows.size());
int32 torow = ceilclamp(r.y() + r.height() - st::emojiPanHeader - st::savedGifsSkip, st::savedGifHeight + st::savedGifsSkip, 0, _gifRows.size());
int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width());
for (int32 row = fromrow; row < torow; ++row) {
const GifRow &gifRow(_gifRows.at(row));
int32 left = st::savedGifsLeft, top = st::emojiPanHeader + row * (st::savedGifHeight + st::savedGifsSkip);
for (int32 col = 0, cols = gifRow.size(); col < cols; ++col) {
if (left >= tox) break;
int32 w = gifRow.at(col)->width();
if (left + w > fromx) {
p.translate(left, top);
gifRow.at(col)->paint(p, _previewShown, ms);
p.translate(-left, -top);
}
left += w + st::savedGifsSkip;
}
}
}
void StickerPanInner::paintStickers(Painter &p, const QRect &r) {
int32 fromcol = floorclamp(r.x() - st::stickerPanPadding, st::stickerPanSize.width(), 0, StickerPanPerRow);
int32 tocol = ceilclamp(r.x() + r.width() - st::stickerPanPadding, st::stickerPanSize.width(), 0, StickerPanPerRow);
if (rtl()) {
@ -1382,6 +1410,35 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
}
if (_selected < 0 || _selected != pressed) return;
if (_showingGifs) {
int32 row = _selected / MatrixRowShift, col = _selected % MatrixRowShift;
bool del = (col >= SavedGifsMaxPerRow);
if (del) col -= SavedGifsMaxPerRow;
if (row < _gifRows.size() && col < _gifRows.at(row).size()) {
DocumentData *doc = _gifRows.at(row).at(col)->document();
if (del) {
int32 index = cSavedGifs().indexOf(doc);
if (index >= 0) {
cRefSavedGifs().remove(index);
Local::writeSavedGifs();
if (App::main()) emit App::main()->savedGifsUpdated();
MTP::send(MTPmessages_SaveGif(MTP_inputDocument(MTP_long(doc->id), MTP_long(doc->access)), MTP_bool(true)));
} else {
refreshSavedGifs();
}
} else {
if (doc->loaded()) {
emit selected(doc);
} else if (doc->loading()) {
doc->cancel();
} else {
DocumentOpenLink::doOpen(doc, ActionOnLoadNone);
}
}
}
return;
}
if (_selected >= MatrixRowShift * _sets.size()) {
return;
}
@ -1416,7 +1473,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
}
}
if (refresh) {
refreshRecent();
refreshRecentStickers();
updateSelected();
update();
}
@ -1448,6 +1505,20 @@ void StickerPanInner::enterFromChildEvent(QEvent *e) {
void StickerPanInner::clearSelection(bool fast) {
_lastMousePos = mapToGlobal(QPoint(-10, -10));
if (fast) {
if (_showingGifs) {
if (_selected >= 0) {
int32 srow = _selected / MatrixRowShift, scol = _selected % MatrixRowShift;
bool sdel = (scol >= SavedGifsMaxPerRow);
if (sdel) scol -= SavedGifsMaxPerRow;
if (srow < _gifRows.size() && scol < _gifRows.at(srow).size()) {
_gifRows.at(srow).at(scol)->notify_over(false);
if (sdel) _gifRows.at(srow).at(scol)->notify_deleteOver(false);
}
setCursor(style::cur_default);
}
_selected = _pressedSel = -1;
return;
}
for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
_sets[tab].hovers[sel] = 0;
@ -1476,28 +1547,156 @@ void StickerPanInner::clearSelection(bool fast) {
}
}
void StickerPanInner::hideFinish() {
clearSavedGifs();
for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) {
i.value()->document()->forget();
}
}
void StickerPanInner::refreshStickers() {
clearSelection(true);
const StickerSets &sets(cStickerSets());
_sets.clear(); _sets.reserve(sets.size() + 1);
refreshRecent(false);
refreshRecentStickers(false);
for (StickerSetsOrder::const_iterator i = cStickerSetsOrder().cbegin(), e = cStickerSetsOrder().cend(); i != e; ++i) {
appendSet(*i);
}
int32 h = countHeight();
if (h != height()) resize(width(), h);
if (!_showingGifs) {
int32 h = countHeight();
if (h != height()) resize(width(), h);
_settings.setVisible(_sets.isEmpty());
} else {
_settings.hide();
}
_settings.setVisible(_sets.isEmpty());
emit refreshIcons();
updateSelected();
}
void StickerPanInner::refreshSavedGifs() {
clearSelection(true);
clearSavedGifs();
if (_showingGifs) {
const SavedGifs &saved(cSavedGifs());
if (saved.isEmpty()) {
showStickerSet(RecentStickerSetId);
return;
} else {
_gifRows.reserve(saved.size());
GifRow row;
row.reserve(SavedGifsMaxPerRow);
int32 maxWidth = width() - st::savedGifsLeft, sumWidth = 0, widths[SavedGifsMaxPerRow] = { 0 };
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
DocumentData *doc = *i;
int32 w = doc->dimensions.width(), h = doc->dimensions.height();
if ((w <= 0 || h <= 0) && !doc->thumb->isNull()) {
w = doc->thumb->width();
h = doc->thumb->height();
}
if (w <= 0 || h <= 0) continue;
w = w * st::savedGifHeight / h;
widths[row.size()] = w;
w = qMax(w, int32(st::savedGifMinWidth));
sumWidth += w;
row.push_back(layoutPrepare(doc, (_gifRows.size() * MatrixRowShift) + row.size(), w));
if (row.size() >= SavedGifsMaxPerRow || sumWidth >= maxWidth - (row.size() - 1) * st::savedGifsSkip) {
_gifRows.push_back(layoutGifRow(row, widths, sumWidth));
row.clear();
row.reserve(SavedGifsMaxPerRow);
sumWidth = 0;
memset(widths, 0, sizeof(widths));
}
}
if (!row.isEmpty()) {
_gifRows.push_back(row);
}
}
deleteUnusedLayouts();
int32 h = countHeight();
if (h != height()) resize(width(), h);
update();
}
emit refreshIcons();
updateSelected();
}
void StickerPanInner::clearSavedGifs() {
for (GifRows::const_iterator i = _gifRows.cbegin(), e = _gifRows.cend(); i != e; ++i) {
for (GifRow::const_iterator j = i->cbegin(), end = i->cend(); j != end; ++j) {
(*j)->setPosition(-1, 0);
}
}
_gifRows.clear();
}
void StickerPanInner::deleteUnusedLayouts() {
if (_gifRows.isEmpty()) { // delete all
for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) {
delete i.value();
}
_gifLayouts.clear();
} else {
for (GifLayouts::iterator i = _gifLayouts.begin(); i != _gifLayouts.cend();) {
if (i.value()->position() < 0) {
delete i.value();
i = _gifLayouts.erase(i);
} else {
++i;
}
}
}
}
LayoutSavedGif *StickerPanInner::layoutPrepare(DocumentData *doc, int32 position, int32 width) {
GifLayouts::const_iterator i = _gifLayouts.constFind(doc);
if (i == _gifLayouts.cend()) {
i = _gifLayouts.insert(doc, new LayoutSavedGif(doc));
}
i.value()->setPosition(position, width);
return i.value();
}
const StickerPanInner::GifRow &StickerPanInner::layoutGifRow(const GifRow &row, int32 *widths, int32 sumWidth) {
int32 count = row.size();
t_assert(count <= SavedGifsMaxPerRow);
int32 availw = width() - st::savedGifsLeft - st::savedGifsSkip * (count - 1);
if (sumWidth != availw) {
for (int32 i = 0; i < count; ++i) {
int32 w = widths[i] * availw / sumWidth;
int32 actualw = qMax(w, int32(st::savedGifMinWidth));
row.at(i)->setWidth(actualw);
availw -= actualw;
sumWidth -= qMax(widths[i], int32(st::savedGifMinWidth));
}
}
return row;
}
void StickerPanInner::preloadImages() {
if (_showingGifs) {
for (int32 row = 0, rows = _gifRows.size(); row < rows; ++row) {
for (int32 col = 0, cols = _gifRows.at(row).size(); col < cols; ++col) {
_gifRows.at(row).at(col)->preload();
}
}
}
uint64 ms = getms();
for (int32 i = 0, l = _sets.size(), k = 0; i < l; ++i) {
for (int32 j = 0, n = _sets.at(i).pack.size(); j < n; ++j) {
@ -1518,6 +1717,8 @@ void StickerPanInner::preloadImages() {
}
uint64 StickerPanInner::currentSet(int yOffset) const {
if (_showingGifs) return NoneStickerSetId;
int y, ytill = 0;
for (int i = 0, l = _sets.size(); i < l; ++i) {
int cnt = _sets.at(i).pack.size();
@ -1530,6 +1731,33 @@ uint64 StickerPanInner::currentSet(int yOffset) const {
return _sets.isEmpty() ? RecentStickerSetId : _sets.back().id;
}
void StickerPanInner::ui_repaintSavedGif(const LayoutSavedGif *layout) {
if (!_showingGifs) return;
int32 position = layout->position();
int32 row = position / MatrixRowShift, col = position % MatrixRowShift;
t_assert((row < _gifRows.size()) && (col < _gifRows.at(row).size()));
const GifRow &gifRow(_gifRows.at(row));
int32 left = st::savedGifsLeft, top = st::emojiPanHeader + row * (st::savedGifHeight + st::savedGifsSkip);
for (int32 i = 0; i < col; ++i) left += gifRow.at(i)->width() + st::savedGifsSkip;
rtlupdate(left, top, gifRow.at(col)->width(), st::savedGifHeight);
}
bool StickerPanInner::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
int32 position = layout->position();
int32 row = position / MatrixRowShift, col = position % MatrixRowShift;
t_assert((row < _gifRows.size()) && (col < _gifRows.at(row).size()));
int32 top = st::emojiPanHeader + row * (st::savedGifHeight + st::savedGifsSkip);
return (top < _top + _maxHeight) && (top + st::savedGifHeight > _top);
}
bool StickerPanInner::ui_isGifBeingChosen() {
return _showingGifs;
}
void StickerPanInner::appendSet(uint64 setId) {
const StickerSets &sets(cStickerSets());
StickerSets::const_iterator it = sets.constFind(setId);
@ -1543,7 +1771,15 @@ void StickerPanInner::appendSet(uint64 setId) {
_sets.push_back(DisplayedSet(it->id, it->flags, it->title, pack.size() + 1, pack));
}
void StickerPanInner::refreshRecent(bool performResize) {
void StickerPanInner::refreshRecent() {
if (_showingGifs) {
refreshSavedGifs();
} else {
refreshRecentStickers();
}
}
void StickerPanInner::refreshRecentStickers(bool performResize) {
_custom.clear();
clearSelection(true);
StickerSets::const_iterator customIt = cStickerSets().constFind(CustomStickerSetId);
@ -1580,7 +1816,7 @@ void StickerPanInner::refreshRecent(bool performResize) {
}
}
if (performResize) {
if (performResize && !_showingGifs) {
int32 h = countHeight();
if (h != height()) {
resize(width(), h);
@ -1591,14 +1827,15 @@ void StickerPanInner::refreshRecent(bool performResize) {
}
}
void StickerPanInner::fillIcons(QVector<StickerIcon> &icons) {
void StickerPanInner::fillIcons(QList<StickerIcon> &icons) {
icons.clear();
if (_sets.isEmpty()) return;
icons.reserve(_sets.size() + 1);
if (!cSavedGifs().isEmpty()) icons.push_back(StickerIcon(NoneStickerSetId));
icons.reserve(_sets.size());
if (_sets.isEmpty()) return;
int32 i = 0;
if (_sets.at(0).id == RecentStickerSetId) ++i;
if (i > 0) icons.push_back(StickerIcon());
if (i > 0) icons.push_back(StickerIcon(RecentStickerSetId));
for (int32 l = _sets.size(); i < l; ++i) {
DocumentData *s = _sets.at(i).pack.at(0);
int32 availw = st::rbEmoji.width - 2 * st::stickerIconPadding, availh = st::rbEmoji.height - 2 * st::stickerIconPadding;
@ -1622,6 +1859,13 @@ void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
panels.at(i)->deleteLater();
}
panels.clear();
if (_showingGifs) {
panels.push_back(new EmojiPanel(parentWidget(), lang(lng_saved_gifs), NoneStickerSetId, true, 0));
panels.back()->show();
return;
}
if (_sets.isEmpty()) return;
int y = 0;
@ -1637,8 +1881,9 @@ void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
}
}
void StickerPanInner::refreshPanels(QVector<EmojiPanel*> &panels) {
if (_showingGifs) return;
if (panels.size() != _sets.size()) return fillPanels(panels);
int32 y = 0;
@ -1656,6 +1901,64 @@ void StickerPanInner::updateSelected() {
int32 selIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos));
if (_showingGifs) {
int sx = (rtl() ? width() - p.x() : p.x()) - st::savedGifsLeft, sy = p.y() - st::emojiPanHeader;
int32 row = sy / int32(st::savedGifHeight + st::savedGifsSkip), col = 0, sel = -1;
bool del = false;
if (sx >= 0 && row >= 0 && row < _gifRows.size() && sy < (row + 1) * st::savedGifHeight) {
const GifRow &gifRow(_gifRows.at(row));
for (int32 left = 0, cols = gifRow.size(); col < cols; ++col) {
int32 width = gifRow.at(col)->width();
if (sx >= left && sx < left + width) {
del = (sx >= left + width - st::stickerPanDelete.pxWidth()) && (sy < row * st::savedGifHeight + st::stickerPanDelete.pxHeight());
break;
}
left += width + st::savedGifsSkip;
}
if (col < gifRow.size()) {
sel = row * MatrixRowShift + col + (del ? SavedGifsMaxPerRow : 0);
} else {
row = col = -1;
}
} else {
row = col = -1;
}
if (_selected != sel) {
int32 srow = (_selected >= 0) ? (_selected / MatrixRowShift) : -1;
int32 scol = (_selected >= 0) ? (_selected % MatrixRowShift) : -1;
bool sdel = (scol >= SavedGifsMaxPerRow);
if (sdel) scol -= SavedGifsMaxPerRow;
if (srow != row || scol != col) {
if (srow >= 0 && srow < _gifRows.size()) {
if (scol >= 0 && scol < _gifRows.at(srow).size()) {
_gifRows.at(srow).at(scol)->notify_over(false);
if (sdel) _gifRows.at(srow).at(scol)->notify_deleteOver(false);
}
}
if (row >= 0 && row < _gifRows.size()) {
if (col >= 0 && col < _gifRows.at(row).size()) {
_gifRows.at(row).at(col)->notify_over(true);
if (del) _gifRows.at(row).at(col)->notify_deleteOver(true);
}
}
} else if (sdel != del) {
if (sdel) _gifRows.at(srow).at(scol)->notify_deleteOver(false);
if (del) _gifRows.at(row).at(col)->notify_deleteOver(true);
}
if ((_selected >= 0 && sel < 0) || (_selected < 0 && sel >= 0)) {
setCursor(sel >= 0 ? style::cur_pointer : style::cur_default);
}
_selected = sel;
if (_pressedSel >= 0 && _selected >= 0 && _pressedSel != _selected) {
_pressedSel = _selected;
if (row >= 0 && col >= 0) {
Ui::showStickerPreview(_gifRows.at(row).at(col)->document());
}
}
}
return;
}
int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::stickerPanPadding;
for (int c = 0, l = _sets.size(); c < l; ++c) {
const DisplayedSet &set(_sets.at(c));
@ -1742,7 +2045,15 @@ void StickerPanInner::onSettings() {
}
void StickerPanInner::onPreview() {
if (_pressedSel >= 0 && _pressedSel < MatrixRowShift * _sets.size()) {
if (_pressedSel < 0) return;
if (_showingGifs) {
int32 row = _pressedSel / MatrixRowShift, col = _pressedSel % MatrixRowShift;
if (col >= SavedGifsMaxPerRow) col -= SavedGifsMaxPerRow;
if (row < _gifRows.size() && col < _gifRows.at(row).size() && _gifRows.at(row).at(col)->document()->loaded()) {
Ui::showStickerPreview(_gifRows.at(row).at(col)->document());
_previewShown = true;
}
} else if (_pressedSel < MatrixRowShift * _sets.size()) {
int tab = (_pressedSel / MatrixRowShift), sel = _pressedSel % MatrixRowShift;
if (sel < _sets.at(tab).pack.size()) {
Ui::showStickerPreview(_sets.at(tab).pack.at(sel));
@ -1765,13 +2076,40 @@ void StickerPanInner::step_selected(uint64 ms, bool timer) {
}
toUpdate += stickerRect(tab, sel);
}
if (timer)rtlupdate(toUpdate.boundingRect());
if (timer) rtlupdate(toUpdate.boundingRect());
if (_animations.isEmpty()) _a_selected.stop();
}
void StickerPanInner::showStickerSet(uint64 setId) {
clearSelection(true);
if (setId == NoneStickerSetId) {
if (_gifRows.isEmpty() && !cSavedGifs().isEmpty()) {
refreshSavedGifs();
}
bool wasNotShowingGifs = !_showingGifs;
if (wasNotShowingGifs) {
_showingGifs = true;
cSetShowingSavedGifs(true);
emit saveConfigDelayed(SaveRecentEmojisTimeout);
}
refreshSavedGifs();
emit scrollToY(0);
emit scrollUpdated();
return;
}
if (_showingGifs) {
_showingGifs = false;
cSetShowingSavedGifs(false);
emit saveConfigDelayed(SaveRecentEmojisTimeout);
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
refreshRecentStickers(true);
emit refreshIcons();
}
int32 y = 0;
for (int c = 0; c < _sets.size(); ++c) {
if (_sets.at(c).id == setId) break;
@ -1780,14 +2118,19 @@ void StickerPanInner::showStickerSet(uint64 setId) {
}
emit scrollToY(y);
emit scrollUpdated();
_lastMousePos = QCursor::pos();
update();
}
EmojiPanel::EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY) : TWidget(parent),
_wantedY(wantedY), _setId(setId), _special(special), _deleteVisible(false), _delete(special ? 0 : new IconedButton(this, st::notifyClose)) { // NoneStickerSetId if in emoji
EmojiPanel::EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY) : TWidget(parent)
, _wantedY(wantedY)
, _setId(setId)
, _special(special)
, _deleteVisible(false)
, _delete(special ? 0 : new IconedButton(this, st::notifyClose)) { // NoneStickerSetId if in emoji
resize(st::emojiPanWidth, st::emojiPanHeader);
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
@ -1815,7 +2158,7 @@ void EmojiPanel::updateText() {
availw -= st::notifyClose.icon.pxWidth() + st::emojiPanHeaderLeft;
}
} else {
QString switchText = lang((_setId != NoneStickerSetId) ? lng_switch_emoji : lng_switch_stickers);
QString switchText = lang((_setId != NoneStickerSetId) ? lng_switch_emoji : (cSavedGifs().isEmpty() ? lng_switch_stickers : lng_switch_stickers_gifs));
availw -= st::emojiSwitchSkip + st::emojiPanHeaderFont->width(switchText);
}
_text = st::emojiPanHeaderFont->elided(_fullText, availw);
@ -1847,11 +2190,17 @@ void EmojiPanel::paintEvent(QPaintEvent *e) {
p.drawTextLeft(st::emojiPanHeaderLeft, st::emojiPanHeaderTop, width(), _text);
}
EmojiSwitchButton::EmojiSwitchButton(QWidget *parent, bool toStickers) : Button(parent),
_toStickers(toStickers), _text(lang(_toStickers ? lng_switch_stickers : lng_switch_emoji)),
_textWidth(st::emojiPanHeaderFont->width(_text)) {
int32 w = st::emojiSwitchSkip + _textWidth + (st::emojiSwitchSkip - st::emojiSwitchImgSkip);
EmojiSwitchButton::EmojiSwitchButton(QWidget *parent, bool toStickers) : Button(parent)
, _toStickers(toStickers) {
setCursor(style::cur_pointer);
updateText();
}
void EmojiSwitchButton::updateText() {
_text = lang(_toStickers ? (cSavedGifs().isEmpty() ? lng_switch_stickers : lng_switch_stickers_gifs) : lng_switch_emoji);
_textWidth = st::emojiPanHeaderFont->width(_text);
int32 w = st::emojiSwitchSkip + _textWidth + (st::emojiSwitchSkip - st::emojiSwitchImgSkip);
resize(w, st::emojiPanHeader);
}
@ -1947,6 +2296,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
connect(&e_inner, SIGNAL(disableScroll(bool)), &e_scroll, SLOT(disableScroll(bool)));
connect(&s_inner, SIGNAL(scrollToY(int)), &s_scroll, SLOT(scrollToY(int)));
connect(&s_inner, SIGNAL(scrollUpdated()), this, SLOT(onScroll()));
connect(&e_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&s_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
@ -1964,6 +2314,11 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
connect(&e_inner, SIGNAL(needRefreshPanels()), this, SLOT(onRefreshPanels()));
connect(&s_inner, SIGNAL(needRefreshPanels()), this, SLOT(onRefreshPanels()));
_saveConfigTimer.setSingleShot(true);
connect(&_saveConfigTimer, SIGNAL(timeout()), this, SLOT(onSaveConfig()));
connect(&e_inner, SIGNAL(saveConfigDelayed(int32)), this, SLOT(onSaveConfigDelayed(int32)));
connect(&s_inner, SIGNAL(saveConfigDelayed(int32)), this, SLOT(onSaveConfigDelayed(int32)));
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
}
@ -2020,6 +2375,14 @@ void EmojiPan::onWndActiveChanged() {
}
}
void EmojiPan::onSaveConfig() {
Local::writeUserSettings();
}
void EmojiPan::onSaveConfigDelayed(int32 delay) {
_saveConfigTimer.start(delay);
}
void EmojiPan::paintEvent(QPaintEvent *e) {
Painter p(this);
@ -2040,24 +2403,20 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
p.drawSpriteLeft(_iconsLeft + 7 * st::rbEmoji.width + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::stickersSettings);
if (!_icons.isEmpty()) {
int32 x = _iconsLeft, i = 0, selxrel = _iconSelX.current(), selx = x + selxrel - _iconsX.current();
if (!_icons.at(i).sticker) {
if (selxrel > 0) {
if (_iconHovers.at(i) < 1) {
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::rbEmojiRecent.imageRect);
}
if (_iconHovers.at(i) > 0) {
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::rbEmojiRecent.overImageRect);
}
int32 x = _iconsLeft, i = 0, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current();
for (int32 l = _icons.size(); i < l && !_icons.at(i).sticker; ++i) {
bool gifs = (_icons.at(i).setId == NoneStickerSetId);
if (selxrel != x) {
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), gifs ? st::savedGifsOver : st::rbEmojiRecent.imageRect);
}
if (selxrel < st::rbEmoji.width) {
p.setOpacity(1 - (selxrel / st::rbEmoji.width));
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::rbEmojiRecent.chkImageRect);
if (selxrel < x + st::rbEmoji.width && selxrel > x - st::rbEmoji.width) {
p.setOpacity(1 - (qAbs(selxrel - x) / st::rbEmoji.width));
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), gifs ? st::savedGifsActive : st::rbEmojiRecent.chkImageRect);
p.setOpacity(1);
}
x += st::rbEmoji.width;
++i;
}
int32 skip = i;
QRect clip(x, _iconsTop, _iconsLeft + 7 * st::rbEmoji.width - x, st::rbEmoji.height);
if (rtl()) clip.moveLeft(width() - x - clip.width());
@ -2065,28 +2424,23 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
i += _iconsX.current() / int(st::rbEmoji.width);
x -= _iconsX.current() % int(st::rbEmoji.width);
for (int32 l = qMin(_icons.size(), i + 7 + (_icons.at(0).sticker ? 1 : 0)); i < l; ++i) {
for (int32 l = qMin(_icons.size(), i + 8 - skip); i < l; ++i) {
const StickerIcon &s(_icons.at(i));
s.sticker->thumb->load();
QPixmap pix(s.sticker->thumb->pix(s.pixw, s.pixh));
//if (_iconSel == i) {
// p.setOpacity(1);
//} else {
// p.setOpacity(1. * _iconHovers.at(i) + st::stickerIconOpacity * (1 - _iconHovers.at(i)));
//}
p.drawPixmapLeft(x + (st::rbEmoji.width - s.pixw) / 2, _iconsTop + (st::rbEmoji.height - s.pixh) / 2, width(), pix);
x += st::rbEmoji.width;
p.setOpacity(1);
}
if (rtl()) selx = width() - selx - st::rbEmoji.width;
p.setOpacity(_icons.at(0).sticker ? 1. : qMax(1., selx / st::rbEmoji.width));
p.fillRect(selx, _iconsTop + st::rbEmoji.height - st::stickerIconPadding, st::rbEmoji.width, st::stickerIconSel, st::stickerIconSelColor->b);
p.setOpacity(skip ? qMax(1., selx / (skip * st::rbEmoji.width)) : 1.);
p.fillRect(selx, _iconsTop + st::rbEmoji.height - st::stickerIconPadding, st::rbEmoji.width, st::stickerIconSel, st::stickerIconSelColor);
float64 o_left = snap(float64(_iconsX.current()) / st::stickerIconLeft.pxWidth(), 0., 1.);
if (o_left > 0) {
p.setOpacity(o_left);
p.drawSpriteLeft(QRect(_iconsLeft + (_icons.at(0).sticker ? 0 : st::rbEmoji.width), _iconsTop, st::stickerIconLeft.pxWidth(), st::rbEmoji.height), width(), st::stickerIconLeft);
p.drawSpriteLeft(QRect(_iconsLeft + skip * st::rbEmoji.width, _iconsTop, st::stickerIconLeft.pxWidth(), st::rbEmoji.height), width(), st::stickerIconLeft);
}
float64 o_right = snap(float64(_iconsMax - _iconsX.current()) / st::stickerIconRight.pxWidth(), 0., 1.);
if (o_right > 0) {
@ -2181,7 +2535,12 @@ void EmojiPan::mouseMoveEvent(QMouseEvent *e) {
_iconsMousePos = e ? e->globalPos() : QCursor::pos();
updateSelected();
if (!_iconsDragging && !_icons.isEmpty() && _iconDown >= (_icons.at(0).sticker ? 0 : 1)) {
int32 skip = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (_icons.at(i).sticker) break;
++skip;
}
if (!_iconsDragging && !_icons.isEmpty() && _iconDown >= skip) {
if ((_iconsMousePos - _iconsMouseDown).manhattanLength() >= QApplication::startDragDistance()) {
_iconsDragging = true;
}
@ -2226,24 +2585,31 @@ void EmojiPan::mouseReleaseEvent(QMouseEvent *e) {
bool EmojiPan::event(QEvent *e) {
if (e->type() == QEvent::TouchBegin) {
int a = 0;
} else if (e->type() == QEvent::Wheel && !_icons.isEmpty() && _iconOver >= (_icons.at(0).sticker ? 0 : 1) && _iconOver < _icons.size() && _iconDown < 0) {
QWheelEvent *ev = static_cast<QWheelEvent*>(e);
bool hor = (ev->angleDelta().x() != 0 || ev->orientation() == Qt::Horizontal);
bool ver = (ev->angleDelta().y() != 0 || ev->orientation() == Qt::Vertical);
if (hor) _horizontal = true;
int32 newX = _iconsX.current();
if (/*_horizontal && */hor) {
newX = snap(newX - (rtl() ? -1 : 1) * (ev->pixelDelta().x() ? ev->pixelDelta().x() : ev->angleDelta().x()), 0, _iconsMax);
} else if (/*!_horizontal && */ver) {
newX = snap(newX - (ev->pixelDelta().y() ? ev->pixelDelta().y() : ev->angleDelta().y()), 0, _iconsMax);
} else if (e->type() == QEvent::Wheel) {
int32 skip = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (_icons.at(i).sticker) break;
++skip;
}
if (newX != _iconsX.current()) {
_iconsX = anim::ivalue(newX, newX);
_iconsStartAnim = 0;
if (_iconAnimations.isEmpty()) _a_icons.stop();
updateSelected();
updateIcons();
if (!_icons.isEmpty() && _iconOver >= skip && _iconOver < _icons.size() && _iconDown < 0) {
QWheelEvent *ev = static_cast<QWheelEvent*>(e);
bool hor = (ev->angleDelta().x() != 0 || ev->orientation() == Qt::Horizontal);
bool ver = (ev->angleDelta().y() != 0 || ev->orientation() == Qt::Vertical);
if (hor) _horizontal = true;
int32 newX = _iconsX.current();
if (/*_horizontal && */hor) {
newX = snap(newX - (rtl() ? -1 : 1) * (ev->pixelDelta().x() ? ev->pixelDelta().x() : ev->angleDelta().x()), 0, _iconsMax);
} else if (/*!_horizontal && */ver) {
newX = snap(newX - (ev->pixelDelta().y() ? ev->pixelDelta().y() : ev->angleDelta().y()), 0, _iconsMax);
}
if (newX != _iconsX.current()) {
_iconsX = anim::ivalue(newX, newX);
_iconsStartAnim = 0;
if (_iconAnimations.isEmpty()) _a_icons.stop();
updateSelected();
updateIcons();
}
}
}
return TWidget::event(e);
@ -2266,6 +2632,15 @@ void EmojiPan::refreshStickers() {
}
}
void EmojiPan::refreshSavedGifs() {
e_switch.updateText();
e_switch.moveToRight(0, 0, st::emojiPanWidth);
s_inner.refreshSavedGifs();
if (!_stickersShown) {
s_inner.preloadImages();
}
}
void EmojiPan::onRefreshIcons() {
_iconOver = -1;
_iconHovers.clear();
@ -2284,6 +2659,7 @@ void EmojiPan::onRefreshIcons() {
}
updatePanelsPositions(s_panels, s_scroll.scrollTop());
updateSelected();
if (_stickersShown) validateSelectedIcon();
updateIcons();
}
@ -2316,16 +2692,18 @@ void EmojiPan::updateSelected() {
newOver = _icons.size();
} else if (!_icons.isEmpty()) {
if (y >= _iconsTop && y < _iconsTop + st::rbEmoji.height && x >= 0 && x < 7 * st::rbEmoji.width && x < _icons.size() * st::rbEmoji.width) {
if (!_icons.at(0).sticker) {
int32 skip = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (x < st::rbEmoji.width) {
newOver = 0;
} else {
x -= st::rbEmoji.width;
newOver = i;
break;
}
x -= st::rbEmoji.width;
++skip;
}
if (newOver < 0) {
x += _iconsX.current();
newOver = qFloor(x / st::rbEmoji.width) + (_icons.at(0).sticker ? 0 : 1);
newOver = qFloor(x / st::rbEmoji.width) + skip;
}
}
}
@ -2459,6 +2837,7 @@ void EmojiPan::hideStart() {
void EmojiPan::hideFinish() {
hide();
e_inner.hideFinish();
s_inner.hideFinish();
_cache = _toCache = _fromCache = QPixmap();
_a_slide.stop();
_horizontal = false;
@ -2478,6 +2857,8 @@ void EmojiPan::hideFinish() {
_a_icons.stop();
_iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0);
_iconAnimations.clear();
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
}
void EmojiPan::showStart() {
@ -2543,6 +2924,26 @@ void EmojiPan::stickersInstalled(uint64 setId) {
showStart();
}
void EmojiPan::ui_repaintSavedGif(const LayoutSavedGif *layout) {
if (_stickersShown && !isHidden()) {
s_inner.ui_repaintSavedGif(layout);
}
}
bool EmojiPan::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
if (_stickersShown && !isHidden()) {
return s_inner.ui_isSavedGifVisible(layout);
}
return false;
}
bool EmojiPan::ui_isGifBeingChosen() {
if (_stickersShown && !isHidden()) {
return s_inner.ui_isGifBeingChosen();
}
return false;
}
void EmojiPan::showAll() {
if (_stickersShown) {
s_scroll.show();
@ -2636,38 +3037,60 @@ void EmojiPan::onScroll() {
st = s_scroll.scrollTop();
if (_stickersShown) {
updatePanelsPositions(s_panels, st);
uint64 setId = s_inner.currentSet(st);
int32 newSel = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (_icons.at(i).setId == setId) {
newSel = i;
break;
}
}
if (newSel != _iconSel) {
_iconSel = newSel;
_iconSelX.start(newSel * st::rbEmoji.width);
_iconsX.start(snap((2 * newSel - 7 - ((_icons.isEmpty() || _icons.at(0).sticker) ? 0 : 1)) * int(st::rbEmoji.width) / 2, 0, _iconsMax));
_iconsStartAnim = getms();
_a_icons.start();
updateSelected();
updateIcons();
}
validateSelectedIcon(true);
}
s_inner.setScrollTop(st);
}
void EmojiPan::validateSelectedIcon(bool animated) {
uint64 setId = s_inner.currentSet(s_scroll.scrollTop());
int32 newSel = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (_icons.at(i).setId == setId) {
newSel = i;
break;
}
}
if (newSel != _iconSel) {
_iconSel = newSel;
int32 skip = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (_icons.at(i).sticker) break;
++skip;
}
if (animated) {
_iconSelX.start(newSel * st::rbEmoji.width);
} else {
_iconSelX = anim::ivalue(newSel * st::rbEmoji.width, newSel * st::rbEmoji.width);
}
_iconsX.start(snap((2 * newSel - 7 - skip) * int(st::rbEmoji.width) / 2, 0, _iconsMax));
_iconsStartAnim = getms();
_a_icons.start();
updateSelected();
updateIcons();
}
}
void EmojiPan::onSwitch() {
QPixmap cache = _cache;
_fromCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
_stickersShown = !_stickersShown;
if (!_stickersShown) {
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
}
if (cShowingSavedGifs() && cSavedGifs().isEmpty()) {
s_inner.showStickerSet(DefaultStickerSetId);
} else if (!cShowingSavedGifs() && !cSavedGifs().isEmpty() && cStickerSets().isEmpty()) {
s_inner.showStickerSet(NoneStickerSetId);
}
_iconOver = -1;
_iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0);
_iconAnimations.clear();
_a_icons.stop();
validateSelectedIcon();
_cache = QPixmap();
showAll();
_toCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
@ -2721,7 +3144,6 @@ void EmojiPan::onRemoveSetSure() {
cRefStickerSets().erase(it);
int32 removeIndex = cStickerSetsOrder().indexOf(_removingSetId);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
cSetStickersHash(stickersCountHash());
refreshStickers();
Local::writeStickers();
if (writeRecent) Local::writeUserSettings();
@ -3337,5 +3759,16 @@ bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
return QWidget::eventFilter(obj, e);
}
void MentionsDropdown::ui_repaintSavedGif(const LayoutSavedGif *layout) {
}
bool MentionsDropdown::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return false;
}
bool MentionsDropdown::ui_isGifBeingChosen() {
return false;
}
MentionsDropdown::~MentionsDropdown() {
}

View file

@ -258,7 +258,6 @@ public:
public slots:
void updateSelected();
void onSaveConfig();
void onShowPicker();
void onPickerHidden();
@ -276,6 +275,7 @@ signals:
void disableScroll(bool dis);
void needRefreshPanels();
void saveConfigDelayed(int32 delay);
private:
@ -300,14 +300,12 @@ private:
int32 _selected, _pressedSel, _pickerSel;
QPoint _lastMousePos;
QTimer _saveConfigTimer;
EmojiColorPicker _picker;
QTimer _showPickerTimer;
};
struct StickerIcon {
StickerIcon() : setId(RecentStickerSetId), sticker(0), pixw(0), pixh(0) {
StickerIcon(uint64 setId) : setId(setId), sticker(0), pixw(0), pixh(0) {
}
StickerIcon(uint64 setId, DocumentData *sticker, int32 pixw, int32 pixh) : setId(setId), sticker(sticker), pixw(pixw), pixh(pixh) {
}
@ -335,14 +333,17 @@ public:
void step_selected(uint64 ms, bool timer);
void hideFinish();
void showStickerSet(uint64 setId);
void clearSelection(bool fast = false);
void refreshStickers();
void refreshRecent(bool resize = true);
void refreshRecentStickers(bool resize = true);
void refreshSavedGifs();
void refreshRecent();
void fillIcons(QVector<StickerIcon> &icons);
void fillIcons(QList<StickerIcon> &icons);
void fillPanels(QVector<EmojiPanel*> &panels);
void refreshPanels(QVector<EmojiPanel*> &panels);
@ -351,6 +352,15 @@ public:
uint64 currentSet(int yOffset) const;
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
~StickerPanInner() {
clearSavedGifs();
deleteUnusedLayouts();
}
public slots:
void updateSelected();
@ -367,11 +377,17 @@ signals:
void switchToEmoji();
void scrollToY(int y);
void scrollUpdated();
void disableScroll(bool dis);
void needRefreshPanels();
void saveConfigDelayed(int32 delay);
private:
void paintSavedGifs(Painter &p, const QRect &r);
void paintStickers(Painter &p, const QRect &r);
int32 _maxHeight;
void appendSet(uint64 setId);
@ -398,6 +414,19 @@ private:
QList<DisplayedSet> _sets;
QList<bool> _custom;
bool _showingGifs;
typedef QList<LayoutSavedGif*> GifRow;
typedef QList<GifRow> GifRows;
GifRows _gifRows;
void clearSavedGifs();
void deleteUnusedLayouts();
typedef QMap<DocumentData*, LayoutSavedGif*> GifLayouts;
GifLayouts _gifLayouts;
LayoutSavedGif *layoutPrepare(DocumentData *doc, int32 position, int32 width);
const GifRow &layoutGifRow(const GifRow &row, int32 *widths, int32 sumWidth);
int32 _selected, _pressedSel;
QPoint _lastMousePos;
@ -452,6 +481,7 @@ public:
EmojiSwitchButton(QWidget *parent, bool toStickers); // otherwise toEmoji
void paintEvent(QPaintEvent *e);
void updateText();
protected:
@ -504,9 +534,14 @@ public:
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
public slots:
void refreshStickers();
void refreshSavedGifs();
void hideStart();
void hideFinish();
@ -525,6 +560,9 @@ public slots:
void onRefreshIcons();
void onRefreshPanels();
void onSaveConfig();
void onSaveConfigDelayed(int32 delay);
signals:
void emojiSelected(EmojiPtr emoji);
@ -533,6 +571,8 @@ signals:
private:
void validateSelectedIcon(bool animated = false);
int32 _maxHeight;
bool _horizontal;
@ -561,7 +601,7 @@ private:
BoxShadow _shadow;
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
QVector<StickerIcon> _icons;
QList<StickerIcon> _icons;
QVector<float64> _iconHovers;
int32 _iconOver, _iconSel, _iconDown;
bool _iconsDragging;
@ -591,6 +631,8 @@ private:
uint64 _removingSetId;
QTimer _saveConfigTimer;
};
typedef QList<UserData*> MentionRows;
@ -679,6 +721,10 @@ public:
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
~MentionsDropdown();
signals:

View file

@ -102,20 +102,36 @@ namespace Ui {
return false;
}
void clipRedraw(ClipReader *reader) {
bool isGifBeingChosen() {
if (MainWidget *m = App::main()) return m->ui_isGifBeingChosen();
return false;
}
void clipRepaint(ClipReader *reader) {
const GifItems &items(App::gifItems());
GifItems::const_iterator it = items.constFind(reader);
if (it != items.cend()) {
if (reader->currentDisplayed()) {
return;
}
Ui::redrawHistoryItem(it.value());
Ui::repaintHistoryItem(it.value());
}
if (Window *w = App::wnd()) w->ui_clipRedraw(reader);
if (Window *w = App::wnd()) w->ui_clipRepaint(reader);
}
void redrawHistoryItem(const HistoryItem *item) {
if (MainWidget *m = App::main()) m->ui_redrawHistoryItem(item);
void repaintHistoryItem(const HistoryItem *item) {
if (!item) return;
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item);
}
void repaintSavedGif(const LayoutSavedGif *layout) {
if (!layout) return;
if (MainWidget *m = App::main()) m->ui_repaintSavedGif(layout);
}
bool isSavedGifVisible(const LayoutSavedGif *layout) {
if (MainWidget *m = App::main()) return m->ui_isSavedGifVisible(layout);
return false;
}
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) {
@ -148,8 +164,8 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer);
}
void mediaViewHidden() {
if (MainWidget *m = App::main()) m->notify_mediaViewHidden();
void clipStopperHidden(ClipStopperType type) {
if (MainWidget *m = App::main()) m->notify_clipStopperHidden(type);
}
void clipReinit(ClipReader *reader) {

View file

@ -46,10 +46,13 @@ namespace Ui { // openssl doesn't allow me to use UI :(
void hideLayer(bool fast = false);
bool isLayerShown();
bool isMediaViewShown();
bool isGifBeingChosen();
void clipRedraw(ClipReader *reader);
void clipRepaint(ClipReader *reader);
void redrawHistoryItem(const HistoryItem *item);
void repaintHistoryItem(const HistoryItem *item);
void repaintSavedGif(const LayoutSavedGif *layout);
bool isSavedGifVisible(const LayoutSavedGif *reader);
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) {
@ -68,6 +71,11 @@ namespace Ui { // openssl doesn't allow me to use UI :(
};
enum ClipStopperType {
ClipStopperMediaview,
ClipStopperSavedGifsPanel,
};
namespace Notify {
void userIsBotChanged(UserData *user);
@ -76,7 +84,7 @@ namespace Notify {
void migrateUpdated(PeerData *peer);
void mediaViewHidden();
void clipStopperHidden(ClipStopperType type);
void clipReinit(ClipReader *reader);

View file

@ -118,34 +118,104 @@ void Animation::stop() {
_manager->stop(this);
}
void AnimationManager::clipReinit(ClipReader *reader) {
AnimationManager::AnimationManager() : _timer(this), _iterating(false) {
_timer.setSingleShot(false);
connect(&_timer, SIGNAL(timeout()), this, SLOT(timeout()));
}
void AnimationManager::start(Animation *obj) {
if (_iterating) {
_starting.insert(obj, NullType());
if (!_stopping.isEmpty()) {
_stopping.remove(obj);
}
} else {
if (_objects.isEmpty()) {
_timer.start(AnimationTimerDelta);
}
_objects.insert(obj, NullType());
}
}
void AnimationManager::stop(Animation *obj) {
if (_iterating) {
_stopping.insert(obj, NullType());
if (!_starting.isEmpty()) {
_starting.insert(obj, NullType());
}
} else {
AnimatingObjects::iterator i = _objects.find(obj);
if (i != _objects.cend()) {
_objects.erase(i);
if (_objects.isEmpty()) {
_timer.stop();
}
}
}
}
void AnimationManager::timeout() {
_iterating = true;
uint64 ms = getms();
for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) {
i.key()->step(ms, true);
}
_iterating = false;
if (!_starting.isEmpty()) {
for (AnimatingObjects::iterator i = _starting.begin(), e = _starting.end(); i != e; ++i) {
_objects.insert(i.key(), NullType());
}
_starting.clear();
}
if (!_stopping.isEmpty()) {
for (AnimatingObjects::iterator i = _stopping.begin(), e = _stopping.end(); i != e; ++i) {
_objects.remove(i.key());
}
_stopping.clear();
}
if (!_objects.size()) {
_timer.stop();
}
}
void AnimationManager::clipReinit(ClipReader *reader, qint32 threadIndex) {
ClipReader::callback(reader, threadIndex, ClipReaderReinit);
Notify::clipReinit(reader);
}
void AnimationManager::clipRedraw(ClipReader *reader) {
Ui::clipRedraw(reader);
void AnimationManager::clipRepaint(ClipReader *reader, qint32 threadIndex) {
ClipReader::callback(reader, threadIndex, ClipReaderRepaint);
Ui::clipRepaint(reader);
}
QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, QImage &cache, bool smooth) {
QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, QImage &cache, bool hasAlpha) {
bool badSize = (original.width() != request.framew) || (original.height() != request.frameh);
bool needOuter = (request.outerw != request.framew) || (request.outerh != request.frameh);
if (badSize || needOuter || request.rounded) {
if (badSize || needOuter || hasAlpha || request.rounded) {
int32 factor(request.factor);
bool fill = false;
if (cache.width() != request.outerw || cache.height() != request.outerh) {
cache = QImage(request.outerw, request.outerh, QImage::Format_ARGB32_Premultiplied);
if (request.framew < request.outerw || request.frameh < request.outerh || original.hasAlphaChannel()) {
if (request.framew < request.outerw || request.frameh < request.outerh || hasAlpha) {
fill = true;
}
cache.setDevicePixelRatio(factor);
}
{
Painter p(&cache);
if (fill) p.fillRect(0, 0, cache.width() / factor, cache.height() / factor, st::black);
if (smooth && badSize) p.setRenderHint(QPainter::SmoothPixmapTransform);
QRect to((request.outerw - request.framew) / (2 * factor), (request.outerh - request.frameh) / (2 * factor), request.framew / factor, request.frameh / factor);
QRect from(0, 0, original.width(), original.height());
p.drawImage(to, original, from, Qt::ColorOnly);
if (fill) {
p.fillRect(0, 0, cache.width() / factor, cache.height() / factor, st::black);
}
QPoint position((request.outerw - request.framew) / (2 * factor), (request.outerh - request.frameh) / (2 * factor));
if (badSize) {
p.setRenderHint(QPainter::SmoothPixmapTransform);
QRect to(position, QSize(request.framew / factor, request.frameh / factor));
QRect from(0, 0, original.width(), original.height());
p.drawImage(to, original, from, Qt::ColorOnly);
} else {
p.drawImage(position, original);
}
}
if (request.rounded) {
imageRound(cache);
@ -155,7 +225,9 @@ QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, Q
return QPixmap::fromImage(original, Qt::ColorOnly);
}
ClipReader::ClipReader(const FileLocation &location, const QByteArray &data) : _state(ClipReading)
ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Callback *cb)
: _cb(cb)
, _state(ClipReading)
, _width(0)
, _height(0)
, _currentDisplayed(1)
@ -182,6 +254,13 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data) : _
_clipManagers.at(_threadIndex)->append(this, location, data);
}
void ClipReader::callback(ClipReader *reader, int32 threadIndex, ClipReaderNotification notification) {
// check if reader is not deleted already
if (_clipManagers.size() > threadIndex && _clipManagers.at(threadIndex)->carries(reader)) {
if (reader->_cb) reader->_cb->call(notification);
}
}
void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded) {
if (_clipManagers.size() <= _threadIndex) error();
if (_state == ClipError) return;
@ -270,6 +349,8 @@ void ClipReader::error() {
ClipReader::~ClipReader() {
stop();
delete _cb;
setBadPointer(_cb);
}
class ClipReaderImplementation {
@ -277,7 +358,7 @@ public:
ClipReaderImplementation(FileLocation *location, QByteArray *data) : _location(location), _data(data), _device(0) {
}
virtual bool readNextFrame(QImage &to) = 0;
virtual bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) = 0;
virtual int32 nextFrameDelay() = 0;
virtual bool start() = 0;
virtual ~ClipReaderImplementation() {
@ -312,7 +393,7 @@ public:
, _frameDelay(0) {
}
bool readNextFrame(QImage &to) {
bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) {
if (_reader) _frameDelay = _reader->nextImageDelay();
if (_framesLeft < 1 && !jumpToStart()) {
return false;
@ -324,19 +405,24 @@ public:
}
--_framesLeft;
int32 w = frame.width(), h = frame.height();
if (to.width() == w && to.height() == h && to.format() == frame.format()) {
if (to.byteCount() != frame.byteCount()) {
int bpl = qMin(to.bytesPerLine(), frame.bytesPerLine());
for (int i = 0; i < h; ++i) {
memcpy(to.scanLine(i), frame.constScanLine(i), bpl);
if (size.isEmpty() || size == frame.size()) {
int32 w = frame.width(), h = frame.height();
if (to.width() == w && to.height() == h && to.format() == frame.format()) {
if (to.byteCount() != frame.byteCount()) {
int bpl = qMin(to.bytesPerLine(), frame.bytesPerLine());
for (int i = 0; i < h; ++i) {
memcpy(to.scanLine(i), frame.constScanLine(i), bpl);
}
} else {
memcpy(to.bits(), frame.constBits(), frame.byteCount());
}
} else {
memcpy(to.bits(), frame.constBits(), frame.byteCount());
to = frame.copy();
}
} else {
to = frame.copy();
to = frame.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
hasAlpha = frame.hasAlphaChannel();
return true;
}
@ -409,7 +495,7 @@ public:
_avpkt.size = 0;
}
bool readNextFrame(QImage &to) {
bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) {
int res;
while (true) {
if (_avpkt.size > 0) { // previous packet not finished
@ -472,25 +558,31 @@ public:
}
}
if (to.isNull() || to.width() != _width || to.height() != _height) {
to = QImage(_width, _height, QImage::Format_ARGB32);
QSize toSize(size.isEmpty() ? QSize(_width, _height) : size);
if (to.isNull() || to.size() != toSize) {
to = QImage(toSize, QImage::Format_ARGB32);
}
if (_frame->width == _width && _frame->height == _height && (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA))) {
if (_frame->width == toSize.width() && _frame->height == toSize.height() && (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA))) {
int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl);
uchar *s = _frame->data[0], *d = to.bits();
for (int32 i = 0, l = _frame->height; i < l; ++i) {
memcpy(d + i * dbpl, s + i * sbpl, bpl);
}
hasAlpha = true;
} else {
if (_frame->width != _width || _frame->height != _height || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) {
_swsContext = sws_getCachedContext(_swsContext, _frame->width, _frame->height, AVPixelFormat(_frame->format), _width, _height, AV_PIX_FMT_BGRA, 0, 0, 0, 0);
if ((_swsSize != toSize) || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) {
_swsSize = toSize;
_swsContext = sws_getCachedContext(_swsContext, _frame->width, _frame->height, AVPixelFormat(_frame->format), toSize.width(), toSize.height(), AV_PIX_FMT_BGRA, 0, 0, 0, 0);
}
uint8_t * toData[1] = { to.bits() };
int toLinesize[1] = { to.bytesPerLine() };
if ((res = sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize)) != _height) {
LOG(("Gif Error: Unable to sws_scale to good size %1, hieght %2, should be %3").arg(logData()).arg(res).arg(_height));
if ((res = sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize)) != _swsSize.height()) {
LOG(("Gif Error: Unable to sws_scale to good size %1, height %2, should be %3").arg(logData()).arg(res).arg(_swsSize.height()));
return false;
}
hasAlpha = false;
}
int64 duration = av_frame_get_pkt_duration(_frame);
@ -634,6 +726,7 @@ private:
int32 _width, _height;
SwsContext *_swsContext;
QSize _swsSize;
int64 _frameMs;
int32 _nextFrameDelay, _currentFrameDelay;
@ -665,6 +758,10 @@ public:
, _location(_data.isEmpty() ? new FileLocation(location) : 0)
, _accessed(false)
, _implementation(0)
, _currentHasAlpha(true)
, _nextHasAlpha(true)
, _width(0)
, _height(0)
, _previousMs(0)
, _currentMs(0)
, _nextUpdateMs(0)
@ -682,9 +779,11 @@ public:
return error();
}
if (_currentOriginal.isNull()) {
if (!_implementation->readNextFrame(_currentOriginal)) {
if (!_implementation->readNextFrame(_currentOriginal, _currentHasAlpha, QSize())) {
return error();
}
_width = _currentOriginal.width();
_height = _currentOriginal.height();
return ClipProcessReinit;
}
return ClipProcessWait;
@ -702,7 +801,7 @@ public:
_previousMs = _currentMs;
_currentMs = ms;
_current = _prepareFrame(_request, _currentOriginal, _currentCache, true);
_current = _prepareFrame(_request, _currentOriginal, _currentCache, _currentHasAlpha);
if (!prepareNextFrame()) {
return error();
@ -710,7 +809,7 @@ public:
return ClipProcessStarted;
} else if (!_paused && ms >= _nextUpdateMs) {
swapBuffers();
return ClipProcessRedraw;
return ClipProcessRepaint;
}
return ClipProcessWait;
}
@ -722,7 +821,7 @@ public:
if (ms >= _nextUpdateMs) { // we are late
swapBuffers(ms); // keep up
return ClipProcessRedraw;
return ClipProcessRepaint;
}
return ClipProcessWait;
}
@ -738,16 +837,17 @@ public:
qSwap(_currentOriginal, _nextOriginal);
qSwap(_current, _next);
qSwap(_currentCache, _nextCache);
qSwap(_currentHasAlpha, _nextHasAlpha);
}
bool prepareNextFrame() {
if (!_implementation->readNextFrame(_nextOriginal)) {
if (!_implementation->readNextFrame(_nextOriginal, _nextHasAlpha, QSize(_request.framew, _request.frameh))) {
return false;
}
_nextUpdateMs = _currentMs + nextFrameDelay();
_nextOriginal.setDevicePixelRatio(_request.factor);
_next = QPixmap();
_next = _prepareFrame(_request, _nextOriginal, _nextCache, true);
_next = _prepareFrame(_request, _nextOriginal, _nextCache, _nextHasAlpha);
return true;
}
@ -809,6 +909,8 @@ private:
ClipFrameRequest _request;
QPixmap _current, _next;
QImage _currentOriginal, _nextOriginal, _currentCache, _nextCache;
bool _currentHasAlpha, _nextHasAlpha;
int32 _width, _height;
uint64 _previousMs, _currentMs, _nextUpdateMs;
@ -828,8 +930,8 @@ ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0), _nee
_timer.moveToThread(thread);
connect(&_timer, SIGNAL(timeout()), this, SLOT(process()));
connect(this, SIGNAL(reinit(ClipReader*)), _manager, SLOT(clipReinit(ClipReader*)));
connect(this, SIGNAL(redraw(ClipReader*)), _manager, SLOT(clipRedraw(ClipReader*)));
connect(this, SIGNAL(reinit(ClipReader*,qint32)), _manager, SLOT(clipReinit(ClipReader*,qint32)));
connect(this, SIGNAL(repaint(ClipReader*,qint32)), _manager, SLOT(clipRepaint(ClipReader*,qint32)));
}
void ClipReadManager::append(ClipReader *reader, const FileLocation &location, const QByteArray &data) {
@ -854,13 +956,18 @@ void ClipReadManager::stop(ClipReader *reader) {
emit processDelayed();
}
bool ClipReadManager::carries(ClipReader *reader) const {
QMutexLocker lock(&_readerPointersMutex);
return _readerPointers.contains(reader);
}
bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
QMutexLocker lock(&_readerPointersMutex);
ReaderPointers::iterator it = _readerPointers.find(reader->_interface);
if (result == ClipProcessError) {
if (it != _readerPointers.cend()) {
it.key()->error();
emit reinit(it.key());
emit reinit(it.key(), it.key()->threadIndex());
_readerPointers.erase(it);
it = _readerPointers.end();
@ -871,9 +978,9 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
}
if (result == ClipProcessStarted) {
_loadLevel.fetchAndAddRelease(reader->_currentOriginal.width() * reader->_currentOriginal.height() - AverageGifSize);
_loadLevel.fetchAndAddRelease(reader->_width * reader->_height - AverageGifSize);
}
if (!reader->_paused && (result == ClipProcessRedraw || result == ClipProcessWait)) {
if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) {
if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
reader->_paused = true;
it.key()->_paused.set(true);
@ -885,14 +992,14 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
}
}
}
if (result == ClipProcessReinit || result == ClipProcessRedraw || result == ClipProcessStarted) {
if (result == ClipProcessReinit || result == ClipProcessRepaint || result == ClipProcessStarted) {
it.key()->_current = reader->_current;
it.key()->_currentOriginal = reader->_currentOriginal;
it.key()->_currentDisplayed.set(false);
if (result == ClipProcessReinit) {
emit reinit(it.key());
} else if (result == ClipProcessRedraw) {
emit redraw(it.key());
emit reinit(it.key(), it.key()->threadIndex());
} else if (result == ClipProcessRepaint) {
emit repaint(it.key(), it.key()->threadIndex());
}
}
return true;
@ -900,7 +1007,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
if (!handleProcessResult(reader, result, ms)) {
_loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_currentOriginal.width() * reader->_currentOriginal.height()));
_loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_width * reader->_height));
delete reader;
return ResultHandleRemove;
}
@ -910,7 +1017,7 @@ ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPriva
return ResultHandleStop;
}
if (result == ClipProcessRedraw) {
if (result == ClipProcessRepaint) {
return handleResult(reader, reader->finishProcess(ms), ms);
}

View file

@ -72,6 +72,8 @@ namespace anim {
_delta = 0;
}
typedef float64 Type;
private:
float64 _cur, _from, _delta;
@ -110,6 +112,8 @@ namespace anim {
_delta = 0;
}
typedef int32 Type;
private:
int32 _cur;
@ -179,6 +183,8 @@ namespace anim {
_delta_r = _delta_g = _delta_b = _delta_a = 0;
}
typedef QColor Type;
private:
QColor _cur;
@ -338,87 +344,129 @@ AnimationCallbacks *animation(Param param, Type *obj, typename AnimationCallback
return new AnimationCallbacksAbsoluteWithParam<Type, Param>(param, obj, method);
}
template <typename AnimType>
class SimpleAnimation {
public:
typedef Function<void> Callbacks;
SimpleAnimation() : _data(0) {
}
bool animating(uint64 ms) {
if (_data && _data->_a.animating()) {
_data->_a.step(ms);
return _data && _data->_a.animating();
}
return false;
}
bool isNull() {
return !_data;
}
typename AnimType::Type current() {
return _data ? _data->a.current() : AnimType::Type();
}
typename AnimType::Type current(uint64 ms, const typename AnimType::Type &def) {
return animating(ms) ? current() : def;
}
void setup(const typename AnimType::Type &from, Callbacks *update) {
if (!_data) {
_data = new Data(from, update, animation(this, &SimpleAnimation<AnimType>::step));
} else {
delete update;
_data->a = AnimType(from, from);
}
}
void start(const typename AnimType::Type &to, float64 duration, anim::transition transition = anim::linear) {
if (_data) {
_data->a.start(to);
_data->_a.start();
_data->duration = duration;
_data->transition = transition;
}
}
~SimpleAnimation() {
delete _data;
setBadPointer(_data);
}
private:
typedef struct _Data {
_Data(const typename AnimType::Type &from, Callbacks *update, AnimationCallbacks *acb)
: a(from, from)
, _a(acb)
, update(update)
, duration(0)
, transition(anim::linear) {
}
~_Data() {
delete update;
setBadPointer(update);
}
AnimType a;
Animation _a;
Callbacks *update;
float64 duration;
anim::transition transition;
} Data;
Data *_data;
void step(float64 ms, bool timer) {
float64 dt = (ms >= _data->duration) ? 1 : (ms / _data->duration);
if (dt >= 1) {
_data->a.finish();
_data->_a.stop();
} else {
_data->a.update(dt, _data->transition);
}
if (timer) {
_data->update->call();
}
if (!_data->_a.animating()) {
delete _data;
_data = 0;
}
}
};
typedef SimpleAnimation<anim::fvalue> FloatAnimation;
typedef SimpleAnimation<anim::ivalue> IntAnimation;
typedef SimpleAnimation<anim::cvalue> ColorAnimation;
#define EnsureAnimation(animation, from, callback) if ((animation).isNull()) { (animation).setup((from), (callback)); }
class ClipReader;
class AnimationManager : public QObject {
Q_OBJECT
public:
AnimationManager();
AnimationManager() : _timer(this), _iterating(false) {
_timer.setSingleShot(false);
connect(&_timer, SIGNAL(timeout()), this, SLOT(timeout()));
}
void start(Animation *obj) {
if (_iterating) {
_starting.insert(obj, NullType());
if (!_stopping.isEmpty()) {
_stopping.remove(obj);
}
} else {
if (_objects.isEmpty()) {
_timer.start(AnimationTimerDelta);
}
_objects.insert(obj, NullType());
}
}
void stop(Animation *obj) {
if (_iterating) {
_stopping.insert(obj, NullType());
if (!_starting.isEmpty()) {
_starting.insert(obj, NullType());
}
} else {
AnimatingObjects::iterator i = _objects.find(obj);
if (i != _objects.cend()) {
_objects.erase(i);
if (_objects.isEmpty()) {
_timer.stop();
}
}
}
}
void start(Animation *obj);
void stop(Animation *obj);
public slots:
void timeout();
void timeout() {
_iterating = true;
uint64 ms = getms();
for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) {
i.key()->step(ms, true);
}
_iterating = false;
if (!_starting.isEmpty()) {
for (AnimatingObjects::iterator i = _starting.begin(), e = _starting.end(); i != e; ++i) {
_objects.insert(i.key(), NullType());
}
_starting.clear();
}
if (!_stopping.isEmpty()) {
for (AnimatingObjects::iterator i = _stopping.begin(), e = _stopping.end(); i != e; ++i) {
_objects.remove(i.key());
}
_stopping.clear();
}
if (!_objects.size()) {
_timer.stop();
}
}
void clipReinit(ClipReader *reader);
void clipRedraw(ClipReader *reader);
void clipReinit(ClipReader *reader, qint32 threadIndex);
void clipRepaint(ClipReader *reader, qint32 threadIndex);
private:
typedef QMap<Animation*, NullType> AnimatingObjects;
AnimatingObjects _objects, _starting, _stopping;
QTimer _timer;
bool _iterating;
};
class FileLocation;
enum ClipState {
@ -460,11 +508,19 @@ private:
};
enum ClipReaderNotification {
ClipReaderReinit,
ClipReaderRepaint,
};
class ClipReaderPrivate;
class ClipReader {
public:
ClipReader(const FileLocation &location, const QByteArray &data);
typedef Function1<void, ClipReaderNotification> Callback;
ClipReader(const FileLocation &location, const QByteArray &data, Callback *cb = 0);
static void callback(ClipReader *reader, int32 threadIndex, ClipReaderNotification notification); // reader can be deleted
void setAutoplay() {
_autoplay = true;
@ -484,6 +540,9 @@ public:
bool paused() const {
return _paused.get();
}
int32 threadIndex() const {
return _threadIndex;
}
int32 width() const;
int32 height() const;
@ -501,6 +560,8 @@ public:
private:
Callback *_cb;
ClipState _state;
ClipFrameRequest _request;
@ -527,7 +588,7 @@ enum ClipProcessResult {
ClipProcessError,
ClipProcessStarted,
ClipProcessReinit,
ClipProcessRedraw,
ClipProcessRepaint,
ClipProcessWait,
};
@ -544,14 +605,15 @@ public:
void start(ClipReader *reader);
void update(ClipReader *reader);
void stop(ClipReader *reader);
bool carries(ClipReader *reader) const;
~ClipReadManager();
signals:
void processDelayed();
void reinit(ClipReader *reader);
void redraw(ClipReader *reader);
void reinit(ClipReader *reader, qint32 threadIndex);
void repaint(ClipReader *reader, qint32 threadIndex);
public slots:
@ -565,7 +627,7 @@ private:
QAtomicInt _loadLevel;
typedef QMap<ClipReader*, ClipReaderPrivate*> ReaderPointers;
ReaderPointers _readerPointers;
QMutex _readerPointersMutex;
mutable QMutex _readerPointersMutex;
bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);

View file

@ -46,6 +46,8 @@ namespace {
static const uint64 RoundedCacheSkip = 0x4000000000000000LLU;
}
StorageImageLocation StorageImageLocation::Null;
bool Image::isNull() const {
return (this == blank());
}
@ -688,6 +690,11 @@ void StorageImage::automaticLoad(const HistoryItem *item) {
}
}
void StorageImage::automaticLoadSettingsChanged() {
if (loaded() || _loader != CancelledFileLoader) return;
_loader = 0;
}
void StorageImage::load(bool loadFirst, bool prior) {
if (loaded()) return;

View file

@ -89,6 +89,8 @@ public:
return _secret;
}
static StorageImageLocation Null;
private:
uint64 _widthheight;
uint64 _dclocal;
@ -118,6 +120,8 @@ public:
virtual void automaticLoad(const HistoryItem *item) { // auto load photo
}
virtual void automaticLoadSettingsChanged() {
}
virtual bool loaded() const {
return true;
@ -164,6 +168,10 @@ public:
virtual void loadEvenCancelled(bool loadFirst = false, bool prior = true) {
}
virtual const StorageImageLocation &location() const {
return StorageImageLocation::Null;
}
bool isNull() const;
void forget() const;
@ -226,6 +234,7 @@ public:
int32 height() const;
void automaticLoad(const HistoryItem *item); // auto load photo
void automaticLoadSettingsChanged();
bool loaded() const;
bool loading() const {
@ -241,6 +250,10 @@ public:
void load(bool loadFirst = false, bool prior = true);
void loadEvenCancelled(bool loadFirst = false, bool prior = true);
virtual const StorageImageLocation &location() const {
return _location;
}
~StorageImage();
protected:

View file

@ -148,6 +148,9 @@ QRect myrtlrect(const QRect &r) { \
void rtlupdate(const QRect &r) { \
update(myrtlrect(r)); \
} \
void rtlupdate(int x, int y, int w, int h) { \
update(myrtlrect(x, y, w, h)); \
} \
protected: \
void enterEvent(QEvent *e) { \
TWidget *p(tparent()); \

View file

@ -884,7 +884,14 @@ HistoryItem *ChannelHistory::addNewToBlocks(const MTPMessage &msg, NewMessageTyp
} else {
to = blocks.back();
}
return addNewItem(to, newBlock, createItem(to, msg, (type == NewMessageUnread)), (type == NewMessageUnread));
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));
}
void ChannelHistory::addNewToOther(HistoryItem *item, NewMessageType type) {
@ -1331,14 +1338,17 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
}
result->attach(block);
}
if (result) {
if (msg.type() == mtpc_message) {
result->updateMedia(msg.c_message().has_media() ? (&msg.c_message().vmedia) : 0, (block ? false : true));
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);
}
return result;
}
return result;
}
bool hasNotForwardedDocument = false;
switch (msg.type()) {
case mtpc_messageEmpty:
result = new HistoryServiceMsg(this, block, msg.c_messageEmpty().vid.v, date(), lang(lng_message_empty));
@ -1387,7 +1397,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
break;
case mtpc_messageMediaDocument:
switch (m.vmedia.c_messageMediaDocument().vdocument.type()) {
case mtpc_document: break;
case mtpc_document: hasNotForwardedDocument = true; break;
case mtpc_documentEmpty: badMedia = 2; break;
default: badMedia = 1; break;
}
@ -1406,9 +1416,11 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
}
if (badMedia) {
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);
hasNotForwardedDocument = false;
} else {
if ((m.has_fwd_date() && m.vfwd_date.v > 0) || (m.has_fwd_from_id() && peerFromMTP(m.vfwd_from_id) != 0)) {
result = new HistoryForwarded(this, block, m);
hasNotForwardedDocument = false;
} else if (m.has_reply_to_msg_id() && m.vreply_to_msg_id.v > 0) {
result = new HistoryReply(this, block, m);
} else {
@ -1543,6 +1555,10 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
} break;
}
if (applyServiceAction) {
App::checkSavedGif(result);
}
return regItem(result);
}
@ -3122,21 +3138,22 @@ void HistoryFileMedia::step_thumbOver(const HistoryItem *parent, float64 ms, boo
_animation->a_thumbOver.finish();
_animation->_a_thumbOver.stop();
checkAnimationFinished();
} else {
} else if (!timer) {
_animation->a_thumbOver.update(dt, anim::linear);
}
if (timer) {
Ui::redrawHistoryItem(parent);
Ui::repaintHistoryItem(parent);
}
}
void HistoryFileMedia::step_radial(const HistoryItem *parent, uint64 ms, bool timer) {
_animation->radial.update(dataProgress(), dataFinished(), ms);
if (!_animation->radial.animating()) {
checkAnimationFinished();
}
if (timer) {
Ui::redrawHistoryItem(parent);
Ui::repaintHistoryItem(parent);
} else {
_animation->radial.update(dataProgress(), dataFinished(), ms);
if (!_animation->radial.animating()) {
checkAnimationFinished();
}
}
}
@ -3344,8 +3361,7 @@ void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(st::msgDateImgBgSelected);
} else if (_animation && _animation->_a_thumbOver.animating()) {
_animation->_a_thumbOver.step(ms);
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
@ -3636,8 +3652,7 @@ void HistoryVideo::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(st::msgDateImgBgSelected);
} else if (_animation && _animation->_a_thumbOver.animating()) {
_animation->_a_thumbOver.step(ms);
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
@ -3835,8 +3850,7 @@ void HistoryAudio::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected);
} else if (_animation && _animation->_a_thumbOver.animating()) {
_animation->_a_thumbOver.step(ms);
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setBrush(style::interpolate(outbg ? st::msgFileOutBg : st::msgFileInBg, outbg ? st::msgFileOutBgOver : st::msgFileInBgOver, over));
} else {
@ -4079,8 +4093,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(st::msgDateImgBgSelected);
} else if (_animation && _animation->_a_thumbOver.animating()) {
_animation->_a_thumbOver.step(ms);
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
@ -4128,7 +4141,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected);
} else if (_animation && _animation->_a_thumbOver.animating()) {
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setBrush(style::interpolate(outbg ? st::msgFileOutBg : st::msgFileInBg, outbg ? st::msgFileOutBgOver : st::msgFileInBgOver, over));
} else {
@ -4432,7 +4445,7 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
_data->automaticLoad(parent);
bool loaded = _data->loaded(), displayLoading = _data->displayLoading();
if (loaded && !gif() && _gif != BadClipReader) {
if (loaded && !gif() && _gif != BadClipReader && cAutoPlayGif()) {
const_cast<HistoryGif*>(this)->playInline(const_cast<HistoryItem*>(parent));
if (gif()) _gif->setAutoplay();
}
@ -4467,7 +4480,7 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
if (animating) {
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, Ui::isMediaViewShown() ? 0 : ms));
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isGifBeingChosen()) ? 0 : ms));
} else {
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height));
}
@ -4475,14 +4488,13 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners);
}
if (radial || (!_gif && !loaded && !_data->loading()) || (_gif == BadClipReader)) {
if (radial || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif())) || (_gif == BadClipReader)) {
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);
} else if (_animation && _animation->_a_thumbOver.animating()) {
_animation->_a_thumbOver.step(ms);
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
@ -4544,7 +4556,7 @@ void HistoryGif::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x,
if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) {
if (_data->uploading()) {
lnk = _cancell;
} else if (!gif()) {
} else if (!gif() || !cAutoPlayGif()) {
lnk = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel);
}
if (parent->getMedia() == this) {
@ -4611,6 +4623,9 @@ bool HistoryGif::playInline(HistoryItem *parent) {
if (gif()) {
stopInline(parent);
} else {
if (!cAutoPlayGif()) {
App::stopGifItems();
}
_gif = new ClipReader(_data->location(), _data->data());
App::regGifItem(_gif, parent);
}
@ -5135,7 +5150,8 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) {
_maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
_minh += st::msgPadding.bottom();
if (_asArticle) {
_minh += st::msgDateFont->height;
_minh = resize(_maxw, parent); // hack
// _minh += st::msgDateFont->height;
}
}
@ -5411,7 +5427,12 @@ const QString HistoryWebPage::inHistoryText() const {
}
ImagePtr HistoryWebPage::replyPreview() {
return _data->photo ? _data->photo->makeReplyPreview() : (_data->doc ? _data->doc->makeReplyPreview() : ImagePtr());
return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
}
HistoryWebPage::~HistoryWebPage() {
delete _attach;
setBadPointer(_attach);
}
namespace {
@ -5999,12 +6020,6 @@ int32 HistoryMessage::plainMaxWidth() const {
void HistoryMessage::initDimensions() {
if (drawBubble()) {
_maxw = plainMaxWidth();
if (_text.isEmpty()) {
_minh = 0;
} else {
_minh = st::msgPadding.top() + _text.minHeight() + st::msgPadding.bottom();
}
if (_media) {
_media->initDimensions(this);
if (_media->isDisplayed()) {
@ -6013,15 +6028,24 @@ void HistoryMessage::initDimensions() {
_textWidth = 0;
_textHeight = 0;
}
int32 maxw = _media->maxWidth();
if (maxw > _maxw) _maxw = maxw;
_minh += _media->minHeight();
} else if (!_text.hasSkipBlock()) {
_text.setSkipBlock(skipBlockWidth(), skipBlockHeight());
_textWidth = 0;
_textHeight = 0;
}
}
_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();
}
} else {
_media->initDimensions(this);
_maxw = _media->maxWidth();
@ -6211,7 +6235,7 @@ void HistoryMessage::setViewsCount(int32 count) {
_viewsText = (_views >= 0) ? formatViewsCount(_views) : QString();
_viewsWidth = _viewsText.isEmpty() ? 0 : st::msgDateFont->width(_viewsText);
if (was == _viewsWidth) {
Ui::redrawHistoryItem(this);
Ui::repaintHistoryItem(this);
} else {
if (_text.hasSkipBlock()) {
_text.setSkipBlock(HistoryMessage::skipBlockWidth(), HistoryMessage::skipBlockHeight());
@ -6227,7 +6251,7 @@ void HistoryMessage::setId(MsgId newId) {
bool wasPositive = (id > 0), positive = (newId > 0);
HistoryItem::setId(newId);
if (wasPositive == positive) {
Ui::redrawHistoryItem(this);
Ui::repaintHistoryItem(this);
} else {
if (_text.hasSkipBlock()) {
_text.setSkipBlock(HistoryMessage::skipBlockWidth(), HistoryMessage::skipBlockHeight());

View file

@ -1235,6 +1235,12 @@ protected:
_animation->radial.step(ms);
return _animation && _animation->radial.animating();
}
bool isThumbAnimation(uint64 ms) const {
if (!_animation || !_animation->_a_thumbOver.animating()) return false;
_animation->_a_thumbOver.step(ms);
return _animation && _animation->_a_thumbOver.animating();
}
virtual float64 dataProgress() const = 0;
virtual bool dataFinished() const = 0;
@ -1812,6 +1818,12 @@ public:
return false;
}
HistoryMedia *attach() const {
return _attach;
}
~HistoryWebPage();
private:
WebPageData *_data;
TextLinkPtr _openl;
@ -2175,6 +2187,13 @@ public:
return _text.adjustSelection(from, to, type);
}
void linkOver(const TextLinkPtr &lnk) {
if (_media) _media->linkOver(this, lnk);
}
void linkOut(const TextLinkPtr &lnk) {
if (_media) _media->linkOut(this, lnk);
}
void drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const;
QString notificationText() const;

View file

@ -38,7 +38,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, History *history) : QWidget(0)
HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, History *history) : TWidget(0)
, _peer(history->peer)
, _migrated(history->peer->migrateFrom() ? App::history(history->peer->migrateFrom()->id) : 0)
, _history(history)
@ -116,7 +116,7 @@ void HistoryInner::messagesReceivedDown(PeerData *peer, const QVector<MTPMessage
}
}
void HistoryInner::redrawItem(const HistoryItem *item) {
void HistoryInner::repaintItem(const HistoryItem *item) {
if (!item || item->detached() || !_history) return;
int32 msgy = itemTop(item);
if (msgy >= 0) {
@ -475,16 +475,16 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
if (button != Qt::LeftButton) return;
if (App::pressedItem() != App::hoveredItem()) {
redrawItem(App::pressedItem());
repaintItem(App::pressedItem());
App::pressedItem(App::hoveredItem());
redrawItem(App::pressedItem());
repaintItem(App::pressedItem());
}
if (textlnkDown() != textlnkOver()) {
redrawItem(App::pressedLinkItem());
repaintItem(App::pressedLinkItem());
textlnkDown(textlnkOver());
App::pressedLinkItem(App::hoveredLinkItem());
redrawItem(App::pressedLinkItem());
redrawItem(App::pressedItem());
repaintItem(App::pressedLinkItem());
repaintItem(App::pressedItem());
}
_dragAction = NoDrag;
@ -512,7 +512,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
uint32 selStatus = (symbol << 16) | symbol;
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key());
repaintItem(_selected.cbegin().key());
_selected.clear();
}
_selected.insert(_dragItem, selStatus);
@ -553,12 +553,12 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol;
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key());
repaintItem(_selected.cbegin().key());
_selected.clear();
}
_selected.insert(_dragItem, selStatus);
_dragAction = Selecting;
redrawItem(_dragItem);
repaintItem(_dragItem);
} else {
_dragAction = PrepareSelect;
}
@ -717,7 +717,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
}
}
if (textlnkDown()) {
redrawItem(App::pressedLinkItem());
repaintItem(App::pressedLinkItem());
textlnkDown(TextLinkPtr());
App::pressedLinkItem(0);
if (!textlnkOver() && _cursor != style::cur_default) {
@ -726,7 +726,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
}
}
if (App::pressedItem()) {
redrawItem(App::pressedItem());
repaintItem(App::pressedItem());
App::pressedItem(0);
}
@ -750,16 +750,16 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
} else {
_selected.erase(i);
}
redrawItem(_dragItem);
repaintItem(_dragItem);
} else if (_dragAction == PrepareDrag && !_dragWasInactive && button != Qt::RightButton) {
SelectedItems::iterator i = _selected.find(_dragItem);
if (i != _selected.cend() && i.value() == FullSelection) {
_selected.erase(i);
redrawItem(_dragItem);
repaintItem(_dragItem);
} else if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
if (_selected.size() < MaxSelectedItems) {
_selected.insert(_dragItem, FullSelection);
redrawItem(_dragItem);
repaintItem(_dragItem);
}
} else {
_selected.clear();
@ -804,7 +804,7 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) {
_dragAction = Selecting;
uint32 selStatus = (symbol << 16) | symbol;
if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key());
repaintItem(_selected.cbegin().key());
_selected.clear();
}
_selected.insert(_dragItem, selStatus);
@ -928,15 +928,35 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
if (item && !isUponSelected && !_contextMenuLnk) {
if (HistoryMedia *media = (msg ? msg->getMedia() : 0)) {
if (media->type() == MediaTypeWebPage && static_cast<HistoryWebPage*>(media)->attach()) {
media = static_cast<HistoryWebPage*>(media)->attach();
}
if (media->type() == MediaTypeSticker) {
DocumentData *doc = media->getDocument();
if (doc && doc->sticker() && doc->sticker()->set.type() != mtpc_inputStickerSetEmpty) {
_menu->addAction(lang(doc->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), _widget, SLOT(onStickerPackInfo()));
}
_menu->addAction(lang(lng_context_save_image), this, SLOT(saveContextFile()))->setEnabled(true);
} else if (media->type() == MediaTypeGif) {
DocumentData *doc = media->getDocument();
if (doc) {
if (doc->loading()) {
_menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true);
} else {
if (doc->mime.toLower() == qstr("video/mp4") && doc->type == AnimatedDocument) {
_menu->addAction(lang(lng_context_save_gif), this, SLOT(saveContextGif()))->setEnabled(true);
}
if (!doc->already(true).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
}
_menu->addAction(lang(lng_context_save_file), this, SLOT(saveContextFile()))->setEnabled(true);
}
}
}
}
QString contextMenuText = item->selectedText(FullSelection);
if (!contextMenuText.isEmpty() && (!msg || !msg->getMedia() || msg->getMedia()->type() != MediaTypeSticker)) {
if (!contextMenuText.isEmpty() && (!msg || !msg->getMedia() || _dragCursorState == HistoryInTextCursorState)) {
_menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true);
}
}
@ -1047,23 +1067,36 @@ void HistoryInner::copyContextImage() {
}
void HistoryInner::cancelContextDownload() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) {
if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
lnkVideo->video()->cancel();
} else if (lnkAudio) {
} else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
lnkAudio->audio()->cancel();
} else if (lnkDocument) {
} else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
lnkDocument->document()->cancel();
} else if (HistoryItem *item = App::contextItem()) {
if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) {
doc->cancel();
}
}
}
}
void HistoryInner::showContextInFolder() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
QString already = lnkVideo ? lnkVideo->video()->already(true) : (lnkAudio ? lnkAudio->audio()->already(true) : (lnkDocument ? lnkDocument->document()->already(true) : QString()));
QString already;
if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
already = lnkVideo->video()->already(true);
} else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
already = lnkAudio->audio()->already(true);
} else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
already = lnkDocument->document()->already(true);
} else if (HistoryItem *item = App::contextItem()) {
if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) {
already = doc->already(true);
}
}
}
if (!already.isEmpty()) psShowInFolder(already);
}
@ -1080,12 +1113,29 @@ void HistoryInner::openContextFile() {
}
void HistoryInner::saveContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoSaveLink::doSave(lnkVideo->video(), true);
if (lnkAudio) AudioSaveLink::doSave(lnkAudio->audio(), true);
if (lnkDocument) DocumentSaveLink::doSave(lnkDocument->document(), true);
if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
VideoSaveLink::doSave(lnkVideo->video(), true);
} else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
AudioSaveLink::doSave(lnkAudio->audio(), true);
} else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
DocumentSaveLink::doSave(lnkDocument->document(), true);
} else if (HistoryItem *item = App::contextItem()) {
if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) {
DocumentSaveLink::doSave(doc, true);
}
}
}
}
void HistoryInner::saveContextGif() {
if (HistoryItem *item = App::contextItem()) {
if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) {
_widget->saveGif(doc);
}
}
}
}
void HistoryInner::copyContextText() {
@ -1345,13 +1395,13 @@ void HistoryInner::enterEvent(QEvent *e) {
void HistoryInner::leaveEvent(QEvent *e) {
if (HistoryItem *item = App::hoveredItem()) {
redrawItem(item);
repaintItem(item);
App::hoveredItem(0);
}
if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) {
item->linkOut(textlnkOver());
redrawItem(item);
repaintItem(item);
App::hoveredLinkItem(0);
}
textlnkOver(TextLinkPtr());
@ -1524,12 +1574,12 @@ void HistoryInner::onUpdateSelected() {
m = mapMouseToItem(point, item);
if (item->hasPoint(m.x(), m.y())) {
if (App::hoveredItem() != item) {
redrawItem(App::hoveredItem());
repaintItem(App::hoveredItem());
App::hoveredItem(item);
redrawItem(App::hoveredItem());
repaintItem(App::hoveredItem());
}
} else if (App::hoveredItem()) {
redrawItem(App::hoveredItem());
repaintItem(App::hoveredItem());
App::hoveredItem(0);
}
}
@ -1557,7 +1607,7 @@ void HistoryInner::onUpdateSelected() {
if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) {
item->linkOut(textlnkOver());
redrawItem(item);
repaintItem(item);
} else {
update(_botDescRect);
}
@ -1568,7 +1618,7 @@ void HistoryInner::onUpdateSelected() {
if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) {
item->linkOver(textlnkOver());
redrawItem(item);
repaintItem(item);
} else {
update(_botDescRect);
}
@ -1610,7 +1660,7 @@ void HistoryInner::onUpdateSelected() {
uint32 selState = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType);
if (_selected[_dragItem] != selState) {
_selected[_dragItem] = selState;
Ui::redrawHistoryItem(_dragItem);
repaintItem(_dragItem);
}
if (!_wasSelectedText && (selState == FullSelection || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) {
_wasSelectedText = true;
@ -2561,6 +2611,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _replyForwardPressed(false)
, _replyReturn(0)
, _stickersUpdateRequest(0)
, _savedGifsUpdateRequest(0)
, _peer(0)
, _clearPeer(0)
, _channel(NoChannel)
@ -2744,7 +2795,11 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
void HistoryWidget::start() {
connect(App::main(), SIGNAL(stickersUpdated()), &_emojiPan, SLOT(refreshStickers()));
connect(App::main(), SIGNAL(savedGifsUpdated()), &_emojiPan, SLOT(refreshSavedGifs()));
updateRecentStickers();
if (App::main()) emit App::main()->savedGifsUpdated();
connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*)));
}
@ -2948,11 +3003,16 @@ void HistoryWidget::onRecordUpdate(qint16 level, qint32 samples) {
}
void HistoryWidget::updateStickers() {
if (cLastStickersUpdate() && getms(true) < cLastStickersUpdate() + StickersUpdateTimeout) return;
if (_stickersUpdateRequest) return;
cSetStickersHash(stickersCountHash(true));
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(cStickersHash())), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed));
if (!cLastStickersUpdate() || getms(true) >= cLastStickersUpdate() + StickersUpdateTimeout) {
if (!_stickersUpdateRequest) {
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true))), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed));
}
}
if (!cLastSavedGifsUpdate() || getms(true) >= cLastSavedGifsUpdate() + StickersUpdateTimeout) {
if (!_savedGifsUpdateRequest) {
_savedGifsUpdateRequest = MTP::send(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash())), rpcDone(&HistoryWidget::savedGifsGot), rpcFail(&HistoryWidget::savedGifsFailed));
}
}
}
void HistoryWidget::notify_botCommandsChanged(UserData *user) {
@ -2993,7 +3053,7 @@ void HistoryWidget::notify_migrateUpdated(PeerData *peer) {
}
}
void HistoryWidget::notify_mediaViewHidden() {
void HistoryWidget::notify_clipStopperHidden(ClipStopperType type) {
if (_list) _list->update();
}
@ -3062,10 +3122,8 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
}
}
int32 countedHash = stickersCountHash();
cSetStickersHash(countedHash);
if (countedHash != d.vhash.v) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(countedHash));
if (Local::countStickersHash() != d.vhash.v) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countStickersHash()));
}
if (!setsToRequest.isEmpty() && App::api()) {
@ -3091,6 +3149,61 @@ bool HistoryWidget::stickersFailed(const RPCError &error) {
return true;
}
void HistoryWidget::savedGifsGot(const MTPmessages_SavedGifs &gifs) {
cSetLastSavedGifsUpdate(getms(true));
_savedGifsUpdateRequest = 0;
if (gifs.type() != mtpc_messages_savedGifs) return;
const MTPDmessages_savedGifs &d(gifs.c_messages_savedGifs());
const QVector<MTPDocument> &d_gifs(d.vgifs.c_vector().v);
SavedGifs &saved(cRefSavedGifs());
saved.clear();
saved.reserve(d_gifs.size());
for (int32 i = 0, l = d_gifs.size(); i != l; ++i) {
DocumentData *doc = App::feedDocument(d_gifs.at(i));
if (!doc || !doc->isAnimation()) {
LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!"));
continue;
}
saved.push_back(doc);
}
if (Local::countSavedGifsHash() != d.vhash.v) {
LOG(("API Error: received saved gifs hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countSavedGifsHash()));
}
Local::writeSavedGifs();
if (App::main()) emit App::main()->savedGifsUpdated();
}
void HistoryWidget::saveGif(DocumentData *doc) {
if (doc->mime.toLower() == qstr("video/mp4") && doc->type == AnimatedDocument) {
if (cSavedGifs().indexOf(doc) != 0) {
MTP::send(MTPmessages_SaveGif(MTP_inputDocument(MTP_long(doc->id), MTP_long(doc->access)), MTP_bool(false)), rpcDone(&HistoryWidget::saveGifDone, doc));
}
}
}
void HistoryWidget::saveGifDone(DocumentData *doc, const MTPBool &result) {
if (mtpIsTrue(result)) {
App::addSavedGif(doc);
}
}
bool HistoryWidget::savedGifsFailed(const RPCError &error) {
if (mtpIsFlood(error)) return false;
LOG(("App Fail: Failed to get saved gifs!"));
cSetLastSavedGifsUpdate(getms(true));
_savedGifsUpdateRequest = 0;
return true;
}
void HistoryWidget::clearReplyReturns() {
_replyReturns.clear();
_replyReturn = 0;
@ -3232,7 +3345,9 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
}
}
// App::stopGifItems();
if (!cAutoPlayGif()) {
App::stopGifItems();
}
clearReplyReturns();
clearAllLoadRequests();
@ -5448,7 +5563,7 @@ void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadPhoto, 0);
}
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -5460,7 +5575,7 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadFile, doc ? doc->uploadOffset : 0);
}
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -5471,7 +5586,7 @@ void HistoryWidget::onAudioProgress(const FullMsgId &newId) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadAudio, audio ? audio->uploadOffset : 0);
}
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -5482,7 +5597,7 @@ void HistoryWidget::onPhotoFailed(const FullMsgId &newId) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadPhoto, -1);
}
// Ui::redrawHistoryItem(item);
// Ui::repaintHistoryItem(item);
}
}
@ -5493,7 +5608,7 @@ void HistoryWidget::onDocumentFailed(const FullMsgId &newId) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadFile, -1);
}
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -5504,7 +5619,7 @@ void HistoryWidget::onAudioFailed(const FullMsgId &newId) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadAudio, -1);
}
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -5602,12 +5717,24 @@ bool HistoryWidget::isItemVisible(HistoryItem *item) {
return true;
}
void HistoryWidget::ui_redrawHistoryItem(const HistoryItem *item) {
void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) {
_list->redrawItem(item);
_list->repaintItem(item);
}
}
void HistoryWidget::ui_repaintSavedGif(const LayoutSavedGif *layout) {
_emojiPan.ui_repaintSavedGif(layout);
}
bool HistoryWidget::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return _emojiPan.ui_isSavedGifVisible(layout) || _attachMention.ui_isSavedGifVisible(layout);
}
bool HistoryWidget::ui_isGifBeingChosen() {
return _emojiPan.ui_isGifBeingChosen() || _attachMention.ui_isGifBeingChosen();
}
void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
if (_peer && _list && (item == App::mousedItem() || item == App::hoveredItem() || item == App::hoveredLinkItem())) {
_list->onUpdateSelected();
@ -6527,7 +6654,7 @@ void HistoryWidget::onAnimActiveStep() {
if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) {
stopAnimActive();
} else {
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}

View file

@ -33,7 +33,7 @@ enum DragState {
};
class HistoryWidget;
class HistoryInner : public QWidget {
class HistoryInner : public TWidget {
Q_OBJECT
public:
@ -69,7 +69,7 @@ public:
int32 recountHeight(const HistoryItem *resizedItem);
void updateSize();
void redrawItem(const HistoryItem *item);
void repaintItem(const HistoryItem *item);
bool canCopySelected() const;
bool canDeleteSelected() const;
@ -114,6 +114,7 @@ public slots:
void showContextInFolder();
void openContextFile();
void saveContextFile();
void saveContextGif();
void copyContextText();
void copySelectedText();
@ -541,6 +542,8 @@ public:
void updateNotifySettings();
void saveGif(DocumentData *doc);
bool contentOverlapped(const QRect &globalRect);
void grabStart() {
@ -556,13 +559,16 @@ public:
bool isItemVisible(HistoryItem *item);
void ui_redrawHistoryItem(const HistoryItem *item);
void ui_repaintHistoryItem(const HistoryItem *item);
void ui_repaintSavedGif(const LayoutSavedGif *gif);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
void notify_historyItemLayoutChanged(const HistoryItem *item);
void notify_botCommandsChanged(UserData *user);
void notify_userIsBotChanged(UserData *user);
void notify_migrateUpdated(PeerData *peer);
void notify_mediaViewHidden();
void notify_clipStopperHidden(ClipStopperType type);
void notify_historyItemResized(const HistoryItem *item, bool scrollToIt);
~HistoryWidget();
@ -701,6 +707,8 @@ private:
void addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
void addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
void saveGifDone(DocumentData *doc, const MTPBool &result);
void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request);
bool reportSpamFail(const RPCError &error, mtpRequestId request);
@ -713,10 +721,13 @@ private:
void countHistoryShowFrom();
mtpRequestId _stickersUpdateRequest;
void stickersGot(const MTPmessages_AllStickers &stickers);
bool stickersFailed(const RPCError &error);
mtpRequestId _stickersUpdateRequest;
mtpRequestId _savedGifsUpdateRequest;
void savedGifsGot(const MTPmessages_SavedGifs &gifs);
bool savedGifsFailed(const RPCError &error);
void writeDraft(MsgId *replyTo = 0, const QString *text = 0, const MessageCursor *cursor = 0, bool *previewCancelled = 0);
void setFieldText(const QString &text);

View file

@ -195,6 +195,7 @@ StickerPreviewWidget::StickerPreviewWidget(QWidget *parent) : TWidget(parent)
, a_shown(0, 0)
, _a_shown(animation(this, &StickerPreviewWidget::step_shown))
, _doc(0)
, _gif(0)
, _cacheStatus(CacheNotLoaded) {
setAttribute(Qt::WA_TransparentForMouseEvents);
}
@ -232,7 +233,7 @@ void StickerPreviewWidget::step_shown(float64 ms, bool timer) {
}
void StickerPreviewWidget::showPreview(DocumentData *sticker) {
if (sticker && !sticker->sticker()) sticker = 0;
if (sticker && !sticker->isAnimation() && !sticker->sticker()) sticker = 0;
if (sticker) {
_cache = QPixmap();
if (isHidden() || _a_shown.animating()) {
@ -245,10 +246,17 @@ void StickerPreviewWidget::showPreview(DocumentData *sticker) {
} else if (isHidden()) {
return;
} else {
if (_gif) _cache = currentImage();
a_shown.start(0);
_a_shown.start();
}
_doc = sticker;
if (_gif) {
if (gif()) {
delete _gif;
}
_gif = 0;
}
_cacheStatus = CacheNotLoaded;
}
@ -259,7 +267,10 @@ void StickerPreviewWidget::hidePreview() {
QSize StickerPreviewWidget::currentDimensions() const {
if (!_doc) return QSize(_cache.width() / cIntRetinaFactor(), _cache.height() / cIntRetinaFactor());
QSize result(qMax(_doc->dimensions.width(), 1), qMax(_doc->dimensions.height(), 1));
QSize result(qMax(convertScale(_doc->dimensions.width()), 1), qMax(convertScale(_doc->dimensions.height()), 1));
if (gif() && _gif->ready()) {
result = QSize(qMax(convertScale(_gif->width()), 1), qMax(convertScale(_gif->height()), 1));
}
if (result.width() > st::maxStickerSize) {
result.setHeight(qMax(qRound((st::maxStickerSize * result.height()) / result.width()), 1));
result.setWidth(st::maxStickerSize);
@ -272,22 +283,64 @@ QSize StickerPreviewWidget::currentDimensions() const {
}
QPixmap StickerPreviewWidget::currentImage() const {
if (_doc && _cacheStatus != CacheLoaded) {
_doc->checkSticker();
if (_doc->sticker()->img->isNull()) {
if (_cacheStatus != CacheThumbLoaded) {
if (_doc) {
if (_doc->sticker()) {
if (_cacheStatus != CacheLoaded) {
_doc->checkSticker();
if (_doc->sticker()->img->isNull()) {
if (_cacheStatus != CacheThumbLoaded && _doc->thumb->loaded()) {
QSize s = currentDimensions();
_cache = _doc->thumb->pixBlurred(s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
}
} else {
QSize s = currentDimensions();
_cache = _doc->sticker()->img->pix(s.width(), s.height());
_cacheStatus = CacheLoaded;
}
}
} else {
_doc->automaticLoad(0);
if (_doc->loaded()) {
if (!_gif && _gif != BadClipReader) {
StickerPreviewWidget *that = const_cast<StickerPreviewWidget*>(this);
that->_gif = new ClipReader(_doc->location(), _doc->data(), func(that, &StickerPreviewWidget::clipCallback));
if (gif()) _gif->setAutoplay();
}
}
if (gif() && _gif->started()) {
QSize s = currentDimensions();
return _gif->current(s.width(), s.height(), s.width(), s.height(), getms());
}
if (_cacheStatus != CacheThumbLoaded && _doc->thumb->loaded()) {
QSize s = currentDimensions();
_cache = _doc->thumb->pixBlurred(s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
}
} else {
QSize s = currentDimensions();
_cache = _doc->sticker()->img->pix(s.width(), s.height());
_cacheStatus = CacheLoaded;
}
}
return _cache;
}
void StickerPreviewWidget::clipCallback(ClipReaderNotification notification) {
switch (notification) {
case ClipReaderReinit: {
if (gif() && _gif->state() == ClipError) {
delete _gif;
_gif = BadClipReader;
}
if (gif() && _gif->ready() && !_gif->started()) {
QSize s = currentDimensions();
_gif->start(s.width(), s.height(), s.width(), s.height(), false);
}
update();
} break;
case ClipReaderRepaint: update(); break;
}
}
StickerPreviewWidget::~StickerPreviewWidget() {
}

View file

@ -131,6 +131,12 @@ private:
anim::fvalue a_shown;
Animation _a_shown;
DocumentData *_doc;
ClipReader *_gif;
bool gif() const {
return (!_gif || _gif == BadClipReader) ? false : true;
}
void clipCallback(ClipReaderNotification notification);
enum CacheStatus {
CacheNotLoaded,

View file

@ -227,21 +227,22 @@ void LayoutRadialProgressItem::step_iconOver(float64 ms, bool timer) {
if (dt >= 1) {
a_iconOver.finish();
_a_iconOver.stop();
} else {
} else if (!timer) {
a_iconOver.update(dt, anim::linear);
}
if (timer && iconAnimated()) {
Ui::redrawHistoryItem(_parent);
Ui::repaintHistoryItem(_parent);
}
}
void LayoutRadialProgressItem::step_radial(uint64 ms, bool timer) {
_radial->update(dataProgress(), dataFinished(), ms);
if (!_radial->animating()) {
checkRadialFinished();
}
if (timer) {
Ui::redrawHistoryItem(_parent);
Ui::repaintHistoryItem(_parent);
} else {
_radial->update(dataProgress(), dataFinished(), ms);
if (!_radial->animating()) {
checkRadialFinished();
}
}
}
@ -590,6 +591,7 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection,
if (selected) {
p.setBrush(st::msgFileInBgSelected);
} else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over));
} else {
@ -787,6 +789,7 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
if (selected) {
p.setBrush(st::msgFileInBgSelected);
} else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over));
} else {
@ -1280,3 +1283,230 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text)
, width(st::normalFont->width(text))
, lnk(linkFromUrl(url)) {
}
LayoutSavedGif::LayoutSavedGif(DocumentData *data)
: _data(data)
, _position(0)
, _width(st::savedGifMinWidth)
, _state(0)
, _gif(0)
, _animation(0) {
}
void LayoutSavedGif::setPosition(int32 position, int32 width) {
_position = position;
_width = width;
if (_position < 0) {
if (gif()) delete _gif;
_gif = 0;
}
}
void LayoutSavedGif::setWidth(int32 width) {
_width = width;
}
int32 LayoutSavedGif::position() const {
return _position;
}
int32 LayoutSavedGif::width() const {
return _width;
}
void LayoutSavedGif::notify_over(bool over) {
if (!_data->loaded()) {
ensureAnimation();
if (over == !(_state & StateOver)) {
EnsureAnimation(_animation->_a_over, (_state & StateOver) ? 1 : 0, (func(this, &LayoutSavedGif::update)));
_animation->_a_over.start(over ? 1 : 0, st::stickersRowDuration);
}
}
if (over) {
_state |= StateOver;
} else {
_state &= ~StateOver;
}
}
void LayoutSavedGif::notify_deleteOver(bool over) {
if (over == !(_state & StateDeleteOver)) {
EnsureAnimation(_a_deleteOver, (_state & StateDeleteOver) ? 1 : 0, func(this, &LayoutSavedGif::update));
if (over) {
_state |= StateDeleteOver;
} else {
_state &= ~StateDeleteOver;
}
_a_deleteOver.start((_state & StateDeleteOver) ? 1 : 0, st::stickersRowDuration);
}
}
void LayoutSavedGif::paint(Painter &p, bool paused, uint64 ms) const {
_data->automaticLoad(0);
bool loaded = _data->loaded(), displayLoading = _data->displayLoading();
if (loaded && !gif() && _gif != BadClipReader) {
LayoutSavedGif *that = const_cast<LayoutSavedGif*>(this);
that->_gif = new ClipReader(_data->location(), _data->data(), func(that, &LayoutSavedGif::clipCallback));
if (gif()) _gif->setAutoplay();
}
bool animating = (gif() && _gif->started());
if (displayLoading) {
ensureAnimation();
if (!_animation->radial.animating()) {
_animation->radial.start(_data->progress());
}
}
bool radial = isRadialAnimation(ms);
int32 height = st::savedGifHeight;
QSize frame = countFrameSize();
QRect r(0, 0, _width, height);
if (animating) {
if (!_thumb.isNull()) const_cast<LayoutSavedGif*>(this)->_thumb = QPixmap();
p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, paused ? 0 : ms));
} else {
if (!_data->thumb->isNull()) {
if (_data->thumb->loaded()) {
if (_thumb.width() != _width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
const_cast<LayoutSavedGif*>(this)->_thumb = _data->thumb->pixNoCache(frame.width(), frame.height(), true, false, false, _width, height);
}
} else {
_data->thumb->load();
}
}
p.drawPixmap(r.topLeft(), _thumb);
}
if (radial || (!_gif && !loaded && !_data->loading()) || (_gif == BadClipReader)) {
float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _animation->radial.opacity() : 1;
if (_animation && _animation->_a_over.animating(ms)) {
float64 over = _animation->_a_over.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.fillRect(r, st::black);
} else {
p.fillRect(r, (_state & StateOver) ? st::msgDateImgBgOver : st::msgDateImgBg);
}
p.setOpacity(radialOpacity * p.opacity());
p.setOpacity(radialOpacity);
style::sprite icon;
if (_data->loaded() && !radial) {
icon = st::msgFileInPlay;
} else if (radial || _data->loading()) {
icon = st::msgFileInCancel;
} else {
icon = st::msgFileInDownload;
}
QRect inner((_width - st::msgFileSize) / 2, (height - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
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, st::msgInBg);
}
}
if (_state & StateOver) {
float64 deleteOver = _a_deleteOver.current(ms, (_state & StateDeleteOver) ? 1 : 0);
QPoint deletePos = QPoint(_width - st::stickerPanDelete.pxWidth(), 0);
p.setOpacity(deleteOver + (1 - deleteOver) * st::stickerPanDeleteOpacity);
p.drawSpriteLeft(deletePos, _width, st::stickerPanDelete);
p.setOpacity(1);
}
}
QSize LayoutSavedGif::countFrameSize() const {
bool animating = (gif() && _gif->ready());
int32 framew = animating ? _gif->width() : _data->thumb->width(), frameh = animating ? _gif->height() : _data->thumb->height(), height = st::savedGifHeight;
if (framew * height > frameh * _width) {
if (framew < st::maxStickerSize || frameh > height) {
if (frameh > height || (framew * height / frameh) <= st::maxStickerSize) {
framew = framew * height / frameh;
frameh = height;
} else {
frameh = int32(frameh * st::maxStickerSize) / framew;
framew = st::maxStickerSize;
}
}
} else {
if (frameh < st::maxStickerSize || framew > _width) {
if (framew > _width || (frameh * _width / framew) <= st::maxStickerSize) {
frameh = frameh * _width / framew;
framew = _width;
} else {
framew = int32(framew * st::maxStickerSize) / frameh;
frameh = st::maxStickerSize;
}
}
}
return QSize(framew, frameh);
}
void LayoutSavedGif::preload() {
_data->thumb->load();
}
LayoutSavedGif::~LayoutSavedGif() {
delete _animation;
setBadPointer(_animation);
}
void LayoutSavedGif::ensureAnimation() const {
if (!_animation) {
_animation = new AnimationData(animation(const_cast<LayoutSavedGif*>(this), &LayoutSavedGif::step_radial));
}
}
bool LayoutSavedGif::isRadialAnimation(uint64 ms) const {
if (!_animation || !_animation->radial.animating()) return false;
_animation->radial.step(ms);
return _animation && _animation->radial.animating();
}
void LayoutSavedGif::step_radial(uint64 ms, bool timer) {
if (timer) {
update();
} else {
_animation->radial.update(_data->progress(), !_data->loading() || _data->loaded(), ms);
if (!_animation->radial.animating() && _data->loaded()) {
delete _animation;
_animation = 0;
}
}
}
void LayoutSavedGif::clipCallback(ClipReaderNotification notification) {
switch (notification) {
case ClipReaderReinit: {
if (gif()) {
if (_gif->state() == ClipError) {
delete _gif;
_gif = BadClipReader;
_data->forget();
} else if (_gif->ready() && !_gif->started()) {
int32 height = st::savedGifHeight;
QSize frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, false);
} else if (_gif->paused() && !Ui::isSavedGifVisible(this)) {
delete _gif;
_gif = 0;
_data->forget();
}
}
update();
} break;
case ClipReaderRepaint: update(); break;
}
}
void LayoutSavedGif::update() {
if (_position >= 0) {
Ui::repaintSavedGif(this);
}
}

View file

@ -470,3 +470,62 @@ private:
QVector<Link> _links;
};
class LayoutSavedGif {
public:
LayoutSavedGif(DocumentData *data);
void paint(Painter &p, bool paused, uint64 ms) const;
void preload();
DocumentData *document() const {
return _data;
}
void setPosition(int32 position, int32 width);
void setWidth(int32 width);
int32 position() const;
int32 width() const;
void notify_over(bool over);
void notify_deleteOver(bool over);
~LayoutSavedGif();
private:
DocumentData *_data;
int32 _position; // < 0 means removed from layout
int32 _width;
QSize countFrameSize() const;
enum StateFlags {
StateOver = 0x01,
StateDeleteOver = 0x02,
};
int32 _state;
ClipReader *_gif;
bool gif() const {
return (!_gif || _gif == BadClipReader) ? false : true;
}
QPixmap _thumb;
void ensureAnimation() const;
bool isRadialAnimation(uint64 ms) const;
void step_radial(uint64 ms, bool timer);
void clipCallback(ClipReaderNotification notification);
void update();
struct AnimationData {
AnimationData(AnimationCallbacks *radialCallbacks)
: over(false)
, radial(radialCallbacks) {
}
bool over;
FloatAnimation _a_over;
RadialAnimation radial;
};
mutable AnimationData *_animation;
mutable FloatAnimation _a_deleteOver;
};

View file

@ -552,6 +552,7 @@ namespace {
lskStickers = 0x0b, // no data
lskSavedPeers = 0x0c, // no data
lskReportSpamStatuses = 0x0d, // no data
lskSavedGifs = 0x0e,
};
typedef QMap<PeerId, FileKey> DraftsMap;
@ -568,7 +569,7 @@ namespace {
FileLocationAliases _fileLocationAliases;
FileKey _locationsKey = 0, _reportSpamStatusesKey = 0;
FileKey _recentStickersKeyOld = 0, _stickersKey = 0;
FileKey _recentStickersKeyOld = 0, _stickersKey = 0, _savedGifsKey;
FileKey _backgroundKey = 0;
bool _backgroundWasRead = false;
@ -797,6 +798,14 @@ namespace {
cSetMaxGroupCount(maxSize);
} break;
case dbiSavedGifsLimit: {
qint32 limit;
stream >> limit;
if (!_checkStreamStatus(stream)) return false;
cSetSavedGifsLimit(limit);
} break;
case dbiMaxMegaGroupCount: {
qint32 maxSize;
stream >> maxSize;
@ -873,6 +882,14 @@ namespace {
cSetAutoDownloadGif(gif);
} break;
case dbiAutoPlay: {
qint32 gif;
stream >> gif;
if (!_checkStreamStatus(stream)) return false;
cSetAutoPlayGif(gif == 1);
} break;
case dbiIncludeMuted: {
qint32 v;
stream >> v;
@ -881,6 +898,14 @@ namespace {
cSetIncludeMuted(v == 1);
} break;
case dbiShowingSavedGifs: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetShowingSavedGifs(v == 1);
} break;
case dbiDesktopNotify: {
qint32 v;
stream >> v;
@ -1438,7 +1463,7 @@ namespace {
_writeMap(WriteMapFast);
}
uint32 size = 14 * (sizeof(quint32) + sizeof(qint32));
uint32 size = 16 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath()) + _bytearraySize(cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
@ -1454,6 +1479,7 @@ namespace {
data.stream << quint32(dbiDefaultAttach) << qint32(cDefaultAttach());
data.stream << quint32(dbiSoundNotify) << qint32(cSoundNotify());
data.stream << quint32(dbiIncludeMuted) << qint32(cIncludeMuted());
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
data.stream << quint32(dbiDesktopNotify) << qint32(cDesktopNotify());
data.stream << quint32(dbiNotifyView) << qint32(cNotifyView());
data.stream << quint32(dbiWindowsNotifications) << qint32(cWindowsNotifications());
@ -1463,6 +1489,7 @@ namespace {
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
data.stream << quint32(dbiSongVolume) << qint32(qRound(cSongVolume() * 1e6));
data.stream << quint32(dbiAutoDownload) << qint32(cAutoDownloadPhoto()) << qint32(cAutoDownloadAudio()) << qint32(cAutoDownloadGif());
data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0);
{
RecentEmojisPreload v(cRecentEmojisPreload());
@ -1608,7 +1635,9 @@ namespace {
DraftsNotReadMap draftsNotReadMap;
StorageMap imagesMap, stickerImagesMap, audiosMap;
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
quint64 locationsKey = 0, reportSpamStatusesKey = 0, recentStickersKeyOld = 0, stickersKey = 0, backgroundKey = 0, userSettingsKey = 0, recentHashtagsKey = 0, savedPeersKey = 0;
quint64 locationsKey = 0, reportSpamStatusesKey = 0;
quint64 recentStickersKeyOld = 0, stickersKey = 0, savedGifsKey = 0;
quint64 backgroundKey = 0, userSettingsKey = 0, recentHashtagsKey = 0, savedPeersKey = 0;
while (!map.stream.atEnd()) {
quint32 keyType;
map.stream >> keyType;
@ -1691,6 +1720,9 @@ namespace {
case lskStickers: {
map.stream >> stickersKey;
} break;
case lskSavedGifs: {
map.stream >> savedGifsKey;
} break;
case lskSavedPeers: {
map.stream >> savedPeersKey;
} break;
@ -1718,6 +1750,7 @@ namespace {
_reportSpamStatusesKey = reportSpamStatusesKey;
_recentStickersKeyOld = recentStickersKeyOld;
_stickersKey = stickersKey;
_savedGifsKey = savedGifsKey;
_savedPeersKey = savedPeersKey;
_backgroundKey = backgroundKey;
_userSettingsKey = userSettingsKey;
@ -1790,6 +1823,7 @@ namespace {
if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64);
if (_stickersKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_savedGifsKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
@ -1837,6 +1871,9 @@ namespace {
if (_stickersKey) {
mapData.stream << quint32(lskStickers) << quint64(_stickersKey);
}
if (_savedGifsKey) {
mapData.stream << quint32(lskSavedGifs) << quint64(_savedGifsKey);
}
if (_savedPeersKey) {
mapData.stream << quint32(lskSavedPeers) << quint64(_savedPeersKey);
}
@ -2040,7 +2077,7 @@ namespace Local {
cSetDcOptions(dcOpts);
}
quint32 size = 11 * (sizeof(quint32) + sizeof(qint32));
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
for (mtpDcOptions::const_iterator i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
size += sizeof(quint32) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
@ -2058,6 +2095,7 @@ namespace Local {
EncryptedDescriptor data(size);
data.stream << quint32(dbiMaxGroupCount) << qint32(cMaxGroupCount());
data.stream << quint32(dbiMaxMegaGroupCount) << qint32(cMaxMegaGroupCount());
data.stream << quint32(dbiSavedGifsLimit) << qint32(cSavedGifsLimit());
data.stream << quint32(dbiAutoStart) << qint32(cAutoStart());
data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized());
data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu());
@ -2111,7 +2149,9 @@ namespace Local {
_stickerImagesMap.clear();
_audiosMap.clear();
_storageImagesSize = _storageStickersSize = _storageAudiosSize = 0;
_locationsKey = _reportSpamStatusesKey = _recentStickersKeyOld = _stickersKey = _backgroundKey = _userSettingsKey = _recentHashtagsKey = _savedPeersKey = 0;
_locationsKey = _reportSpamStatusesKey = 0;
_recentStickersKeyOld = _stickersKey = _savedGifsKey = 0;
_backgroundKey = _userSettingsKey = _recentHashtagsKey = _savedPeersKey = 0;
_oldMapVersion = _oldSettingsVersion = 0;
_mapChanged = true;
_writeMap(WriteMapNow);
@ -2667,7 +2707,7 @@ namespace Local {
_writeMap();
} else {
int32 setsCount = 0;
QByteArray hashToWrite = (qsl("%d:") + QString::number(cStickersHash())).toUtf8();
QByteArray hashToWrite;
quint32 size = sizeof(quint32) + _bytearraySize(hashToWrite);
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
bool notLoaded = (i->flags & MTPDstickerSet_flag_NOT_LOADED);
@ -2729,8 +2769,6 @@ namespace Local {
RecentStickerPack &recent(cRefRecentStickers());
recent.clear();
cSetStickersHash(0);
StickerSet &def(sets.insert(DefaultStickerSetId, StickerSet(DefaultStickerSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::flag_official)).value());
StickerSet &custom(sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, 0)).value());
@ -2806,9 +2844,8 @@ namespace Local {
quint32 cnt;
QByteArray hash;
stickers.stream >> cnt >> hash;
if (stickers.version < 8019) {
hash.clear(); // bad data in old caches
stickers.stream >> cnt >> hash; // ignore hash, it is counted
if (stickers.version < 8019) { // bad data in old caches
cnt += 2; // try to read at least something
}
for (uint32 i = 0; i < cnt; ++i) {
@ -2886,11 +2923,124 @@ namespace Local {
++set.count;
}
}
}
if (hash.startsWith(qsl("%d:").toUtf8())) {
cSetStickersHash(QString::fromUtf8(hash.mid(3)).toInt());
int32 countStickersHash(bool checkOfficial) {
uint32 acc = 0;
bool foundOfficial = false, foundBad = false;;
const StickerSets &sets(cStickerSets());
const StickerSetsOrder &order(cStickerSetsOrder());
for (StickerSetsOrder::const_iterator i = order.cbegin(), e = order.cend(); i != e; ++i) {
StickerSets::const_iterator j = sets.constFind(*i);
if (j != sets.cend()) {
if (j->id == 0) {
foundBad = true;
} else if (j->flags & MTPDstickerSet::flag_official) {
foundOfficial = true;
}
if (!(j->flags & MTPDstickerSet::flag_disabled)) {
acc = (acc * 20261) + j->hash;
}
}
}
return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0;
}
int32 countSavedGifsHash() {
uint32 acc = 0;
const SavedGifs &saved(cSavedGifs());
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
uint64 docId = (*i)->id;
acc = (acc * 20261) + uint32(docId >> 32);
acc = (acc * 20261) + uint32(docId & 0xFFFFFFFF);
}
return int32(acc & 0x7FFFFFFF);
}
void writeSavedGifs() {
if (!_working()) return;
const SavedGifs &saved(cSavedGifs());
if (saved.isEmpty()) {
if (_savedGifsKey) {
clearKey(_savedGifsKey);
_savedGifsKey = 0;
_mapChanged = true;
}
_writeMap();
} else {
cSetStickersHash(0);
quint32 size = sizeof(quint32); // count
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
DocumentData *doc = *i;
// id + access + date + namelen + name + mimelen + mime + dc + size + width + height + type
size += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
// thumb
size += _storageImageLocationSize();
}
if (!_savedGifsKey) {
_savedGifsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
}
EncryptedDescriptor data(size);
data.stream << quint32(saved.size());
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
DocumentData *doc = *i;
data.stream << quint64(doc->id) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type);
_writeStorageImageLocation(data.stream, doc->thumb->location());
}
FileWriteDescriptor file(_savedGifsKey);
file.writeEncrypted(data);
}
}
void readSavedGifs() {
if (!_savedGifsKey) return;
FileReadDescriptor gifs;
if (!readEncryptedFile(gifs, _savedGifsKey)) {
clearKey(_savedGifsKey);
_savedGifsKey = 0;
_writeMap();
return;
}
SavedGifs &saved(cRefSavedGifs());
saved.clear();
quint32 cnt;
gifs.stream >> cnt;
saved.reserve(cnt);
QMap<uint64, NullType> read;
for (uint32 i = 0; i < cnt; ++i) {
quint64 id, access;
QString name, mime;
qint32 date, dc, size, width, height, type;
gifs.stream >> id >> access >> date >> name >> mime >> dc >> size >> width >> height >> type;
StorageImageLocation thumb(_readStorageImageLocation(gifs));
if (read.contains(id)) continue;
read.insert(id, NullType());
QVector<MTPDocumentAttribute> attributes;
if (!name.isEmpty()) attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
if (type == AnimatedDocument) {
attributes.push_back(MTP_documentAttributeAnimated());
}
if (width > 0 && height > 0) {
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
}
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb);
if (!doc->isAnimation()) continue;
saved.push_back(doc);
}
}

View file

@ -142,6 +142,11 @@ namespace Local {
void writeStickers();
void readStickers();
int32 countStickersHash(bool checkOfficial = false);
void writeSavedGifs();
void readSavedGifs();
int32 countSavedGifsHash();
void writeBackground(int32 id, const QImage &img);
bool readBackground();

View file

@ -742,7 +742,7 @@ QPixmap MainWidget::grabTopBar() {
}
void MainWidget::ui_showStickerPreview(DocumentData *sticker) {
if (!sticker || !sticker->sticker()) return;
if (!sticker || ((!sticker->isAnimation() || !sticker->loaded()) && !sticker->sticker())) return;
if (!_stickerPreview) {
_stickerPreview = new StickerPreviewWidget(this);
resizeEvent(0);
@ -773,7 +773,7 @@ void MainWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp) {
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
j.key()->initDimensions();
Ui::redrawHistoryItem(j.key());
Ui::repaintHistoryItem(j.key());
}
}
@ -786,18 +786,28 @@ void MainWidget::notify_migrateUpdated(PeerData *peer) {
history.notify_migrateUpdated(peer);
}
void MainWidget::notify_mediaViewHidden() {
history.notify_mediaViewHidden();
void MainWidget::notify_clipStopperHidden(ClipStopperType type) {
history.notify_clipStopperHidden(type);
}
void MainWidget::ui_redrawHistoryItem(const HistoryItem *item) {
if (!item) return;
history.ui_redrawHistoryItem(item);
void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) {
history.ui_repaintHistoryItem(item);
if (!item->history()->dialogs.isEmpty() && item->history()->lastMsg == item) {
dialogs.dlgUpdated(item->history()->dialogs[0]);
}
if (overview) overview->ui_redrawHistoryItem(item);
if (overview) overview->ui_repaintHistoryItem(item);
}
void MainWidget::ui_repaintSavedGif(const LayoutSavedGif *layout) {
history.ui_repaintSavedGif(layout);
}
bool MainWidget::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return history.ui_isSavedGifVisible(layout);
}
bool MainWidget::ui_isGifBeingChosen() {
return history.ui_isGifBeingChosen();
}
void MainWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
@ -814,7 +824,7 @@ void MainWidget::notify_historyItemResized(const HistoryItem *item, bool scrollT
history.resizeEvent(0);
}
}
if (item) Ui::redrawHistoryItem(item);
if (item) Ui::repaintHistoryItem(item);
}
void MainWidget::noHider(HistoryHider *destroyed) {
@ -1638,7 +1648,7 @@ void MainWidget::videoLoadProgress(mtpFileLoader *loader) {
VideoItems::const_iterator i = items.constFind(video);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
Ui::redrawHistoryItem(j.key());
Ui::repaintHistoryItem(j.key());
}
}
}
@ -1694,7 +1704,7 @@ void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
AudioItems::const_iterator i = items.constFind(audio);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
Ui::redrawHistoryItem(j.key());
Ui::repaintHistoryItem(j.key());
}
}
}
@ -1729,7 +1739,7 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
}
if (HistoryItem *item = App::histItemById(audioId.msgId)) {
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -1790,7 +1800,7 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) {
}
if (HistoryItem *item = App::histItemById(songId.msgId)) {
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
}
}
@ -1828,7 +1838,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
DocumentItems::const_iterator i = items.constFind(document);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
Ui::redrawHistoryItem(j.key());
Ui::repaintHistoryItem(j.key());
}
}
App::wnd()->documentUpdated(document);
@ -3415,6 +3425,7 @@ void MainWidget::start(const MTPUser &user) {
_started = true;
App::wnd()->sendServiceHistoryRequest();
Local::readStickers();
Local::readSavedGifs();
history.start();
}
@ -4155,7 +4166,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
msgRow->history()->unregTyping(App::self());
}
App::historyRegItem(msgRow);
Ui::redrawHistoryItem(msgRow);
Ui::repaintHistoryItem(msgRow);
}
}
App::historyUnregRandom(d.vrandom_id.v);
@ -4176,7 +4187,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (HistoryItem *item = App::histItemById(NoChannel, v.at(i).v)) {
if (item->isMediaUnread()) {
item->markMediaRead();
Ui::redrawHistoryItem(item);
Ui::repaintHistoryItem(item);
if (item->out() && item->history()->peer->isUser()) {
item->history()->peer->asUser()->madeAction();
}
@ -4580,7 +4591,6 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
sets.erase(custom);
}
}
cSetStickersHash(stickersCountHash());
Local::writeStickers();
emit stickersUpdated();
}
@ -4600,11 +4610,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
}
if (result.size() != cStickerSetsOrder().size() || result.size() != order.size()) {
cSetLastStickersUpdate(0);
cSetStickersHash(0);
App::main()->updateStickers();
} else {
cSetStickerSetsOrder(result);
cSetStickersHash(stickersCountHash());
Local::writeStickers();
emit stickersUpdated();
}
@ -4612,7 +4620,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateStickerSets: {
cSetLastStickersUpdate(0);
cSetStickersHash(0);
App::main()->updateStickers();
} break;
case mtpc_updateSavedGifs: {
cSetLastSavedGifsUpdate(0);
App::main()->updateStickers();
} break;

View file

@ -409,14 +409,17 @@ public:
void ui_showStickerPreview(DocumentData *sticker);
void ui_hideStickerPreview();
void ui_redrawHistoryItem(const HistoryItem *item);
void ui_repaintHistoryItem(const HistoryItem *item);
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back);
void notify_botCommandsChanged(UserData *bot);
void notify_userIsBotChanged(UserData *bot);
void notify_userIsContactChanged(UserData *user, bool fromThisApp);
void notify_migrateUpdated(PeerData *peer);
void notify_mediaViewHidden();
void notify_clipStopperHidden(ClipStopperType type);
void notify_historyItemResized(const HistoryItem *row, bool scrollToIt);
void notify_historyItemLayoutChanged(const HistoryItem *item);
@ -430,6 +433,7 @@ signals:
void dialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
void dialogsUpdated();
void stickersUpdated();
void savedGifsUpdated();
public slots:

View file

@ -603,7 +603,7 @@ void MediaView::onDocClick() {
}
}
void MediaView::ui_clipRedraw(ClipReader *reader) {
void MediaView::ui_clipRepaint(ClipReader *reader) {
if (reader == _gif) {
update(_x, _y, _w, _h);
}
@ -1960,7 +1960,7 @@ void MediaView::hide() {
QWidget::hide();
stopGif();
Notify::mediaViewHidden();
Notify::clipStopperHidden(ClipStopperMediaview);
}
void MediaView::onMenuDestroy(QObject *obj) {

View file

@ -71,7 +71,7 @@ public:
void activateControls();
void onDocClick();
void ui_clipRedraw(ClipReader *reader);
void ui_clipRepaint(ClipReader *reader);
void notify_clipReinit(ClipReader *reader);

View file

@ -154,6 +154,9 @@ namespace {
bool onErrorDefault(mtpRequestId requestId, const RPCError &error) {
const QString &err(error.type());
int32 code = error.code();
if (!mtpIsFlood(error)) {
int breakpoint = 0;
}
bool badGuestDC = (code == 400) && (err == qsl("FILE_ID_INVALID"));
QRegularExpressionMatch m;
if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) {

View file

@ -154,6 +154,7 @@ namespace {
mtpUpdateDcOptions(data.vdc_options.c_vector().v);
cSetMaxGroupCount(data.vchat_size_max.v);
cSetMaxMegaGroupCount(data.vmegagroup_size_max.v);
cSetSavedGifsLimit(data.vsaved_gifs_limit.v);
configLoadedOnce = true;
Local::writeSettings();

View file

@ -2466,6 +2466,10 @@ void _serialize_inputMessagesFilterUrl(MTPStringLogger &to, int32 stage, int32 l
to.add("{ inputMessagesFilterUrl }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputMessagesFilterGif(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputMessagesFilterGif }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_updateNewMessage(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -3039,6 +3043,10 @@ void _serialize_updateStickerSets(MTPStringLogger &to, int32 stage, int32 lev, T
to.add("{ updateStickerSets }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_updateSavedGifs(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ updateSavedGifs }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_updates_state(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -3336,7 +3344,8 @@ void _serialize_config(MTPStringLogger &to, int32 stage, int32 lev, Types &types
case 14: to.add(" chat_big_size: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 15: to.add(" push_chat_period_ms: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 16: to.add(" push_chat_limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 17: to.add(" disabled_features: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 17: to.add(" saved_gifs_limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 18: to.add(" disabled_features: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
@ -5107,6 +5116,24 @@ void _serialize_messages_foundGifs(MTPStringLogger &to, int32 stage, int32 lev,
}
}
void _serialize_messages_savedGifsNotModified(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ messages_savedGifsNotModified }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_messages_savedGifs(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ messages_savedGifs");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" gifs: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -5621,6 +5648,20 @@ void _serialize_messages_reorderStickerSets(MTPStringLogger &to, int32 stage, in
}
}
void _serialize_messages_saveGif(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ messages_saveGif");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" unsave: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_upload_saveFilePart(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -7098,6 +7139,19 @@ void _serialize_messages_searchGifs(MTPStringLogger &to, int32 stage, int32 lev,
}
}
void _serialize_messages_getSavedGifs(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ messages_getSavedGifs");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
@ -7546,6 +7600,7 @@ namespace {
_serializers.insert(mtpc_inputMessagesFilterAudio, _serialize_inputMessagesFilterAudio);
_serializers.insert(mtpc_inputMessagesFilterAudioDocuments, _serialize_inputMessagesFilterAudioDocuments);
_serializers.insert(mtpc_inputMessagesFilterUrl, _serialize_inputMessagesFilterUrl);
_serializers.insert(mtpc_inputMessagesFilterGif, _serialize_inputMessagesFilterGif);
_serializers.insert(mtpc_updateNewMessage, _serialize_updateNewMessage);
_serializers.insert(mtpc_updateMessageID, _serialize_updateMessageID);
_serializers.insert(mtpc_updateDeleteMessages, _serialize_updateDeleteMessages);
@ -7586,6 +7641,7 @@ namespace {
_serializers.insert(mtpc_updateNewStickerSet, _serialize_updateNewStickerSet);
_serializers.insert(mtpc_updateStickerSetsOrder, _serialize_updateStickerSetsOrder);
_serializers.insert(mtpc_updateStickerSets, _serialize_updateStickerSets);
_serializers.insert(mtpc_updateSavedGifs, _serialize_updateSavedGifs);
_serializers.insert(mtpc_updates_state, _serialize_updates_state);
_serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty);
_serializers.insert(mtpc_updates_difference, _serialize_updates_difference);
@ -7754,6 +7810,8 @@ namespace {
_serializers.insert(mtpc_help_termsOfService, _serialize_help_termsOfService);
_serializers.insert(mtpc_foundGif, _serialize_foundGif);
_serializers.insert(mtpc_messages_foundGifs, _serialize_messages_foundGifs);
_serializers.insert(mtpc_messages_savedGifsNotModified, _serialize_messages_savedGifsNotModified);
_serializers.insert(mtpc_messages_savedGifs, _serialize_messages_savedGifs);
_serializers.insert(mtpc_req_pq, _serialize_req_pq);
_serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params);
@ -7794,6 +7852,7 @@ namespace {
_serializers.insert(mtpc_messages_uninstallStickerSet, _serialize_messages_uninstallStickerSet);
_serializers.insert(mtpc_messages_editChatAdmin, _serialize_messages_editChatAdmin);
_serializers.insert(mtpc_messages_reorderStickerSets, _serialize_messages_reorderStickerSets);
_serializers.insert(mtpc_messages_saveGif, _serialize_messages_saveGif);
_serializers.insert(mtpc_upload_saveFilePart, _serialize_upload_saveFilePart);
_serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart);
_serializers.insert(mtpc_help_saveAppLog, _serialize_help_saveAppLog);
@ -7902,6 +7961,7 @@ namespace {
_serializers.insert(mtpc_messages_getStickerSet, _serialize_messages_getStickerSet);
_serializers.insert(mtpc_messages_getDocumentByHash, _serialize_messages_getDocumentByHash);
_serializers.insert(mtpc_messages_searchGifs, _serialize_messages_searchGifs);
_serializers.insert(mtpc_messages_getSavedGifs, _serialize_messages_getSavedGifs);
_serializers.insert(mtpc_updates_getState, _serialize_updates_getState);
_serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference);
_serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference);

View file

@ -240,6 +240,7 @@ enum {
mtpc_inputMessagesFilterAudio = 0xcfc87522,
mtpc_inputMessagesFilterAudioDocuments = 0x5afbf764,
mtpc_inputMessagesFilterUrl = 0x7ef0dd87,
mtpc_inputMessagesFilterGif = 0xffc86587,
mtpc_updateNewMessage = 0x1f2b0afd,
mtpc_updateMessageID = 0x4e90bfd6,
mtpc_updateDeleteMessages = 0xa20db0e5,
@ -280,6 +281,7 @@ enum {
mtpc_updateNewStickerSet = 0x688a30aa,
mtpc_updateStickerSetsOrder = 0xf0dfb451,
mtpc_updateStickerSets = 0x43ae3dec,
mtpc_updateSavedGifs = 0x9375341e,
mtpc_updates_state = 0xa56c2a3e,
mtpc_updates_differenceEmpty = 0x5d75a138,
mtpc_updates_difference = 0xf49ca0,
@ -296,7 +298,7 @@ enum {
mtpc_photos_photo = 0x20212ca8,
mtpc_upload_file = 0x96a18d5,
mtpc_dcOption = 0x5d8c6cc,
mtpc_config = 0x6cb6e65e,
mtpc_config = 0x6bbc5f8,
mtpc_nearestDc = 0x8e1a1775,
mtpc_help_appUpdate = 0x8987f311,
mtpc_help_noAppUpdate = 0xc45a6536,
@ -448,6 +450,8 @@ enum {
mtpc_help_termsOfService = 0xf1ee3e90,
mtpc_foundGif = 0xd579cccb,
mtpc_messages_foundGifs = 0x450a1c0a,
mtpc_messages_savedGifsNotModified = 0xe8025ca2,
mtpc_messages_savedGifs = 0x2e0709a5,
mtpc_invokeAfterMsg = 0xcb9f372d,
mtpc_invokeAfterMsgs = 0x3dc4b4f0,
mtpc_initConnection = 0x69796de9,
@ -559,6 +563,8 @@ enum {
mtpc_messages_reorderStickerSets = 0x9fcfbc30,
mtpc_messages_getDocumentByHash = 0x338e2464,
mtpc_messages_searchGifs = 0xbf9a776b,
mtpc_messages_getSavedGifs = 0x83bf3d52,
mtpc_messages_saveGif = 0x327a30cb,
mtpc_updates_getState = 0xedd4882a,
mtpc_updates_getDifference = 0xa041495,
mtpc_updates_getChannelDifference = 0xbb32d7c0,
@ -1229,6 +1235,9 @@ class MTPDfoundGif;
class MTPmessages_foundGifs;
class MTPDmessages_foundGifs;
class MTPmessages_savedGifs;
class MTPDmessages_savedGifs;
// Boxed types definitions
typedef MTPBoxed<MTPresPQ> MTPResPQ;
@ -1390,6 +1399,7 @@ typedef MTPBoxed<MTPchannels_channelParticipant> MTPchannels_ChannelParticipant;
typedef MTPBoxed<MTPhelp_termsOfService> MTPhelp_TermsOfService;
typedef MTPBoxed<MTPfoundGif> MTPFoundGif;
typedef MTPBoxed<MTPmessages_foundGifs> MTPmessages_FoundGifs;
typedef MTPBoxed<MTPmessages_savedGifs> MTPmessages_SavedGifs;
// Type classes definitions
@ -5198,6 +5208,7 @@ private:
friend MTPmessagesFilter MTP_inputMessagesFilterAudio();
friend MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments();
friend MTPmessagesFilter MTP_inputMessagesFilterUrl();
friend MTPmessagesFilter MTP_inputMessagesFilterGif();
mtpTypeId _type;
};
@ -5768,6 +5779,7 @@ private:
friend MTPupdate MTP_updateNewStickerSet(const MTPmessages_StickerSet &_stickerset);
friend MTPupdate MTP_updateStickerSetsOrder(const MTPVector<MTPlong> &_order);
friend MTPupdate MTP_updateStickerSets();
friend MTPupdate MTP_updateSavedGifs();
mtpTypeId _type;
};
@ -6148,7 +6160,7 @@ public:
private:
explicit MTPconfig(MTPDconfig *_data);
friend MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, const MTPVector<MTPDisabledFeature> &_disabled_features);
friend MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, const MTPVector<MTPDisabledFeature> &_disabled_features);
};
typedef MTPBoxed<MTPconfig> MTPConfig;
@ -9013,6 +9025,44 @@ private:
};
typedef MTPBoxed<MTPmessages_foundGifs> MTPmessages_FoundGifs;
class MTPmessages_savedGifs : private mtpDataOwner {
public:
MTPmessages_savedGifs() : mtpDataOwner(0), _type(0) {
}
MTPmessages_savedGifs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) {
read(from, end, cons);
}
MTPDmessages_savedGifs &_messages_savedGifs() {
if (!data) throw mtpErrorUninitialized();
if (_type != mtpc_messages_savedGifs) throw mtpErrorWrongTypeId(_type, mtpc_messages_savedGifs);
split();
return *(MTPDmessages_savedGifs*)data;
}
const MTPDmessages_savedGifs &c_messages_savedGifs() const {
if (!data) throw mtpErrorUninitialized();
if (_type != mtpc_messages_savedGifs) throw mtpErrorWrongTypeId(_type, mtpc_messages_savedGifs);
return *(const MTPDmessages_savedGifs*)data;
}
uint32 innerLength() const;
mtpTypeId type() const;
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
void write(mtpBuffer &to) const;
typedef void ResponseType;
private:
explicit MTPmessages_savedGifs(mtpTypeId type);
explicit MTPmessages_savedGifs(MTPDmessages_savedGifs *_data);
friend MTPmessages_savedGifs MTP_messages_savedGifsNotModified();
friend MTPmessages_savedGifs MTP_messages_savedGifs(MTPint _hash, const MTPVector<MTPDocument> &_gifs);
mtpTypeId _type;
};
typedef MTPBoxed<MTPmessages_savedGifs> MTPmessages_SavedGifs;
// Type constructors with data
class MTPDresPQ : public mtpDataImpl<MTPDresPQ> {
@ -11635,7 +11685,7 @@ class MTPDconfig : public mtpDataImpl<MTPDconfig> {
public:
MTPDconfig() {
}
MTPDconfig(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) : vdate(_date), vexpires(_expires), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vmegagroup_size_max(_megagroup_size_max), vforwarded_count_max(_forwarded_count_max), vonline_update_period_ms(_online_update_period_ms), voffline_blur_timeout_ms(_offline_blur_timeout_ms), voffline_idle_timeout_ms(_offline_idle_timeout_ms), vonline_cloud_timeout_ms(_online_cloud_timeout_ms), vnotify_cloud_delay_ms(_notify_cloud_delay_ms), vnotify_default_delay_ms(_notify_default_delay_ms), vchat_big_size(_chat_big_size), vpush_chat_period_ms(_push_chat_period_ms), vpush_chat_limit(_push_chat_limit), vdisabled_features(_disabled_features) {
MTPDconfig(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) : vdate(_date), vexpires(_expires), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vmegagroup_size_max(_megagroup_size_max), vforwarded_count_max(_forwarded_count_max), vonline_update_period_ms(_online_update_period_ms), voffline_blur_timeout_ms(_offline_blur_timeout_ms), voffline_idle_timeout_ms(_offline_idle_timeout_ms), vonline_cloud_timeout_ms(_online_cloud_timeout_ms), vnotify_cloud_delay_ms(_notify_cloud_delay_ms), vnotify_default_delay_ms(_notify_default_delay_ms), vchat_big_size(_chat_big_size), vpush_chat_period_ms(_push_chat_period_ms), vpush_chat_limit(_push_chat_limit), vsaved_gifs_limit(_saved_gifs_limit), vdisabled_features(_disabled_features) {
}
MTPint vdate;
@ -11655,6 +11705,7 @@ public:
MTPint vchat_big_size;
MTPint vpush_chat_period_ms;
MTPint vpush_chat_limit;
MTPint vsaved_gifs_limit;
MTPVector<MTPDisabledFeature> vdisabled_features;
};
@ -13048,6 +13099,17 @@ public:
MTPVector<MTPFoundGif> vresults;
};
class MTPDmessages_savedGifs : public mtpDataImpl<MTPDmessages_savedGifs> {
public:
MTPDmessages_savedGifs() {
}
MTPDmessages_savedGifs(MTPint _hash, const MTPVector<MTPDocument> &_gifs) : vhash(_hash), vgifs(_gifs) {
}
MTPint vhash;
MTPVector<MTPDocument> vgifs;
};
// RPC methods
class MTPreq_pq { // RPC method 'req_pq'
@ -18085,6 +18147,87 @@ public:
}
};
class MTPmessages_getSavedGifs { // RPC method 'messages.getSavedGifs'
public:
MTPint vhash;
MTPmessages_getSavedGifs() {
}
MTPmessages_getSavedGifs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getSavedGifs) {
read(from, end, cons);
}
MTPmessages_getSavedGifs(MTPint _hash) : vhash(_hash) {
}
uint32 innerLength() const {
return vhash.innerLength();
}
mtpTypeId type() const {
return mtpc_messages_getSavedGifs;
}
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getSavedGifs) {
vhash.read(from, end);
}
void write(mtpBuffer &to) const {
vhash.write(to);
}
typedef MTPmessages_SavedGifs ResponseType;
};
class MTPmessages_GetSavedGifs : public MTPBoxed<MTPmessages_getSavedGifs> {
public:
MTPmessages_GetSavedGifs() {
}
MTPmessages_GetSavedGifs(const MTPmessages_getSavedGifs &v) : MTPBoxed<MTPmessages_getSavedGifs>(v) {
}
MTPmessages_GetSavedGifs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_getSavedGifs>(from, end, cons) {
}
MTPmessages_GetSavedGifs(MTPint _hash) : MTPBoxed<MTPmessages_getSavedGifs>(MTPmessages_getSavedGifs(_hash)) {
}
};
class MTPmessages_saveGif { // RPC method 'messages.saveGif'
public:
MTPInputDocument vid;
MTPBool vunsave;
MTPmessages_saveGif() {
}
MTPmessages_saveGif(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_saveGif) {
read(from, end, cons);
}
MTPmessages_saveGif(const MTPInputDocument &_id, MTPBool _unsave) : vid(_id), vunsave(_unsave) {
}
uint32 innerLength() const {
return vid.innerLength() + vunsave.innerLength();
}
mtpTypeId type() const {
return mtpc_messages_saveGif;
}
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_saveGif) {
vid.read(from, end);
vunsave.read(from, end);
}
void write(mtpBuffer &to) const {
vid.write(to);
vunsave.write(to);
}
typedef MTPBool ResponseType;
};
class MTPmessages_SaveGif : public MTPBoxed<MTPmessages_saveGif> {
public:
MTPmessages_SaveGif() {
}
MTPmessages_SaveGif(const MTPmessages_saveGif &v) : MTPBoxed<MTPmessages_saveGif>(v) {
}
MTPmessages_SaveGif(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_saveGif>(from, end, cons) {
}
MTPmessages_SaveGif(const MTPInputDocument &_id, MTPBool _unsave) : MTPBoxed<MTPmessages_saveGif>(MTPmessages_saveGif(_id, _unsave)) {
}
};
class MTPupdates_getState { // RPC method 'updates.getState'
public:
MTPupdates_getState() {
@ -24951,6 +25094,7 @@ inline void MTPmessagesFilter::read(const mtpPrime *&from, const mtpPrime *end,
case mtpc_inputMessagesFilterAudio: _type = cons; break;
case mtpc_inputMessagesFilterAudioDocuments: _type = cons; break;
case mtpc_inputMessagesFilterUrl: _type = cons; break;
case mtpc_inputMessagesFilterGif: _type = cons; break;
default: throw mtpErrorUnexpected(cons, "MTPmessagesFilter");
}
}
@ -24969,6 +25113,7 @@ inline MTPmessagesFilter::MTPmessagesFilter(mtpTypeId type) : _type(type) {
case mtpc_inputMessagesFilterAudio: break;
case mtpc_inputMessagesFilterAudioDocuments: break;
case mtpc_inputMessagesFilterUrl: break;
case mtpc_inputMessagesFilterGif: break;
default: throw mtpErrorBadTypeId(type, "MTPmessagesFilter");
}
}
@ -24999,6 +25144,9 @@ inline MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments() {
inline MTPmessagesFilter MTP_inputMessagesFilterUrl() {
return MTPmessagesFilter(mtpc_inputMessagesFilterUrl);
}
inline MTPmessagesFilter MTP_inputMessagesFilterGif() {
return MTPmessagesFilter(mtpc_inputMessagesFilterGif);
}
inline uint32 MTPupdate::innerLength() const {
switch (_type) {
@ -25426,6 +25574,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
v.vorder.read(from, end);
} break;
case mtpc_updateStickerSets: _type = cons; break;
case mtpc_updateSavedGifs: _type = cons; break;
default: throw mtpErrorUnexpected(cons, "MTPupdate");
}
}
@ -25693,6 +25842,7 @@ inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) {
case mtpc_updateNewStickerSet: setData(new MTPDupdateNewStickerSet()); break;
case mtpc_updateStickerSetsOrder: setData(new MTPDupdateStickerSetsOrder()); break;
case mtpc_updateStickerSets: break;
case mtpc_updateSavedGifs: break;
default: throw mtpErrorBadTypeId(type, "MTPupdate");
}
}
@ -25894,6 +26044,9 @@ inline MTPupdate MTP_updateStickerSetsOrder(const MTPVector<MTPlong> &_order) {
inline MTPupdate MTP_updateStickerSets() {
return MTPupdate(mtpc_updateStickerSets);
}
inline MTPupdate MTP_updateSavedGifs() {
return MTPupdate(mtpc_updateSavedGifs);
}
inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) {
}
@ -26419,7 +26572,7 @@ inline MTPconfig::MTPconfig() : mtpDataOwner(new MTPDconfig()) {
inline uint32 MTPconfig::innerLength() const {
const MTPDconfig &v(c_config());
return v.vdate.innerLength() + v.vexpires.innerLength() + v.vtest_mode.innerLength() + v.vthis_dc.innerLength() + v.vdc_options.innerLength() + v.vchat_size_max.innerLength() + v.vmegagroup_size_max.innerLength() + v.vforwarded_count_max.innerLength() + v.vonline_update_period_ms.innerLength() + v.voffline_blur_timeout_ms.innerLength() + v.voffline_idle_timeout_ms.innerLength() + v.vonline_cloud_timeout_ms.innerLength() + v.vnotify_cloud_delay_ms.innerLength() + v.vnotify_default_delay_ms.innerLength() + v.vchat_big_size.innerLength() + v.vpush_chat_period_ms.innerLength() + v.vpush_chat_limit.innerLength() + v.vdisabled_features.innerLength();
return v.vdate.innerLength() + v.vexpires.innerLength() + v.vtest_mode.innerLength() + v.vthis_dc.innerLength() + v.vdc_options.innerLength() + v.vchat_size_max.innerLength() + v.vmegagroup_size_max.innerLength() + v.vforwarded_count_max.innerLength() + v.vonline_update_period_ms.innerLength() + v.voffline_blur_timeout_ms.innerLength() + v.voffline_idle_timeout_ms.innerLength() + v.vonline_cloud_timeout_ms.innerLength() + v.vnotify_cloud_delay_ms.innerLength() + v.vnotify_default_delay_ms.innerLength() + v.vchat_big_size.innerLength() + v.vpush_chat_period_ms.innerLength() + v.vpush_chat_limit.innerLength() + v.vsaved_gifs_limit.innerLength() + v.vdisabled_features.innerLength();
}
inline mtpTypeId MTPconfig::type() const {
return mtpc_config;
@ -26446,6 +26599,7 @@ inline void MTPconfig::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
v.vchat_big_size.read(from, end);
v.vpush_chat_period_ms.read(from, end);
v.vpush_chat_limit.read(from, end);
v.vsaved_gifs_limit.read(from, end);
v.vdisabled_features.read(from, end);
}
inline void MTPconfig::write(mtpBuffer &to) const {
@ -26467,12 +26621,13 @@ inline void MTPconfig::write(mtpBuffer &to) const {
v.vchat_big_size.write(to);
v.vpush_chat_period_ms.write(to);
v.vpush_chat_limit.write(to);
v.vsaved_gifs_limit.write(to);
v.vdisabled_features.write(to);
}
inline MTPconfig::MTPconfig(MTPDconfig *_data) : mtpDataOwner(_data) {
}
inline MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) {
return MTPconfig(new MTPDconfig(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _disabled_features));
inline MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) {
return MTPconfig(new MTPDconfig(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _disabled_features));
}
inline MTPnearestDc::MTPnearestDc() : mtpDataOwner(new MTPDnearestDc()) {
@ -30193,6 +30348,57 @@ inline MTPmessages_foundGifs MTP_messages_foundGifs(MTPint _next_offset, const M
return MTPmessages_foundGifs(new MTPDmessages_foundGifs(_next_offset, _results));
}
inline uint32 MTPmessages_savedGifs::innerLength() const {
switch (_type) {
case mtpc_messages_savedGifs: {
const MTPDmessages_savedGifs &v(c_messages_savedGifs());
return v.vhash.innerLength() + v.vgifs.innerLength();
}
}
return 0;
}
inline mtpTypeId MTPmessages_savedGifs::type() const {
if (!_type) throw mtpErrorUninitialized();
return _type;
}
inline void MTPmessages_savedGifs::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
if (cons != _type) setData(0);
switch (cons) {
case mtpc_messages_savedGifsNotModified: _type = cons; break;
case mtpc_messages_savedGifs: _type = cons; {
if (!data) setData(new MTPDmessages_savedGifs());
MTPDmessages_savedGifs &v(_messages_savedGifs());
v.vhash.read(from, end);
v.vgifs.read(from, end);
} break;
default: throw mtpErrorUnexpected(cons, "MTPmessages_savedGifs");
}
}
inline void MTPmessages_savedGifs::write(mtpBuffer &to) const {
switch (_type) {
case mtpc_messages_savedGifs: {
const MTPDmessages_savedGifs &v(c_messages_savedGifs());
v.vhash.write(to);
v.vgifs.write(to);
} break;
}
}
inline MTPmessages_savedGifs::MTPmessages_savedGifs(mtpTypeId type) : mtpDataOwner(0), _type(type) {
switch (type) {
case mtpc_messages_savedGifsNotModified: break;
case mtpc_messages_savedGifs: setData(new MTPDmessages_savedGifs()); break;
default: throw mtpErrorBadTypeId(type, "MTPmessages_savedGifs");
}
}
inline MTPmessages_savedGifs::MTPmessages_savedGifs(MTPDmessages_savedGifs *_data) : mtpDataOwner(_data), _type(mtpc_messages_savedGifs) {
}
inline MTPmessages_savedGifs MTP_messages_savedGifsNotModified() {
return MTPmessages_savedGifs(mtpc_messages_savedGifsNotModified);
}
inline MTPmessages_savedGifs MTP_messages_savedGifs(MTPint _hash, const MTPVector<MTPDocument> &_gifs) {
return MTPmessages_savedGifs(new MTPDmessages_savedGifs(_hash, _gifs));
}
// Human-readable text serialization
#if (defined _DEBUG || defined _WITH_DEBUG)

View file

@ -357,6 +357,7 @@ inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterAudio#cfc87522 = MessagesFilter;
inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
@ -398,6 +399,7 @@ updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool versio
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
updateStickerSetsOrder#f0dfb451 order:Vector<long> = Update;
updateStickerSets#43ae3dec = Update;
updateSavedGifs#9375341e = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -422,7 +424,7 @@ upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true id:int ip_address:string port:int = DcOption;
config#6cb6e65e date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int disabled_features:Vector<DisabledFeature> = Config;
config#6bbc5f8 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int disabled_features:Vector<DisabledFeature> = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@ -641,6 +643,9 @@ foundGif#d579cccb webpage:WebPage = FoundGif;
messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs;
messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -759,6 +764,8 @@ messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer of
messages.reorderStickerSets#9fcfbc30 order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
updates.getState#edd4882a = updates.State;
updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference;

View file

@ -345,7 +345,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32
}
}
void OverviewInner::redrawItem(MsgId itemId, int32 itemIndex) {
void OverviewInner::repaintItem(MsgId itemId, int32 itemIndex) {
fixItemIndex(itemIndex, itemId);
if (itemIndex >= 0) {
if (_type == OverviewPhotos || _type == OverviewVideos) {
@ -476,10 +476,10 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but
if (button != Qt::LeftButton) return;
if (textlnkDown() != textlnkOver()) {
redrawItem(App::pressedLinkItem());
repaintItem(App::pressedLinkItem());
textlnkDown(textlnkOver());
App::pressedLinkItem(App::hoveredLinkItem());
redrawItem(App::pressedLinkItem());
repaintItem(App::pressedLinkItem());
}
_dragAction = NoDrag;
@ -508,12 +508,12 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol;
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key(), -1);
repaintItem(_selected.cbegin().key(), -1);
_selected.clear();
}
_selected.insert(_dragItem, selStatus);
_dragAction = Selecting;
redrawItem(_dragItem, _dragItemIndex);
repaintItem(_dragItem, _dragItemIndex);
_overview->updateTopBarSelection();
} else {
_dragAction = PrepareSelect;
@ -552,7 +552,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
}
}
if (textlnkDown()) {
redrawItem(App::pressedLinkItem());
repaintItem(App::pressedLinkItem());
textlnkDown(TextLinkPtr());
App::pressedLinkItem(0);
if (!textlnkOver() && _cursor != style::cur_default) {
@ -577,16 +577,16 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
} else {
_selected.erase(i);
}
redrawItem(_dragItem, _dragItemIndex);
repaintItem(_dragItem, _dragItemIndex);
} else if (_dragAction == PrepareDrag && !needClick && !_dragWasInactive && button != Qt::RightButton) {
SelectedItems::iterator i = _selected.find(_dragItem);
if (i != _selected.cend() && i.value() == FullSelection) {
_selected.erase(i);
redrawItem(_dragItem, _dragItemIndex);
repaintItem(_dragItem, _dragItemIndex);
} else if (i == _selected.cend() && itemMsgId(_dragItem) > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
if (_selected.size() < MaxSelectedItems) {
_selected.insert(_dragItem, FullSelection);
redrawItem(_dragItem, _dragItemIndex);
repaintItem(_dragItem, _dragItemIndex);
}
} else {
_selected.clear();
@ -994,7 +994,7 @@ void OverviewInner::onUpdateSelected() {
fixItemIndex(itemIndex, itemId);
if (itemIndex >= 0) {
_items.at(itemIndex)->linkOut(textlnkOver());
redrawItem(itemId, itemIndex);
repaintItem(itemId, itemIndex);
}
}
}
@ -1004,7 +1004,7 @@ void OverviewInner::onUpdateSelected() {
if (textlnkOver()) {
if (item && index >= 0) {
_items.at(index)->linkOver(textlnkOver());
redrawItem(complexMsgId(item), index);
repaintItem(complexMsgId(item), index);
}
}
} else {
@ -1012,8 +1012,8 @@ void OverviewInner::onUpdateSelected() {
}
if (_mousedItem != oldMousedItem) {
lnkChanged = true;
if (oldMousedItem) redrawItem(oldMousedItem, oldMousedItemIndex);
if (item) redrawItem(item);
if (oldMousedItem) repaintItem(oldMousedItem, oldMousedItemIndex);
if (item) repaintItem(item);
QToolTip::hideText();
}
if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) {
@ -1199,11 +1199,11 @@ void OverviewInner::enterEvent(QEvent *e) {
void OverviewInner::leaveEvent(QEvent *e) {
if (_selectedMsgId) {
redrawItem(_selectedMsgId, -1);
repaintItem(_selectedMsgId, -1);
_selectedMsgId = 0;
}
if (textlnkOver()) {
redrawItem(App::hoveredLinkItem());
repaintItem(App::hoveredLinkItem());
textlnkOver(TextLinkPtr());
App::hoveredLinkItem(0);
if (!textlnkDown() && _cursor != style::cur_default) {
@ -1223,8 +1223,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (_menu) {
_menu->deleteLater();
_menu = 0;
redrawItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1);
repaintItem(App::contextItem());
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
}
if (e->reason() == QContextMenuEvent::Mouse) {
dragActionUpdate(e->globalPos());
@ -1301,8 +1301,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
}
App::contextItem(App::hoveredLinkItem());
redrawItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1);
repaintItem(App::contextItem());
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
} else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) {
_menu = new PopupMenu();
if ((_contextMenuLnk && dynamic_cast<TextLink*>(_contextMenuLnk.data()))) {
@ -1340,8 +1340,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
}
App::contextItem(App::mousedItem());
redrawItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1);
repaintItem(App::contextItem());
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
}
if (_menu) {
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
@ -1627,8 +1627,8 @@ void OverviewInner::onMenuDestroy(QObject *obj) {
if (_menu == obj) {
_menu = 0;
dragActionUpdate(QCursor::pos());
redrawItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1);
repaintItem(App::contextItem());
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
}
}
@ -1719,7 +1719,7 @@ void OverviewInner::mediaOverviewUpdated() {
allGood = false;
}
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
LayoutMediaItem *layout = getItemLayout(item);
LayoutMediaItem *layout = layoutPrepare(item);
if (!layout) continue;
setLayoutItem(index, layout, 0);
@ -1765,13 +1765,13 @@ void OverviewInner::mediaOverviewUpdated() {
allGood = false;
}
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
LayoutMediaItem *layout = getItemLayout(item);
LayoutMediaItem *layout = layoutPrepare(item);
if (!layout) continue;
if (withDates) {
QDate date = item->date.date();
if (!index || (index > 0 && (dateEveryMonth ? (date.month() != prevDate.month() || date.year() != prevDate.year()) : (date != prevDate)))) {
top += setLayoutItem(index, getDateLayout(date, dateEveryMonth), top);
top += setLayoutItem(index, layoutPrepare(date, dateEveryMonth), top);
++index;
prevDate = date;
}
@ -1851,7 +1851,7 @@ void OverviewInner::itemRemoved(HistoryItem *item) {
update();
}
void OverviewInner::redrawItem(const HistoryItem *msg) {
void OverviewInner::repaintItem(const HistoryItem *msg) {
if (!msg) return;
History *history = (msg->history() == _history) ? _history : (msg->history() == _migrated ? _migrated : 0);
@ -1921,7 +1921,7 @@ void OverviewInner::recountMargins() {
}
}
LayoutMediaItem *OverviewInner::getItemLayout(HistoryItem *item) {
LayoutMediaItem *OverviewInner::layoutPrepare(HistoryItem *item) {
if (!item) return 0;
LayoutItems::const_iterator i = _layoutItems.cend();
@ -1963,7 +1963,7 @@ LayoutMediaItem *OverviewInner::getItemLayout(HistoryItem *item) {
return (i == _layoutItems.cend()) ? 0 : i.value();
}
LayoutItem *OverviewInner::getDateLayout(const QDate &date, bool month) {
LayoutItem *OverviewInner::layoutPrepare(const QDate &date, bool month) {
int32 key = date.year() * 100 + date.month();
if (!month) key = key * 100 + date.day();
LayoutDates::const_iterator i = _layoutDates.constFind(key);
@ -2288,9 +2288,9 @@ void OverviewWidget::changingMsgId(HistoryItem *row, MsgId newId) {
}
}
void OverviewWidget::ui_redrawHistoryItem(const HistoryItem *item) {
void OverviewWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (peer() == item->history()->peer || migratePeer() == item->history()->peer) {
_inner.redrawItem(item);
_inner.repaintItem(item);
}
}

View file

@ -69,7 +69,7 @@ public:
void mediaOverviewUpdated();
void changingMsgId(HistoryItem *row, MsgId newId);
void redrawItem(const HistoryItem *msg);
void repaintItem(const HistoryItem *msg);
void itemRemoved(HistoryItem *item);
void getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const;
@ -124,7 +124,7 @@ private:
void updateDragSelection(MsgId dragSelFrom, int32 dragSelFromIndex, MsgId dragSelTo, int32 dragSelToIndex, bool dragSelecting);
void redrawItem(MsgId itemId, int32 itemIndex);
void repaintItem(MsgId itemId, int32 itemIndex);
void touchResetSpeed();
void touchUpdateSpeed();
@ -157,8 +157,8 @@ private:
LayoutItems _layoutItems;
typedef QMap<int32, LayoutOverviewDate*> LayoutDates;
LayoutDates _layoutDates;
LayoutMediaItem *getItemLayout(HistoryItem *item);
LayoutItem *getDateLayout(const QDate &date, bool month);
LayoutMediaItem *layoutPrepare(HistoryItem *item);
LayoutItem *layoutPrepare(const QDate &date, bool month);
int32 setLayoutItem(int32 index, LayoutItem *item, int32 top);
FlatInput _search;
@ -299,7 +299,7 @@ public:
resizeEvent(0);
}
void ui_redrawHistoryItem(const HistoryItem *item);
void ui_repaintHistoryItem(const HistoryItem *item);
void notify_historyItemLayoutChanged(const HistoryItem *item);

View file

@ -1832,7 +1832,9 @@ int32 ProfileWidget::lastScrollTop() const {
void ProfileWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) {
if (App::app()) App::app()->mtpPause();
// App::stopGifItems();
if (!cAutoPlayGif()) {
App::stopGifItems();
}
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
(back ? _cacheTopBarOver : _cacheTopBarUnder) = bgAnimTopBarCache;

View file

@ -108,15 +108,17 @@ RecentEmojiPack gRecentEmojis;
RecentEmojisPreload gRecentEmojisPreload;
EmojiColorVariants gEmojiVariants;
int32 gStickersHash = 0;
RecentStickerPreload gRecentStickersPreload;
RecentStickerPack gRecentStickers;
StickerSets gStickerSets;
StickerSetsOrder gStickerSetsOrder;
uint64 gLastStickersUpdate = 0;
SavedGifs gSavedGifs;
uint64 gLastSavedGifsUpdate = 0;
bool gShowingSavedGifs = false;
int32 gSavedGifsLimit = 100;
RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags;
bool gPasswordRecovered = false;
@ -174,6 +176,7 @@ ReportSpamStatuses gReportSpamStatuses;
int32 gAutoDownloadPhoto = 0; // all auto download
int32 gAutoDownloadAudio = 0;
int32 gAutoDownloadGif = 0;
bool gAutoPlayGif = true;
void settingsParseArgs(int argc, char *argv[]) {
#ifdef Q_OS_MAC

View file

@ -197,7 +197,6 @@ RecentEmojiPack &cGetRecentEmojis();
class DocumentData;
typedef QVector<DocumentData*> StickerPack;
DeclareSetting(int32, StickersHash);
typedef QList<QPair<DocumentData*, int16> > RecentStickerPackOld;
typedef QVector<QPair<uint64, ushort> > RecentStickerPreload;
@ -207,8 +206,6 @@ DeclareRefSetting(RecentStickerPack, RecentStickers);
RecentStickerPack &cGetRecentStickers();
DeclareSetting(uint64, LastStickersUpdate);
static const uint64 DefaultStickerSetId = 0; // for backward compatibility
static const uint64 CustomStickerSetId = 0xFFFFFFFFFFFFFFFFULL, RecentStickerSetId = 0xFFFFFFFFFFFFFFFEULL;
static const uint64 NoneStickerSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel
@ -224,6 +221,13 @@ typedef QMap<uint64, StickerSet> StickerSets;
DeclareRefSetting(StickerSets, StickerSets);
typedef QList<uint64> StickerSetsOrder;
DeclareRefSetting(StickerSetsOrder, StickerSetsOrder);
DeclareSetting(uint64, LastStickersUpdate);
typedef QVector<DocumentData*> SavedGifs;
DeclareRefSetting(SavedGifs, SavedGifs);
DeclareSetting(uint64, LastSavedGifsUpdate);
DeclareSetting(bool, ShowingSavedGifs);
DeclareSetting(int32, SavedGifsLimit);
typedef QList<QPair<QString, ushort> > RecentHashtagPack;
DeclareSetting(RecentHashtagPack, RecentWriteHashtags);
@ -335,5 +339,6 @@ enum DBIAutoDownloadFlags {
DeclareSetting(int32, AutoDownloadPhoto);
DeclareSetting(int32, AutoDownloadAudio);
DeclareSetting(int32, AutoDownloadGif);
DeclareSetting(bool, AutoPlayGif);
void settingsParseArgs(int argc, char *argv[]);

View file

@ -578,6 +578,10 @@ void PhotoData::automaticLoad(const HistoryItem *item) {
full->automaticLoad(item);
}
void PhotoData::automaticLoadSettingsChanged() {
full->automaticLoadSettingsChanged();
}
void PhotoData::download() {
full->loadEvenCancelled();
notifyLayoutChanged();
@ -1158,6 +1162,11 @@ void AudioData::automaticLoad(const HistoryItem *item) {
}
}
void AudioData::automaticLoadSettingsChanged() {
if (loaded() || status != FileReady || !saveToCache() || _loader != CancelledFileLoader) return;
_loader = 0;
}
void AudioData::performActionOnLoad() {
if (_actionOnLoad == ActionOnLoadNone) return;
@ -1332,6 +1341,8 @@ void DocumentOpenLink::doOpen(DocumentData *data, ActionOnLoad action) {
HistoryItem *item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : 0);
MTP::send(MTPmessages_SendMedia(MTP_int(0), item->history()->peer->input, MTP_int(0), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(data->id), MTP_long(data->access))), MTP_long(MTP::nonce<uint64>()), MTPnullMarkup));
bool playMusic = data->song() && audioPlayer() && item;
bool playAnimation = data->isAnimation() && item && item->getMedia();
const FileLocation &location(data->location(true));
@ -1556,18 +1567,27 @@ void DocumentData::automaticLoad(const HistoryItem *item) {
if (saveToCache() && _loader != CancelledFileLoader) {
if (type == StickerDocument) {
save(QString(), _actionOnLoad, _actionOnLoadMsgId);
} else if (isAnimation() && item) {
} else if (isAnimation()) {
bool loadFromCloud = false;
if (item->history()->peer->isUser()) {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate);
} else {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoGroups);
if (item) {
if (item->history()->peer->isUser()) {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate);
} else {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoGroups);
}
} else { // if load at least anywhere
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups);
}
save(QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
}
}
}
void DocumentData::automaticLoadSettingsChanged() {
if (loaded() || status != FileReady || !isAnimation() || !saveToCache() || _loader != CancelledFileLoader) return;
_loader = 0;
}
void DocumentData::performActionOnLoad() {
if (_actionOnLoad == ActionOnLoadNone) return;

View file

@ -733,6 +733,7 @@ public:
PhotoData(const PhotoId &id, const uint64 &access = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr());
void automaticLoad(const HistoryItem *item);
void automaticLoadSettingsChanged();
void download();
bool loaded() const;
@ -823,6 +824,8 @@ public:
void automaticLoad(const HistoryItem *item) {
}
void automaticLoadSettingsChanged() {
}
bool loaded(bool check = false) const;
bool loading() const;
@ -919,6 +922,7 @@ public:
AudioData(const AudioId &id, const uint64 &access = 0, int32 date = 0, const QString &mime = QString(), int32 duration = 0, int32 dc = 0, int32 size = 0);
void automaticLoad(const HistoryItem *item); // auto load voice message
void automaticLoadSettingsChanged();
bool loaded(bool check = false) const;
bool loading() const;
@ -1079,6 +1083,7 @@ public:
void setattributes(const QVector<MTPDocumentAttribute> &attributes);
void automaticLoad(const HistoryItem *item); // auto load sticker or video
void automaticLoadSettingsChanged();
bool loaded(bool check = false) const;
bool loading() const;

View file

@ -294,6 +294,9 @@ enum DataBlockId {
dbiMaxMegaGroupCount = 0x32,
dbiDownloadPath = 0x33,
dbiAutoDownload = 0x34,
dbiSavedGifsLimit = 0x35,
dbiShowingSavedGifs = 0x36,
dbiAutoPlay = 0x37,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,
@ -469,3 +472,69 @@ static int32 FullArcLength = 360 * 16;
static int32 QuarterArcLength = (FullArcLength / 4);
static int32 MinArcLength = (FullArcLength / 360);
static int32 AlmostFullArcLength = (FullArcLength - MinArcLength);
template <typename ReturnType>
class Function {
public:
virtual ReturnType call() = 0;
virtual ~Function() {
}
};
template <typename Object, typename ReturnType>
class ObjectFunction : public Function<ReturnType> {
public:
typedef ReturnType (Object::*Method)();
ObjectFunction(Object *obj, Method method) : _obj(obj), _method(method) {
}
virtual ReturnType call() {
return (_obj->*_method)();
}
private:
Object *_obj;
Method _method;
};
template <typename Object, typename ReturnType>
Function<ReturnType> *func(Object *obj, typename ReturnType (Object::*method)()) {
return new ObjectFunction<Object, ReturnType>(obj, method);
}
template <typename ReturnType, typename ArgumentType1>
class Function1 {
public:
virtual ReturnType call(ArgumentType1 arg1) = 0;
virtual ~Function1() {
}
};
template <typename Object, typename ReturnType, typename ArgumentType1>
class ObjectFunction1 : public Function1<ReturnType, ArgumentType1> {
public:
typedef ReturnType (Object::*Method)(ArgumentType1);
ObjectFunction1(Object *obj, Method method) : _obj(obj), _method(method) {
}
virtual ReturnType call(ArgumentType1 arg1) {
return (_obj->*_method)(arg1);
}
private:
Object *_obj;
Method _method;
};
template <typename Object, typename ReturnType, typename ArgumentType1>
Function1<ReturnType, ArgumentType1> *func(Object *obj, ReturnType (Object::*method)(ArgumentType1)) {
return new ObjectFunction1<Object, ReturnType, ArgumentType1>(obj, method);
}

View file

@ -647,8 +647,6 @@ void Window::sendServiceHistoryRequest() {
}
void Window::setupMain(bool anim, const MTPUser *self) {
Local::readStickers();
QPixmap bg = anim ? grabInner() : QPixmap();
clearWidgets();
main = new MainWidget(this);
@ -797,9 +795,9 @@ void Window::showDocument(DocumentData *doc, HistoryItem *item) {
_mediaView->setFocus();
}
void Window::ui_clipRedraw(ClipReader *reader) {
void Window::ui_clipRepaint(ClipReader *reader) {
if (_mediaView && !_mediaView->isHidden()) {
_mediaView->ui_clipRedraw(reader);
_mediaView->ui_clipRepaint(reader);
}
}

View file

@ -237,7 +237,7 @@ public:
return contentOverlapped(QRect(w->mapToGlobal(r.boundingRect().topLeft()), r.boundingRect().size()));
}
void ui_clipRedraw(ClipReader *reader);
void ui_clipRepaint(ClipReader *reader);
void ui_showLayer(LayeredWidget *box, ShowLayerOptions options);
bool ui_isLayerShown();
bool ui_isMediaViewShown();