Improve mixed stickerpacks support.

This commit is contained in:
John Preston 2024-03-16 10:58:07 +04:00
parent b1795f8c5a
commit 90e572c8b1
11 changed files with 117 additions and 42 deletions

View file

@ -353,6 +353,7 @@ private:
int _perRow = 0; int _perRow = 0;
QSize _singleSize; QSize _singleSize;
TimeId _setInstallDate = TimeId(0); TimeId _setInstallDate = TimeId(0);
StickerType _setThumbnailType = StickerType::Webp;
ImageWithLocation _setThumbnail; ImageWithLocation _setThumbnail;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient; const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
@ -755,6 +756,8 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
set, set,
thumb); thumb);
if (result.location.valid()) { if (result.location.valid()) {
_setThumbnailType
= Data::ThumbnailTypeFromPhotoSize(thumb);
return result; return result;
} }
} }
@ -775,7 +778,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
set->installDate = _setInstallDate; set->installDate = _setInstallDate;
set->stickers = _pack; set->stickers = _pack;
set->emoji = _emoji; set->emoji = _emoji;
set->setThumbnail(_setThumbnail); set->setThumbnail(_setThumbnail, _setThumbnailType);
} }
}); });
}, [&](const MTPDmessages_stickerSetNotModified &data) { }, [&](const MTPDmessages_stickerSetNotModified &data) {
@ -855,7 +858,7 @@ void StickerSetBox::Inner::installDone(
} }
const auto set = it->second.get(); const auto set = it->second.get();
set->thumbnailDocumentId = _setThumbnailDocumentId; set->thumbnailDocumentId = _setThumbnailDocumentId;
set->setThumbnail(_setThumbnail); set->setThumbnail(_setThumbnail, _setThumbnailType);
set->stickers = _pack; set->stickers = _pack;
set->emoji = _emoji; set->emoji = _emoji;

View file

