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
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:
1116
Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp
Normal file
1116
Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp
Normal file
File diff suppressed because it is too large
Load Diff
214
Telegram/SourceFiles/data/stickers/data_custom_emoji.h
Normal file
214
Telegram/SourceFiles/data/stickers/data_custom_emoji.h
Normal 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
|
||||
1849
Telegram/SourceFiles/data/stickers/data_stickers.cpp
Normal file
1849
Telegram/SourceFiles/data/stickers/data_stickers.cpp
Normal file
File diff suppressed because it is too large
Load Diff
332
Telegram/SourceFiles/data/stickers/data_stickers.h
Normal file
332
Telegram/SourceFiles/data/stickers/data_stickers.h
Normal 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
|
||||
249
Telegram/SourceFiles/data/stickers/data_stickers_set.cpp
Normal file
249
Telegram/SourceFiles/data/stickers/data_stickers_set.cpp
Normal 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
|
||||
138
Telegram/SourceFiles/data/stickers/data_stickers_set.h
Normal file
138
Telegram/SourceFiles/data/stickers/data_stickers_set.h
Normal 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
|
||||
Reference in New Issue
Block a user