init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,214 @@
/*
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 "data/stickers/data_stickers_set.h"
#include "ui/text/custom_emoji_instance.h"
#include "base/timer.h"
#include "base/weak_ptr.h"
namespace Main {
class Session;
} // namespace Main
namespace Data {
class Session;
class CustomEmojiLoader;
enum class CustomEmojiSizeTag : uchar {
Normal,
Large,
Isolated,
SetIcon,
kCount,
};
class CustomEmojiManager final : public base::has_weak_ptr {
public:
using SizeTag = CustomEmojiSizeTag;
CustomEmojiManager(not_null<Session*> owner);
~CustomEmojiManager();
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
QStringView data,
Fn<void()> update,
SizeTag tag = SizeTag::Normal,
int sizeOverride = 0);
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
DocumentId documentId,
Fn<void()> update,
SizeTag tag = SizeTag::Normal,
int sizeOverride = 0);
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
not_null<DocumentData*> document,
Fn<void()> update,
SizeTag tag = SizeTag::Normal,
int sizeOverride = 0);
[[nodiscard]] Ui::Text::CustomEmojiFactory factory(
SizeTag tag = SizeTag::Normal,
int sizeOverride = 0);
class Listener {
public:
virtual void customEmojiResolveDone(
not_null<DocumentData*> document) = 0;
};
void resolve(QStringView data, not_null<Listener*> listener);
void resolve(DocumentId documentId, not_null<Listener*> listener);
void unregisterListener(not_null<Listener*> listener);
[[nodiscard]] auto resolve(DocumentId documentId)
-> rpl::producer<not_null<DocumentData*>, rpl::empty_error>;
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
not_null<DocumentData*> document,
SizeTag tag,
int sizeOverride = 0);
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
DocumentId documentId,
SizeTag tag,
int sizeOverride = 0);
[[nodiscard]] QString lookupSetName(uint64 setId);
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] Session &owner() const;
[[nodiscard]] QString peerUserpicEmojiData(
not_null<PeerData*> peer,
QMargins padding = {},
bool respectSavedRepliesEtc = false);
[[nodiscard]] uint64 coloredSetId() const;
private:
static constexpr auto kSizeCount = int(SizeTag::kCount);
struct InternalEmojiData {
QImage image;
bool textColor = true;
};
struct RepaintBunch {
crl::time when = 0;
std::vector<base::weak_ptr<Ui::CustomEmoji::Instance>> instances;
};
struct LoaderWithSetId {
std::unique_ptr<Ui::CustomEmoji::Loader> loader;
uint64 setId = 0;
bool colored = false;
};
[[nodiscard]] LoaderWithSetId createLoaderWithSetId(
not_null<DocumentData*> document,
SizeTag tag,
int sizeOverride = 0);
[[nodiscard]] LoaderWithSetId createLoaderWithSetId(
DocumentId documentId,
SizeTag tag,
int sizeOverride = 0);
void request();
void requestFinished();
void repaintLater(
not_null<Ui::CustomEmoji::Instance*> instance,
Ui::CustomEmoji::RepaintRequest request);
void scheduleRepaintTimer();
bool checkEmptyRepaints();
void invokeRepaints();
void fillColoredFlags(not_null<DocumentData*> document);
void processLoaders(not_null<DocumentData*> document);
void processListeners(not_null<DocumentData*> document);
void requestSetFor(not_null<DocumentData*> document);
[[nodiscard]] Ui::CustomEmoji::Preview prepareNonExactPreview(
DocumentId documentId,
SizeTag tag,
int sizeOverride) const;
template <typename LoaderFactory>
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
DocumentId documentId,
Fn<void()> update,
SizeTag tag,
int sizeOverride,
LoaderFactory factory);
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> userpic(
QStringView data,
Fn<void()> update,
int size);
[[nodiscard]] static int SizeIndex(SizeTag tag);
const not_null<Session*> _owner;
std::array<
base::flat_map<
DocumentId,
std::unique_ptr<Ui::CustomEmoji::Instance>>,
kSizeCount> _instances;
std::array<
base::flat_map<
DocumentId,
std::vector<base::weak_ptr<CustomEmojiLoader>>>,
kSizeCount> _loaders;
base::flat_map<
DocumentId,
base::flat_set<not_null<Listener*>>> _resolvers;
base::flat_map<
not_null<Listener*>,
base::flat_set<DocumentId>> _listeners;
base::flat_set<DocumentId> _pendingForRequest;
mtpRequestId _requestId = 0;
uint64 _coloredSetId = 0;
base::flat_map<crl::time, RepaintBunch> _repaints;
crl::time _repaintNext = 0;
base::Timer _repaintTimer;
bool _repaintTimerScheduled = false;
bool _requestSetsScheduled = false;
#if 0 // inject-to-on_main
crl::time _repaintsLastAdded = 0;
rpl::lifetime _repaintsLifetime;
#endif
rpl::lifetime _lifetime;
};
[[nodiscard]] int FrameSizeFromTag(CustomEmojiManager::SizeTag tag);
[[nodiscard]] QString SerializeCustomEmojiId(DocumentId id);
[[nodiscard]] QString SerializeCustomEmojiId(
not_null<DocumentData*> document);
[[nodiscard]] DocumentId ParseCustomEmojiData(QStringView data);
[[nodiscard]] TextWithEntities SingleCustomEmoji(DocumentId id);
[[nodiscard]] TextWithEntities SingleCustomEmoji(
not_null<DocumentData*> document);
[[nodiscard]] bool AllowEmojiWithoutPremium(
not_null<PeerData*> peer,
DocumentData *exactEmoji = nullptr);
void InsertCustomEmoji(
not_null<Ui::InputField*> field,
not_null<DocumentData*> document);
[[nodiscard]] Ui::Text::CustomEmojiFactory ReactedMenuFactory(
not_null<Main::Session*> session);
[[nodiscard]] QString CollectibleCustomEmojiId(
Data::EmojiStatusCollectible &data);
[[nodiscard]] QString EmojiStatusCustomId(const EmojiStatusId &id);
} // namespace Data

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,332 @@
/*
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 "mtproto/sender.h"
#include "data/stickers/data_stickers_set.h"
#include "settings.h"
class HistoryItem;
class DocumentData;
namespace Main {
class Session;
} // namespace Main
namespace Window {
class SessionController;
} // namespace Window
namespace ChatHelpers {
class Show;
} // namespace ChatHelpers
namespace Data {
class Session;
class DocumentMedia;
enum class StickersType : uchar {
Stickers,
Masks,
Emoji,
};
[[nodiscard]] StickerType ThumbnailTypeFromPhotoSize(
const MTPPhotoSize &size);
class Stickers final {
public:
explicit Stickers(not_null<Session*> owner);
[[nodiscard]] Session &owner() const;
[[nodiscard]] Main::Session &session() const;
// for backward compatibility
static constexpr auto DefaultSetId = 0;
static constexpr auto CustomSetId = 0xFFFFFFFFFFFFFFFFULL;
// For stickers panel, should not appear in Sets.
static constexpr auto RecentSetId = 0xFFFFFFFFFFFFFFFEULL;
static constexpr auto NoneSetId = 0xFFFFFFFFFFFFFFFDULL;
static constexpr auto FeaturedSetId = 0xFFFFFFFFFFFFFFFBULL;
// For cloud-stored recent stickers.
static constexpr auto CloudRecentSetId = 0xFFFFFFFFFFFFFFFCULL;
static constexpr auto CloudRecentAttachedSetId = 0xFFFFFFFFFFFFFFF9ULL;
// For cloud-stored faved stickers.
static constexpr auto FavedSetId = 0xFFFFFFFFFFFFFFFAULL;
// For setting up megagroup sticker set.
static constexpr auto MegagroupSetId = 0xFFFFFFFFFFFFFFEFULL;
// For collectible emoji statuses.
static constexpr auto CollectibleSetId = 0xFFFFFFFFFFFFFFF8ULL;
void notifyUpdated(StickersType type);
[[nodiscard]] rpl::producer<StickersType> updated() const;
[[nodiscard]] rpl::producer<> updated(StickersType type) const;
void notifyRecentUpdated(StickersType type);
[[nodiscard]] rpl::producer<StickersType> recentUpdated() const;
[[nodiscard]] rpl::producer<> recentUpdated(StickersType type) const;
void notifySavedGifsUpdated();
[[nodiscard]] rpl::producer<> savedGifsUpdated() const;
void notifyStickerSetInstalled(uint64 setId);
[[nodiscard]] rpl::producer<uint64> stickerSetInstalled() const;
void notifyEmojiSetInstalled(uint64 setId);
[[nodiscard]] rpl::producer<uint64> emojiSetInstalled() const;
void incrementSticker(not_null<DocumentData*> document);
[[nodiscard]] bool updateNeeded(crl::time now) const {
return updateNeeded(_lastUpdate, now);
}
void setLastUpdate(crl::time update) {
_lastUpdate = update;
}
[[nodiscard]] bool recentUpdateNeeded(crl::time now) const {
return updateNeeded(_lastRecentUpdate, now);
}
void setLastRecentUpdate(crl::time update) {
if (update) {
notifyRecentUpdated(StickersType::Stickers);
}
_lastRecentUpdate = update;
}
[[nodiscard]] bool masksUpdateNeeded(crl::time now) const {
return updateNeeded(_lastMasksUpdate, now);
}
void setLastMasksUpdate(crl::time update) {
_lastMasksUpdate = update;
}
[[nodiscard]] bool emojiUpdateNeeded(crl::time now) const {
return updateNeeded(_lastEmojiUpdate, now);
}
void setLastEmojiUpdate(crl::time update) {
_lastEmojiUpdate = update;
}
[[nodiscard]] bool recentAttachedUpdateNeeded(crl::time now) const {
return updateNeeded(_lastRecentAttachedUpdate, now);
}
void setLastRecentAttachedUpdate(crl::time update) {
if (update) {
notifyRecentUpdated(StickersType::Masks);
}
_lastRecentAttachedUpdate = update;
}
[[nodiscard]] bool favedUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFavedUpdate, now);
}
void setLastFavedUpdate(crl::time update) {
_lastFavedUpdate = update;
}
[[nodiscard]] bool featuredUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFeaturedUpdate, now);
}
void setLastFeaturedUpdate(crl::time update) {
_lastFeaturedUpdate = update;
}
[[nodiscard]] bool featuredEmojiUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFeaturedEmojiUpdate, now);
}
void setLastFeaturedEmojiUpdate(crl::time update) {
_lastFeaturedEmojiUpdate = update;
}
[[nodiscard]] bool savedGifsUpdateNeeded(crl::time now) const {
return updateNeeded(_lastSavedGifsUpdate, now);
}
void setLastSavedGifsUpdate(crl::time update) {
_lastSavedGifsUpdate = update;
}
[[nodiscard]] int featuredSetsUnreadCount() const {
return _featuredSetsUnreadCount.current();
}
void setFeaturedSetsUnreadCount(int count) {
_featuredSetsUnreadCount = count;
}
[[nodiscard]] rpl::producer<int> featuredSetsUnreadCountValue() const {
return _featuredSetsUnreadCount.value();
}
[[nodiscard]] const StickersSets &sets() const {
return _sets;
}
[[nodiscard]] StickersSets &setsRef() {
return _sets;
}
[[nodiscard]] const StickersSetsOrder &setsOrder() const {
return _setsOrder;
}
[[nodiscard]] StickersSetsOrder &setsOrderRef() {
return _setsOrder;
}
[[nodiscard]] const StickersSetsOrder &maskSetsOrder() const {
return _maskSetsOrder;
}
[[nodiscard]] StickersSetsOrder &maskSetsOrderRef() {
return _maskSetsOrder;
}
[[nodiscard]] const StickersSetsOrder &emojiSetsOrder() const {
return _emojiSetsOrder;
}
[[nodiscard]] StickersSetsOrder &emojiSetsOrderRef() {
return _emojiSetsOrder;
}
[[nodiscard]] const StickersSetsOrder &featuredSetsOrder() const {
return _featuredSetsOrder;
}
[[nodiscard]] StickersSetsOrder &featuredSetsOrderRef() {
return _featuredSetsOrder;
}
[[nodiscard]] const StickersSetsOrder &featuredEmojiSetsOrder() const {
return _featuredEmojiSetsOrder;
}
[[nodiscard]] StickersSetsOrder &featuredEmojiSetsOrderRef() {
return _featuredEmojiSetsOrder;
}
[[nodiscard]] const StickersSetsOrder &archivedSetsOrder() const {
return _archivedSetsOrder;
}
[[nodiscard]] StickersSetsOrder &archivedSetsOrderRef() {
return _archivedSetsOrder;
}
[[nodiscard]] const StickersSetsOrder &archivedMaskSetsOrder() const {
return _archivedMaskSetsOrder;
}
[[nodiscard]] StickersSetsOrder &archivedMaskSetsOrderRef() {
return _archivedMaskSetsOrder;
}
[[nodiscard]] const SavedGifs &savedGifs() const {
return _savedGifs;
}
[[nodiscard]] SavedGifs &savedGifsRef() {
return _savedGifs;
}
void removeFromRecentSet(not_null<DocumentData*> document);
void addSavedGif(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document);
void checkSavedGif(not_null<HistoryItem*> item);
void applyArchivedResult(
const MTPDmessages_stickerSetInstallResultArchive &d);
void installLocally(uint64 setId);
void undoInstallLocally(uint64 setId);
[[nodiscard]] bool isFaved(not_null<const DocumentData*> document) const;
void setFaved(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document,
bool faved);
void setsReceived(const QVector<MTPStickerSet> &data, uint64 hash);
void masksReceived(const QVector<MTPStickerSet> &data, uint64 hash);
void emojiReceived(const QVector<MTPStickerSet> &data, uint64 hash);
void specialSetReceived(
uint64 setId,
const QString &setTitle,
const QVector<MTPDocument> &items,
uint64 hash,
const QVector<MTPStickerPack> &packs = QVector<MTPStickerPack>(),
const QVector<MTPint> &usageDates = QVector<MTPint>());
void featuredSetsReceived(const MTPmessages_FeaturedStickers &result);
void featuredEmojiSetsReceived(
const MTPmessages_FeaturedStickers &result);
void gifsReceived(const QVector<MTPDocument> &items, uint64 hash);
[[nodiscard]] std::vector<not_null<DocumentData*>> getPremiumList(
uint64 seed);
[[nodiscard]] std::vector<not_null<DocumentData*>> getListByEmoji(
std::vector<EmojiPtr> emoji,
uint64 seed,
bool forceAllResults = false);
[[nodiscard]] auto getEmojiListFromSet(not_null<DocumentData*> document)
-> std::optional<std::vector<not_null<EmojiPtr>>>;
[[nodiscard]] not_null<StickersSet*> collectibleSet();
not_null<StickersSet*> feedSet(const MTPStickerSet &data);
not_null<StickersSet*> feedSet(const MTPStickerSetCovered &data);
not_null<StickersSet*> feedSetFull(const MTPDmessages_stickerSet &data);
void feedSetStickers(
not_null<StickersSet*> set,
const QVector<MTPDocument> &documents,
const QVector<MTPStickerPack> &packs);
void feedSetCovers(
not_null<StickersSet*> set,
const QVector<MTPDocument> &documents);
void newSetReceived(const MTPDmessages_stickerSet &set);
[[nodiscard]] QString getSetTitle(const MTPDstickerSet &s);
[[nodiscard]] RecentStickerPack &getRecentPack() const;
private:
[[nodiscard]] bool updateNeeded(crl::time last, crl::time now) const {
constexpr auto kUpdateTimeout = crl::time(3600'000);
return (last == 0) || (now >= last + kUpdateTimeout);
}
void checkFavedLimit(
StickersSet &set,
std::shared_ptr<ChatHelpers::Show> show);
void setIsFaved(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document,
std::optional<std::vector<not_null<EmojiPtr>>> emojiList
= std::nullopt);
void setIsNotFaved(not_null<DocumentData*> document);
void pushFavedToFront(
StickersSet &set,
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document,
const std::vector<not_null<EmojiPtr>> &emojiList);
void moveFavedToFront(StickersSet &set, int index);
void requestSetToPushFaved(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document);
void setPackAndEmoji(
StickersSet &set,
StickersPack &&pack,
std::vector<TimeId> &&dates,
const QVector<MTPStickerPack> &packs);
void somethingReceived(
const QVector<MTPStickerSet> &list,
uint64 hash,
StickersType type);
void featuredReceived(
const MTPDmessages_featuredStickers &data,
StickersType type);
const not_null<Session*> _owner;
rpl::event_stream<StickersType> _updated;
rpl::event_stream<StickersType> _recentUpdated;
rpl::event_stream<> _savedGifsUpdated;
rpl::event_stream<uint64> _stickerSetInstalled;
rpl::event_stream<uint64> _emojiSetInstalled;
crl::time _lastUpdate = 0;
crl::time _lastRecentUpdate = 0;
crl::time _lastFavedUpdate = 0;
crl::time _lastFeaturedUpdate = 0;
crl::time _lastSavedGifsUpdate = 0;
crl::time _lastMasksUpdate = 0;
crl::time _lastEmojiUpdate = 0;
crl::time _lastFeaturedEmojiUpdate = 0;
crl::time _lastRecentAttachedUpdate = 0;
rpl::variable<int> _featuredSetsUnreadCount = 0;
StickersSets _sets;
StickersSetsOrder _setsOrder;
StickersSetsOrder _maskSetsOrder;
StickersSetsOrder _emojiSetsOrder;
StickersSetsOrder _featuredSetsOrder;
StickersSetsOrder _featuredEmojiSetsOrder;
StickersSetsOrder _archivedSetsOrder;
StickersSetsOrder _archivedMaskSetsOrder;
SavedGifs _savedGifs;
};
} // namespace Data

View File

@@ -0,0 +1,249 @@
/*
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 "data/stickers/data_stickers_set.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_document.h"
#include "data/stickers/data_stickers.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
namespace Data {
StickersSetThumbnailView::StickersSetThumbnailView(
not_null<StickersSet*> owner)
: _owner(owner) {
}
not_null<StickersSet*> StickersSetThumbnailView::owner() const {
return _owner;
}
void StickersSetThumbnailView::set(
not_null<Main::Session*> session,
QByteArray content) {
auto image = Images::Read({ .content = content }).image;
if (image.isNull()) {
_content = std::move(content);
} else {
_image = std::make_unique<Image>(std::move(image));
}
session->notifyDownloaderTaskFinished();
}
Image *StickersSetThumbnailView::image() const {
return _image.get();
}
QByteArray StickersSetThumbnailView::content() const {
return _content;
}
StickersSetFlags ParseStickersSetFlags(const MTPDstickerSet &data) {
using Flag = StickersSetFlag;
return (data.is_archived() ? Flag::Archived : Flag())
| (data.is_official() ? Flag::Official : Flag())
| (data.is_masks() ? Flag::Masks : Flag())
| (data.is_emojis() ? Flag::Emoji : Flag())
| (data.vinstalled_date() ? Flag::Installed : Flag())
//| (data.is_videos() ? Flag::Webm : Flag())
| (data.is_text_color() ? Flag::TextColor : Flag())
| (data.is_channel_emoji_status() ? Flag::ChannelStatus : Flag())
| (data.is_creator() ? Flag::AmCreator : Flag());
}
StickersSet::StickersSet(
not_null<Data::Session*> owner,
uint64 id,
uint64 accessHash,
uint64 hash,
const QString &title,
const QString &shortName,
int count,
StickersSetFlags flags,
TimeId installDate)
: id(id)
, accessHash(accessHash)
, hash(hash)
, title(title)
, shortName(shortName)
, count(count)
, flags(flags)
, installDate(installDate)
, _owner(owner) {
}
StickersSet::~StickersSet() = default;
Data::Session &StickersSet::owner() const {
return *_owner;
}
Main::Session &StickersSet::session() const {
return _owner->session();
}
MTPInputStickerSet StickersSet::mtpInput() const {
return (id && accessHash)
? MTP_inputStickerSetID(MTP_long(id), MTP_long(accessHash))
: MTP_inputStickerSetShortName(MTP_string(shortName));
}
StickerSetIdentifier StickersSet::identifier() const {
return StickerSetIdentifier{
.id = id,
.accessHash = accessHash,
};
}
StickersType StickersSet::type() const {
return (flags & StickersSetFlag::Emoji)
? StickersType::Emoji
: (flags & StickersSetFlag::Masks)
? StickersType::Masks
: StickersType::Stickers;
}
bool StickersSet::textColor() const {
return flags & StickersSetFlag::TextColor;
}
bool StickersSet::channelStatus() const {
return flags & StickersSetFlag::ChannelStatus;
}
void StickersSet::setThumbnail(
const ImageWithLocation &data,
StickerType type) {
_thumbnailType = type;
Data::UpdateCloudFile(
_thumbnail,
data,
_owner->cache(),
Data::kImageCacheTag,
[=](Data::FileOrigin origin) { loadThumbnail(); });
if (!data.bytes.isEmpty()) {
if (_thumbnail.loader) {
_thumbnail.loader->cancel();
}
if (const auto view = activeThumbnailView()) {
view->set(&_owner->session(), data.bytes);
}
}
}
bool StickersSet::hasThumbnail() const {
return _thumbnail.location.valid();
}
StickerType StickersSet::thumbnailType() const {
return _thumbnailType;
}
bool StickersSet::thumbnailLoading() const {
return (_thumbnail.loader != nullptr);
}
bool StickersSet::thumbnailFailed() const {
return (_thumbnail.flags & Data::CloudFile::Flag::Failed);
}
void StickersSet::loadThumbnail() {
const auto autoLoading = false;
const auto finalCheck = [=] {
if (const auto active = activeThumbnailView()) {
return !active->image() && active->content().isEmpty();
}
return true;
};
const auto done = [=](QByteArray result) {
if (const auto active = activeThumbnailView()) {
active->set(&_owner->session(), std::move(result));
}
};
Data::LoadCloudFile(
&_owner->session(),
_thumbnail,
Data::FileOriginStickerSet(id, accessHash),
LoadFromCloudOrLocal,
autoLoading,
Data::kImageCacheTag,
finalCheck,
done);
}
const ImageLocation &StickersSet::thumbnailLocation() const {
return _thumbnail.location;
}
Storage::Cache::Key StickersSet::thumbnailBigFileBaseCacheKey() const {
const auto &location = _thumbnail.location.file().data;
if (const auto storage = std::get_if<StorageFileLocation>(&location)) {
return storage->bigFileBaseCacheKey();
}
return {};
}
int StickersSet::thumbnailByteSize() const {
return _thumbnail.byteSize;
}
DocumentData *StickersSet::lookupThumbnailDocument() const {
if (thumbnailDocumentId) {
const auto i = ranges::find(
stickers,
thumbnailDocumentId,
&DocumentData::id);
if (i != stickers.end()) {
return *i;
}
}
return !stickers.empty()
? stickers.front()
: !covers.empty()
? covers.front()
: nullptr;
}
std::shared_ptr<StickersSetThumbnailView> StickersSet::createThumbnailView() {
if (auto active = activeThumbnailView()) {
return active;
}
auto view = std::make_shared<StickersSetThumbnailView>(this);
_thumbnailView = view;
return view;
}
std::shared_ptr<StickersSetThumbnailView> StickersSet::activeThumbnailView() {
return _thumbnailView.lock();
}
MTPInputStickerSet InputStickerSet(StickerSetIdentifier id) {
return !id
? MTP_inputStickerSetEmpty()
: id.id
? MTP_inputStickerSetID(MTP_long(id.id), MTP_long(id.accessHash))
: MTP_inputStickerSetShortName(MTP_string(id.shortName));
}
StickerSetIdentifier FromInputSet(const MTPInputStickerSet &id) {
return id.match([](const MTPDinputStickerSetID &data) {
return StickerSetIdentifier{
.id = data.vid().v,
.accessHash = data.vaccess_hash().v,
};
}, [](const MTPDinputStickerSetShortName &data) {
return StickerSetIdentifier{ .shortName = qs(data.vshort_name()) };
}, [](const auto &) {
return StickerSetIdentifier();
});
}
} // namespace Stickers

View File

@@ -0,0 +1,138 @@
/*
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 "data/data_cloud_file.h"
class DocumentData;
enum class StickerType : uchar;
namespace Main {
class Session;
} // namespace Main
namespace Data {
class Session;
using StickersSetsOrder = QList<uint64>;
using SavedGifs = QVector<DocumentData*>;
using StickersPack = QVector<DocumentData*>;
enum class StickersType : uchar;
class StickersSet;
using StickersSets = base::flat_map<uint64, std::unique_ptr<StickersSet>>;
class StickersSetThumbnailView final {
public:
explicit StickersSetThumbnailView(not_null<StickersSet*> owner);
[[nodiscard]] not_null<StickersSet*> owner() const;
void set(not_null<Main::Session*> session, QByteArray content);
[[nodiscard]] Image *image() const;
[[nodiscard]] QByteArray content() const;
private:
const not_null<StickersSet*> _owner;
std::unique_ptr<Image> _image;
QByteArray _content;
};
enum class StickersSetFlag : ushort {
Installed = (1 << 0),
Archived = (1 << 1),
Masks = (1 << 2),
Official = (1 << 3),
NotLoaded = (1 << 4),
Featured = (1 << 5),
Unread = (1 << 6),
Special = (1 << 7),
Emoji = (1 << 9),
TextColor = (1 << 10),
ChannelStatus = (1 << 11),
AmCreator = (1 << 12),
};
inline constexpr bool is_flag_type(StickersSetFlag) { return true; };
using StickersSetFlags = base::flags<StickersSetFlag>;
[[nodiscard]] StickersSetFlags ParseStickersSetFlags(
const MTPDstickerSet &data);
class StickersSet final {
public:
StickersSet(
not_null<Data::Session*> owner,
uint64 id,
uint64 accessHash,
uint64 hash,
const QString &title,
const QString &shortName,
int count,
StickersSetFlags flags,
TimeId installDate);
~StickersSet();
[[nodiscard]] Data::Session &owner() const;
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] MTPInputStickerSet mtpInput() const;
[[nodiscard]] StickerSetIdentifier identifier() const;
[[nodiscard]] StickersType type() const;
[[nodiscard]] bool textColor() const;
[[nodiscard]] bool channelStatus() const;
void setThumbnail(const ImageWithLocation &data, StickerType type);
[[nodiscard]] bool hasThumbnail() const;
[[nodiscard]] StickerType thumbnailType() const;
[[nodiscard]] bool thumbnailLoading() const;
[[nodiscard]] bool thumbnailFailed() const;
void loadThumbnail();
[[nodiscard]] const ImageLocation &thumbnailLocation() const;
[[nodiscard]] Storage::Cache::Key thumbnailBigFileBaseCacheKey() const;
[[nodiscard]] int thumbnailByteSize() const;
[[nodiscard]] DocumentData *lookupThumbnailDocument() const;
[[nodiscard]] std::shared_ptr<StickersSetThumbnailView> createThumbnailView();
[[nodiscard]] std::shared_ptr<StickersSetThumbnailView> activeThumbnailView();
uint64 id = 0;
uint64 accessHash = 0;
uint64 hash = 0;
DocumentId thumbnailDocumentId = 0;
QString title, shortName;
int count = 0;
int locked = 0;
StickersSetFlags flags;
private:
StickerType _thumbnailType = {};
public:
TimeId installDate = 0;
StickersPack covers;
StickersPack stickers;
std::vector<TimeId> dates;
base::flat_map<EmojiPtr, StickersPack> emoji;
private:
const not_null<Data::Session*> _owner;
CloudFile _thumbnail;
std::weak_ptr<StickersSetThumbnailView> _thumbnailView;
};
[[nodiscard]] MTPInputStickerSet InputStickerSet(StickerSetIdentifier id);
[[nodiscard]] StickerSetIdentifier FromInputSet(const MTPInputStickerSet &id);
} // namespace Data