@ -178,7 +178,6 @@ private:
[[nodiscard]] bool isRecentSet() const; [[nodiscard]] bool isRecentSet() const;
[[nodiscard]] bool isMasksSet() const; [[nodiscard]] bool isMasksSet() const;
[[nodiscard]] bool isEmojiSet() const; [[nodiscard]] bool isEmojiSet() const;
[[nodiscard]] bool isWebm() const;
[[nodiscard]] bool isInstalled() const; [[nodiscard]] bool isInstalled() const;
[[nodiscard]] bool isUnread() const; [[nodiscard]] bool isUnread() const;
[[nodiscard]] bool isArchived() const; [[nodiscard]] bool isArchived() const;
@ -1174,10 +1173,6 @@ bool StickersBox::Inner::Row::isEmojiSet() const {
return (set->type() == Data::StickersType::Emoji); return (set->type() == Data::StickersType::Emoji);
} }
bool StickersBox::Inner::Row::isWebm() const {
return (set->flags & SetFlag::Webm);
}
bool StickersBox::Inner::Row::isInstalled() const { bool StickersBox::Inner::Row::isInstalled() const {
return (flagsOverride & SetFlag::Installed); return (flagsOverride & SetFlag::Installed);
} }
@ -1569,7 +1564,7 @@ void StickersBox::Inner::paintRowThumbnail(
void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) { void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) {
if (row->lottie if (row->lottie
|| !ChatHelpers::HasLottieThumbnail( || !ChatHelpers::HasLottieThumbnail(
row->set->flags, row->set->thumbnailType(),
row->thumbnailMedia.get(), row->thumbnailMedia.get(),
row->stickerMedia.get())) { row->stickerMedia.get())) {
return; return;
@ -1592,7 +1587,7 @@ void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) {
void StickersBox::Inner::validateWebmAnimation(not_null<Row*> row) { void StickersBox::Inner::validateWebmAnimation(not_null<Row*> row) {
if (row->webm if (row->webm
|| !ChatHelpers::HasWebmThumbnail( || !ChatHelpers::HasWebmThumbnail(
row->set->flags, row->set->thumbnailType(),
row->thumbnailMedia.get(), row->thumbnailMedia.get(),
row->stickerMedia.get())) { row->stickerMedia.get())) {
return; return;

View file

@ -668,8 +668,9 @@ GroupCall::GroupCall(
GroupCall::~GroupCall() { GroupCall::~GroupCall() {
destroyScreencast(); destroyScreencast();
destroyController(); destroyController();
if (!_rtmp) {
Core::App().mediaDevices().setCaptureMuteTracker(this, false); Core::App().mediaDevices().setCaptureMuteTracker(this, false);
}
} }
bool GroupCall::isSharingScreen() const { bool GroupCall::isSharingScreen() const {
@ -2091,14 +2092,16 @@ void GroupCall::setupMediaDevices() {
_cameraCapture->switchToDevice(deviceId.value.toStdString(), false); _cameraCapture->switchToDevice(deviceId.value.toStdString(), false);
}, _lifetime); }, _lifetime);
_muted.value() | rpl::start_with_next([=](MuteState state) { if (!_rtmp) {
const auto devices = &Core::App().mediaDevices(); _muted.value() | rpl::start_with_next([=](MuteState state) {
const auto muted = (state != MuteState::Active) const auto devices = &Core::App().mediaDevices();
&& (state != MuteState::PushToTalk); const auto muted = (state != MuteState::Active)
const auto track = !muted || (state == MuteState::Muted); && (state != MuteState::PushToTalk);
devices->setCaptureMuteTracker(this, track); const auto track = !muted || (state == MuteState::Muted);
devices->setCaptureMuted(muted); devices->setCaptureMuteTracker(this, track);
}, _lifetime); devices->setCaptureMuted(muted);
}, _lifetime);
}
} }
void GroupCall::captureMuteChanged(bool mute) { void GroupCall::captureMuteChanged(bool mute) {

View file

@ -1182,7 +1182,7 @@ void StickersListFooter::validateIconLottieAnimation(
if (icon.lottie if (icon.lottie
|| !icon.sticker || !icon.sticker
|| !HasLottieThumbnail( || !HasLottieThumbnail(
icon.set ? icon.set->flags : Data::StickersSetFlags(), icon.set ? icon.set->thumbnailType() : StickerType(),
icon.thumbnailMedia.get(), icon.thumbnailMedia.get(),
icon.stickerMedia.get())) { icon.stickerMedia.get())) {
return; return;
@ -1211,7 +1211,7 @@ void StickersListFooter::validateIconWebmAnimation(
if (icon.webm if (icon.webm
|| !icon.sticker || !icon.sticker
|| !HasWebmThumbnail( || !HasWebmThumbnail(
icon.set ? icon.set->flags : Data::StickersSetFlags(), icon.set ? icon.set->thumbnailType() : StickerType(),
icon.thumbnailMedia.get(), icon.thumbnailMedia.get(),
icon.stickerMedia.get())) { icon.stickerMedia.get())) {
return; return;

View file

@ -138,11 +138,11 @@ not_null<Lottie::Animation*> LottieAnimationFromDocument(
} }
bool HasLottieThumbnail( bool HasLottieThumbnail(
Data::StickersSetFlags flags, StickerType thumbType,
Data::StickersSetThumbnailView *thumb, Data::StickersSetThumbnailView *thumb,
Data::DocumentMedia *media) { Data::DocumentMedia *media) {
if (thumb) { if (thumb) {
return !(flags & Data::StickersSetFlag::Webm) return (thumbType == StickerType::Tgs)
&& !thumb->content().isEmpty(); && !thumb->content().isEmpty();
} else if (!media) { } else if (!media) {
return false; return false;
@ -200,11 +200,11 @@ std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
} }
bool HasWebmThumbnail( bool HasWebmThumbnail(
Data::StickersSetFlags flags, StickerType thumbType,
Data::StickersSetThumbnailView *thumb, Data::StickersSetThumbnailView *thumb,
Data::DocumentMedia *media) { Data::DocumentMedia *media) {
if (thumb) { if (thumb) {
return (flags & Data::StickersSetFlag::Webm) return (thumbType == StickerType::Webm)
&& !thumb->content().isEmpty(); && !thumb->content().isEmpty();
} else if (!media) { } else if (!media) {
return false; return false;

View file

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
enum class StickerType : uchar;
namespace base { namespace base {
template <typename Enum> template <typename Enum>
class Flags; class Flags;
@ -43,7 +45,7 @@ class PathShiftGradient;
namespace Data { namespace Data {
class DocumentMedia; class DocumentMedia;
class StickersSetThumbnailView; class StickersSetThumbnailView;
enum class StickersSetFlag; enum class StickersSetFlag : ushort;
using StickersSetFlags = base::flags<StickersSetFlag>; using StickersSetFlags = base::flags<StickersSetFlag>;
} // namespace Data } // namespace Data
@ -90,7 +92,7 @@ enum class StickerLottieSize : uint8 {
QSize box); QSize box);
[[nodiscard]] bool HasLottieThumbnail( [[nodiscard]] bool HasLottieThumbnail(
Data::StickersSetFlags flags, StickerType thumbType,
Data::StickersSetThumbnailView *thumb, Data::StickersSetThumbnailView *thumb,
Data::DocumentMedia *media); Data::DocumentMedia *media);
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail( [[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
@ -101,7 +103,7 @@ enum class StickerLottieSize : uint8 {
std::shared_ptr<Lottie::FrameRenderer> renderer = nullptr); std::shared_ptr<Lottie::FrameRenderer> renderer = nullptr);
[[nodiscard]] bool HasWebmThumbnail( [[nodiscard]] bool HasWebmThumbnail(
Data::StickersSetFlags flags, StickerType thumbType,
Data::StickersSetThumbnailView *thumb, Data::StickersSetThumbnailView *thumb,
Data::DocumentMedia *media); Data::DocumentMedia *media);
[[nodiscard]] Media::Clip::ReaderPointer WebmThumbnail( [[nodiscard]] Media::Clip::ReaderPointer WebmThumbnail(

View file

@ -1003,6 +1003,7 @@ void Stickers::featuredReceived(
auto it = sets.find(data->vid().v); auto it = sets.find(data->vid().v);
const auto title = getSetTitle(*data); const auto title = getSetTitle(*data);
const auto installDate = data->vinstalled_date().value_or_empty(); const auto installDate = data->vinstalled_date().value_or_empty();
auto thumbnailType = StickerType::Webp;
const auto thumbnail = [&] { const auto thumbnail = [&] {
if (const auto thumbs = data->vthumbs()) { if (const auto thumbs = data->vthumbs()) {
for (const auto &thumb : thumbs->v) { for (const auto &thumb : thumbs->v) {
@ -1011,6 +1012,7 @@ void Stickers::featuredReceived(
*data, *data,
thumb); thumb);
if (result.location.valid()) { if (result.location.valid()) {
thumbnailType = ThumbnailTypeFromPhotoSize(thumb);
return result; return result;
} }
} }
@ -1046,7 +1048,7 @@ void Stickers::featuredReceived(
set->flags |= SetFlag::NotLoaded; // need to request this set set->flags |= SetFlag::NotLoaded; // need to request this set
} }
} }
it->second->setThumbnail(thumbnail); it->second->setThumbnail(thumbnail, thumbnailType);
it->second->thumbnailDocumentId = data->vthumb_document_id().value_or_empty(); it->second->thumbnailDocumentId = data->vthumb_document_id().value_or_empty();
featuredOrder.push_back(data->vid().v); featuredOrder.push_back(data->vid().v);
if (it->second->stickers.isEmpty() if (it->second->stickers.isEmpty()
@ -1415,6 +1417,7 @@ not_null<StickersSet*> Stickers::feedSet(const MTPStickerSet &info) {
auto it = sets.find(data.vid().v); auto it = sets.find(data.vid().v);
auto title = getSetTitle(data); auto title = getSetTitle(data);
auto oldFlags = StickersSetFlags(0); auto oldFlags = StickersSetFlags(0);
auto thumbnailType = StickerType::Webp;
const auto thumbnail = [&] { const auto thumbnail = [&] {
if (const auto thumbs = data.vthumbs()) { if (const auto thumbs = data.vthumbs()) {
for (const auto &thumb : thumbs->v) { for (const auto &thumb : thumbs->v) {
@ -1423,6 +1426,7 @@ not_null<StickersSet*> Stickers::feedSet(const MTPStickerSet &info) {
data, data,
thumb); thumb);
if (result.location.valid()) { if (result.location.valid()) {
thumbnailType = Data::ThumbnailTypeFromPhotoSize(thumb);
return result; return result;
} }
} }
@ -1467,7 +1471,7 @@ not_null<StickersSet*> Stickers::feedSet(const MTPStickerSet &info) {
} }
} }
const auto set = it->second.get(); const auto set = it->second.get();
set->setThumbnail(thumbnail); set->setThumbnail(thumbnail, thumbnailType);
set->thumbnailDocumentId = data.vthumb_document_id().value_or_empty(); set->thumbnailDocumentId = data.vthumb_document_id().value_or_empty();
auto changedFlags = (oldFlags ^ set->flags); auto changedFlags = (oldFlags ^ set->flags);
if (changedFlags & SetFlag::Archived) { if (changedFlags & SetFlag::Archived) {
@ -1683,4 +1687,17 @@ RecentStickerPack &Stickers::getRecentPack() const {
return cRefRecentStickers(); return cRefRecentStickers();
} }
StickerType ThumbnailTypeFromPhotoSize(const MTPPhotoSize &size) {
const auto &type = size.match([&](const auto &data) {
return data.vtype().v;
});
const auto ch = type.isEmpty() ? char() : type[0];
switch (ch) {
case 's': return StickerType::Webp;
case 'a': return StickerType::Tgs;
case 'v': return StickerType::Webm;
}
return StickerType::Webp;
}
} // namespace Stickers } // namespace Stickers

View file

@ -36,6 +36,8 @@ enum class StickersType : uchar {
Masks, Masks,
Emoji, Emoji,
}; };
[[nodiscard]] StickerType ThumbnailTypeFromPhotoSize(
const MTPPhotoSize &size);
class Stickers final { class Stickers final {
public: public:

View file

@ -118,7 +118,10 @@ bool StickersSet::channelStatus() const {
return flags & StickersSetFlag::ChannelStatus; return flags & StickersSetFlag::ChannelStatus;
} }
void StickersSet::setThumbnail(const ImageWithLocation &data) { void StickersSet::setThumbnail(
const ImageWithLocation &data,
StickerType type) {
_thumbnailType = type;
Data::UpdateCloudFile( Data::UpdateCloudFile(
_thumbnail, _thumbnail,
data, data,
@ -139,6 +142,10 @@ bool StickersSet::hasThumbnail() const {
return _thumbnail.location.valid(); return _thumbnail.location.valid();
} }
StickerType StickersSet::thumbnailType() const {
return _thumbnailType;
}
bool StickersSet::thumbnailLoading() const { bool StickersSet::thumbnailLoading() const {
return (_thumbnail.loader != nullptr); return (_thumbnail.loader != nullptr);
} }

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_cloud_file.h" #include "data/data_cloud_file.h"
class DocumentData; class DocumentData;
enum class StickerType : uchar;
namespace Main { namespace Main {
class Session; class Session;
@ -46,7 +47,7 @@ private:
}; };
enum class StickersSetFlag { enum class StickersSetFlag : ushort {
Installed = (1 << 0), Installed = (1 << 0),
Archived = (1 << 1), Archived = (1 << 1),
Masks = (1 << 2), Masks = (1 << 2),
@ -55,7 +56,6 @@ enum class StickersSetFlag {
Featured = (1 << 5), Featured = (1 << 5),
Unread = (1 << 6), Unread = (1 << 6),
Special = (1 << 7), Special = (1 << 7),
Webm = (1 << 8),
Emoji = (1 << 9), Emoji = (1 << 9),
TextColor = (1 << 10), TextColor = (1 << 10),
ChannelStatus = (1 << 11), ChannelStatus = (1 << 11),
@ -89,9 +89,10 @@ public:
[[nodiscard]] bool textColor() const; [[nodiscard]] bool textColor() const;
[[nodiscard]] bool channelStatus() const; [[nodiscard]] bool channelStatus() const;
void setThumbnail(const ImageWithLocation &data); void setThumbnail(const ImageWithLocation &data, StickerType type);
[[nodiscard]] bool hasThumbnail() const; [[nodiscard]] bool hasThumbnail() const;
[[nodiscard]] StickerType thumbnailType() const;
[[nodiscard]] bool thumbnailLoading() const; [[nodiscard]] bool thumbnailLoading() const;
[[nodiscard]] bool thumbnailFailed() const; [[nodiscard]] bool thumbnailFailed() const;
void loadThumbnail(); void loadThumbnail();
@ -111,6 +112,11 @@ public:
int count = 0; int count = 0;
int locked = 0; int locked = 0;
StickersSetFlags flags; StickersSetFlags flags;
private:
StickerType _thumbnailType = {};
public:
TimeId installDate = 0; TimeId installDate = 0;
StickersPack covers; StickersPack covers;
StickersPack stickers; StickersPack stickers;

View file

@ -44,7 +44,7 @@ using Database = Cache::Database;
constexpr auto kDelayedWriteTimeout = crl::time(1000); constexpr auto kDelayedWriteTimeout = crl::time(1000);
constexpr auto kStickersVersionTag = quint32(-1); constexpr auto kStickersVersionTag = quint32(-1);
constexpr auto kStickersSerializeVersion = 3; constexpr auto kStickersSerializeVersion = 4;
constexpr auto kMaxSavedStickerSetsCount = 1000; constexpr auto kMaxSavedStickerSetsCount = 1000;
constexpr auto kDefaultStickerInstallDate = TimeId(1); constexpr auto kDefaultStickerInstallDate = TimeId(1);
@ -1683,7 +1683,8 @@ void Account::writeStickerSet(
<< qint32(count) << qint32(count)
<< qint32(set.flags) << qint32(set.flags)
<< qint32(set.installDate) << qint32(set.installDate)
<< quint64(set.thumbnailDocumentId); << quint64(set.thumbnailDocumentId)
<< qint32(set.thumbnailType());
Serialize::writeImageLocation(stream, set.thumbnailLocation()); Serialize::writeImageLocation(stream, set.thumbnailLocation());
}; };
if (set.flags & SetFlag::NotLoaded) { if (set.flags & SetFlag::NotLoaded) {
@ -1752,11 +1753,23 @@ void Account::writeStickerSets(
continue; continue;
} }
// id + accessHash + hash + title + shortName + stickersCount + flags + installDate // id
// + accessHash
// + hash
// + title
// + shortName
// + stickersCount
// + flags
// + installDate
// + thumbnailDocumentId
// + thumbnailType
// + thumbnailLocation
size += sizeof(quint64) * 3 size += sizeof(quint64) * 3
+ Serialize::stringSize(raw->title) + Serialize::stringSize(raw->title)
+ Serialize::stringSize(raw->shortName) + Serialize::stringSize(raw->shortName)
+ sizeof(qint32) * 3 + sizeof(qint32) * 3
+ sizeof(quint64)
+ sizeof(qint32)
+ Serialize::imageLocationSize(raw->thumbnailLocation()); + Serialize::imageLocationSize(raw->thumbnailLocation());
if (raw->flags & SetFlag::NotLoaded) { if (raw->flags & SetFlag::NotLoaded) {
continue; continue;
@ -1838,8 +1851,7 @@ void Account::readStickerSets(
quint32 versionTag = 0; quint32 versionTag = 0;
qint32 version = 0; qint32 version = 0;
stickers.stream >> versionTag >> version; stickers.stream >> versionTag >> version;
if (versionTag != kStickersVersionTag if (versionTag != kStickersVersionTag || version < 2) {
|| (version != 2 && version != kStickersSerializeVersion)) {
// Old data, without sticker set thumbnails. // Old data, without sticker set thumbnails.
return failed(); return failed();
} }
@ -1858,6 +1870,7 @@ void Account::readStickerSets(
qint32 setInstallDate = 0; qint32 setInstallDate = 0;
Data::StickersSetFlags setFlags = 0; Data::StickersSetFlags setFlags = 0;
qint32 setFlagsValue = 0; qint32 setFlagsValue = 0;
qint32 setThumbnailType = qint32(StickerType::Webp);
ImageLocation setThumbnail; ImageLocation setThumbnail;
stickers.stream stickers.stream
@ -1871,6 +1884,14 @@ void Account::readStickerSets(
>> setInstallDate; >> setInstallDate;
if (version > 2) { if (version > 2) {
stickers.stream >> setThumbnailDocumentId; stickers.stream >> setThumbnailDocumentId;
if (version > 3) {
stickers.stream >> setThumbnailType;
}
}
constexpr auto kLegacyFlagWebm = (1 << 8);
if ((version < 4) && (setFlagsValue & kLegacyFlagWebm)) {
setThumbnailType = qint32(StickerType::Webm);
} }
const auto thumbnail = Serialize::readImageLocation( const auto thumbnail = Serialize::readImageLocation(
stickers.version, stickers.version,
@ -1903,7 +1924,8 @@ void Account::readStickerSets(
} }
auto it = sets.find(setId); auto it = sets.find(setId);
if (it == sets.cend()) { auto settingSet = (it == sets.cend());
if (settingSet) {
// We will set this flags from order lists when reading those stickers. // We will set this flags from order lists when reading those stickers.
setFlags &= ~(SetFlag::Installed | SetFlag::Featured); setFlags &= ~(SetFlag::Installed | SetFlag::Featured);
it = sets.emplace(setId, std::make_unique<Data::StickersSet>( it = sets.emplace(setId, std::make_unique<Data::StickersSet>(
@ -1916,8 +1938,6 @@ void Account::readStickerSets(
0, 0,
setFlags, setFlags,
setInstallDate)).first; setInstallDate)).first;
it->second->setThumbnail(
ImageWithLocation{ .location = setThumbnail });
it->second->thumbnailDocumentId = setThumbnailDocumentId; it->second->thumbnailDocumentId = setThumbnailDocumentId;
} }
const auto set = it->second.get(); const auto set = it->second.get();
@ -2014,6 +2034,26 @@ void Account::readStickerSets(
} }
} }
} }
if (settingSet) {
if (version < 4
&& setThumbnailType == qint32(StickerType::Webp)
&& !set->stickers.empty()
&& set->stickers.front()->sticker()) {
const auto first = set->stickers.front();
setThumbnailType = qint32(first->sticker()->type);
}
const auto thumbType = [&] {
switch (setThumbnailType) {
case qint32(StickerType::Webp): return StickerType::Webp;
case qint32(StickerType::Tgs): return StickerType::Tgs;
case qint32(StickerType::Webm): return StickerType::Webm;
}
return StickerType::Webp;
}();
set->setThumbnail(
ImageWithLocation{ .location = setThumbnail }, thumbType);
}
} }
// Read orders of installed and featured stickers. // Read orders of installed and featured stickers.