mirror of https://github.com/procxx/kepka.git
				
				
				
			Implement dice media display.
This commit is contained in:
		
							parent
							
								
									d4b9b65724
								
							
						
					
					
						commit
						c83e297554
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -47,6 +47,7 @@
 | 
			
		|||
    <file alias="art/logo_256.png">../../art/logo_256.png</file>
 | 
			
		||||
    <file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
 | 
			
		||||
    <file alias="art/sunrise.jpg">../../art/sunrise.jpg</file>
 | 
			
		||||
    <file alias="art/dice_idle.tgs">../../art/dice_idle.tgs</file>
 | 
			
		||||
    <file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
 | 
			
		||||
    <file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
 | 
			
		||||
    <file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <QtCore/QFile>
 | 
			
		||||
#include <QtCore/QFileInfo>
 | 
			
		||||
 | 
			
		||||
namespace Stickers {
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
constexpr auto kZeroDiceDocumentId = 0xa3b83c9f84fa9e83ULL;
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
DicePack::DicePack(not_null<Main::Session*> 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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<Main::Session*> session);
 | 
			
		||||
	~DicePack();
 | 
			
		||||
 | 
			
		||||
	DocumentData *lookup(int value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void load();
 | 
			
		||||
	void applySet(const MTPDmessages_stickerSet &data);
 | 
			
		||||
	void ensureZeroGenerated();
 | 
			
		||||
 | 
			
		||||
	not_null<Main::Session*> _session;
 | 
			
		||||
	base::flat_map<int, not_null<DocumentData*>> _map;
 | 
			
		||||
	DocumentData *_zero = nullptr;
 | 
			
		||||
	mtpRequestId _requestId = 0;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Stickers
 | 
			
		||||
| 
						 | 
				
			
			@ -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<HistoryView::Media> MediaPoll::createView(
 | 
			
		|||
	return std::make_unique<HistoryView::Poll>(message, _poll);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MediaDice::MediaDice(not_null<HistoryItem*> parent, int value)
 | 
			
		||||
: Media(parent)
 | 
			
		||||
, _value(value) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Media> MediaDice::clone(not_null<HistoryItem*> parent) {
 | 
			
		||||
	return std::make_unique<MediaDice>(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<HistoryView::Media> MediaDice::createView(
 | 
			
		||||
		not_null<HistoryView::Element*> message,
 | 
			
		||||
		not_null<HistoryItem*> realParent) {
 | 
			
		||||
	return std::make_unique<HistoryView::UnwrappedMedia>(
 | 
			
		||||
		message,
 | 
			
		||||
		std::make_unique<HistoryView::Dice>(message, _value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Data
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaPhoto : public Media {
 | 
			
		||||
class MediaPhoto final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaPhoto(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaFile : public Media {
 | 
			
		||||
class MediaFile final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaFile(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaContact : public Media {
 | 
			
		||||
class MediaContact final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaContact(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +223,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaLocation : public Media {
 | 
			
		||||
class MediaLocation final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaLocation(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +255,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaCall : public Media {
 | 
			
		||||
class MediaCall final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaCall(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -284,7 +284,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaWebPage : public Media {
 | 
			
		||||
class MediaWebPage final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaWebPage(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -316,7 +316,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaGame : public Media {
 | 
			
		||||
class MediaGame final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaGame(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +348,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaInvoice : public Media {
 | 
			
		||||
class MediaInvoice final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaInvoice(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +378,7 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaPoll : public Media {
 | 
			
		||||
class MediaPoll final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaPoll(
 | 
			
		||||
		not_null<HistoryItem*> parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -405,6 +405,28 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MediaDice final : public Media {
 | 
			
		||||
public:
 | 
			
		||||
	MediaDice(not_null<HistoryItem*> parent, int value);
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<Media> clone(not_null<HistoryItem*> 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<HistoryView::Media> createView(
 | 
			
		||||
		not_null<HistoryView::Element*> message,
 | 
			
		||||
		not_null<HistoryItem*> realParent) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int _value = 0;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TextForMimeData WithCaptionClipboardText(
 | 
			
		||||
	const QString &attachType,
 | 
			
		||||
	TextForMimeData &&caption);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
	});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1024,8 +1024,8 @@ std::unique_ptr<Data::Media> HistoryMessage::CreateMedia(
 | 
			
		|||
		return std::make_unique<Data::MediaPoll>(
 | 
			
		||||
			item,
 | 
			
		||||
			item->history()->owner().processPoll(media));
 | 
			
		||||
	}, [](const MTPDmessageMediaDice &media) -> Result {
 | 
			
		||||
		return nullptr; // #TODO dice
 | 
			
		||||
	}, [&](const MTPDmessageMediaDice &media) -> Result {
 | 
			
		||||
		return std::make_unique<Data::MediaDice>(item, media.vvalue().v);
 | 
			
		||||
	}, [](const MTPDmessageMediaEmpty &) -> Result {
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}, [](const MTPDmessageMediaUnsupported &) -> Result {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<Element*> view, int value) {
 | 
			
		||||
	const auto &session = view->data()->history()->session();
 | 
			
		||||
	return session.diceStickersPack().lookup(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
Dice::Dice(not_null<Element*> 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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<Element*> 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<Element*> _parent;
 | 
			
		||||
	std::optional<Sticker> _end;
 | 
			
		||||
	Sticker _start;
 | 
			
		||||
	int _value = 0;
 | 
			
		||||
	mutable bool _lottieOncePlayed = false;
 | 
			
		||||
	mutable bool _drawingEnd = false;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace HistoryView
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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::SinglePlayer> _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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<Data::Session>(this))
 | 
			
		||||
, _user(_data->processUser(user))
 | 
			
		||||
, _emojiStickersPack(std::make_unique<Stickers::EmojiPack>(this))
 | 
			
		||||
, _diceStickersPack(std::make_unique<Stickers::DicePack>(this))
 | 
			
		||||
, _changelogs(Core::Changelogs::Create(this))
 | 
			
		||||
, _supportHelper(Support::Helper::Create(this)) {
 | 
			
		||||
	Core::App().passcodeLockChanges(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<void> &downloaderTaskFinished();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -157,6 +161,7 @@ private:
 | 
			
		|||
 | 
			
		||||
	// _emojiStickersPack depends on _data.
 | 
			
		||||
	const std::unique_ptr<Stickers::EmojiPack> _emojiStickersPack;
 | 
			
		||||
	const std::unique_ptr<Stickers::DicePack> _diceStickersPack;
 | 
			
		||||
 | 
			
		||||
	// _changelogs depends on _data, subscribes on chats loading event.
 | 
			
		||||
	const std::unique_ptr<Core::Changelogs> _changelogs;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -967,6 +967,10 @@ void FileLoadTask::finish() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileLoadResult *FileLoadTask::peekResult() const {
 | 
			
		||||
	return _result.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileLoadTask::removeFromAlbum() {
 | 
			
		||||
	if (!_album) {
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -292,6 +292,8 @@ public:
 | 
			
		|||
	void process();
 | 
			
		||||
	void finish();
 | 
			
		||||
 | 
			
		||||
	FileLoadResult *peekResult() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static bool CheckForSong(
 | 
			
		||||
		const QString &filepath,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue