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_gif" = "Automatic GIF download";
"lng_media_auto_private_chats" = "Private chats"; "lng_media_auto_private_chats" = "Private chats";
"lng_media_auto_groups" = "Groups and channels"; "lng_media_auto_groups" = "Groups and channels";
"lng_media_auto_play" = "Autoplay";
"lng_emoji_category0" = "Frequently used"; "lng_emoji_category0" = "Frequently used";
"lng_emoji_category1" = "People"; "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_stickers_gifs" = "GIFs & Stickers";
"lng_switch_emoji" = "Emoji"; "lng_switch_emoji" = "Emoji";
"lng_saved_gifs" = "Saved GIFs";
"lng_box_remove" = "Remove"; "lng_box_remove" = "Remove";
"lng_custom_stickers" = "Custom stickers"; "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_delete_file" = "Delete File";
"lng_context_close_file" = "Close File"; "lng_context_close_file" = "Close File";
"lng_context_copy_text" = "Copy Text"; "lng_context_copy_text" = "Copy Text";
"lng_context_save_gif" = "Save GIF";
"lng_context_to_msg" = "Go To Message"; "lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply"; "lng_context_reply_msg" = "Reply";
"lng_context_forward_msg" = "Forward Message"; "lng_context_forward_msg" = "Forward Message";

View file

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

View file

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

View file

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

View file

