mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Init webm player for sticker set thumbnails.
This commit is contained in:
parent
10ff71e8f6
commit
20dbf18106
13 changed files with 251 additions and 117 deletions
|
@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/image/image.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
@ -143,10 +144,7 @@ private:
|
|||
int32 count,
|
||||
const QString &title,
|
||||
int titleWidth,
|
||||
bool installed,
|
||||
bool official,
|
||||
bool unread,
|
||||
bool archived,
|
||||
Data::StickersSetFlags flagsOverride,
|
||||
bool removed,
|
||||
int32 pixw,
|
||||
int32 pixh);
|
||||
|
@ -154,6 +152,10 @@ private:
|
|||
|
||||
bool isRecentSet() const;
|
||||
bool isMasksSet() const;
|
||||
bool isWebm() const;
|
||||
bool isInstalled() const;
|
||||
bool isUnread() const;
|
||||
bool isArchived() const;
|
||||
|
||||
const not_null<StickersSet*> set;
|
||||
DocumentData *sticker = nullptr;
|
||||
|
@ -162,16 +164,14 @@ private:
|
|||
int32 count = 0;
|
||||
QString title;
|
||||
int titleWidth = 0;
|
||||
bool installed = false;
|
||||
bool official = false;
|
||||
bool unread = false;
|
||||
bool archived = false;
|
||||
Data::StickersSetFlags flagsOverride;
|
||||
bool removed = false;
|
||||
int32 pixw = 0;
|
||||
int32 pixh = 0;
|
||||
anim::value yadd;
|
||||
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
Media::Clip::ReaderPointer webm;
|
||||
};
|
||||
struct MegagroupSet {
|
||||
inline bool operator==(const MegagroupSet &other) const {
|
||||
|
@ -221,6 +221,8 @@ private:
|
|||
void setActionSel(int32 actionSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
void validateLottieAnimation(not_null<Row*> row);
|
||||
void validateWebmAnimation(not_null<Row*> row);
|
||||
void validateAnimation(not_null<Row*> row);
|
||||
void updateRowThumbnail(not_null<Row*> row);
|
||||
|
||||
void readVisibleSets();
|
||||
|
@ -229,8 +231,12 @@ private:
|
|||
void rebuildAppendSet(not_null<StickersSet*> set, int maxNameWidth);
|
||||
void fillSetCover(not_null<StickersSet*> set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(not_null<StickersSet*> set) const;
|
||||
QString fillSetTitle(not_null<StickersSet*> set, int maxNameWidth, int *outTitleWidth) const;
|
||||
void fillSetFlags(not_null<StickersSet*> set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived);
|
||||
[[nodiscard]] QString fillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) const;
|
||||
[[nodiscard]] Data::StickersSetFlags fillSetFlags(
|
||||
not_null<StickersSet*> set) const;
|
||||
void rebuildMegagroupSet();
|
||||
void fixupMegagroupSetAddress();
|
||||
void handleMegagroupSetAddressChange();
|
||||
|
@ -1030,10 +1036,7 @@ StickersBox::Inner::Row::Row(
|
|||
int32 count,
|
||||
const QString &title,
|
||||
int titleWidth,
|
||||
bool installed,
|
||||
bool official,
|
||||
bool unread,
|
||||
bool archived,
|
||||
Data::StickersSetFlags flagsOverride,
|
||||
bool removed,
|
||||
int32 pixw,
|
||||
int32 pixh)
|
||||
|
@ -1042,10 +1045,7 @@ StickersBox::Inner::Row::Row(
|
|||
, count(count)
|
||||
, title(title)
|
||||
, titleWidth(titleWidth)
|
||||
, installed(installed)
|
||||
, official(official)
|
||||
, unread(unread)
|
||||
, archived(archived)
|
||||
, flagsOverride(flagsOverride)
|
||||
, removed(removed)
|
||||
, pixw(pixw)
|
||||
, pixh(pixh) {
|
||||
|
@ -1062,6 +1062,22 @@ bool StickersBox::Inner::Row::isMasksSet() const {
|
|||
return (set->flags & SetFlag::Masks);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isWebm() const {
|
||||
return (set->flags & SetFlag::Webm);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isInstalled() const {
|
||||
return (flagsOverride & SetFlag::Installed);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isUnread() const {
|
||||
return (flagsOverride & SetFlag::Unread);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isArchived() const {
|
||||
return (flagsOverride & SetFlag::Archived);
|
||||
}
|
||||
|
||||
StickersBox::Inner::Inner(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
|
@ -1302,7 +1318,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
|
|||
p.setPen(st::contactsNameFg);
|
||||
p.drawTextLeft(namex, namey, width(), row->title, row->titleWidth);
|
||||
|
||||
if (row->unread) {
|
||||
if (row->isUnread()) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::stickersFeaturedUnreadBg);
|
||||
|
||||
|
@ -1344,7 +1360,7 @@ void StickersBox::Inner::paintRowThumbnail(
|
|||
row->stickerMedia->thumbnailWanted(origin);
|
||||
}
|
||||
}
|
||||
validateLottieAnimation(row);
|
||||
validateAnimation(row);
|
||||
if (!row->lottie) {
|
||||
const auto thumb = row->thumbnailMedia
|
||||
? row->thumbnailMedia->image()
|
||||
|
@ -1380,6 +1396,7 @@ void StickersBox::Inner::paintRowThumbnail(
|
|||
void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) {
|
||||
if (row->lottie
|
||||
|| !ChatHelpers::HasLottieThumbnail(
|
||||
row->set->flags,
|
||||
row->thumbnailMedia.get(),
|
||||
row->stickerMedia.get())) {
|
||||
return;
|
||||
|
@ -1401,6 +1418,25 @@ void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) {
|
|||
}, lifetime());
|
||||
}
|
||||
|
||||
void StickersBox::Inner::validateWebmAnimation(not_null<Row*> row) {
|
||||
if (row->webm
|
||||
|| !ChatHelpers::HasWebmThumbnail(
|
||||
row->set->flags,
|
||||
row->thumbnailMedia.get(),
|
||||
row->stickerMedia.get())) {
|
||||
return;
|
||||
}
|
||||
row->webm = ChatHelpers::WebmThumbnail(
|
||||
row->thumbnailMedia.get(),
|
||||
row->stickerMedia.get(),
|
||||
[=](Media::Clip::Notification) { updateRowThumbnail(row); });
|
||||
}
|
||||
|
||||
void StickersBox::Inner::validateAnimation(not_null<Row*> row) {
|
||||
validateWebmAnimation(row);
|
||||
validateLottieAnimation(row);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::updateRowThumbnail(not_null<Row*> row) {
|
||||
const auto rowTop = [&] {
|
||||
if (row == _megagroupSelectedSet.get()) {
|
||||
|
@ -1429,7 +1465,7 @@ void StickersBox::Inner::updateRowThumbnail(not_null<Row*> row) {
|
|||
void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int index) {
|
||||
auto removeButton = (_isInstalled && !row->removed);
|
||||
auto rect = relativeButtonRect(removeButton);
|
||||
if (!_isInstalled && row->installed && !row->archived && !row->removed) {
|
||||
if (!_isInstalled && row->isInstalled() && !row->isArchived() && !row->removed) {
|
||||
// Checkbox after installed from Trending or Archived.
|
||||
int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2);
|
||||
int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2;
|
||||
|
@ -1516,7 +1552,7 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
|
|||
auto rippleMask = Ui::RippleAnimation::ellipseMask(QSize(rippleSize, rippleSize));
|
||||
ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton);
|
||||
}
|
||||
} else if (!row->installed || row->archived || row->removed) {
|
||||
} else if (!row->isInstalled() || row->isArchived() || row->removed) {
|
||||
auto rippleSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height);
|
||||
auto rippleMask = Ui::RippleAnimation::roundRectMask(rippleSize, st::roundRadiusSmall);
|
||||
ensureRipple(st::stickersTrendingAdd.ripple, std::move(rippleMask), removeButton);
|
||||
|
@ -1649,7 +1685,7 @@ void StickersBox::Inner::updateSelected() {
|
|||
selected = selectedIndex;
|
||||
local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight);
|
||||
const auto row = _rows[selectedIndex].get();
|
||||
if (!_megagroupSet && (_isInstalled || !row->installed || row->archived || row->removed)) {
|
||||
if (!_megagroupSet && (_isInstalled || !row->isInstalled() || row->isArchived() || row->removed)) {
|
||||
auto removeButton = (_isInstalled && !row->removed);
|
||||
auto rect = myrtlrect(relativeButtonRect(removeButton));
|
||||
actionSel = rect.contains(local) ? selectedIndex : -1;
|
||||
|
@ -1952,8 +1988,10 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
|||
auto sticker = (DocumentData*)nullptr;
|
||||
auto pixw = 0, pixh = 0;
|
||||
fillSetCover(set, &sticker, &pixw, &pixh);
|
||||
auto installed = true, official = false, unread = false, archived = false, removed = false;
|
||||
if (!_megagroupSelectedSet || _megagroupSelectedSet->set->id != set->id) {
|
||||
auto flagsOverride = SetFlag::Installed;
|
||||
auto removed = false;
|
||||
if (!_megagroupSelectedSet
|
||||
|| _megagroupSelectedSet->set->id != set->id) {
|
||||
_megagroupSetField->setText(set->shortName);
|
||||
_megagroupSetField->finishAnimating();
|
||||
}
|
||||
|
@ -1963,10 +2001,7 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
|||
count,
|
||||
title,
|
||||
titleWidth,
|
||||
installed,
|
||||
official,
|
||||
unread,
|
||||
archived,
|
||||
flagsOverride,
|
||||
removed,
|
||||
pixw,
|
||||
pixh);
|
||||
|
@ -2095,13 +2130,14 @@ void StickersBox::Inner::updateRows() {
|
|||
}
|
||||
}
|
||||
if (!row->isRecentSet()) {
|
||||
auto wasInstalled = row->installed;
|
||||
auto wasArchived = row->archived;
|
||||
fillSetFlags(set, &row->installed, &row->official, &row->unread, &row->archived);
|
||||
auto wasInstalled = row->isInstalled();
|
||||
auto wasArchived = row->isArchived();
|
||||
row->flagsOverride = fillSetFlags(set);
|
||||
if (_isInstalled) {
|
||||
row->archived = false;
|
||||
row->flagsOverride &= ~SetFlag::Archived;
|
||||
}
|
||||
if (row->installed != wasInstalled || row->archived != wasArchived) {
|
||||
if (row->isInstalled() != wasInstalled
|
||||
|| row->isArchived() != wasArchived) {
|
||||
row->ripple.reset();
|
||||
}
|
||||
}
|
||||
|
@ -2143,11 +2179,11 @@ int StickersBox::Inner::countMaxNameWidth() const {
|
|||
void StickersBox::Inner::rebuildAppendSet(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth) {
|
||||
bool installed = true, official = true, unread = false, archived = false, removed = false;
|
||||
if (set->id != Data::Stickers::CloudRecentSetId) {
|
||||
fillSetFlags(set, &installed, &official, &unread, &archived);
|
||||
}
|
||||
if (_isInstalled && archived) {
|
||||
auto flagsOverride = (set->id != Data::Stickers::CloudRecentSetId)
|
||||
? fillSetFlags(set)
|
||||
: SetFlag::Installed;
|
||||
auto removed = false;
|
||||
if (_isInstalled && (flagsOverride & SetFlag::Archived)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2176,10 +2212,7 @@ void StickersBox::Inner::rebuildAppendSet(
|
|||
raw->count = count;
|
||||
raw->title = title;
|
||||
raw->titleWidth = titleWidth;
|
||||
raw->installed = installed;
|
||||
raw->official = official;
|
||||
raw->unread = unread;
|
||||
raw->archived = archived;
|
||||
raw->flagsOverride = flagsOverride;
|
||||
raw->removed = removed;
|
||||
raw->pixw = pixw;
|
||||
raw->pixh = pixh;
|
||||
|
@ -2200,10 +2233,7 @@ void StickersBox::Inner::rebuildAppendSet(
|
|||
count,
|
||||
title,
|
||||
titleWidth,
|
||||
installed,
|
||||
official,
|
||||
unread,
|
||||
archived,
|
||||
flagsOverride,
|
||||
removed,
|
||||
pixw,
|
||||
pixh));
|
||||
|
@ -2289,20 +2319,12 @@ QString StickersBox::Inner::fillSetTitle(
|
|||
return result;
|
||||
}
|
||||
|
||||
void StickersBox::Inner::fillSetFlags(
|
||||
not_null<StickersSet*> set,
|
||||
bool *outInstalled,
|
||||
bool *outOfficial,
|
||||
bool *outUnread,
|
||||
bool *outArchived) {
|
||||
*outInstalled = (set->flags & SetFlag::Installed);
|
||||
*outOfficial = (set->flags & SetFlag::Official);
|
||||
*outArchived = (set->flags & SetFlag::Archived);
|
||||
if (_section == Section::Featured) {
|
||||
*outUnread = (set->flags & SetFlag::Unread);
|
||||
} else {
|
||||
*outUnread = false;
|
||||
}
|
||||
Data::StickersSetFlags StickersBox::Inner::fillSetFlags(
|
||||
not_null<StickersSet*> set) const {
|
||||
const auto result = set->flags;
|
||||
return (_section == Section::Featured)
|
||||
? result
|
||||
: (result & ~SetFlag::Unread);
|
||||
}
|
||||
|
||||
template <typename Check>
|
||||
|
@ -2319,7 +2341,7 @@ StickersSetsOrder StickersBox::Inner::collectSets(Check check) const {
|
|||
|
||||
StickersSetsOrder StickersBox::Inner::getOrder() const {
|
||||
return collectSets([](Row *row) {
|
||||
return !row->archived && !row->removed && !row->isRecentSet();
|
||||
return !row->isArchived() && !row->removed && !row->isRecentSet();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2394,7 +2416,7 @@ void StickersBox::Inner::readVisibleSets() {
|
|||
int rowTo = ceilclamp(itemsVisibleBottom, _rowHeight, 0, _rows.size());
|
||||
for (int i = rowFrom; i < rowTo; ++i) {
|
||||
const auto row = _rows[i].get();
|
||||
if (!row->unread) {
|
||||
if (!row->isUnread()) {
|
||||
continue;
|
||||
}
|
||||
if ((i * _rowHeight < itemsVisibleTop)
|
||||
|
|
|
@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h" // GifPauseReason.
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_toggling_media.h" // Api::ToggleFavedSticker
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
@ -97,6 +98,7 @@ struct StickerIcon {
|
|||
uint64 setId = 0;
|
||||
StickersSet *set = nullptr;
|
||||
mutable std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
mutable Media::Clip::ReaderPointer webm;
|
||||
mutable QPixmap savedFrame;
|
||||
DocumentData *sticker = nullptr;
|
||||
ChannelData *megagroup = nullptr;
|
||||
|
@ -157,6 +159,8 @@ private:
|
|||
int newSelected,
|
||||
ValidateIconAnimations animations);
|
||||
void validateIconLottieAnimation(const StickerIcon &icon);
|
||||
void validateIconWebmAnimation(const StickerIcon &icon);
|
||||
void validateIconAnimation(const StickerIcon &icon);
|
||||
|
||||
void refreshIconsGeometry(ValidateIconAnimations animations);
|
||||
void updateSelected();
|
||||
|
@ -792,6 +796,7 @@ void StickersListWidget::Footer::validateIconLottieAnimation(
|
|||
if (icon.lottie
|
||||
|| !icon.sticker
|
||||
|| !HasLottieThumbnail(
|
||||
icon.set ? icon.set->flags : Data::StickersSetFlags(),
|
||||
icon.thumbnailMedia.get(),
|
||||
icon.stickerMedia.get())) {
|
||||
return;
|
||||
|
@ -817,6 +822,30 @@ void StickersListWidget::Footer::validateIconLottieAnimation(
|
|||
}, icon.lifetime);
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::validateIconWebmAnimation(
|
||||
const StickerIcon &icon) {
|
||||
icon.ensureMediaCreated();
|
||||
if (icon.webm
|
||||
|| !icon.sticker
|
||||
|| !HasWebmThumbnail(
|
||||
icon.set ? icon.set->flags : Data::StickersSetFlags(),
|
||||
icon.thumbnailMedia.get(),
|
||||
icon.stickerMedia.get())) {
|
||||
return;
|
||||
}
|
||||
const auto id = icon.setId;
|
||||
icon.webm = WebmThumbnail(
|
||||
icon.thumbnailMedia.get(),
|
||||
icon.stickerMedia.get(),
|
||||
[=](Media::Clip::Notification) { updateSetIcon(id); });
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::validateIconAnimation(
|
||||
const StickerIcon &icon) {
|
||||
validateIconWebmAnimation(icon);
|
||||
validateIconLottieAnimation(icon);
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::updateSetIcon(uint64 setId) {
|
||||
enumerateVisibleIcons([&](const StickerIcon &icon, int x) {
|
||||
if (icon.setId != setId) {
|
||||
|
@ -832,7 +861,7 @@ void StickersListWidget::Footer::paintSetIcon(
|
|||
int x) const {
|
||||
if (icon.sticker) {
|
||||
icon.ensureMediaCreated();
|
||||
const_cast<Footer*>(this)->validateIconLottieAnimation(icon);
|
||||
const_cast<Footer*>(this)->validateIconAnimation(icon);
|
||||
const auto origin = icon.sticker->stickerSetOrigin();
|
||||
const auto thumb = icon.thumbnailMedia
|
||||
? icon.thumbnailMedia->image()
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_session.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "storage/cache/storage_cache_database.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
|
@ -130,10 +131,12 @@ not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
|||
}
|
||||
|
||||
bool HasLottieThumbnail(
|
||||
Data::StickersSetFlags flags,
|
||||
Data::StickersSetThumbnailView *thumb,
|
||||
Data::DocumentMedia *media) {
|
||||
if (thumb) {
|
||||
return !thumb->content().isEmpty();
|
||||
return !(flags & Data::StickersSetFlag::Webm)
|
||||
&& !thumb->content().isEmpty();
|
||||
} else if (!media) {
|
||||
return false;
|
||||
}
|
||||
|
@ -189,6 +192,44 @@ std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
|
|||
box);
|
||||
}
|
||||
|
||||
bool HasWebmThumbnail(
|
||||
Data::StickersSetFlags flags,
|
||||
Data::StickersSetThumbnailView *thumb,
|
||||
Data::DocumentMedia *media) {
|
||||
if (thumb) {
|
||||
return (flags & Data::StickersSetFlag::Webm)
|
||||
&& !thumb->content().isEmpty();
|
||||
} else if (!media) {
|
||||
return false;
|
||||
}
|
||||
const auto document = media->owner();
|
||||
if (const auto info = document->sticker()) {
|
||||
if (!info->isWebm()) {
|
||||
return false;
|
||||
}
|
||||
media->automaticLoad(document->stickerSetOrigin(), nullptr);
|
||||
if (!media->loaded()) {
|
||||
return false;
|
||||
}
|
||||
return document->bigFileBaseCacheKey().valid();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Media::Clip::ReaderPointer WebmThumbnail(
|
||||
Data::StickersSetThumbnailView *thumb,
|
||||
Data::DocumentMedia *media,
|
||||
Fn<void(Media::Clip::Notification)> callback) {
|
||||
return thumb
|
||||
? ::Media::Clip::MakeReader(
|
||||
thumb->content(),
|
||||
std::move(callback))
|
||||
: ::Media::Clip::MakeReader(
|
||||
media->owner()->location(),
|
||||
media->bytes(),
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
bool PaintStickerThumbnailPath(
|
||||
QPainter &p,
|
||||
not_null<Data::DocumentMedia*> media,
|
||||
|
|
|
@ -7,12 +7,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
namespace base {
|
||||
template <typename Enum>
|
||||
class Flags;
|
||||
} // namespace base
|
||||
|
||||
namespace Storage {
|
||||
namespace Cache {
|
||||
struct Key;
|
||||
} // namespace Cache
|
||||
} // namespace Storage
|
||||
|
||||
namespace Media::Clip {
|
||||
class ReaderPointer;
|
||||
enum class Notification;
|
||||
} // namespace Media::Clip
|
||||
|
||||
namespace Lottie {
|
||||
class SinglePlayer;
|
||||
class MultiPlayer;
|
||||
|
@ -33,6 +43,8 @@ class PathShiftGradient;
|
|||
namespace Data {
|
||||
class DocumentMedia;
|
||||
class StickersSetThumbnailView;
|
||||
enum class StickersSetFlag;
|
||||
using StickersSetFlags = base::flags<StickersSetFlag>;
|
||||
} // namespace Data
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
@ -70,6 +82,7 @@ enum class StickerLottieSize : uchar {
|
|||
QSize box);
|
||||
|
||||
[[nodiscard]] bool HasLottieThumbnail(
|
||||
Data::StickersSetFlags flags,
|
||||
Data::StickersSetThumbnailView *thumb,
|
||||
Data::DocumentMedia *media);
|
||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
|
||||
|
@ -79,6 +92,15 @@ enum class StickerLottieSize : uchar {
|
|||
QSize box,
|
||||
std::shared_ptr<Lottie::FrameRenderer> renderer = nullptr);
|
||||
|
||||
[[nodiscard]] bool HasWebmThumbnail(
|
||||
Data::StickersSetFlags flags,
|
||||
Data::StickersSetThumbnailView *thumb,
|
||||
Data::DocumentMedia *media);
|
||||
[[nodiscard]] Media::Clip::ReaderPointer WebmThumbnail(
|
||||
Data::StickersSetThumbnailView *thumb,
|
||||
Data::DocumentMedia *media,
|
||||
Fn<void(Media::Clip::Notification)> callback);
|
||||
|
||||
bool PaintStickerThumbnailPath(
|
||||
QPainter &p,
|
||||
not_null<Data::DocumentMedia*> media,
|
||||
|
|
|
@ -14,7 +14,7 @@ class FileLoader;
|
|||
|
||||
namespace Media {
|
||||
namespace Clip {
|
||||
enum Notification : int;
|
||||
enum class Notification;
|
||||
class ReaderPointer;
|
||||
} // namespace Clip
|
||||
} // namespace Media
|
||||
|
|
|
@ -49,7 +49,8 @@ StickersSetFlags ParseStickersSetFlags(const MTPDstickerSet &data) {
|
|||
return (data.is_archived() ? Flag::Archived : Flag())
|
||||
| (data.is_official() ? Flag::Official : Flag())
|
||||
| (data.is_masks() ? Flag::Masks : Flag())
|
||||
| (data.vinstalled_date() ? Flag::Installed : Flag());
|
||||
| (data.vinstalled_date() ? Flag::Installed : Flag())
|
||||
| (data.is_gifs() ? Flag::Webm : Flag());
|
||||
}
|
||||
|
||||
StickersSet::StickersSet(
|
||||
|
|
|
@ -54,6 +54,7 @@ enum class StickersSetFlag {
|
|||
Featured = (1 << 5),
|
||||
Unread = (1 << 6),
|
||||
Special = (1 << 7),
|
||||
Webm = (1 << 8),
|
||||
};
|
||||
inline constexpr bool is_flag_type(StickersSetFlag) { return true; };
|
||||
using StickersSetFlags = base::flags<StickersSetFlag>;
|
||||
|
|
|
@ -393,7 +393,7 @@ void Gif::unloadHeavyPart() {
|
|||
void Gif::clipCallback(Media::Clip::Notification notification) {
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case NotificationReinit: {
|
||||
case Notification::Reinit: {
|
||||
if (_gif) {
|
||||
if (_gif->state() == State::Error) {
|
||||
_gif.setBad();
|
||||
|
@ -416,7 +416,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
|
|||
update();
|
||||
} break;
|
||||
|
||||
case NotificationRepaint: {
|
||||
case Notification::Repaint: {
|
||||
if (_gif && !_gif->currentDisplayed()) {
|
||||
update();
|
||||
}
|
||||
|
@ -1583,7 +1583,7 @@ void Game::unloadHeavyPart() {
|
|||
void Game::clipCallback(Media::Clip::Notification notification) {
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case NotificationReinit: {
|
||||
case Notification::Reinit: {
|
||||
if (_gif) {
|
||||
if (_gif->state() == State::Error) {
|
||||
_gif.setBad();
|
||||
|
@ -1610,7 +1610,7 @@ void Game::clipCallback(Media::Clip::Notification notification) {
|
|||
update();
|
||||
} break;
|
||||
|
||||
case NotificationRepaint: {
|
||||
case Notification::Repaint: {
|
||||
if (_gif && !_gif->currentDisplayed()) {
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -133,12 +133,12 @@ void Reader::init(const Core::FileLocation &location, const QByteArray &data) {
|
|||
|
||||
Reader::Frame *Reader::frameToShow(int32 *index) const { // 0 means not ready
|
||||
int step = _step.loadAcquire(), i;
|
||||
if (step == WaitingForDimensionsStep) {
|
||||
if (step == kWaitingForDimensionsStep) {
|
||||
if (index) *index = 0;
|
||||
return nullptr;
|
||||
} else if (step == WaitingForRequestStep) {
|
||||
} else if (step == kWaitingForRequestStep) {
|
||||
i = 0;
|
||||
} else if (step == WaitingForFirstFrameStep) {
|
||||
} else if (step == kWaitingForFirstFrameStep) {
|
||||
i = 0;
|
||||
} else {
|
||||
i = (step / 2) % 3;
|
||||
|
@ -149,12 +149,12 @@ Reader::Frame *Reader::frameToShow(int32 *index) const { // 0 means not ready
|
|||
|
||||
Reader::Frame *Reader::frameToWrite(int32 *index) const { // 0 means not ready
|
||||
int32 step = _step.loadAcquire(), i;
|
||||
if (step == WaitingForDimensionsStep) {
|
||||
if (step == kWaitingForDimensionsStep) {
|
||||
i = 0;
|
||||
} else if (step == WaitingForRequestStep) {
|
||||
} else if (step == kWaitingForRequestStep) {
|
||||
if (index) *index = 0;
|
||||
return nullptr;
|
||||
} else if (step == WaitingForFirstFrameStep) {
|
||||
} else if (step == kWaitingForFirstFrameStep) {
|
||||
i = 0;
|
||||
} else {
|
||||
i = ((step + 2) / 2) % 3;
|
||||
|
@ -165,7 +165,9 @@ Reader::Frame *Reader::frameToWrite(int32 *index) const { // 0 means not ready
|
|||
|
||||
Reader::Frame *Reader::frameToWriteNext(bool checkNotWriting, int32 *index) const {
|
||||
int32 step = _step.loadAcquire(), i;
|
||||
if (step == WaitingForDimensionsStep || step == WaitingForRequestStep || (checkNotWriting && (step % 2))) {
|
||||
if (step == kWaitingForDimensionsStep
|
||||
|| step == kWaitingForRequestStep
|
||||
|| (checkNotWriting && (step % 2))) {
|
||||
if (index) *index = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -176,10 +178,10 @@ Reader::Frame *Reader::frameToWriteNext(bool checkNotWriting, int32 *index) cons
|
|||
|
||||
void Reader::moveToNextShow() const {
|
||||
int32 step = _step.loadAcquire();
|
||||
if (step == WaitingForDimensionsStep) {
|
||||
} else if (step == WaitingForRequestStep) {
|
||||
_step.storeRelease(WaitingForFirstFrameStep);
|
||||
} else if (step == WaitingForFirstFrameStep) {
|
||||
if (step == kWaitingForDimensionsStep) {
|
||||
} else if (step == kWaitingForRequestStep) {
|
||||
_step.storeRelease(kWaitingForFirstFrameStep);
|
||||
} else if (step == kWaitingForFirstFrameStep) {
|
||||
} else if (!(step % 2)) {
|
||||
_step.storeRelease(step + 1);
|
||||
}
|
||||
|
@ -187,10 +189,10 @@ void Reader::moveToNextShow() const {
|
|||
|
||||
void Reader::moveToNextWrite() const {
|
||||
int32 step = _step.loadAcquire();
|
||||
if (step == WaitingForDimensionsStep) {
|
||||
_step.storeRelease(WaitingForRequestStep);
|
||||
} else if (step == WaitingForRequestStep) {
|
||||
} else if (step == WaitingForFirstFrameStep) {
|
||||
if (step == kWaitingForDimensionsStep) {
|
||||
_step.storeRelease(kWaitingForRequestStep);
|
||||
} else if (step == kWaitingForRequestStep) {
|
||||
} else if (step == kWaitingForFirstFrameStep) {
|
||||
_step.storeRelease(0);
|
||||
|
||||
// Force paint the first frame so moveToNextShow() is called.
|
||||
|
@ -200,7 +202,10 @@ void Reader::moveToNextWrite() const {
|
|||
}
|
||||
}
|
||||
|
||||
void Reader::callback(Reader *reader, qint32 threadIndex, qint32 notification) {
|
||||
void Reader::SafeCallback(
|
||||
Reader *reader,
|
||||
int threadIndex,
|
||||
Notification notification) {
|
||||
// Check if reader is not deleted already
|
||||
if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader) && reader->_callback) {
|
||||
reader->_callback(Notification(notification));
|
||||
|
@ -211,7 +216,7 @@ void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, Image
|
|||
if (managers.size() <= _threadIndex) error();
|
||||
if (_state == State::Error) return;
|
||||
|
||||
if (_step.loadAcquire() == WaitingForRequestStep) {
|
||||
if (_step.loadAcquire() == kWaitingForRequestStep) {
|
||||
int factor = style::DevicePixelRatio();
|
||||
FrameRequest request;
|
||||
request.factor = factor;
|
||||
|
@ -613,23 +618,29 @@ bool Manager::carries(Reader *reader) const {
|
|||
return _readerPointers.contains(reader);
|
||||
}
|
||||
|
||||
Manager::ReaderPointers::iterator Manager::unsafeFindReaderPointer(ReaderPrivate *reader) {
|
||||
ReaderPointers::iterator it = _readerPointers.find(reader->_interface);
|
||||
auto Manager::unsafeFindReaderPointer(ReaderPrivate *reader)
|
||||
-> ReaderPointers::iterator {
|
||||
const auto it = _readerPointers.find(reader->_interface);
|
||||
|
||||
// could be a new reader which was realloced in the same address
|
||||
return (it == _readerPointers.cend() || it.key()->_private == reader) ? it : _readerPointers.end();
|
||||
return (it == _readerPointers.cend() || it.key()->_private == reader)
|
||||
? it
|
||||
: _readerPointers.end();
|
||||
}
|
||||
|
||||
Manager::ReaderPointers::const_iterator Manager::constUnsafeFindReaderPointer(ReaderPrivate *reader) const {
|
||||
ReaderPointers::const_iterator it = _readerPointers.constFind(reader->_interface);
|
||||
auto Manager::constUnsafeFindReaderPointer(ReaderPrivate *reader) const
|
||||
-> ReaderPointers::const_iterator {
|
||||
const auto it = _readerPointers.constFind(reader->_interface);
|
||||
|
||||
// could be a new reader which was realloced in the same address
|
||||
return (it == _readerPointers.cend() || it.key()->_private == reader) ? it : _readerPointers.cend();
|
||||
return (it == _readerPointers.cend() || it.key()->_private == reader)
|
||||
? it
|
||||
: _readerPointers.cend();
|
||||
}
|
||||
|
||||
void Manager::callback(Reader *reader, Notification notification) {
|
||||
crl::on_main([=, threadIndex = reader->threadIndex()] {
|
||||
Reader::callback(reader, threadIndex, notification);
|
||||
Reader::SafeCallback(reader, threadIndex, notification);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -639,14 +650,14 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, c
|
|||
if (result == ProcessResult::Error) {
|
||||
if (it != _readerPointers.cend()) {
|
||||
it.key()->error();
|
||||
callback(it.key(), NotificationReinit);
|
||||
callback(it.key(), Notification::Reinit);
|
||||
_readerPointers.erase(it);
|
||||
}
|
||||
return false;
|
||||
} else if (result == ProcessResult::Finished) {
|
||||
if (it != _readerPointers.cend()) {
|
||||
it.key()->finished();
|
||||
callback(it.key(), NotificationReinit);
|
||||
callback(it.key(), Notification::Reinit);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -682,14 +693,14 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, c
|
|||
if (result == ProcessResult::Started) {
|
||||
reader->startedAt(ms);
|
||||
it.key()->moveToNextWrite();
|
||||
callback(it.key(), NotificationReinit);
|
||||
callback(it.key(), Notification::Reinit);
|
||||
}
|
||||
} else if (result == ProcessResult::Paused) {
|
||||
it.key()->moveToNextWrite();
|
||||
callback(it.key(), NotificationReinit);
|
||||
callback(it.key(), Notification::Reinit);
|
||||
} else if (result == ProcessResult::Repaint) {
|
||||
it.key()->moveToNextWrite();
|
||||
callback(it.key(), NotificationRepaint);
|
||||
callback(it.key(), Notification::Repaint);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,15 +39,19 @@ struct FrameRequest {
|
|||
RectParts corners = RectPart::AllCorners;
|
||||
};
|
||||
|
||||
enum ReaderSteps : int {
|
||||
WaitingForDimensionsStep = -3, // before ReaderPrivate read the first image and got the original frame size
|
||||
WaitingForRequestStep = -2, // before Reader got the original frame size and prepared the frame request
|
||||
WaitingForFirstFrameStep = -1, // before ReaderPrivate got the frame request and started waiting for the 1-2 delay
|
||||
};
|
||||
// Before ReaderPrivate read the first image and got the original frame size.
|
||||
inline constexpr auto kWaitingForDimensionsStep = -3;
|
||||
|
||||
enum Notification : int {
|
||||
NotificationReinit,
|
||||
NotificationRepaint,
|
||||
// Before Reader got the original frame size and prepared the frame request.
|
||||
inline constexpr auto kWaitingForRequestStep = -2;
|
||||
|
||||
// Before ReaderPrivate got the frame request
|
||||
// and started waiting for the 1-2 delay.
|
||||
inline constexpr auto kWaitingForFirstFrameStep = -1;
|
||||
|
||||
enum class Notification {
|
||||
Reinit,
|
||||
Repaint,
|
||||
};
|
||||
|
||||
class ReaderPrivate;
|
||||
|
@ -64,7 +68,10 @@ public:
|
|||
Reader(const QByteArray &data, Callback &&callback);
|
||||
|
||||
// Reader can be already deleted.
|
||||
static void callback(Reader *reader, qint32 threadIndex, qint32 notification);
|
||||
static void SafeCallback(
|
||||
Reader *reader,
|
||||
int threadIndex,
|
||||
Notification notification);
|
||||
|
||||
void start(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius, RectParts corners);
|
||||
QPixmap current(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius, RectParts corners, crl::time ms);
|
||||
|
@ -94,7 +101,7 @@ public:
|
|||
State state() const;
|
||||
bool started() const {
|
||||
auto step = _step.loadAcquire();
|
||||
return (step == WaitingForFirstFrameStep) || (step >= 0);
|
||||
return (step == kWaitingForFirstFrameStep) || (step >= 0);
|
||||
}
|
||||
bool ready() const;
|
||||
|
||||
|
@ -120,7 +127,7 @@ private:
|
|||
mutable int _height = 0;
|
||||
|
||||
// -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
|
||||
mutable QAtomicInt _step = WaitingForDimensionsStep;
|
||||
mutable QAtomicInt _step = kWaitingForDimensionsStep;
|
||||
struct Frame {
|
||||
void clear() {
|
||||
pix = QPixmap();
|
||||
|
|
|
@ -1897,7 +1897,7 @@ QSize Gif::countFrameSize() const {
|
|||
void Gif::clipCallback(Media::Clip::Notification notification) {
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case NotificationReinit: {
|
||||
case Notification::Reinit: {
|
||||
if (_gif) {
|
||||
if (_gif->state() == State::Error) {
|
||||
_gif.setBad();
|
||||
|
@ -1926,7 +1926,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
|
|||
update();
|
||||
} break;
|
||||
|
||||
case NotificationRepaint: {
|
||||
case Notification::Repaint: {
|
||||
if (_gif && !_gif->currentDisplayed()) {
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ void SingleMediaPreview::clipCallback(
|
|||
Media::Clip::Notification notification) {
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case NotificationReinit: {
|
||||
case Notification::Reinit: {
|
||||
if (_gifPreview && _gifPreview->state() == State::Error) {
|
||||
_gifPreview.setBad();
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ void SingleMediaPreview::clipCallback(
|
|||
update();
|
||||
} break;
|
||||
|
||||
case NotificationRepaint: {
|
||||
case Notification::Repaint: {
|
||||
if (_gifPreview && !_gifPreview->currentDisplayed()) {
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -391,7 +391,7 @@ void MediaPreviewWidget::clipCallback(
|
|||
Media::Clip::Notification notification) {
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case NotificationReinit: {
|
||||
case Notification::Reinit: {
|
||||
if (_gifThumbnail && _gifThumbnail->state() == State::Error) {
|
||||
_gifThumbnail.setBad();
|
||||
}
|
||||
|
@ -413,7 +413,7 @@ void MediaPreviewWidget::clipCallback(
|
|||
update();
|
||||
} break;
|
||||
|
||||
case NotificationRepaint: {
|
||||
case Notification::Repaint: {
|
||||
if ((_gif && _gif->started() && !_gif->currentDisplayed())
|
||||
|| (_gifThumbnail
|
||||
&& _gifThumbnail->started()
|
||||
|
|
Loading…
Add table
Reference in a new issue