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