@ -35,13 +35,19 @@ class FileUploader;
#include "layout.h" #include "layout.h"
typedef QMap<HistoryItem*, NullType> HistoryItemsMap; typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
typedef QMap<PhotoData*, HistoryItemsMap> PhotoItems; typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
typedef QMap<VideoData*, HistoryItemsMap> VideoItems; typedef QHash<VideoData*, HistoryItemsMap> VideoItems;
typedef QMap<AudioData*, HistoryItemsMap> AudioItems; typedef QHash<AudioData*, HistoryItemsMap> AudioItems;
typedef QMap<DocumentData*, HistoryItemsMap> DocumentItems; typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
typedef QMap<WebPageData*, HistoryItemsMap> WebPageItems; typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
typedef QMap<int32, HistoryItemsMap> SharedContactItems; typedef QHash<int32, HistoryItemsMap> SharedContactItems;
typedef QMap<ClipReader*, HistoryItem*> GifItems; 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 { struct ReplyMarkup {
ReplyMarkup(int32 flags = 0) : flags(flags) { ReplyMarkup(int32 flags = 0) : flags(flags) {
} }
@ -79,6 +85,8 @@ namespace App {
void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true); void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true);
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &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 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 QVector<MTPMessage> &msgs, NewMessageType type);
void feedMsgs(const MTPVector<MTPMessage> &msgs, NewMessageType type); void feedMsgs(const MTPVector<MTPMessage> &msgs, NewMessageType type);
void feedInboxRead(const PeerId &peer, MsgId upTo); void feedInboxRead(const PeerId &peer, MsgId upTo);
@ -184,8 +192,10 @@ namespace App {
const QPixmap &emojiLarge(); const QPixmap &emojiLarge();
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight); const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight);
void clearHistories();
void initMedia(); void initMedia();
void deinitMedia(bool completely = true); void deinitMedia();
void playSound(); void playSound();
void checkImageCacheSize(); void checkImageCacheSize();
@ -202,18 +212,22 @@ namespace App {
void regPhotoItem(PhotoData *data, HistoryItem *item); void regPhotoItem(PhotoData *data, HistoryItem *item);
void unregPhotoItem(PhotoData *data, HistoryItem *item); void unregPhotoItem(PhotoData *data, HistoryItem *item);
const PhotoItems &photoItems(); const PhotoItems &photoItems();
const PhotosData &photosData();
void regVideoItem(VideoData *data, HistoryItem *item); void regVideoItem(VideoData *data, HistoryItem *item);
void unregVideoItem(VideoData *data, HistoryItem *item); void unregVideoItem(VideoData *data, HistoryItem *item);
const VideoItems &videoItems(); const VideoItems &videoItems();
const VideosData &videosData();
void regAudioItem(AudioData *data, HistoryItem *item); void regAudioItem(AudioData *data, HistoryItem *item);
void unregAudioItem(AudioData*data, HistoryItem *item); void unregAudioItem(AudioData*data, HistoryItem *item);
const AudioItems &audioItems(); const AudioItems &audioItems();
const AudiosData &audiosData();
void regDocumentItem(DocumentData *data, HistoryItem *item); void regDocumentItem(DocumentData *data, HistoryItem *item);
void unregDocumentItem(DocumentData *data, HistoryItem *item); void unregDocumentItem(DocumentData *data, HistoryItem *item);
const DocumentItems &documentItems(); const DocumentItems &documentItems();
const DocumentsData &documentsData();
void regWebPageItem(WebPageData *data, HistoryItem *item); void regWebPageItem(WebPageData *data, HistoryItem *item);
void unregWebPageItem(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" #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)) , _audioGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadAudio() & dbiadNoGroups))
, _gifPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadGif() & dbiadNoPrivate)) , _gifPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadGif() & dbiadNoPrivate))
, _gifGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadGif() & dbiadNoGroups)) , _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)) , _sectionHeight(st::boxTitleHeight + 2 * (st::defaultCheckbox.height + st::setLittleSkip))
, _save(this, lang(lng_connection_save), st::defaultBoxButton) , _save(this, lang(lng_connection_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) { , _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(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
@ -245,6 +246,7 @@ void AutoDownloadBox::hideAll() {
_audioGroups.hide(); _audioGroups.hide();
_gifPrivate.hide(); _gifPrivate.hide();
_gifGroups.hide(); _gifGroups.hide();
_gifPlay.hide();
_save.hide(); _save.hide();
_cancel.hide(); _cancel.hide();
@ -257,6 +259,7 @@ void AutoDownloadBox::showAll() {
_audioGroups.show(); _audioGroups.show();
_gifPrivate.show(); _gifPrivate.show();
_gifGroups.show(); _gifGroups.show();
_gifPlay.show();
_save.show(); _save.show();
_cancel.show(); _cancel.show();
@ -282,15 +285,60 @@ void AutoDownloadBox::resizeEvent(QResizeEvent *e) {
_gifPrivate.moveToLeft(st::boxTitlePosition.x(), 2 * _sectionHeight + st::boxTitleHeight + st::setLittleSkip); _gifPrivate.moveToLeft(st::boxTitlePosition.x(), 2 * _sectionHeight + st::boxTitleHeight + st::setLittleSkip);
_gifGroups.moveToLeft(st::boxTitlePosition.x(), _gifPrivate.y() + _gifPrivate.height() + 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()); _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
} }
void AutoDownloadBox::onSave() { void AutoDownloadBox::onSave() {
cSetAutoDownloadPhoto((_photoPrivate.checked() ? 0 : dbiadNoPrivate) | (_photoGroups.checked() ? 0 : dbiadNoGroups)); bool changed = false;
cSetAutoDownloadAudio((_audioPrivate.checked() ? 0 : dbiadNoPrivate) | (_audioGroups.checked() ? 0 : dbiadNoGroups)); int32 autoDownloadPhoto = (_photoPrivate.checked() ? 0 : dbiadNoPrivate) | (_photoGroups.checked() ? 0 : dbiadNoGroups);
cSetAutoDownloadGif((_gifPrivate.checked() ? 0 : dbiadNoPrivate) | (_gifGroups.checked() ? 0 : dbiadNoGroups)); if (cAutoDownloadPhoto() != autoDownloadPhoto) {
Local::writeUserSettings(); 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(); onClose();
} }

View file

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

View file

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

View file

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

View file

@ -28,6 +28,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "window.h" #include "window.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "mainwidget.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "boxes/stickersetbox.h" #include "boxes/stickersetbox.h"
@ -732,9 +733,6 @@ EmojiPanInner::EmojiPanInner() : TWidget()
_hovers[i] = QVector<float64>(_counts[i], 0); _hovers[i] = QVector<float64>(_counts[i], 0);
} }
_saveConfigTimer.setSingleShot(true);
connect(&_saveConfigTimer, SIGNAL(timeout()), this, SLOT(onSaveConfig()));
_showPickerTimer.setSingleShot(true); _showPickerTimer.setSingleShot(true);
connect(&_showPickerTimer, SIGNAL(timeout()), this, SLOT(onShowPicker())); connect(&_showPickerTimer, SIGNAL(timeout()), this, SLOT(onShowPicker()));
connect(&_picker, SIGNAL(emojiSelected(EmojiPtr)), this, SLOT(onColorSelected(EmojiPtr))); connect(&_picker, SIGNAL(emojiSelected(EmojiPtr)), this, SLOT(onColorSelected(EmojiPtr)));
@ -937,15 +935,11 @@ void EmojiPanInner::selectEmoji(EmojiPtr emoji) {
qSwap(*i, *(i - 1)); qSwap(*i, *(i - 1));
} }
} }
_saveConfigTimer.start(SaveRecentEmojisTimeout); emit saveConfigDelayed(SaveRecentEmojisTimeout);
emit selected(emoji); emit selected(emoji);
} }
void EmojiPanInner::onSaveConfig() {
Local::writeUserSettings();
}
void EmojiPanInner::onShowPicker() { void EmojiPanInner::onShowPicker() {
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift; int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) { if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
@ -1219,6 +1213,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
StickerPanInner::StickerPanInner() : TWidget() StickerPanInner::StickerPanInner() : TWidget()
, _a_selected(animation(this, &StickerPanInner::step_selected)) , _a_selected(animation(this, &StickerPanInner::step_selected))
, _top(0) , _top(0)
, _showingGifs(cShowingSavedGifs())
, _selected(-1) , _selected(-1)
, _pressedSel(-1) , _pressedSel(-1)
, _settings(this, lang(lng_stickers_you_have)) , _settings(this, lang(lng_stickers_you_have))
@ -1234,8 +1229,6 @@ StickerPanInner::StickerPanInner() : TWidget()
_previewTimer.setSingleShot(true); _previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview())); connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
refreshStickers();
} }
void StickerPanInner::setMaxHeight(int32 h) { void StickerPanInner::setMaxHeight(int32 h) {
@ -1253,11 +1246,15 @@ void StickerPanInner::setScrollTop(int top) {
int StickerPanInner::countHeight() { int StickerPanInner::countHeight() {
int result = 0, minLastH = _maxHeight - st::rbEmoji.height - st::stickerPanPadding; int result = 0, minLastH = _maxHeight - st::rbEmoji.height - st::stickerPanPadding;
for (int i = 0; i < _sets.size(); ++i) { if (_showingGifs) {
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0); result = st::emojiPanHeader + _gifRows.count() * (st::savedGifHeight + st::savedGifsSkip) - st::savedGifsSkip;
int h = st::emojiPanHeader + rows * st::stickerPanSize.height(); } else {
if (i == _sets.size() - 1 && h < minLastH) h = minLastH; for (int i = 0; i < _sets.size(); ++i) {
result += h; 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; return qMax(minLastH, result) + st::stickerPanPadding;
} }
@ -1285,8 +1282,39 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
if (r != rect()) { if (r != rect()) {
p.setClipRect(r); 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 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); int32 tocol = ceilclamp(r.x() + r.width() - st::stickerPanPadding, st::stickerPanSize.width(), 0, StickerPanPerRow);
if (rtl()) { if (rtl()) {
@ -1382,6 +1410,35 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
} }
if (_selected < 0 || _selected != pressed) return; 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()) { if (_selected >= MatrixRowShift * _sets.size()) {
return; return;
} }
@ -1416,7 +1473,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
} }
} }
if (refresh) { if (refresh) {
refreshRecent(); refreshRecentStickers();
updateSelected(); updateSelected();
update(); update();
} }
@ -1448,6 +1505,20 @@ void StickerPanInner::enterFromChildEvent(QEvent *e) {
void StickerPanInner::clearSelection(bool fast) { void StickerPanInner::clearSelection(bool fast) {
_lastMousePos = mapToGlobal(QPoint(-10, -10)); _lastMousePos = mapToGlobal(QPoint(-10, -10));
if (fast) { 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) { for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift; int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
_sets[tab].hovers[sel] = 0; _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() { void StickerPanInner::refreshStickers() {
clearSelection(true); clearSelection(true);
const StickerSets &sets(cStickerSets()); const StickerSets &sets(cStickerSets());
_sets.clear(); _sets.reserve(sets.size() + 1); _sets.clear(); _sets.reserve(sets.size() + 1);
refreshRecent(false); refreshRecentStickers(false);
for (StickerSetsOrder::const_iterator i = cStickerSetsOrder().cbegin(), e = cStickerSetsOrder().cend(); i != e; ++i) { for (StickerSetsOrder::const_iterator i = cStickerSetsOrder().cbegin(), e = cStickerSetsOrder().cend(); i != e; ++i) {
appendSet(*i); appendSet(*i);
} }
int32 h = countHeight(); if (!_showingGifs) {
if (h != height()) resize(width(), h); int32 h = countHeight();
if (h != height()) resize(width(), h);
_settings.setVisible(_sets.isEmpty());
} else {
_settings.hide();
}
_settings.setVisible(_sets.isEmpty());
emit refreshIcons(); emit refreshIcons();
updateSelected(); 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() { 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(); uint64 ms = getms();
for (int32 i = 0, l = _sets.size(), k = 0; i < l; ++i) { 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) { 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 { uint64 StickerPanInner::currentSet(int yOffset) const {
if (_showingGifs) return NoneStickerSetId;
int y, ytill = 0; int y, ytill = 0;
for (int i = 0, l = _sets.size(); i < l; ++i) { for (int i = 0, l = _sets.size(); i < l; ++i) {
int cnt = _sets.at(i).pack.size(); int cnt = _sets.at(i).pack.size();
@ -1530,6 +1731,33 @@ uint64 StickerPanInner::currentSet(int yOffset) const {
return _sets.isEmpty() ? RecentStickerSetId : _sets.back().id; 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) { void StickerPanInner::appendSet(uint64 setId) {
const StickerSets &sets(cStickerSets()); const StickerSets &sets(cStickerSets());
StickerSets::const_iterator it = sets.constFind(setId); 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)); _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(); _custom.clear();
clearSelection(true); clearSelection(true);
StickerSets::const_iterator customIt = cStickerSets().constFind(CustomStickerSetId); StickerSets::const_iterator customIt = cStickerSets().constFind(CustomStickerSetId);
@ -1580,7 +1816,7 @@ void StickerPanInner::refreshRecent(bool performResize) {
} }
} }
if (performResize) { if (performResize && !_showingGifs) {
int32 h = countHeight(); int32 h = countHeight();
if (h != height()) { if (h != height()) {
resize(width(), h); 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(); 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; int32 i = 0;
if (_sets.at(0).id == RecentStickerSetId) ++i; 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) { for (int32 l = _sets.size(); i < l; ++i) {
DocumentData *s = _sets.at(i).pack.at(0); DocumentData *s = _sets.at(i).pack.at(0);
int32 availw = st::rbEmoji.width - 2 * st::stickerIconPadding, availh = st::rbEmoji.height - 2 * st::stickerIconPadding; 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.at(i)->deleteLater();
} }
panels.clear(); 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; if (_sets.isEmpty()) return;
int y = 0; int y = 0;
@ -1637,8 +1881,9 @@ void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
} }
} }
void StickerPanInner::refreshPanels(QVector<EmojiPanel*> &panels) { void StickerPanInner::refreshPanels(QVector<EmojiPanel*> &panels) {
if (_showingGifs) return;
if (panels.size() != _sets.size()) return fillPanels(panels); if (panels.size() != _sets.size()) return fillPanels(panels);
int32 y = 0; int32 y = 0;
@ -1656,6 +1901,64 @@ void StickerPanInner::updateSelected() {
int32 selIndex = -1; int32 selIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos)); 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; int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::stickerPanPadding;
for (int c = 0, l = _sets.size(); c < l; ++c) { for (int c = 0, l = _sets.size(); c < l; ++c) {
const DisplayedSet &set(_sets.at(c)); const DisplayedSet &set(_sets.at(c));
@ -1742,7 +2045,15 @@ void StickerPanInner::onSettings() {
} }
void StickerPanInner::onPreview() { 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; int tab = (_pressedSel / MatrixRowShift), sel = _pressedSel % MatrixRowShift;
if (sel < _sets.at(tab).pack.size()) { if (sel < _sets.at(tab).pack.size()) {
Ui::showStickerPreview(_sets.at(tab).pack.at(sel)); Ui::showStickerPreview(_sets.at(tab).pack.at(sel));
@ -1765,13 +2076,40 @@ void StickerPanInner::step_selected(uint64 ms, bool timer) {
} }
toUpdate += stickerRect(tab, sel); toUpdate += stickerRect(tab, sel);
} }
if (timer)rtlupdate(toUpdate.boundingRect()); if (timer) rtlupdate(toUpdate.boundingRect());
if (_animations.isEmpty()) _a_selected.stop(); if (_animations.isEmpty()) _a_selected.stop();
} }
void StickerPanInner::showStickerSet(uint64 setId) { void StickerPanInner::showStickerSet(uint64 setId) {
clearSelection(true); 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; int32 y = 0;
for (int c = 0; c < _sets.size(); ++c) { for (int c = 0; c < _sets.size(); ++c) {
if (_sets.at(c).id == setId) break; if (_sets.at(c).id == setId) break;
@ -1780,14 +2118,19 @@ void StickerPanInner::showStickerSet(uint64 setId) {
} }
emit scrollToY(y); emit scrollToY(y);
emit scrollUpdated();
_lastMousePos = QCursor::pos(); _lastMousePos = QCursor::pos();
update(); update();
} }
EmojiPanel::EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY) : TWidget(parent), 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 , _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); resize(st::emojiPanWidth, st::emojiPanHeader);
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
@ -1815,7 +2158,7 @@ void EmojiPanel::updateText() {
availw -= st::notifyClose.icon.pxWidth() + st::emojiPanHeaderLeft; availw -= st::notifyClose.icon.pxWidth() + st::emojiPanHeaderLeft;
} }
} else { } 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); availw -= st::emojiSwitchSkip + st::emojiPanHeaderFont->width(switchText);
} }
_text = st::emojiPanHeaderFont->elided(_fullText, availw); _text = st::emojiPanHeaderFont->elided(_fullText, availw);
@ -1847,11 +2190,17 @@ void EmojiPanel::paintEvent(QPaintEvent *e) {
p.drawTextLeft(st::emojiPanHeaderLeft, st::emojiPanHeaderTop, width(), _text); p.drawTextLeft(st::emojiPanHeaderLeft, st::emojiPanHeaderTop, width(), _text);
} }
EmojiSwitchButton::EmojiSwitchButton(QWidget *parent, bool toStickers) : Button(parent), EmojiSwitchButton::EmojiSwitchButton(QWidget *parent, bool toStickers) : Button(parent)
_toStickers(toStickers), _text(lang(_toStickers ? lng_switch_stickers : lng_switch_emoji)), , _toStickers(toStickers) {
_textWidth(st::emojiPanHeaderFont->width(_text)) {
int32 w = st::emojiSwitchSkip + _textWidth + (st::emojiSwitchSkip - st::emojiSwitchImgSkip);
setCursor(style::cur_pointer); 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); 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(&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(scrollToY(int)), &s_scroll, SLOT(scrollToY(int)));
connect(&s_inner, SIGNAL(scrollUpdated()), this, SLOT(onScroll()));
connect(&e_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&e_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&s_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(&e_inner, SIGNAL(needRefreshPanels()), this, SLOT(onRefreshPanels()));
connect(&s_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) { if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged())); 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) { void EmojiPan::paintEvent(QPaintEvent *e) {
Painter p(this); 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); p.drawSpriteLeft(_iconsLeft + 7 * st::rbEmoji.width + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::stickersSettings);
if (!_icons.isEmpty()) { if (!_icons.isEmpty()) {
int32 x = _iconsLeft, i = 0, selxrel = _iconSelX.current(), selx = x + selxrel - _iconsX.current(); int32 x = _iconsLeft, i = 0, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current();
if (!_icons.at(i).sticker) { for (int32 l = _icons.size(); i < l && !_icons.at(i).sticker; ++i) {
if (selxrel > 0) { bool gifs = (_icons.at(i).setId == NoneStickerSetId);
if (_iconHovers.at(i) < 1) { if (selxrel != x) {
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::rbEmojiRecent.imageRect); p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), gifs ? st::savedGifsOver : st::rbEmojiRecent.imageRect);
}
if (_iconHovers.at(i) > 0) {
p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::rbEmojiRecent.overImageRect);
}
} }
if (selxrel < st::rbEmoji.width) { if (selxrel < x + st::rbEmoji.width && selxrel > x - st::rbEmoji.width) {
p.setOpacity(1 - (selxrel / 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(), st::rbEmojiRecent.chkImageRect); p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), gifs ? st::savedGifsActive : st::rbEmojiRecent.chkImageRect);
p.setOpacity(1); p.setOpacity(1);
} }
x += st::rbEmoji.width; x += st::rbEmoji.width;
++i;
} }
int32 skip = i;
QRect clip(x, _iconsTop, _iconsLeft + 7 * st::rbEmoji.width - x, st::rbEmoji.height); QRect clip(x, _iconsTop, _iconsLeft + 7 * st::rbEmoji.width - x, st::rbEmoji.height);
if (rtl()) clip.moveLeft(width() - x - clip.width()); if (rtl()) clip.moveLeft(width() - x - clip.width());
@ -2065,28 +2424,23 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
i += _iconsX.current() / int(st::rbEmoji.width); i += _iconsX.current() / int(st::rbEmoji.width);
x -= _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)); const StickerIcon &s(_icons.at(i));
s.sticker->thumb->load(); s.sticker->thumb->load();
QPixmap pix(s.sticker->thumb->pix(s.pixw, s.pixh)); 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); p.drawPixmapLeft(x + (st::rbEmoji.width - s.pixw) / 2, _iconsTop + (st::rbEmoji.height - s.pixh) / 2, width(), pix);
x += st::rbEmoji.width; x += st::rbEmoji.width;
p.setOpacity(1);
} }
if (rtl()) selx = width() - selx - st::rbEmoji.width; if (rtl()) selx = width() - selx - st::rbEmoji.width;
p.setOpacity(_icons.at(0).sticker ? 1. : qMax(1., selx / st::rbEmoji.width)); 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->b); 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.); float64 o_left = snap(float64(_iconsX.current()) / st::stickerIconLeft.pxWidth(), 0., 1.);
if (o_left > 0) { if (o_left > 0) {
p.setOpacity(o_left); 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.); float64 o_right = snap(float64(_iconsMax - _iconsX.current()) / st::stickerIconRight.pxWidth(), 0., 1.);
if (o_right > 0) { if (o_right > 0) {
@ -2181,7 +2535,12 @@ void EmojiPan::mouseMoveEvent(QMouseEvent *e) {
_iconsMousePos = e ? e->globalPos() : QCursor::pos(); _iconsMousePos = e ? e->globalPos() : QCursor::pos();
updateSelected(); 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()) { if ((_iconsMousePos - _iconsMouseDown).manhattanLength() >= QApplication::startDragDistance()) {
_iconsDragging = true; _iconsDragging = true;
} }
@ -2226,24 +2585,31 @@ void EmojiPan::mouseReleaseEvent(QMouseEvent *e) {
bool EmojiPan::event(QEvent *e) { bool EmojiPan::event(QEvent *e) {
if (e->type() == QEvent::TouchBegin) { 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) { } else if (e->type() == QEvent::Wheel) {
QWheelEvent *ev = static_cast<QWheelEvent*>(e); int32 skip = 0;
bool hor = (ev->angleDelta().x() != 0 || ev->orientation() == Qt::Horizontal); for (int32 i = 0, l = _icons.size(); i < l; ++i) {
bool ver = (ev->angleDelta().y() != 0 || ev->orientation() == Qt::Vertical); if (_icons.at(i).sticker) break;
if (hor) _horizontal = true; ++skip;
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()) { if (!_icons.isEmpty() && _iconOver >= skip && _iconOver < _icons.size() && _iconDown < 0) {
_iconsX = anim::ivalue(newX, newX); QWheelEvent *ev = static_cast<QWheelEvent*>(e);
_iconsStartAnim = 0; bool hor = (ev->angleDelta().x() != 0 || ev->orientation() == Qt::Horizontal);
if (_iconAnimations.isEmpty()) _a_icons.stop(); bool ver = (ev->angleDelta().y() != 0 || ev->orientation() == Qt::Vertical);
updateSelected(); if (hor) _horizontal = true;
updateIcons(); 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); 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() { void EmojiPan::onRefreshIcons() {
_iconOver = -1; _iconOver = -1;
_iconHovers.clear(); _iconHovers.clear();
@ -2284,6 +2659,7 @@ void EmojiPan::onRefreshIcons() {
} }
updatePanelsPositions(s_panels, s_scroll.scrollTop()); updatePanelsPositions(s_panels, s_scroll.scrollTop());
updateSelected(); updateSelected();
if (_stickersShown) validateSelectedIcon();
updateIcons(); updateIcons();
} }
@ -2316,16 +2692,18 @@ void EmojiPan::updateSelected() {
newOver = _icons.size(); newOver = _icons.size();
} else if (!_icons.isEmpty()) { } 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 (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) { if (x < st::rbEmoji.width) {
newOver = 0; newOver = i;
} else { break;
x -= st::rbEmoji.width;
} }
x -= st::rbEmoji.width;
++skip;
} }
if (newOver < 0) { if (newOver < 0) {
x += _iconsX.current(); 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() { void EmojiPan::hideFinish() {
hide(); hide();
e_inner.hideFinish(); e_inner.hideFinish();
s_inner.hideFinish();
_cache = _toCache = _fromCache = QPixmap(); _cache = _toCache = _fromCache = QPixmap();
_a_slide.stop(); _a_slide.stop();
_horizontal = false; _horizontal = false;
@ -2478,6 +2857,8 @@ void EmojiPan::hideFinish() {
_a_icons.stop(); _a_icons.stop();
_iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0); _iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0);
_iconAnimations.clear(); _iconAnimations.clear();
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
} }
void EmojiPan::showStart() { void EmojiPan::showStart() {
@ -2543,6 +2924,26 @@ void EmojiPan::stickersInstalled(uint64 setId) {
showStart(); 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() { void EmojiPan::showAll() {
if (_stickersShown) { if (_stickersShown) {
s_scroll.show(); s_scroll.show();
@ -2636,38 +3037,60 @@ void EmojiPan::onScroll() {
st = s_scroll.scrollTop(); st = s_scroll.scrollTop();
if (_stickersShown) { if (_stickersShown) {
updatePanelsPositions(s_panels, st); updatePanelsPositions(s_panels, st);
validateSelectedIcon(true);
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();
}
} }
s_inner.setScrollTop(st); 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() { void EmojiPan::onSwitch() {
QPixmap cache = _cache; QPixmap cache = _cache;
_fromCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding)); _fromCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
_stickersShown = !_stickersShown; _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; _iconOver = -1;
_iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0); _iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0);
_iconAnimations.clear(); _iconAnimations.clear();
_a_icons.stop(); _a_icons.stop();
validateSelectedIcon();
_cache = QPixmap(); _cache = QPixmap();
showAll(); showAll();
_toCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding)); _toCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
@ -2721,7 +3144,6 @@ void EmojiPan::onRemoveSetSure() {
cRefStickerSets().erase(it); cRefStickerSets().erase(it);
int32 removeIndex = cStickerSetsOrder().indexOf(_removingSetId); int32 removeIndex = cStickerSetsOrder().indexOf(_removingSetId);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex); if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
cSetStickersHash(stickersCountHash());
refreshStickers(); refreshStickers();
Local::writeStickers(); Local::writeStickers();
if (writeRecent) Local::writeUserSettings(); if (writeRecent) Local::writeUserSettings();
@ -3337,5 +3759,16 @@ bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
return QWidget::eventFilter(obj, 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() { MentionsDropdown::~MentionsDropdown() {
} }

View file

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

View file

@ -102,20 +102,36 @@ namespace Ui {
return false; 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()); const GifItems &items(App::gifItems());
GifItems::const_iterator it = items.constFind(reader); GifItems::const_iterator it = items.constFind(reader);
if (it != items.cend()) { if (it != items.cend()) {
if (reader->currentDisplayed()) { if (reader->currentDisplayed()) {
return; 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) { void repaintHistoryItem(const HistoryItem *item) {
if (MainWidget *m = App::main()) m->ui_redrawHistoryItem(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) { void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) {
@ -148,8 +164,8 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer);
} }
void mediaViewHidden() { void clipStopperHidden(ClipStopperType type) {
if (MainWidget *m = App::main()) m->notify_mediaViewHidden(); if (MainWidget *m = App::main()) m->notify_clipStopperHidden(type);
} }
void clipReinit(ClipReader *reader) { 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); void hideLayer(bool fast = false);
bool isLayerShown(); bool isLayerShown();
bool isMediaViewShown(); 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); void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
inline void showPeerHistory(const PeerData *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 { namespace Notify {
void userIsBotChanged(UserData *user); void userIsBotChanged(UserData *user);
@ -76,7 +84,7 @@ namespace Notify {
void migrateUpdated(PeerData *peer); void migrateUpdated(PeerData *peer);
void mediaViewHidden(); void clipStopperHidden(ClipStopperType type);
void clipReinit(ClipReader *reader); void clipReinit(ClipReader *reader);

View file

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

View file

@ -72,6 +72,8 @@ namespace anim {
_delta = 0; _delta = 0;
} }
typedef float64 Type;
private: private:
float64 _cur, _from, _delta; float64 _cur, _from, _delta;
@ -110,6 +112,8 @@ namespace anim {
_delta = 0; _delta = 0;
} }
typedef int32 Type;
private: private:
int32 _cur; int32 _cur;
@ -179,6 +183,8 @@ namespace anim {
_delta_r = _delta_g = _delta_b = _delta_a = 0; _delta_r = _delta_g = _delta_b = _delta_a = 0;
} }
typedef QColor Type;
private: private:
QColor _cur; QColor _cur;
@ -338,87 +344,129 @@ AnimationCallbacks *animation(Param param, Type *obj, typename AnimationCallback
return new AnimationCallbacksAbsoluteWithParam<Type, Param>(param, obj, method); 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 ClipReader;
class AnimationManager : public QObject { class AnimationManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
AnimationManager();
AnimationManager() : _timer(this), _iterating(false) { void start(Animation *obj);
_timer.setSingleShot(false); void stop(Animation *obj);
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();
}
}
}
}
public slots: public slots:
void timeout();
void timeout() { void clipReinit(ClipReader *reader, qint32 threadIndex);
_iterating = true; void clipRepaint(ClipReader *reader, qint32 threadIndex);
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);
private: private:
typedef QMap<Animation*, NullType> AnimatingObjects; typedef QMap<Animation*, NullType> AnimatingObjects;
AnimatingObjects _objects, _starting, _stopping; AnimatingObjects _objects, _starting, _stopping;
QTimer _timer; QTimer _timer;
bool _iterating; bool _iterating;
}; };
class FileLocation; class FileLocation;
enum ClipState { enum ClipState {
@ -460,11 +508,19 @@ private:
}; };
enum ClipReaderNotification {
ClipReaderReinit,
ClipReaderRepaint,
};
class ClipReaderPrivate; class ClipReaderPrivate;
class ClipReader { class ClipReader {
public: 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() { void setAutoplay() {
_autoplay = true; _autoplay = true;
@ -484,6 +540,9 @@ public:
bool paused() const { bool paused() const {
return _paused.get(); return _paused.get();
} }
int32 threadIndex() const {
return _threadIndex;
}
int32 width() const; int32 width() const;
int32 height() const; int32 height() const;
@ -501,6 +560,8 @@ public:
private: private:
Callback *_cb;
ClipState _state; ClipState _state;
ClipFrameRequest _request; ClipFrameRequest _request;
@ -527,7 +588,7 @@ enum ClipProcessResult {
ClipProcessError, ClipProcessError,
ClipProcessStarted, ClipProcessStarted,
ClipProcessReinit, ClipProcessReinit,
ClipProcessRedraw, ClipProcessRepaint,
ClipProcessWait, ClipProcessWait,
}; };
@ -544,14 +605,15 @@ public:
void start(ClipReader *reader); void start(ClipReader *reader);
void update(ClipReader *reader); void update(ClipReader *reader);
void stop(ClipReader *reader); void stop(ClipReader *reader);
bool carries(ClipReader *reader) const;
~ClipReadManager(); ~ClipReadManager();
signals: signals:
void processDelayed(); void processDelayed();
void reinit(ClipReader *reader); void reinit(ClipReader *reader, qint32 threadIndex);
void redraw(ClipReader *reader); void repaint(ClipReader *reader, qint32 threadIndex);
public slots: public slots:
@ -565,7 +627,7 @@ private:
QAtomicInt _loadLevel; QAtomicInt _loadLevel;
typedef QMap<ClipReader*, ClipReaderPrivate*> ReaderPointers; typedef QMap<ClipReader*, ClipReaderPrivate*> ReaderPointers;
ReaderPointers _readerPointers; ReaderPointers _readerPointers;
QMutex _readerPointersMutex; mutable QMutex _readerPointersMutex;
bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms); bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);

View file

@ -46,6 +46,8 @@ namespace {
static const uint64 RoundedCacheSkip = 0x4000000000000000LLU; static const uint64 RoundedCacheSkip = 0x4000000000000000LLU;
} }
StorageImageLocation StorageImageLocation::Null;
bool Image::isNull() const { bool Image::isNull() const {
return (this == blank()); 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) { void StorageImage::load(bool loadFirst, bool prior) {
if (loaded()) return; if (loaded()) return;

View file

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

View file

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

View file

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

View file

@ -1235,6 +1235,12 @@ protected:
_animation->radial.step(ms); _animation->radial.step(ms);
return _animation && _animation->radial.animating(); 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 float64 dataProgress() const = 0;
virtual bool dataFinished() const = 0; virtual bool dataFinished() const = 0;
@ -1812,6 +1818,12 @@ public:
return false; return false;
} }
HistoryMedia *attach() const {
return _attach;
}
~HistoryWebPage();
private: private:
WebPageData *_data; WebPageData *_data;
TextLinkPtr _openl; TextLinkPtr _openl;
@ -2175,6 +2187,13 @@ public:
return _text.adjustSelection(from, to, type); 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; void drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const;
QString notificationText() 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 // 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) , _peer(history->peer)
, _migrated(history->peer->migrateFrom() ? App::history(history->peer->migrateFrom()->id) : 0) , _migrated(history->peer->migrateFrom() ? App::history(history->peer->migrateFrom()->id) : 0)
, _history(history) , _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; if (!item || item->detached() || !_history) return;
int32 msgy = itemTop(item); int32 msgy = itemTop(item);
if (msgy >= 0) { if (msgy >= 0) {
@ -475,16 +475,16 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
if (button != Qt::LeftButton) return; if (button != Qt::LeftButton) return;
if (App::pressedItem() != App::hoveredItem()) { if (App::pressedItem() != App::hoveredItem()) {
redrawItem(App::pressedItem()); repaintItem(App::pressedItem());
App::pressedItem(App::hoveredItem()); App::pressedItem(App::hoveredItem());
redrawItem(App::pressedItem()); repaintItem(App::pressedItem());
} }
if (textlnkDown() != textlnkOver()) { if (textlnkDown() != textlnkOver()) {
redrawItem(App::pressedLinkItem()); repaintItem(App::pressedLinkItem());
textlnkDown(textlnkOver()); textlnkDown(textlnkOver());
App::pressedLinkItem(App::hoveredLinkItem()); App::pressedLinkItem(App::hoveredLinkItem());
redrawItem(App::pressedLinkItem()); repaintItem(App::pressedLinkItem());
redrawItem(App::pressedItem()); repaintItem(App::pressedItem());
} }
_dragAction = NoDrag; _dragAction = NoDrag;
@ -512,7 +512,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
uint32 selStatus = (symbol << 16) | symbol; uint32 selStatus = (symbol << 16) | symbol;
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key()); repaintItem(_selected.cbegin().key());
_selected.clear(); _selected.clear();
} }
_selected.insert(_dragItem, selStatus); _selected.insert(_dragItem, selStatus);
@ -553,12 +553,12 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; uint32 selStatus = (_dragSymbol << 16) | _dragSymbol;
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key()); repaintItem(_selected.cbegin().key());
_selected.clear(); _selected.clear();
} }
_selected.insert(_dragItem, selStatus); _selected.insert(_dragItem, selStatus);
_dragAction = Selecting; _dragAction = Selecting;
redrawItem(_dragItem); repaintItem(_dragItem);
} else { } else {
_dragAction = PrepareSelect; _dragAction = PrepareSelect;
} }
@ -717,7 +717,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
} }
} }
if (textlnkDown()) { if (textlnkDown()) {
redrawItem(App::pressedLinkItem()); repaintItem(App::pressedLinkItem());
textlnkDown(TextLinkPtr()); textlnkDown(TextLinkPtr());
App::pressedLinkItem(0); App::pressedLinkItem(0);
if (!textlnkOver() && _cursor != style::cur_default) { if (!textlnkOver() && _cursor != style::cur_default) {
@ -726,7 +726,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
} }
} }
if (App::pressedItem()) { if (App::pressedItem()) {
redrawItem(App::pressedItem()); repaintItem(App::pressedItem());
App::pressedItem(0); App::pressedItem(0);
} }
@ -750,16 +750,16 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
} else { } else {
_selected.erase(i); _selected.erase(i);
} }
redrawItem(_dragItem); repaintItem(_dragItem);
} else if (_dragAction == PrepareDrag && !_dragWasInactive && button != Qt::RightButton) { } else if (_dragAction == PrepareDrag && !_dragWasInactive && button != Qt::RightButton) {
SelectedItems::iterator i = _selected.find(_dragItem); SelectedItems::iterator i = _selected.find(_dragItem);
if (i != _selected.cend() && i.value() == FullSelection) { if (i != _selected.cend() && i.value() == FullSelection) {
_selected.erase(i); _selected.erase(i);
redrawItem(_dragItem); repaintItem(_dragItem);
} else if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { } else if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
if (_selected.size() < MaxSelectedItems) { if (_selected.size() < MaxSelectedItems) {
_selected.insert(_dragItem, FullSelection); _selected.insert(_dragItem, FullSelection);
redrawItem(_dragItem); repaintItem(_dragItem);
} }
} else { } else {
_selected.clear(); _selected.clear();
@ -804,7 +804,7 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) {
_dragAction = Selecting; _dragAction = Selecting;
uint32 selStatus = (symbol << 16) | symbol; uint32 selStatus = (symbol << 16) | symbol;
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key()); repaintItem(_selected.cbegin().key());
_selected.clear(); _selected.clear();
} }
_selected.insert(_dragItem, selStatus); _selected.insert(_dragItem, selStatus);
@ -928,15 +928,35 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
if (item && !isUponSelected && !_contextMenuLnk) { if (item && !isUponSelected && !_contextMenuLnk) {
if (HistoryMedia *media = (msg ? msg->getMedia() : 0)) { 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) { if (media->type() == MediaTypeSticker) {
DocumentData *doc = media->getDocument(); DocumentData *doc = media->getDocument();
if (doc && doc->sticker() && doc->sticker()->set.type() != mtpc_inputStickerSetEmpty) { 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(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); 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); _menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true);
} }
} }
@ -1047,23 +1067,36 @@ void HistoryInner::copyContextImage() {
} }
void HistoryInner::cancelContextDownload() { void HistoryInner::cancelContextDownload() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data()); if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) {
lnkVideo->video()->cancel(); lnkVideo->video()->cancel();
} else if (lnkAudio) { } else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
lnkAudio->audio()->cancel(); lnkAudio->audio()->cancel();
} else if (lnkDocument) { } else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
lnkDocument->document()->cancel(); lnkDocument->document()->cancel();
} else if (HistoryItem *item = App::contextItem()) {
if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) {
doc->cancel();
}
}
} }
} }
void HistoryInner::showContextInFolder() { void HistoryInner::showContextInFolder() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data()); QString already;
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data()); if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data()); already = lnkVideo->video()->already(true);
QString already = lnkVideo ? lnkVideo->video()->already(true) : (lnkAudio ? lnkAudio->audio()->already(true) : (lnkDocument ? lnkDocument->document()->already(true) : QString())); } 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); if (!already.isEmpty()) psShowInFolder(already);
} }
@ -1080,12 +1113,29 @@ void HistoryInner::openContextFile() {
} }
void HistoryInner::saveContextFile() { void HistoryInner::saveContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data()); if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data()); VideoSaveLink::doSave(lnkVideo->video(), true);
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data()); } else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
if (lnkVideo) VideoSaveLink::doSave(lnkVideo->video(), true); AudioSaveLink::doSave(lnkAudio->audio(), true);
if (lnkAudio) AudioSaveLink::doSave(lnkAudio->audio(), true); } else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
if (lnkDocument) DocumentSaveLink::doSave(lnkDocument->document(), true); 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() { void HistoryInner::copyContextText() {
@ -1345,13 +1395,13 @@ void HistoryInner::enterEvent(QEvent *e) {
void HistoryInner::leaveEvent(QEvent *e) { void HistoryInner::leaveEvent(QEvent *e) {
if (HistoryItem *item = App::hoveredItem()) { if (HistoryItem *item = App::hoveredItem()) {
redrawItem(item); repaintItem(item);
App::hoveredItem(0); App::hoveredItem(0);
} }
if (textlnkOver()) { if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) { if (HistoryItem *item = App::hoveredLinkItem()) {
item->linkOut(textlnkOver()); item->linkOut(textlnkOver());
redrawItem(item); repaintItem(item);
App::hoveredLinkItem(0); App::hoveredLinkItem(0);
} }
textlnkOver(TextLinkPtr()); textlnkOver(TextLinkPtr());
@ -1524,12 +1574,12 @@ void HistoryInner::onUpdateSelected() {
m = mapMouseToItem(point, item); m = mapMouseToItem(point, item);
if (item->hasPoint(m.x(), m.y())) { if (item->hasPoint(m.x(), m.y())) {
if (App::hoveredItem() != item) { if (App::hoveredItem() != item) {
redrawItem(App::hoveredItem()); repaintItem(App::hoveredItem());
App::hoveredItem(item); App::hoveredItem(item);
redrawItem(App::hoveredItem()); repaintItem(App::hoveredItem());
} }
} else if (App::hoveredItem()) { } else if (App::hoveredItem()) {
redrawItem(App::hoveredItem()); repaintItem(App::hoveredItem());
App::hoveredItem(0); App::hoveredItem(0);
} }
} }
@ -1557,7 +1607,7 @@ void HistoryInner::onUpdateSelected() {
if (textlnkOver()) { if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) { if (HistoryItem *item = App::hoveredLinkItem()) {
item->linkOut(textlnkOver()); item->linkOut(textlnkOver());
redrawItem(item); repaintItem(item);
} else { } else {
update(_botDescRect); update(_botDescRect);
} }
@ -1568,7 +1618,7 @@ void HistoryInner::onUpdateSelected() {
if (textlnkOver()) { if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) { if (HistoryItem *item = App::hoveredLinkItem()) {
item->linkOver(textlnkOver()); item->linkOver(textlnkOver());
redrawItem(item); repaintItem(item);
} else { } else {
update(_botDescRect); update(_botDescRect);
} }
@ -1610,7 +1660,7 @@ void HistoryInner::onUpdateSelected() {
uint32 selState = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType); uint32 selState = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType);
if (_selected[_dragItem] != selState) { if (_selected[_dragItem] != selState) {
_selected[_dragItem] = selState; _selected[_dragItem] = selState;
Ui::redrawHistoryItem(_dragItem); repaintItem(_dragItem);
} }
if (!_wasSelectedText && (selState == FullSelection || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) { if (!_wasSelectedText && (selState == FullSelection || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) {
_wasSelectedText = true; _wasSelectedText = true;
@ -2561,6 +2611,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _replyForwardPressed(false) , _replyForwardPressed(false)
, _replyReturn(0) , _replyReturn(0)
, _stickersUpdateRequest(0) , _stickersUpdateRequest(0)
, _savedGifsUpdateRequest(0)
, _peer(0) , _peer(0)
, _clearPeer(0) , _clearPeer(0)
, _channel(NoChannel) , _channel(NoChannel)
@ -2744,7 +2795,11 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
void HistoryWidget::start() { void HistoryWidget::start() {
connect(App::main(), SIGNAL(stickersUpdated()), &_emojiPan, SLOT(refreshStickers())); connect(App::main(), SIGNAL(stickersUpdated()), &_emojiPan, SLOT(refreshStickers()));
connect(App::main(), SIGNAL(savedGifsUpdated()), &_emojiPan, SLOT(refreshSavedGifs()));
updateRecentStickers(); updateRecentStickers();
if (App::main()) emit App::main()->savedGifsUpdated();
connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*))); connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*)));
} }
@ -2948,11 +3003,16 @@ void HistoryWidget::onRecordUpdate(qint16 level, qint32 samples) {
} }
void HistoryWidget::updateStickers() { void HistoryWidget::updateStickers() {
if (cLastStickersUpdate() && getms(true) < cLastStickersUpdate() + StickersUpdateTimeout) return; if (!cLastStickersUpdate() || getms(true) >= cLastStickersUpdate() + StickersUpdateTimeout) {
if (_stickersUpdateRequest) return; if (!_stickersUpdateRequest) {
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true))), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed));
cSetStickersHash(stickersCountHash(true)); }
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(cStickersHash())), 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) { 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(); if (_list) _list->update();
} }
@ -3062,10 +3122,8 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
} }
} }
int32 countedHash = stickersCountHash(); if (Local::countStickersHash() != d.vhash.v) {
cSetStickersHash(countedHash); LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countStickersHash()));
if (countedHash != d.vhash.v) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(countedHash));
} }
if (!setsToRequest.isEmpty() && App::api()) { if (!setsToRequest.isEmpty() && App::api()) {
@ -3091,6 +3149,61 @@ bool HistoryWidget::stickersFailed(const RPCError &error) {
return true; 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() { void HistoryWidget::clearReplyReturns() {
_replyReturns.clear(); _replyReturns.clear();
_replyReturn = 0; _replyReturn = 0;
@ -3232,7 +3345,9 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
} }
} }
// App::stopGifItems(); if (!cAutoPlayGif()) {
App::stopGifItems();
}
clearReplyReturns(); clearReplyReturns();
clearAllLoadRequests(); clearAllLoadRequests();
@ -5448,7 +5563,7 @@ void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
if (!item->fromChannel()) { if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadPhoto, 0); updateSendAction(item->history(), SendActionUploadPhoto, 0);
} }
Ui::redrawHistoryItem(item); Ui::repaintHistoryItem(item);
} }
} }
@ -5460,7 +5575,7 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
if (!item->fromChannel()) { if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadFile, doc ? doc->uploadOffset : 0); 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()) { if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadAudio, audio ? audio->uploadOffset : 0); 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()) { if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadPhoto, -1); updateSendAction(item->history(), SendActionUploadPhoto, -1);
} }
// Ui::redrawHistoryItem(item); // Ui::repaintHistoryItem(item);
} }
} }
@ -5493,7 +5608,7 @@ void HistoryWidget::onDocumentFailed(const FullMsgId &newId) {
if (!item->fromChannel()) { if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadFile, -1); updateSendAction(item->history(), SendActionUploadFile, -1);
} }
Ui::redrawHistoryItem(item); Ui::repaintHistoryItem(item);
} }
} }
@ -5504,7 +5619,7 @@ void HistoryWidget::onAudioFailed(const FullMsgId &newId) {
if (!item->fromChannel()) { if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadAudio, -1); updateSendAction(item->history(), SendActionUploadAudio, -1);
} }
Ui::redrawHistoryItem(item); Ui::repaintHistoryItem(item);
} }
} }
@ -5602,12 +5717,24 @@ bool HistoryWidget::isItemVisible(HistoryItem *item) {
return true; 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))) { 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) { void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
if (_peer && _list && (item == App::mousedItem() || item == App::hoveredItem() || item == App::hoveredLinkItem())) { if (_peer && _list && (item == App::mousedItem() || item == App::hoveredItem() || item == App::hoveredLinkItem())) {
_list->onUpdateSelected(); _list->onUpdateSelected();
@ -6527,7 +6654,7 @@ void HistoryWidget::onAnimActiveStep() {
if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) { if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) {
stopAnimActive(); stopAnimActive();
} else { } else {
Ui::redrawHistoryItem(item); Ui::repaintHistoryItem(item);
} }
} }

