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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1003,6 +1003,7 @@ void Stickers::featuredReceived(
auto it = sets.find(data->vid().v);
const auto title = getSetTitle(*data);
const auto installDate = data->vinstalled_date().value_or_empty();
auto thumbnailType = StickerType::Webp;
const auto thumbnail = [&] {
if (const auto thumbs = data->vthumbs()) {
for (const auto &thumb : thumbs->v) {
@ -1011,6 +1012,7 @@ void Stickers::featuredReceived(
*data,
thumb);
if (result.location.valid()) {
thumbnailType = ThumbnailTypeFromPhotoSize(thumb);
return result;
}
}
@ -1046,7 +1048,7 @@ void Stickers::featuredReceived(
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();
featuredOrder.push_back(data->vid().v);
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 title = getSetTitle(data);
auto oldFlags = StickersSetFlags(0);
auto thumbnailType = StickerType::Webp;
const auto thumbnail = [&] {
if (const auto thumbs = data.vthumbs()) {
for (const auto &thumb : thumbs->v) {
@ -1423,6 +1426,7 @@ not_null<StickersSet*> Stickers::feedSet(const MTPStickerSet &info) {
data,
thumb);
if (result.location.valid()) {
thumbnailType = Data::ThumbnailTypeFromPhotoSize(thumb);
return result;
}
}
@ -1467,7 +1471,7 @@ not_null<StickersSet*> Stickers::feedSet(const MTPStickerSet &info) {
}
}
const auto set = it->second.get();
set->setThumbnail(thumbnail);
set->setThumbnail(thumbnail, thumbnailType);
set->thumbnailDocumentId = data.vthumb_document_id().value_or_empty();
auto changedFlags = (oldFlags ^ set->flags);
if (changedFlags & SetFlag::Archived) {
@ -1683,4 +1687,17 @@ RecentStickerPack &Stickers::getRecentPack() const {
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

View file

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

View file

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

View file

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

View file

@ -44,7 +44,7 @@ using Database = Cache::Database;
constexpr auto kDelayedWriteTimeout = crl::time(1000);
constexpr auto kStickersVersionTag = quint32(-1);
constexpr auto kStickersSerializeVersion = 3;
constexpr auto kStickersSerializeVersion = 4;
constexpr auto kMaxSavedStickerSetsCount = 1000;
constexpr auto kDefaultStickerInstallDate = TimeId(1);
@ -1683,7 +1683,8 @@ void Account::writeStickerSet(
<< qint32(count)
<< qint32(set.flags)
<< qint32(set.installDate)
<< quint64(set.thumbnailDocumentId);
<< quint64(set.thumbnailDocumentId)
<< qint32(set.thumbnailType());
Serialize::writeImageLocation(stream, set.thumbnailLocation());
};
if (set.flags & SetFlag::NotLoaded) {
@ -1752,11 +1753,23 @@ void Account::writeStickerSets(
continue;
}
// id + accessHash + hash + title + shortName + stickersCount + flags + installDate
// id
// + accessHash
// + hash
// + title
// + shortName
// + stickersCount
// + flags
// + installDate
// + thumbnailDocumentId
// + thumbnailType
// + thumbnailLocation
size += sizeof(quint64) * 3
+ Serialize::stringSize(raw->title)
+ Serialize::stringSize(raw->shortName)
+ sizeof(qint32) * 3
+ sizeof(quint64)
+ sizeof(qint32)
+ Serialize::imageLocationSize(raw->thumbnailLocation());
if (raw->flags & SetFlag::NotLoaded) {
continue;
@ -1838,8 +1851,7 @@ void Account::readStickerSets(
quint32 versionTag = 0;
qint32 version = 0;
stickers.stream >> versionTag >> version;
if (versionTag != kStickersVersionTag
|| (version != 2 && version != kStickersSerializeVersion)) {
if (versionTag != kStickersVersionTag || version < 2) {
// Old data, without sticker set thumbnails.
return failed();
}
@ -1858,6 +1870,7 @@ void Account::readStickerSets(
qint32 setInstallDate = 0;
Data::StickersSetFlags setFlags = 0;
qint32 setFlagsValue = 0;
qint32 setThumbnailType = qint32(StickerType::Webp);
ImageLocation setThumbnail;
stickers.stream
@ -1871,6 +1884,14 @@ void Account::readStickerSets(
>> setInstallDate;
if (version > 2) {
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(
stickers.version,
@ -1903,7 +1924,8 @@ void Account::readStickerSets(
}
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.
setFlags &= ~(SetFlag::Installed | SetFlag::Featured);
it = sets.emplace(setId, std::make_unique<Data::StickersSet>(
@ -1916,8 +1938,6 @@ void Account::readStickerSets(
0,
setFlags,
setInstallDate)).first;
it->second->setThumbnail(
ImageWithLocation{ .location = setThumbnail });
it->second->thumbnailDocumentId = setThumbnailDocumentId;
}
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.