diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index e0acb5c18..06d89a81a 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -270,6 +270,8 @@ PRIVATE
chat_helpers/stickers.h
chat_helpers/stickers_emoji_pack.cpp
chat_helpers/stickers_emoji_pack.h
+ chat_helpers/stickers_dice_pack.cpp
+ chat_helpers/stickers_dice_pack.h
chat_helpers/stickers_list_widget.cpp
chat_helpers/stickers_list_widget.h
chat_helpers/tabbed_panel.cpp
@@ -436,6 +438,8 @@ PRIVATE
history/view/media/history_view_call.cpp
history/view/media/history_view_contact.h
history/view/media/history_view_contact.cpp
+ history/view/media/history_view_dice.h
+ history/view/media/history_view_dice.cpp
history/view/media/history_view_document.h
history/view/media/history_view_document.cpp
history/view/media/history_view_file.h
diff --git a/Telegram/Resources/art/dice_idle.tgs b/Telegram/Resources/art/dice_idle.tgs
new file mode 100644
index 000000000..aad33bffe
Binary files /dev/null and b/Telegram/Resources/art/dice_idle.tgs differ
diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc
index 2a9d64d3c..68b67373b 100644
--- a/Telegram/Resources/qrc/telegram/telegram.qrc
+++ b/Telegram/Resources/qrc/telegram/telegram.qrc
@@ -47,6 +47,7 @@
../../art/logo_256.png
../../art/logo_256_no_margin.png
../../art/sunrise.jpg
+ ../../art/dice_idle.tgs
../../day-blue.tdesktop-theme
../../night.tdesktop-theme
../../night-green.tdesktop-theme
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp
new file mode 100644
index 000000000..1e9c6a7f6
--- /dev/null
+++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp
@@ -0,0 +1,96 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "chat_helpers/stickers_dice_pack.h"
+
+#include "main/main_session.h"
+#include "data/data_session.h"
+#include "data/data_document.h"
+#include "storage/localimageloader.h"
+#include "base/unixtime.h"
+#include "apiwrap.h"
+
+#include
+#include
+
+namespace Stickers {
+namespace {
+
+constexpr auto kZeroDiceDocumentId = 0xa3b83c9f84fa9e83ULL;
+
+} // namespace
+
+DicePack::DicePack(not_null session)
+: _session(session) {
+}
+
+DicePack::~DicePack() = default;
+
+DocumentData *DicePack::lookup(int value) {
+ if (!_requestId) {
+ load();
+ }
+ if (!value) {
+ ensureZeroGenerated();
+ return _zero;
+ }
+ const auto i = _map.find(value);
+ return (i != end(_map)) ? i->second.get() : nullptr;
+}
+
+void DicePack::load() {
+ if (_requestId) {
+ return;
+ }
+ _requestId = _session->api().request(MTPmessages_GetStickerSet(
+ MTP_inputStickerSetDice()
+ )).done([=](const MTPmessages_StickerSet &result) {
+ result.match([&](const MTPDmessages_stickerSet &data) {
+ applySet(data);
+ });
+ }).fail([=](const RPCError &error) {
+ _requestId = 0;
+ }).send();
+}
+
+void DicePack::applySet(const MTPDmessages_stickerSet &data) {
+ auto index = 0;
+ for (const auto &sticker : data.vdocuments().v) {
+ const auto document = _session->data().processDocument(
+ sticker);
+ if (document->sticker()) {
+ _map.emplace(++index, document);
+ }
+ }
+}
+
+void DicePack::ensureZeroGenerated() {
+ if (_zero) {
+ return;
+ }
+
+ const auto path = qsl(":/gui/art/dice_idle.tgs");
+ auto task = FileLoadTask(
+ path,
+ QByteArray(),
+ nullptr,
+ SendMediaType::File,
+ FileLoadTo(0, {}, 0),
+ {});
+ task.process();
+ const auto result = task.peekResult();
+ Assert(result != nullptr);
+ _zero = _session->data().processDocument(
+ result->document,
+ std::move(result->thumb));
+ _zero->setLocation(FileLocation(path));
+
+ Ensures(_zero->sticker());
+ Ensures(_zero->sticker()->animated);
+}
+
+} // namespace Stickers
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h
new file mode 100644
index 000000000..59a22a11a
--- /dev/null
+++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h
@@ -0,0 +1,37 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+class DocumentData;
+
+namespace Main {
+class Session;
+} // namespace Main
+
+namespace Stickers {
+
+class DicePack final {
+public:
+ explicit DicePack(not_null session);
+ ~DicePack();
+
+ DocumentData *lookup(int value);
+
+private:
+ void load();
+ void applySet(const MTPDmessages_stickerSet &data);
+ void ensureZeroGenerated();
+
+ not_null _session;
+ base::flat_map> _map;
+ DocumentData *_zero = nullptr;
+ mtpRequestId _requestId = 0;
+
+};
+
+} // namespace Stickers
diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp
index e0f6bd6f7..5e6a9d9c0 100644
--- a/Telegram/SourceFiles/data/data_media_types.cpp
+++ b/Telegram/SourceFiles/data/data_media_types.cpp
@@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_web_page.h"
#include "history/view/media/history_view_poll.h"
#include "history/view/media/history_view_theme_document.h"
+#include "history/view/media/history_view_dice.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "ui/text_options.h"
@@ -1325,4 +1326,49 @@ std::unique_ptr MediaPoll::createView(
return std::make_unique(message, _poll);
}
+MediaDice::MediaDice(not_null parent, int value)
+: Media(parent)
+, _value(value) {
+}
+
+std::unique_ptr MediaDice::clone(not_null parent) {
+ return std::make_unique(parent, _value);
+}
+
+int MediaDice::diceValue() const {
+ return _value;
+}
+
+QString MediaDice::notificationText() const {
+ return QString::fromUtf8("\xF0\x9F\x8E\xB2");
+}
+
+QString MediaDice::pinnedTextSubstring() const {
+ return QChar(171) + notificationText() + QChar(187);
+}
+
+TextForMimeData MediaDice::clipboardText() const {
+ return { notificationText() };
+}
+
+bool MediaDice::updateInlineResultMedia(const MTPMessageMedia &media) {
+ return updateSentMedia(media);
+}
+
+bool MediaDice::updateSentMedia(const MTPMessageMedia &media) {
+ if (media.type() != mtpc_messageMediaDice) {
+ return false;
+ }
+ _value = media.c_messageMediaDice().vvalue().v;
+ return true;
+}
+
+std::unique_ptr MediaDice::createView(
+ not_null message,
+ not_null realParent) {
+ return std::make_unique(
+ message,
+ std::make_unique(message, _value));
+}
+
} // namespace Data
diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h
index 7803e503d..6b77e7255 100644
--- a/Telegram/SourceFiles/data/data_media_types.h
+++ b/Telegram/SourceFiles/data/data_media_types.h
@@ -118,7 +118,7 @@ private:
};
-class MediaPhoto : public Media {
+class MediaPhoto final : public Media {
public:
MediaPhoto(
not_null parent,
@@ -158,7 +158,7 @@ private:
};
-class MediaFile : public Media {
+class MediaFile final : public Media {
public:
MediaFile(
not_null parent,
@@ -195,7 +195,7 @@ private:
};
-class MediaContact : public Media {
+class MediaContact final : public Media {
public:
MediaContact(
not_null parent,
@@ -223,7 +223,7 @@ private:
};
-class MediaLocation : public Media {
+class MediaLocation final : public Media {
public:
MediaLocation(
not_null parent,
@@ -255,7 +255,7 @@ private:
};
-class MediaCall : public Media {
+class MediaCall final : public Media {
public:
MediaCall(
not_null parent,
@@ -284,7 +284,7 @@ private:
};
-class MediaWebPage : public Media {
+class MediaWebPage final : public Media {
public:
MediaWebPage(
not_null parent,
@@ -316,7 +316,7 @@ private:
};
-class MediaGame : public Media {
+class MediaGame final : public Media {
public:
MediaGame(
not_null parent,
@@ -348,7 +348,7 @@ private:
};
-class MediaInvoice : public Media {
+class MediaInvoice final : public Media {
public:
MediaInvoice(
not_null parent,
@@ -378,7 +378,7 @@ private:
};
-class MediaPoll : public Media {
+class MediaPoll final : public Media {
public:
MediaPoll(
not_null parent,
@@ -405,6 +405,28 @@ private:
};
+class MediaDice final : public Media {
+public:
+ MediaDice(not_null parent, int value);
+
+ std::unique_ptr clone(not_null parent) override;
+
+ int diceValue() const;
+
+ QString notificationText() const override;
+ QString pinnedTextSubstring() const override;
+ TextForMimeData clipboardText() const override;
+ bool updateInlineResultMedia(const MTPMessageMedia &media) override;
+ bool updateSentMedia(const MTPMessageMedia &media) override;
+ std::unique_ptr createView(
+ not_null message,
+ not_null realParent) override;
+
+private:
+ int _value = 0;
+
+};
+
TextForMimeData WithCaptionClipboardText(
const QString &attachType,
TextForMimeData &&caption);
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index 0503a60d5..4bc32948a 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -154,7 +154,7 @@ MediaCheckResult CheckMessageMedia(const MTPMessageMedia &media) {
}, [](const MTPDmessageMediaPoll &) {
return Result::Good;
}, [](const MTPDmessageMediaDice &) {
- return Result::Unsupported; // #TODO dice
+ return Result::Good;
}, [](const MTPDmessageMediaUnsupported &) {
return Result::Unsupported;
});
diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp
index d2b0fdfe1..c461982b4 100644
--- a/Telegram/SourceFiles/history/history_message.cpp
+++ b/Telegram/SourceFiles/history/history_message.cpp
@@ -1024,8 +1024,8 @@ std::unique_ptr HistoryMessage::CreateMedia(
return std::make_unique(
item,
item->history()->owner().processPoll(media));
- }, [](const MTPDmessageMediaDice &media) -> Result {
- return nullptr; // #TODO dice
+ }, [&](const MTPDmessageMediaDice &media) -> Result {
+ return std::make_unique(item, media.vvalue().v);
}, [](const MTPDmessageMediaEmpty &) -> Result {
return nullptr;
}, [](const MTPDmessageMediaUnsupported &) -> Result {
diff --git a/Telegram/SourceFiles/history/view/media/history_view_dice.cpp b/Telegram/SourceFiles/history/view/media/history_view_dice.cpp
new file mode 100644
index 000000000..0f780802d
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/media/history_view_dice.cpp
@@ -0,0 +1,60 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "history/view/media/history_view_dice.h"
+
+#include "data/data_session.h"
+#include "chat_helpers/stickers_dice_pack.h"
+#include "history/history.h"
+#include "history/history_item.h"
+#include "history/view/history_view_element.h"
+#include "main/main_session.h"
+
+namespace HistoryView {
+namespace {
+
+DocumentData *Lookup(not_null view, int value) {
+ const auto &session = view->data()->history()->session();
+ return session.diceStickersPack().lookup(value);
+}
+
+} // namespace
+
+Dice::Dice(not_null parent, int value)
+: _parent(parent)
+, _start(parent, Lookup(parent, 0))
+, _value(value) {
+ _start.setDiceIndex(0);
+}
+
+Dice::~Dice() = default;
+
+QSize Dice::size() {
+ return _start.size();
+}
+
+void Dice::draw(Painter &p, const QRect &r, bool selected) {
+ Expects(_end.has_value() || !_drawingEnd);
+
+ if (_drawingEnd) {
+ _end->draw(p, r, selected);
+ } else {
+ _start.draw(p, r, selected);
+ if (!_end && _value) {
+ if (const auto document = Lookup(_parent, _value)) {
+ _end.emplace(_parent, document);
+ _end->setDiceIndex(_value);
+ _end->initSize();
+ }
+ }
+ if (_end && _end->readyToDrawLottie() && _start.atTheEnd()) {
+ _drawingEnd = true;
+ }
+ }
+}
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/media/history_view_dice.h b/Telegram/SourceFiles/history/view/media/history_view_dice.h
new file mode 100644
index 000000000..5d0d7c4a9
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/media/history_view_dice.h
@@ -0,0 +1,43 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+#include "history/view/media/history_view_media_unwrapped.h"
+#include "history/view/media/history_view_sticker.h"
+
+namespace HistoryView {
+
+class Dice final : public UnwrappedMedia::Content {
+public:
+ Dice(not_null parent, int value);
+ ~Dice();
+
+ QSize size() override;
+ void draw(Painter &p, const QRect &r, bool selected) override;
+
+ void clearStickerLoopPlayed() override {
+ _lottieOncePlayed = false;
+ }
+ void unloadHeavyPart() override {
+ _start.unloadHeavyPart();
+ if (_end) {
+ _end->unloadHeavyPart();
+ }
+ }
+
+private:
+ const not_null _parent;
+ std::optional _end;
+ Sticker _start;
+ int _value = 0;
+ mutable bool _lottieOncePlayed = false;
+ mutable bool _drawingEnd = false;
+
+};
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
index 717a0bf78..00e2b9bce 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
@@ -57,7 +57,7 @@ bool Sticker::isEmojiSticker() const {
return (_parent->data()->media() == nullptr);
}
-QSize Sticker::size() {
+void Sticker::initSize() {
_size = _document->dimensions;
if (isEmojiSticker()) {
constexpr auto kIdealStickerSize = 512;
@@ -70,14 +70,22 @@ QSize Sticker::size() {
_size = DownscaledSize(
_size,
{ st::maxStickerSize, st::maxStickerSize });
+ [[maybe_unused]] bool result = readyToDrawLottie();
}
+}
+
+QSize Sticker::size() {
+ initSize();
return _size;
}
-void Sticker::draw(Painter &p, const QRect &r, bool selected) {
+bool Sticker::readyToDrawLottie() {
+ if (!_lastDiceFrame.isNull()) {
+ return true;
+ }
const auto sticker = _document->sticker();
if (!sticker) {
- return;
+ return false;
}
_document->checkStickerLarge();
@@ -85,10 +93,14 @@ void Sticker::draw(Painter &p, const QRect &r, bool selected) {
if (sticker->animated && !_lottie && loaded) {
setupLottie();
}
+ return (_lottie && _lottie->ready());
+}
- if (_lottie && _lottie->ready()) {
+void Sticker::draw(Painter &p, const QRect &r, bool selected) {
+ if (readyToDrawLottie()) {
paintLottie(p, r, selected);
- } else if (!sticker->animated || !_replacements) {
+ } else if (_document->sticker()
+ && (!_document->sticker()->animated || !_replacements)) {
paintPixmap(p, r, selected);
}
}
@@ -96,24 +108,51 @@ void Sticker::draw(Painter &p, const QRect &r, bool selected) {
void Sticker::paintLottie(Painter &p, const QRect &r, bool selected) {
auto request = Lottie::FrameRequest();
request.box = _size * cIntRetinaFactor();
- if (selected) {
+ if (selected && !_nextLastDiceFrame) {
request.colored = st::msgStickerOverlay->c;
}
- const auto frame = _lottie->frameInfo(request);
- const auto size = frame.image.size() / cIntRetinaFactor();
+ const auto frame = _lottie
+ ? _lottie->frameInfo(request)
+ : Lottie::Animation::FrameInfo();
+ if (_nextLastDiceFrame) {
+ _nextLastDiceFrame = false;
+ _lastDiceFrame = frame.image;
+ }
+ const auto &image = _lastDiceFrame.isNull()
+ ? frame.image
+ : _lastDiceFrame;
+ const auto prepared = (!_lastDiceFrame.isNull() && selected)
+ ? Images::prepareColored(st::msgStickerOverlay->c, image)
+ : image;
+ const auto size = prepared.size() / cIntRetinaFactor();
p.drawImage(
QRect(
QPoint(
r.x() + (r.width() - size.width()) / 2,
r.y() + (r.height() - size.height()) / 2),
size),
- frame.image);
+ prepared);
+ if (!_lastDiceFrame.isNull()) {
+ return;
+ }
const auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
- const auto playOnce = isEmojiSticker()
- || !_document->session().settings().loopAnimatedStickers();
+ const auto playOnce = (_diceIndex > 0)
+ ? true
+ : (_diceIndex == 0)
+ ? false
+ : (isEmojiSticker()
+ || !_document->session().settings().loopAnimatedStickers());
+ const auto count = _lottie->information().framesCount;
+ _atTheEnd = (frame.index + 1 == count);
+ _nextLastDiceFrame = !paused
+ && (_diceIndex > 0)
+ && (frame.index + 2 == count);
+ const auto lastDiceFrame = (_diceIndex > 0) && _atTheEnd;
+ const auto switchToNext = !playOnce
+ || (!lastDiceFrame && (frame.index != 0 || !_lottieOncePlayed));
if (!paused
- && (!playOnce || frame.index != 0 || !_lottieOncePlayed)
+ && switchToNext
&& _lottie->markFrameShown()
&& playOnce
&& !_lottieOncePlayed) {
@@ -188,6 +227,10 @@ void Sticker::refreshLink() {
}
}
+void Sticker::setDiceIndex(int index) {
+ _diceIndex = index;
+}
+
void Sticker::setupLottie() {
_lottie = Stickers::LottiePlayerFromDocument(
_document,
diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.h b/Telegram/SourceFiles/history/view/media/history_view_sticker.h
index 6ee7370e4..6c9f4d0a6 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_sticker.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.h
@@ -31,6 +31,7 @@ public:
const Lottie::ColorReplacements *replacements = nullptr);
~Sticker();
+ void initSize();
QSize size() override;
void draw(Painter &p, const QRect &r, bool selected) override;
ClickHandlerPtr link() override {
@@ -48,6 +49,12 @@ public:
}
void refreshLink() override;
+ void setDiceIndex(int index);
+ [[nodiscard]] bool atTheEnd() const {
+ return _atTheEnd;
+ }
+ [[nodiscard]] bool readyToDrawLottie();
+
private:
[[nodiscard]] bool isEmojiSticker() const;
void paintLottie(Painter &p, const QRect &r, bool selected);
@@ -63,7 +70,11 @@ private:
std::unique_ptr _lottie;
ClickHandlerPtr _link;
QSize _size;
+ QImage _lastDiceFrame;
+ int _diceIndex = -1;
mutable bool _lottieOncePlayed = false;
+ mutable bool _atTheEnd = false;
+ mutable bool _nextLastDiceFrame = false;
rpl::lifetime _lifetime;
diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp
index 90de3897d..303be0c59 100644
--- a/Telegram/SourceFiles/main/main_session.cpp
+++ b/Telegram/SourceFiles/main/main_session.cpp
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/changelogs.h"
#include "main/main_account.h"
#include "chat_helpers/stickers_emoji_pack.h"
+#include "chat_helpers/stickers_dice_pack.h"
#include "storage/file_download.h"
#include "storage/download_manager_mtproto.h"
#include "storage/file_upload.h"
@@ -56,6 +57,7 @@ Session::Session(
, _data(std::make_unique(this))
, _user(_data->processUser(user))
, _emojiStickersPack(std::make_unique(this))
+, _diceStickersPack(std::make_unique(this))
, _changelogs(Core::Changelogs::Create(this))
, _supportHelper(Support::Helper::Create(this)) {
Core::App().passcodeLockChanges(
diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h
index 10ef88afb..552bd7630 100644
--- a/Telegram/SourceFiles/main/main_session.h
+++ b/Telegram/SourceFiles/main/main_session.h
@@ -46,6 +46,7 @@ class Instance;
namespace Stickers {
class EmojiPack;
+class DicePack;
} // namespace Stickers;
namespace Core {
@@ -89,9 +90,12 @@ public:
[[nodiscard]] Storage::Facade &storage() {
return *_storage;
}
- [[nodiscard]] Stickers::EmojiPack &emojiStickersPack() {
+ [[nodiscard]] Stickers::EmojiPack &emojiStickersPack() const {
return *_emojiStickersPack;
}
+ [[nodiscard]] Stickers::DicePack &diceStickersPack() const {
+ return *_diceStickersPack;
+ }
[[nodiscard]] base::Observable &downloaderTaskFinished();
@@ -157,6 +161,7 @@ private:
// _emojiStickersPack depends on _data.
const std::unique_ptr _emojiStickersPack;
+ const std::unique_ptr _diceStickersPack;
// _changelogs depends on _data, subscribes on chats loading event.
const std::unique_ptr _changelogs;
diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp
index 53de99d95..5d497fe99 100644
--- a/Telegram/SourceFiles/storage/localimageloader.cpp
+++ b/Telegram/SourceFiles/storage/localimageloader.cpp
@@ -967,6 +967,10 @@ void FileLoadTask::finish() {
}
}
+FileLoadResult *FileLoadTask::peekResult() const {
+ return _result.get();
+}
+
void FileLoadTask::removeFromAlbum() {
if (!_album) {
return;
diff --git a/Telegram/SourceFiles/storage/localimageloader.h b/Telegram/SourceFiles/storage/localimageloader.h
index 1f4ada86b..029b71637 100644
--- a/Telegram/SourceFiles/storage/localimageloader.h
+++ b/Telegram/SourceFiles/storage/localimageloader.h
@@ -292,6 +292,8 @@ public:
void process();
void finish();
+ FileLoadResult *peekResult() const;
+
private:
static bool CheckForSong(
const QString &filepath,