View file

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

View file

@ -195,6 +195,7 @@ StickerPreviewWidget::StickerPreviewWidget(QWidget *parent) : TWidget(parent)
, a_shown(0, 0) , a_shown(0, 0)
, _a_shown(animation(this, &StickerPreviewWidget::step_shown)) , _a_shown(animation(this, &StickerPreviewWidget::step_shown))
, _doc(0) , _doc(0)
, _gif(0)
, _cacheStatus(CacheNotLoaded) { , _cacheStatus(CacheNotLoaded) {
setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TransparentForMouseEvents);
} }
@ -232,7 +233,7 @@ void StickerPreviewWidget::step_shown(float64 ms, bool timer) {
} }
void StickerPreviewWidget::showPreview(DocumentData *sticker) { void StickerPreviewWidget::showPreview(DocumentData *sticker) {
if (sticker && !sticker->sticker()) sticker = 0; if (sticker && !sticker->isAnimation() && !sticker->sticker()) sticker = 0;
if (sticker) { if (sticker) {
_cache = QPixmap(); _cache = QPixmap();
if (isHidden() || _a_shown.animating()) { if (isHidden() || _a_shown.animating()) {
@ -245,10 +246,17 @@ void StickerPreviewWidget::showPreview(DocumentData *sticker) {
} else if (isHidden()) { } else if (isHidden()) {
return; return;
} else { } else {
if (_gif) _cache = currentImage();
a_shown.start(0); a_shown.start(0);
_a_shown.start(); _a_shown.start();
} }
_doc = sticker; _doc = sticker;
if (_gif) {
if (gif()) {
delete _gif;
}
_gif = 0;
}
_cacheStatus = CacheNotLoaded; _cacheStatus = CacheNotLoaded;
} }
@ -259,7 +267,10 @@ void StickerPreviewWidget::hidePreview() {
QSize StickerPreviewWidget::currentDimensions() const { QSize StickerPreviewWidget::currentDimensions() const {
if (!_doc) return QSize(_cache.width() / cIntRetinaFactor(), _cache.height() / cIntRetinaFactor()); 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) { if (result.width() > st::maxStickerSize) {
result.setHeight(qMax(qRound((st::maxStickerSize * result.height()) / result.width()), 1)); result.setHeight(qMax(qRound((st::maxStickerSize * result.height()) / result.width()), 1));
result.setWidth(st::maxStickerSize); result.setWidth(st::maxStickerSize);
@ -272,22 +283,64 @@ QSize StickerPreviewWidget::currentDimensions() const {
} }
QPixmap StickerPreviewWidget::currentImage() const { QPixmap StickerPreviewWidget::currentImage() const {
if (_doc && _cacheStatus != CacheLoaded) { if (_doc) {
_doc->checkSticker(); if (_doc->sticker()) {
if (_doc->sticker()->img->isNull()) { if (_cacheStatus != CacheLoaded) {
if (_cacheStatus != CacheThumbLoaded) { _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(); QSize s = currentDimensions();
_cache = _doc->thumb->pixBlurred(s.width(), s.height()); _cache = _doc->thumb->pixBlurred(s.width(), s.height());
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} }
} else {
QSize s = currentDimensions();
_cache = _doc->sticker()->img->pix(s.width(), s.height());
_cacheStatus = CacheLoaded;
} }
} }
return _cache; 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() { StickerPreviewWidget::~StickerPreviewWidget() {
} }

View file

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

View file

@ -227,21 +227,22 @@ void LayoutRadialProgressItem::step_iconOver(float64 ms, bool timer) {
if (dt >= 1) { if (dt >= 1) {
a_iconOver.finish(); a_iconOver.finish();
_a_iconOver.stop(); _a_iconOver.stop();
} else { } else if (!timer) {
a_iconOver.update(dt, anim::linear); a_iconOver.update(dt, anim::linear);
} }
if (timer && iconAnimated()) { if (timer && iconAnimated()) {
Ui::redrawHistoryItem(_parent); Ui::repaintHistoryItem(_parent);
} }
} }
void LayoutRadialProgressItem::step_radial(uint64 ms, bool timer) { void LayoutRadialProgressItem::step_radial(uint64 ms, bool timer) {
_radial->update(dataProgress(), dataFinished(), ms);
if (!_radial->animating()) {
checkRadialFinished();
}
if (timer) { 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) { if (selected) {
p.setBrush(st::msgFileInBgSelected); p.setBrush(st::msgFileInBgSelected);
} else if (_a_iconOver.animating()) { } else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current(); float64 over = a_iconOver.current();
p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over));
} else { } else {
@ -787,6 +789,7 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
if (selected) { if (selected) {
p.setBrush(st::msgFileInBgSelected); p.setBrush(st::msgFileInBgSelected);
} else if (_a_iconOver.animating()) { } else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current(); float64 over = a_iconOver.current();
p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over));
} else { } else {
@ -1280,3 +1283,230 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text)
, width(st::normalFont->width(text)) , width(st::normalFont->width(text))
, lnk(linkFromUrl(url)) { , 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; 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 lskStickers = 0x0b, // no data
lskSavedPeers = 0x0c, // no data lskSavedPeers = 0x0c, // no data
lskReportSpamStatuses = 0x0d, // no data lskReportSpamStatuses = 0x0d, // no data
lskSavedGifs = 0x0e,
}; };
typedef QMap<PeerId, FileKey> DraftsMap; typedef QMap<PeerId, FileKey> DraftsMap;
@ -568,7 +569,7 @@ namespace {
FileLocationAliases _fileLocationAliases; FileLocationAliases _fileLocationAliases;
FileKey _locationsKey = 0, _reportSpamStatusesKey = 0; FileKey _locationsKey = 0, _reportSpamStatusesKey = 0;
FileKey _recentStickersKeyOld = 0, _stickersKey = 0; FileKey _recentStickersKeyOld = 0, _stickersKey = 0, _savedGifsKey;
FileKey _backgroundKey = 0; FileKey _backgroundKey = 0;
bool _backgroundWasRead = false; bool _backgroundWasRead = false;
@ -797,6 +798,14 @@ namespace {
cSetMaxGroupCount(maxSize); cSetMaxGroupCount(maxSize);
} break; } break;
case dbiSavedGifsLimit: {
qint32 limit;
stream >> limit;
if (!_checkStreamStatus(stream)) return false;
cSetSavedGifsLimit(limit);
} break;
case dbiMaxMegaGroupCount: { case dbiMaxMegaGroupCount: {
qint32 maxSize; qint32 maxSize;
stream >> maxSize; stream >> maxSize;
@ -873,6 +882,14 @@ namespace {
cSetAutoDownloadGif(gif); cSetAutoDownloadGif(gif);
} break; } break;
case dbiAutoPlay: {
qint32 gif;
stream >> gif;
if (!_checkStreamStatus(stream)) return false;
cSetAutoPlayGif(gif == 1);
} break;
case dbiIncludeMuted: { case dbiIncludeMuted: {
qint32 v; qint32 v;
stream >> v; stream >> v;
@ -881,6 +898,14 @@ namespace {
cSetIncludeMuted(v == 1); cSetIncludeMuted(v == 1);
} break; } break;
case dbiShowingSavedGifs: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetShowingSavedGifs(v == 1);
} break;
case dbiDesktopNotify: { case dbiDesktopNotify: {
qint32 v; qint32 v;
stream >> v; stream >> v;
@ -1438,7 +1463,7 @@ namespace {
_writeMap(WriteMapFast); _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) + _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) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64)); 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(dbiDefaultAttach) << qint32(cDefaultAttach());
data.stream << quint32(dbiSoundNotify) << qint32(cSoundNotify()); data.stream << quint32(dbiSoundNotify) << qint32(cSoundNotify());
data.stream << quint32(dbiIncludeMuted) << qint32(cIncludeMuted()); data.stream << quint32(dbiIncludeMuted) << qint32(cIncludeMuted());
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
data.stream << quint32(dbiDesktopNotify) << qint32(cDesktopNotify()); data.stream << quint32(dbiDesktopNotify) << qint32(cDesktopNotify());
data.stream << quint32(dbiNotifyView) << qint32(cNotifyView()); data.stream << quint32(dbiNotifyView) << qint32(cNotifyView());
data.stream << quint32(dbiWindowsNotifications) << qint32(cWindowsNotifications()); data.stream << quint32(dbiWindowsNotifications) << qint32(cWindowsNotifications());
@ -1463,6 +1489,7 @@ namespace {
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath(); data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
data.stream << quint32(dbiSongVolume) << qint32(qRound(cSongVolume() * 1e6)); data.stream << quint32(dbiSongVolume) << qint32(qRound(cSongVolume() * 1e6));
data.stream << quint32(dbiAutoDownload) << qint32(cAutoDownloadPhoto()) << qint32(cAutoDownloadAudio()) << qint32(cAutoDownloadGif()); data.stream << quint32(dbiAutoDownload) << qint32(cAutoDownloadPhoto()) << qint32(cAutoDownloadAudio()) << qint32(cAutoDownloadGif());
data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0);
{ {
RecentEmojisPreload v(cRecentEmojisPreload()); RecentEmojisPreload v(cRecentEmojisPreload());
@ -1608,7 +1635,9 @@ namespace {
DraftsNotReadMap draftsNotReadMap; DraftsNotReadMap draftsNotReadMap;
StorageMap imagesMap, stickerImagesMap, audiosMap; StorageMap imagesMap, stickerImagesMap, audiosMap;
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; 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()) { while (!map.stream.atEnd()) {
quint32 keyType; quint32 keyType;
map.stream >> keyType; map.stream >> keyType;
@ -1691,6 +1720,9 @@ namespace {
case lskStickers: { case lskStickers: {
map.stream >> stickersKey; map.stream >> stickersKey;
} break; } break;
case lskSavedGifs: {
map.stream >> savedGifsKey;
} break;
case lskSavedPeers: { case lskSavedPeers: {
map.stream >> savedPeersKey; map.stream >> savedPeersKey;
} break; } break;
@ -1718,6 +1750,7 @@ namespace {
_reportSpamStatusesKey = reportSpamStatusesKey; _reportSpamStatusesKey = reportSpamStatusesKey;
_recentStickersKeyOld = recentStickersKeyOld; _recentStickersKeyOld = recentStickersKeyOld;
_stickersKey = stickersKey; _stickersKey = stickersKey;
_savedGifsKey = savedGifsKey;
_savedPeersKey = savedPeersKey; _savedPeersKey = savedPeersKey;
_backgroundKey = backgroundKey; _backgroundKey = backgroundKey;
_userSettingsKey = userSettingsKey; _userSettingsKey = userSettingsKey;
@ -1790,6 +1823,7 @@ namespace {
if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64); if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64);
if (_stickersKey) 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 (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
@ -1837,6 +1871,9 @@ namespace {
if (_stickersKey) { if (_stickersKey) {
mapData.stream << quint32(lskStickers) << quint64(_stickersKey); mapData.stream << quint32(lskStickers) << quint64(_stickersKey);
} }
if (_savedGifsKey) {
mapData.stream << quint32(lskSavedGifs) << quint64(_savedGifsKey);
}
if (_savedPeersKey) { if (_savedPeersKey) {
mapData.stream << quint32(lskSavedPeers) << quint64(_savedPeersKey); mapData.stream << quint32(lskSavedPeers) << quint64(_savedPeersKey);
} }
@ -2040,7 +2077,7 @@ namespace Local {
cSetDcOptions(dcOpts); 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) { for (mtpDcOptions::const_iterator i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32); size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
size += sizeof(quint32) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size())); size += sizeof(quint32) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
@ -2058,6 +2095,7 @@ namespace Local {
EncryptedDescriptor data(size); EncryptedDescriptor data(size);
data.stream << quint32(dbiMaxGroupCount) << qint32(cMaxGroupCount()); data.stream << quint32(dbiMaxGroupCount) << qint32(cMaxGroupCount());
data.stream << quint32(dbiMaxMegaGroupCount) << qint32(cMaxMegaGroupCount()); data.stream << quint32(dbiMaxMegaGroupCount) << qint32(cMaxMegaGroupCount());
data.stream << quint32(dbiSavedGifsLimit) << qint32(cSavedGifsLimit());
data.stream << quint32(dbiAutoStart) << qint32(cAutoStart()); data.stream << quint32(dbiAutoStart) << qint32(cAutoStart());
data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized()); data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized());
data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu()); data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu());
@ -2111,7 +2149,9 @@ namespace Local {
_stickerImagesMap.clear(); _stickerImagesMap.clear();
_audiosMap.clear(); _audiosMap.clear();
_storageImagesSize = _storageStickersSize = _storageAudiosSize = 0; _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; _oldMapVersion = _oldSettingsVersion = 0;
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapNow); _writeMap(WriteMapNow);
@ -2667,7 +2707,7 @@ namespace Local {
_writeMap(); _writeMap();
} else { } else {
int32 setsCount = 0; int32 setsCount = 0;
QByteArray hashToWrite = (qsl("%d:") + QString::number(cStickersHash())).toUtf8(); QByteArray hashToWrite;
quint32 size = sizeof(quint32) + _bytearraySize(hashToWrite); quint32 size = sizeof(quint32) + _bytearraySize(hashToWrite);
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) { for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
bool notLoaded = (i->flags & MTPDstickerSet_flag_NOT_LOADED); bool notLoaded = (i->flags & MTPDstickerSet_flag_NOT_LOADED);
@ -2729,8 +2769,6 @@ namespace Local {
RecentStickerPack &recent(cRefRecentStickers()); RecentStickerPack &recent(cRefRecentStickers());
recent.clear(); 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 &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()); 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; quint32 cnt;
QByteArray hash; QByteArray hash;
stickers.stream >> cnt >> hash; stickers.stream >> cnt >> hash; // ignore hash, it is counted
if (stickers.version < 8019) { if (stickers.version < 8019) { // bad data in old caches
hash.clear(); // bad data in old caches
cnt += 2; // try to read at least something cnt += 2; // try to read at least something
} }
for (uint32 i = 0; i < cnt; ++i) { for (uint32 i = 0; i < cnt; ++i) {
@ -2886,11 +2923,124 @@ namespace Local {
++set.count; ++set.count;
} }
} }
}
if (hash.startsWith(qsl("%d:").toUtf8())) { int32 countStickersHash(bool checkOfficial) {
cSetStickersHash(QString::fromUtf8(hash.mid(3)).toInt()); 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 { } 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 writeStickers();
void readStickers(); void readStickers();
int32 countStickersHash(bool checkOfficial = false);
void writeSavedGifs();
void readSavedGifs();
int32 countSavedGifsHash();
void writeBackground(int32 id, const QImage &img); void writeBackground(int32 id, const QImage &img);
bool readBackground(); bool readBackground();

View file

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

View file

@ -409,14 +409,17 @@ public:
void ui_showStickerPreview(DocumentData *sticker); void ui_showStickerPreview(DocumentData *sticker);
void ui_hideStickerPreview(); 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 ui_showPeerHistory(quint64 peer, qint32 msgId, bool back);
void notify_botCommandsChanged(UserData *bot); void notify_botCommandsChanged(UserData *bot);
void notify_userIsBotChanged(UserData *bot); void notify_userIsBotChanged(UserData *bot);
void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_userIsContactChanged(UserData *user, bool fromThisApp);
void notify_migrateUpdated(PeerData *peer); void notify_migrateUpdated(PeerData *peer);
void notify_mediaViewHidden(); void notify_clipStopperHidden(ClipStopperType type);
void notify_historyItemResized(const HistoryItem *row, bool scrollToIt); void notify_historyItemResized(const HistoryItem *row, bool scrollToIt);
void notify_historyItemLayoutChanged(const HistoryItem *item); void notify_historyItemLayoutChanged(const HistoryItem *item);
@ -430,6 +433,7 @@ signals:
void dialogRowReplaced(DialogRow *oldRow, DialogRow *newRow); void dialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
void dialogsUpdated(); void dialogsUpdated();
void stickersUpdated(); void stickersUpdated();
void savedGifsUpdated();
public slots: 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) { if (reader == _gif) {
update(_x, _y, _w, _h); update(_x, _y, _w, _h);
} }
@ -1960,7 +1960,7 @@ void MediaView::hide() {
QWidget::hide(); QWidget::hide();
stopGif(); stopGif();
Notify::mediaViewHidden(); Notify::clipStopperHidden(ClipStopperMediaview);
} }
void MediaView::onMenuDestroy(QObject *obj) { void MediaView::onMenuDestroy(QObject *obj) {

View file

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

View file

@ -154,6 +154,9 @@ namespace {
bool onErrorDefault(mtpRequestId requestId, const RPCError &error) { bool onErrorDefault(mtpRequestId requestId, const RPCError &error) {
const QString &err(error.type()); const QString &err(error.type());
int32 code = error.code(); int32 code = error.code();
if (!mtpIsFlood(error)) {
int breakpoint = 0;
}
bool badGuestDC = (code == 400) && (err == qsl("FILE_ID_INVALID")); bool badGuestDC = (code == 400) && (err == qsl("FILE_ID_INVALID"));
QRegularExpressionMatch m; QRegularExpressionMatch m;
if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) { 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); mtpUpdateDcOptions(data.vdc_options.c_vector().v);
cSetMaxGroupCount(data.vchat_size_max.v); cSetMaxGroupCount(data.vchat_size_max.v);
cSetMaxMegaGroupCount(data.vmegagroup_size_max.v); cSetMaxMegaGroupCount(data.vmegagroup_size_max.v);
cSetSavedGifsLimit(data.vsaved_gifs_limit.v);
configLoadedOnce = true; configLoadedOnce = true;
Local::writeSettings(); 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(); 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) { 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) { if (stage) {
to.add(",\n").addSpaces(lev); 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(); 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) { 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) { if (stage) {
to.add(",\n").addSpaces(lev); 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 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 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 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; 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) { 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) { if (stage) {
to.add(",\n").addSpaces(lev); 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) { 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) { if (stage) {
to.add(",\n").addSpaces(lev); 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) { 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(); 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_inputMessagesFilterAudio, _serialize_inputMessagesFilterAudio);
_serializers.insert(mtpc_inputMessagesFilterAudioDocuments, _serialize_inputMessagesFilterAudioDocuments); _serializers.insert(mtpc_inputMessagesFilterAudioDocuments, _serialize_inputMessagesFilterAudioDocuments);
_serializers.insert(mtpc_inputMessagesFilterUrl, _serialize_inputMessagesFilterUrl); _serializers.insert(mtpc_inputMessagesFilterUrl, _serialize_inputMessagesFilterUrl);
_serializers.insert(mtpc_inputMessagesFilterGif, _serialize_inputMessagesFilterGif);
_serializers.insert(mtpc_updateNewMessage, _serialize_updateNewMessage); _serializers.insert(mtpc_updateNewMessage, _serialize_updateNewMessage);
_serializers.insert(mtpc_updateMessageID, _serialize_updateMessageID); _serializers.insert(mtpc_updateMessageID, _serialize_updateMessageID);
_serializers.insert(mtpc_updateDeleteMessages, _serialize_updateDeleteMessages); _serializers.insert(mtpc_updateDeleteMessages, _serialize_updateDeleteMessages);
@ -7586,6 +7641,7 @@ namespace {
_serializers.insert(mtpc_updateNewStickerSet, _serialize_updateNewStickerSet); _serializers.insert(mtpc_updateNewStickerSet, _serialize_updateNewStickerSet);
_serializers.insert(mtpc_updateStickerSetsOrder, _serialize_updateStickerSetsOrder); _serializers.insert(mtpc_updateStickerSetsOrder, _serialize_updateStickerSetsOrder);
_serializers.insert(mtpc_updateStickerSets, _serialize_updateStickerSets); _serializers.insert(mtpc_updateStickerSets, _serialize_updateStickerSets);
_serializers.insert(mtpc_updateSavedGifs, _serialize_updateSavedGifs);
_serializers.insert(mtpc_updates_state, _serialize_updates_state); _serializers.insert(mtpc_updates_state, _serialize_updates_state);
_serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty); _serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty);
_serializers.insert(mtpc_updates_difference, _serialize_updates_difference); _serializers.insert(mtpc_updates_difference, _serialize_updates_difference);
@ -7754,6 +7810,8 @@ namespace {
_serializers.insert(mtpc_help_termsOfService, _serialize_help_termsOfService); _serializers.insert(mtpc_help_termsOfService, _serialize_help_termsOfService);
_serializers.insert(mtpc_foundGif, _serialize_foundGif); _serializers.insert(mtpc_foundGif, _serialize_foundGif);
_serializers.insert(mtpc_messages_foundGifs, _serialize_messages_foundGifs); _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_pq, _serialize_req_pq);
_serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); _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_uninstallStickerSet, _serialize_messages_uninstallStickerSet);
_serializers.insert(mtpc_messages_editChatAdmin, _serialize_messages_editChatAdmin); _serializers.insert(mtpc_messages_editChatAdmin, _serialize_messages_editChatAdmin);
_serializers.insert(mtpc_messages_reorderStickerSets, _serialize_messages_reorderStickerSets); _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_saveFilePart, _serialize_upload_saveFilePart);
_serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart); _serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart);
_serializers.insert(mtpc_help_saveAppLog, _serialize_help_saveAppLog); _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_getStickerSet, _serialize_messages_getStickerSet);
_serializers.insert(mtpc_messages_getDocumentByHash, _serialize_messages_getDocumentByHash); _serializers.insert(mtpc_messages_getDocumentByHash, _serialize_messages_getDocumentByHash);
_serializers.insert(mtpc_messages_searchGifs, _serialize_messages_searchGifs); _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_getState, _serialize_updates_getState);
_serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference); _serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference);
_serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference); _serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference);

View file

@ -240,6 +240,7 @@ enum {
mtpc_inputMessagesFilterAudio = 0xcfc87522, mtpc_inputMessagesFilterAudio = 0xcfc87522,
mtpc_inputMessagesFilterAudioDocuments = 0x5afbf764, mtpc_inputMessagesFilterAudioDocuments = 0x5afbf764,
mtpc_inputMessagesFilterUrl = 0x7ef0dd87, mtpc_inputMessagesFilterUrl = 0x7ef0dd87,
mtpc_inputMessagesFilterGif = 0xffc86587,
mtpc_updateNewMessage = 0x1f2b0afd, mtpc_updateNewMessage = 0x1f2b0afd,
mtpc_updateMessageID = 0x4e90bfd6, mtpc_updateMessageID = 0x4e90bfd6,
mtpc_updateDeleteMessages = 0xa20db0e5, mtpc_updateDeleteMessages = 0xa20db0e5,
@ -280,6 +281,7 @@ enum {
mtpc_updateNewStickerSet = 0x688a30aa, mtpc_updateNewStickerSet = 0x688a30aa,
mtpc_updateStickerSetsOrder = 0xf0dfb451, mtpc_updateStickerSetsOrder = 0xf0dfb451,
mtpc_updateStickerSets = 0x43ae3dec, mtpc_updateStickerSets = 0x43ae3dec,
mtpc_updateSavedGifs = 0x9375341e,
mtpc_updates_state = 0xa56c2a3e, mtpc_updates_state = 0xa56c2a3e,
mtpc_updates_differenceEmpty = 0x5d75a138, mtpc_updates_differenceEmpty = 0x5d75a138,
mtpc_updates_difference = 0xf49ca0, mtpc_updates_difference = 0xf49ca0,
@ -296,7 +298,7 @@ enum {
mtpc_photos_photo = 0x20212ca8, mtpc_photos_photo = 0x20212ca8,
mtpc_upload_file = 0x96a18d5, mtpc_upload_file = 0x96a18d5,
mtpc_dcOption = 0x5d8c6cc, mtpc_dcOption = 0x5d8c6cc,
mtpc_config = 0x6cb6e65e, mtpc_config = 0x6bbc5f8,
mtpc_nearestDc = 0x8e1a1775, mtpc_nearestDc = 0x8e1a1775,
mtpc_help_appUpdate = 0x8987f311, mtpc_help_appUpdate = 0x8987f311,
mtpc_help_noAppUpdate = 0xc45a6536, mtpc_help_noAppUpdate = 0xc45a6536,
@ -448,6 +450,8 @@ enum {
mtpc_help_termsOfService = 0xf1ee3e90, mtpc_help_termsOfService = 0xf1ee3e90,
mtpc_foundGif = 0xd579cccb, mtpc_foundGif = 0xd579cccb,
mtpc_messages_foundGifs = 0x450a1c0a, mtpc_messages_foundGifs = 0x450a1c0a,
mtpc_messages_savedGifsNotModified = 0xe8025ca2,
mtpc_messages_savedGifs = 0x2e0709a5,
mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsg = 0xcb9f372d,
mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_invokeAfterMsgs = 0x3dc4b4f0,
mtpc_initConnection = 0x69796de9, mtpc_initConnection = 0x69796de9,
@ -559,6 +563,8 @@ enum {
mtpc_messages_reorderStickerSets = 0x9fcfbc30, mtpc_messages_reorderStickerSets = 0x9fcfbc30,
mtpc_messages_getDocumentByHash = 0x338e2464, mtpc_messages_getDocumentByHash = 0x338e2464,
mtpc_messages_searchGifs = 0xbf9a776b, mtpc_messages_searchGifs = 0xbf9a776b,
mtpc_messages_getSavedGifs = 0x83bf3d52,
mtpc_messages_saveGif = 0x327a30cb,
mtpc_updates_getState = 0xedd4882a, mtpc_updates_getState = 0xedd4882a,
mtpc_updates_getDifference = 0xa041495, mtpc_updates_getDifference = 0xa041495,
mtpc_updates_getChannelDifference = 0xbb32d7c0, mtpc_updates_getChannelDifference = 0xbb32d7c0,
@ -1229,6 +1235,9 @@ class MTPDfoundGif;
class MTPmessages_foundGifs; class MTPmessages_foundGifs;
class MTPDmessages_foundGifs; class MTPDmessages_foundGifs;
class MTPmessages_savedGifs;
class MTPDmessages_savedGifs;
// Boxed types definitions // Boxed types definitions
typedef MTPBoxed<MTPresPQ> MTPResPQ; typedef MTPBoxed<MTPresPQ> MTPResPQ;
@ -1390,6 +1399,7 @@ typedef MTPBoxed<MTPchannels_channelParticipant> MTPchannels_ChannelParticipant;
typedef MTPBoxed<MTPhelp_termsOfService> MTPhelp_TermsOfService; typedef MTPBoxed<MTPhelp_termsOfService> MTPhelp_TermsOfService;
typedef MTPBoxed<MTPfoundGif> MTPFoundGif; typedef MTPBoxed<MTPfoundGif> MTPFoundGif;
typedef MTPBoxed<MTPmessages_foundGifs> MTPmessages_FoundGifs; typedef MTPBoxed<MTPmessages_foundGifs> MTPmessages_FoundGifs;
typedef MTPBoxed<MTPmessages_savedGifs> MTPmessages_SavedGifs;
// Type classes definitions // Type classes definitions
@ -5198,6 +5208,7 @@ private:
friend MTPmessagesFilter MTP_inputMessagesFilterAudio(); friend MTPmessagesFilter MTP_inputMessagesFilterAudio();
friend MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments(); friend MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments();
friend MTPmessagesFilter MTP_inputMessagesFilterUrl(); friend MTPmessagesFilter MTP_inputMessagesFilterUrl();
friend MTPmessagesFilter MTP_inputMessagesFilterGif();
mtpTypeId _type; mtpTypeId _type;
}; };
@ -5768,6 +5779,7 @@ private:
friend MTPupdate MTP_updateNewStickerSet(const MTPmessages_StickerSet &_stickerset); friend MTPupdate MTP_updateNewStickerSet(const MTPmessages_StickerSet &_stickerset);
friend MTPupdate MTP_updateStickerSetsOrder(const MTPVector<MTPlong> &_order); friend MTPupdate MTP_updateStickerSetsOrder(const MTPVector<MTPlong> &_order);
friend MTPupdate MTP_updateStickerSets(); friend MTPupdate MTP_updateStickerSets();
friend MTPupdate MTP_updateSavedGifs();
mtpTypeId _type; mtpTypeId _type;
}; };
@ -6148,7 +6160,7 @@ public:
private: private:
explicit MTPconfig(MTPDconfig *_data); 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; typedef MTPBoxed<MTPconfig> MTPConfig;
@ -9013,6 +9025,44 @@ private:
}; };
typedef MTPBoxed<MTPmessages_foundGifs> MTPmessages_FoundGifs; 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 // Type constructors with data
class MTPDresPQ : public mtpDataImpl<MTPDresPQ> { class MTPDresPQ : public mtpDataImpl<MTPDresPQ> {
@ -11635,7 +11685,7 @@ class MTPDconfig : public mtpDataImpl<MTPDconfig> {
public: public:
MTPDconfig() { 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; MTPint vdate;
@ -11655,6 +11705,7 @@ public:
MTPint vchat_big_size; MTPint vchat_big_size;
MTPint vpush_chat_period_ms; MTPint vpush_chat_period_ms;
MTPint vpush_chat_limit; MTPint vpush_chat_limit;
MTPint vsaved_gifs_limit;
MTPVector<MTPDisabledFeature> vdisabled_features; MTPVector<MTPDisabledFeature> vdisabled_features;
}; };
@ -13048,6 +13099,17 @@ public:
MTPVector<MTPFoundGif> vresults; 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 // RPC methods
class MTPreq_pq { // RPC method 'req_pq' 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' class MTPupdates_getState { // RPC method 'updates.getState'
public: public:
MTPupdates_getState() { MTPupdates_getState() {
@ -24951,6 +25094,7 @@ inline void MTPmessagesFilter::read(const mtpPrime *&from, const mtpPrime *end,
case mtpc_inputMessagesFilterAudio: _type = cons; break; case mtpc_inputMessagesFilterAudio: _type = cons; break;
case mtpc_inputMessagesFilterAudioDocuments: _type = cons; break; case mtpc_inputMessagesFilterAudioDocuments: _type = cons; break;
case mtpc_inputMessagesFilterUrl: _type = cons; break; case mtpc_inputMessagesFilterUrl: _type = cons; break;
case mtpc_inputMessagesFilterGif: _type = cons; break;
default: throw mtpErrorUnexpected(cons, "MTPmessagesFilter"); default: throw mtpErrorUnexpected(cons, "MTPmessagesFilter");
} }
} }
@ -24969,6 +25113,7 @@ inline MTPmessagesFilter::MTPmessagesFilter(mtpTypeId type) : _type(type) {
case mtpc_inputMessagesFilterAudio: break; case mtpc_inputMessagesFilterAudio: break;
case mtpc_inputMessagesFilterAudioDocuments: break; case mtpc_inputMessagesFilterAudioDocuments: break;
case mtpc_inputMessagesFilterUrl: break; case mtpc_inputMessagesFilterUrl: break;
case mtpc_inputMessagesFilterGif: break;
default: throw mtpErrorBadTypeId(type, "MTPmessagesFilter"); default: throw mtpErrorBadTypeId(type, "MTPmessagesFilter");
} }
} }
@ -24999,6 +25144,9 @@ inline MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments() {
inline MTPmessagesFilter MTP_inputMessagesFilterUrl() { inline MTPmessagesFilter MTP_inputMessagesFilterUrl() {
return MTPmessagesFilter(mtpc_inputMessagesFilterUrl); return MTPmessagesFilter(mtpc_inputMessagesFilterUrl);
} }
inline MTPmessagesFilter MTP_inputMessagesFilterGif() {
return MTPmessagesFilter(mtpc_inputMessagesFilterGif);
}
inline uint32 MTPupdate::innerLength() const { inline uint32 MTPupdate::innerLength() const {
switch (_type) { switch (_type) {
@ -25426,6 +25574,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
v.vorder.read(from, end); v.vorder.read(from, end);
} break; } break;
case mtpc_updateStickerSets: _type = cons; break; case mtpc_updateStickerSets: _type = cons; break;
case mtpc_updateSavedGifs: _type = cons; break;
default: throw mtpErrorUnexpected(cons, "MTPupdate"); 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_updateNewStickerSet: setData(new MTPDupdateNewStickerSet()); break;
case mtpc_updateStickerSetsOrder: setData(new MTPDupdateStickerSetsOrder()); break; case mtpc_updateStickerSetsOrder: setData(new MTPDupdateStickerSetsOrder()); break;
case mtpc_updateStickerSets: break; case mtpc_updateStickerSets: break;
case mtpc_updateSavedGifs: break;
default: throw mtpErrorBadTypeId(type, "MTPupdate"); default: throw mtpErrorBadTypeId(type, "MTPupdate");
} }
} }
@ -25894,6 +26044,9 @@ inline MTPupdate MTP_updateStickerSetsOrder(const MTPVector<MTPlong> &_order) {
inline MTPupdate MTP_updateStickerSets() { inline MTPupdate MTP_updateStickerSets() {
return MTPupdate(mtpc_updateStickerSets); return MTPupdate(mtpc_updateStickerSets);
} }
inline MTPupdate MTP_updateSavedGifs() {
return MTPupdate(mtpc_updateSavedGifs);
}
inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) { inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) {
} }
@ -26419,7 +26572,7 @@ inline MTPconfig::MTPconfig() : mtpDataOwner(new MTPDconfig()) {
inline uint32 MTPconfig::innerLength() const { inline uint32 MTPconfig::innerLength() const {
const MTPDconfig &v(c_config()); 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 { inline mtpTypeId MTPconfig::type() const {
return mtpc_config; 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.vchat_big_size.read(from, end);
v.vpush_chat_period_ms.read(from, end); v.vpush_chat_period_ms.read(from, end);
v.vpush_chat_limit.read(from, end); v.vpush_chat_limit.read(from, end);
v.vsaved_gifs_limit.read(from, end);
v.vdisabled_features.read(from, end); v.vdisabled_features.read(from, end);
} }
inline void MTPconfig::write(mtpBuffer &to) const { 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.vchat_big_size.write(to);
v.vpush_chat_period_ms.write(to); v.vpush_chat_period_ms.write(to);
v.vpush_chat_limit.write(to); v.vpush_chat_limit.write(to);
v.vsaved_gifs_limit.write(to);
v.vdisabled_features.write(to); v.vdisabled_features.write(to);
} }
inline MTPconfig::MTPconfig(MTPDconfig *_data) : mtpDataOwner(_data) { 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) { 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, _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()) { 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)); 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 // Human-readable text serialization
#if (defined _DEBUG || defined _WITH_DEBUG) #if (defined _DEBUG || defined _WITH_DEBUG)

View file

@ -357,6 +357,7 @@ inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterAudio#cfc87522 = MessagesFilter; inputMessagesFilterAudio#cfc87522 = MessagesFilter;
inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter; inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = 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; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
updateStickerSetsOrder#f0dfb451 order:Vector<long> = Update; updateStickerSetsOrder#f0dfb451 order:Vector<long> = Update;
updateStickerSets#43ae3dec = Update; updateStickerSets#43ae3dec = Update;
updateSavedGifs#9375341e = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; 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; 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; 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.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--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; 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.reorderStickerSets#9fcfbc30 order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; 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.getState#edd4882a = updates.State;
updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; 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); fixItemIndex(itemIndex, itemId);
if (itemIndex >= 0) { if (itemIndex >= 0) {
if (_type == OverviewPhotos || _type == OverviewVideos) { if (_type == OverviewPhotos || _type == OverviewVideos) {
@ -476,10 +476,10 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but
if (button != Qt::LeftButton) return; if (button != Qt::LeftButton) return;
if (textlnkDown() != textlnkOver()) { if (textlnkDown() != textlnkOver()) {
redrawItem(App::pressedLinkItem()); repaintItem(App::pressedLinkItem());
textlnkDown(textlnkOver()); textlnkDown(textlnkOver());
App::pressedLinkItem(App::hoveredLinkItem()); App::pressedLinkItem(App::hoveredLinkItem());
redrawItem(App::pressedLinkItem()); repaintItem(App::pressedLinkItem());
} }
_dragAction = NoDrag; _dragAction = NoDrag;
@ -508,12 +508,12 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; uint32 selStatus = (_dragSymbol << 16) | _dragSymbol;
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
redrawItem(_selected.cbegin().key(), -1); repaintItem(_selected.cbegin().key(), -1);
_selected.clear(); _selected.clear();
} }
_selected.insert(_dragItem, selStatus); _selected.insert(_dragItem, selStatus);
_dragAction = Selecting; _dragAction = Selecting;
redrawItem(_dragItem, _dragItemIndex); repaintItem(_dragItem, _dragItemIndex);
_overview->updateTopBarSelection(); _overview->updateTopBarSelection();
} else { } else {
_dragAction = PrepareSelect; _dragAction = PrepareSelect;
@ -552,7 +552,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
} }
} }
if (textlnkDown()) { if (textlnkDown()) {
redrawItem(App::pressedLinkItem()); repaintItem(App::pressedLinkItem());
textlnkDown(TextLinkPtr()); textlnkDown(TextLinkPtr());
App::pressedLinkItem(0); App::pressedLinkItem(0);
if (!textlnkOver() && _cursor != style::cur_default) { if (!textlnkOver() && _cursor != style::cur_default) {
@ -577,16 +577,16 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
} else { } else {
_selected.erase(i); _selected.erase(i);
} }
redrawItem(_dragItem, _dragItemIndex); repaintItem(_dragItem, _dragItemIndex);
} else if (_dragAction == PrepareDrag && !needClick && !_dragWasInactive && button != Qt::RightButton) { } else if (_dragAction == PrepareDrag && !needClick && !_dragWasInactive && button != Qt::RightButton) {
SelectedItems::iterator i = _selected.find(_dragItem); SelectedItems::iterator i = _selected.find(_dragItem);
if (i != _selected.cend() && i.value() == FullSelection) { if (i != _selected.cend() && i.value() == FullSelection) {
_selected.erase(i); _selected.erase(i);
redrawItem(_dragItem, _dragItemIndex); repaintItem(_dragItem, _dragItemIndex);
} else if (i == _selected.cend() && itemMsgId(_dragItem) > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { } else if (i == _selected.cend() && itemMsgId(_dragItem) > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
if (_selected.size() < MaxSelectedItems) { if (_selected.size() < MaxSelectedItems) {
_selected.insert(_dragItem, FullSelection); _selected.insert(_dragItem, FullSelection);
redrawItem(_dragItem, _dragItemIndex); repaintItem(_dragItem, _dragItemIndex);
} }
} else { } else {
_selected.clear(); _selected.clear();
@ -994,7 +994,7 @@ void OverviewInner::onUpdateSelected() {
fixItemIndex(itemIndex, itemId); fixItemIndex(itemIndex, itemId);
if (itemIndex >= 0) { if (itemIndex >= 0) {
_items.at(itemIndex)->linkOut(textlnkOver()); _items.at(itemIndex)->linkOut(textlnkOver());
redrawItem(itemId, itemIndex); repaintItem(itemId, itemIndex);
} }
} }
} }
@ -1004,7 +1004,7 @@ void OverviewInner::onUpdateSelected() {
if (textlnkOver()) { if (textlnkOver()) {
if (item && index >= 0) { if (item && index >= 0) {
_items.at(index)->linkOver(textlnkOver()); _items.at(index)->linkOver(textlnkOver());
redrawItem(complexMsgId(item), index); repaintItem(complexMsgId(item), index);
} }
} }
} else { } else {
@ -1012,8 +1012,8 @@ void OverviewInner::onUpdateSelected() {
} }
if (_mousedItem != oldMousedItem) { if (_mousedItem != oldMousedItem) {
lnkChanged = true; lnkChanged = true;
if (oldMousedItem) redrawItem(oldMousedItem, oldMousedItemIndex); if (oldMousedItem) repaintItem(oldMousedItem, oldMousedItemIndex);
if (item) redrawItem(item); if (item) repaintItem(item);
QToolTip::hideText(); QToolTip::hideText();
} }
if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) { if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) {
@ -1199,11 +1199,11 @@ void OverviewInner::enterEvent(QEvent *e) {
void OverviewInner::leaveEvent(QEvent *e) { void OverviewInner::leaveEvent(QEvent *e) {
if (_selectedMsgId) { if (_selectedMsgId) {
redrawItem(_selectedMsgId, -1); repaintItem(_selectedMsgId, -1);
_selectedMsgId = 0; _selectedMsgId = 0;
} }
if (textlnkOver()) { if (textlnkOver()) {
redrawItem(App::hoveredLinkItem()); repaintItem(App::hoveredLinkItem());
textlnkOver(TextLinkPtr()); textlnkOver(TextLinkPtr());
App::hoveredLinkItem(0); App::hoveredLinkItem(0);
if (!textlnkDown() && _cursor != style::cur_default) { if (!textlnkDown() && _cursor != style::cur_default) {
@ -1223,8 +1223,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (_menu) { if (_menu) {
_menu->deleteLater(); _menu->deleteLater();
_menu = 0; _menu = 0;
redrawItem(App::contextItem()); repaintItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1); if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
} }
if (e->reason() == QContextMenuEvent::Mouse) { if (e->reason() == QContextMenuEvent::Mouse) {
dragActionUpdate(e->globalPos()); dragActionUpdate(e->globalPos());
@ -1301,8 +1301,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
} }
App::contextItem(App::hoveredLinkItem()); App::contextItem(App::hoveredLinkItem());
redrawItem(App::contextItem()); repaintItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1); if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
} else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) { } else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) {
_menu = new PopupMenu(); _menu = new PopupMenu();
if ((_contextMenuLnk && dynamic_cast<TextLink*>(_contextMenuLnk.data()))) { if ((_contextMenuLnk && dynamic_cast<TextLink*>(_contextMenuLnk.data()))) {
@ -1340,8 +1340,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
} }
App::contextItem(App::mousedItem()); App::contextItem(App::mousedItem());
redrawItem(App::contextItem()); repaintItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1); if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
} }
if (_menu) { if (_menu) {
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
@ -1627,8 +1627,8 @@ void OverviewInner::onMenuDestroy(QObject *obj) {
if (_menu == obj) { if (_menu == obj) {
_menu = 0; _menu = 0;
dragActionUpdate(QCursor::pos()); dragActionUpdate(QCursor::pos());
redrawItem(App::contextItem()); repaintItem(App::contextItem());
if (_selectedMsgId) redrawItem(_selectedMsgId, -1); if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
} }
} }
@ -1719,7 +1719,7 @@ void OverviewInner::mediaOverviewUpdated() {
allGood = false; allGood = false;
} }
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
LayoutMediaItem *layout = getItemLayout(item); LayoutMediaItem *layout = layoutPrepare(item);
if (!layout) continue; if (!layout) continue;
setLayoutItem(index, layout, 0); setLayoutItem(index, layout, 0);
@ -1765,13 +1765,13 @@ void OverviewInner::mediaOverviewUpdated() {
allGood = false; allGood = false;
} }
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
LayoutMediaItem *layout = getItemLayout(item); LayoutMediaItem *layout = layoutPrepare(item);
if (!layout) continue; if (!layout) continue;
if (withDates) { if (withDates) {
QDate date = item->date.date(); QDate date = item->date.date();
if (!index || (index > 0 && (dateEveryMonth ? (date.month() != prevDate.month() || date.year() != prevDate.year()) : (date != prevDate)))) { 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; ++index;
prevDate = date; prevDate = date;
} }
@ -1851,7 +1851,7 @@ void OverviewInner::itemRemoved(HistoryItem *item) {
update(); update();
} }
void OverviewInner::redrawItem(const HistoryItem *msg) { void OverviewInner::repaintItem(const HistoryItem *msg) {
if (!msg) return; if (!msg) return;
History *history = (msg->history() == _history) ? _history : (msg->history() == _migrated ? _migrated : 0); 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; if (!item) return 0;
LayoutItems::const_iterator i = _layoutItems.cend(); LayoutItems::const_iterator i = _layoutItems.cend();
@ -1963,7 +1963,7 @@ LayoutMediaItem *OverviewInner::getItemLayout(HistoryItem *item) {
return (i == _layoutItems.cend()) ? 0 : i.value(); 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(); int32 key = date.year() * 100 + date.month();
if (!month) key = key * 100 + date.day(); if (!month) key = key * 100 + date.day();
LayoutDates::const_iterator i = _layoutDates.constFind(key); 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) { 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 mediaOverviewUpdated();
void changingMsgId(HistoryItem *row, MsgId newId); void changingMsgId(HistoryItem *row, MsgId newId);
void redrawItem(const HistoryItem *msg); void repaintItem(const HistoryItem *msg);
void itemRemoved(HistoryItem *item); void itemRemoved(HistoryItem *item);
void getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const; 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 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 touchResetSpeed();
void touchUpdateSpeed(); void touchUpdateSpeed();
@ -157,8 +157,8 @@ private:
LayoutItems _layoutItems; LayoutItems _layoutItems;
typedef QMap<int32, LayoutOverviewDate*> LayoutDates; typedef QMap<int32, LayoutOverviewDate*> LayoutDates;
LayoutDates _layoutDates; LayoutDates _layoutDates;
LayoutMediaItem *getItemLayout(HistoryItem *item); LayoutMediaItem *layoutPrepare(HistoryItem *item);
LayoutItem *getDateLayout(const QDate &date, bool month); LayoutItem *layoutPrepare(const QDate &date, bool month);
int32 setLayoutItem(int32 index, LayoutItem *item, int32 top); int32 setLayoutItem(int32 index, LayoutItem *item, int32 top);
FlatInput _search; FlatInput _search;
@ -299,7 +299,7 @@ public:
resizeEvent(0); resizeEvent(0);
} }
void ui_redrawHistoryItem(const HistoryItem *item); void ui_repaintHistoryItem(const HistoryItem *item);
void notify_historyItemLayoutChanged(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) { void ProfileWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) {
if (App::app()) App::app()->mtpPause(); if (App::app()) App::app()->mtpPause();
// App::stopGifItems(); if (!cAutoPlayGif()) {
App::stopGifItems();
}
(back ? _cacheOver : _cacheUnder) = bgAnimCache; (back ? _cacheOver : _cacheUnder) = bgAnimCache;
(back ? _cacheTopBarOver : _cacheTopBarUnder) = bgAnimTopBarCache; (back ? _cacheTopBarOver : _cacheTopBarUnder) = bgAnimTopBarCache;

View file

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

View file

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

View file

@ -578,6 +578,10 @@ void PhotoData::automaticLoad(const HistoryItem *item) {
full->automaticLoad(item); full->automaticLoad(item);
} }
void PhotoData::automaticLoadSettingsChanged() {
full->automaticLoadSettingsChanged();
}
void PhotoData::download() { void PhotoData::download() {
full->loadEvenCancelled(); full->loadEvenCancelled();
notifyLayoutChanged(); 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() { void AudioData::performActionOnLoad() {
if (_actionOnLoad == ActionOnLoadNone) return; 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); 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 playMusic = data->song() && audioPlayer() && item;
bool playAnimation = data->isAnimation() && item && item->getMedia(); bool playAnimation = data->isAnimation() && item && item->getMedia();
const FileLocation &location(data->location(true)); const FileLocation &location(data->location(true));
@ -1556,18 +1567,27 @@ void DocumentData::automaticLoad(const HistoryItem *item) {
if (saveToCache() && _loader != CancelledFileLoader) { if (saveToCache() && _loader != CancelledFileLoader) {
if (type == StickerDocument) { if (type == StickerDocument) {
save(QString(), _actionOnLoad, _actionOnLoadMsgId); save(QString(), _actionOnLoad, _actionOnLoadMsgId);
} else if (isAnimation() && item) { } else if (isAnimation()) {
bool loadFromCloud = false; bool loadFromCloud = false;
if (item->history()->peer->isUser()) { if (item) {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate); if (item->history()->peer->isUser()) {
} else { loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate);
loadFromCloud = !(cAutoDownloadGif() & dbiadNoGroups); } else {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoGroups);
}
} else { // if load at least anywhere
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups);
} }
save(QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true); 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() { void DocumentData::performActionOnLoad() {
if (_actionOnLoad == ActionOnLoadNone) return; 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()); 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 automaticLoad(const HistoryItem *item);
void automaticLoadSettingsChanged();
void download(); void download();
bool loaded() const; bool loaded() const;
@ -823,6 +824,8 @@ public:
void automaticLoad(const HistoryItem *item) { void automaticLoad(const HistoryItem *item) {
} }
void automaticLoadSettingsChanged() {
}
bool loaded(bool check = false) const; bool loaded(bool check = false) const;
bool loading() 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); 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 automaticLoad(const HistoryItem *item); // auto load voice message
void automaticLoadSettingsChanged();
bool loaded(bool check = false) const; bool loaded(bool check = false) const;
bool loading() const; bool loading() const;
@ -1079,6 +1083,7 @@ public:
void setattributes(const QVector<MTPDocumentAttribute> &attributes); void setattributes(const QVector<MTPDocumentAttribute> &attributes);
void automaticLoad(const HistoryItem *item); // auto load sticker or video void automaticLoad(const HistoryItem *item); // auto load sticker or video
void automaticLoadSettingsChanged();
bool loaded(bool check = false) const; bool loaded(bool check = false) const;
bool loading() const; bool loading() const;

View file

@ -294,6 +294,9 @@ enum DataBlockId {
dbiMaxMegaGroupCount = 0x32, dbiMaxMegaGroupCount = 0x32,
dbiDownloadPath = 0x33, dbiDownloadPath = 0x33,
dbiAutoDownload = 0x34, dbiAutoDownload = 0x34,
dbiSavedGifsLimit = 0x35,
dbiShowingSavedGifs = 0x36,
dbiAutoPlay = 0x37,
dbiEncryptedWithSalt = 333, dbiEncryptedWithSalt = 333,
dbiEncrypted = 444, dbiEncrypted = 444,
@ -469,3 +472,69 @@ static int32 FullArcLength = 360 * 16;
static int32 QuarterArcLength = (FullArcLength / 4); static int32 QuarterArcLength = (FullArcLength / 4);
static int32 MinArcLength = (FullArcLength / 360); static int32 MinArcLength = (FullArcLength / 360);
static int32 AlmostFullArcLength = (FullArcLength - MinArcLength); 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) { void Window::setupMain(bool anim, const MTPUser *self) {
Local::readStickers();
QPixmap bg = anim ? grabInner() : QPixmap(); QPixmap bg = anim ? grabInner() : QPixmap();
clearWidgets(); clearWidgets();
main = new MainWidget(this); main = new MainWidget(this);
@ -797,9 +795,9 @@ void Window::showDocument(DocumentData *doc, HistoryItem *item) {
_mediaView->setFocus(); _mediaView->setFocus();
} }
void Window::ui_clipRedraw(ClipReader *reader) { void Window::ui_clipRepaint(ClipReader *reader) {
if (_mediaView && !_mediaView->isHidden()) { 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())); 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); void ui_showLayer(LayeredWidget *box, ShowLayerOptions options);
bool ui_isLayerShown(); bool ui_isLayerShown();
bool ui_isMediaViewShown(); bool ui_isMediaViewShown();