mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Add 'Loop animated stickers' setting.
This commit is contained in:
parent
abf49e1672
commit
708b1d7ad4
31 changed files with 285 additions and 105 deletions
|
@ -395,6 +395,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_settings_performance" = "Performance";
|
||||
"lng_settings_enable_animations" = "Enable animations";
|
||||
"lng_settings_autoplay_gifs" = "Autoplay GIFs";
|
||||
"lng_settings_loop_stickers" = "Loop animated stickers";
|
||||
|
||||
"lng_backgrounds_header" = "Choose your new chat background";
|
||||
"lng_theme_sure_keep" = "Keep this theme?";
|
||||
|
|
|
@ -548,6 +548,17 @@ bool InnerWidget::elementIntersectsRange(
|
|||
return (top < till && bottom > from);
|
||||
}
|
||||
|
||||
bool InnerWidget::elementStartStickerLoop(not_null<const Element*> view) {
|
||||
if (_controller->session().settings().loopAnimatedStickers()) {
|
||||
return true;
|
||||
}
|
||||
return !_animatedStickersPlayed.contains(view->data()->fullId());
|
||||
}
|
||||
|
||||
void InnerWidget::elementStickerLoopStarted(not_null<const Element*> view) {
|
||||
_animatedStickersPlayed.emplace(view->data()->fullId());
|
||||
}
|
||||
|
||||
void InnerWidget::saveState(not_null<SectionMemento*> memento) {
|
||||
memento->setFilter(std::move(_filter));
|
||||
memento->setAdmins(std::move(_admins));
|
||||
|
@ -1024,15 +1035,15 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
cancelContextDownload(document);
|
||||
});
|
||||
} else {
|
||||
if (document->loaded() && document->isGifv()) {
|
||||
if (!cAutoPlayGif()) {
|
||||
const auto itemId = view
|
||||
? view->data()->fullId()
|
||||
: FullMsgId();
|
||||
_menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
|
||||
openContextGif(itemId);
|
||||
});
|
||||
}
|
||||
if (document->loaded()
|
||||
&& document->isGifv()
|
||||
&& !document->session().settings().autoplayGifs()) {
|
||||
const auto itemId = view
|
||||
? view->data()->fullId()
|
||||
: FullMsgId();
|
||||
_menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
|
||||
openContextGif(itemId);
|
||||
});
|
||||
}
|
||||
if (!document->filepath(DocumentData::FilePathResolve::Checked).isEmpty()) {
|
||||
_menu->addAction(Platform::IsMac() ? tr::lng_context_show_in_finder(tr::now) : tr::lng_context_show_in_folder(tr::now), [=] {
|
||||
|
|
|
@ -99,6 +99,10 @@ public:
|
|||
not_null<const HistoryView::Element*> view,
|
||||
int from,
|
||||
int till) override;
|
||||
bool elementStartStickerLoop(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementStickerLoopStarted(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
|
||||
~InnerWidget();
|
||||
|
||||
|
@ -219,6 +223,7 @@ private:
|
|||
std::vector<OwnedItem> _items;
|
||||
std::set<uint64> _eventIds;
|
||||
std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;
|
||||
base::flat_set<FullMsgId> _animatedStickersPlayed;
|
||||
int _itemsTop = 0;
|
||||
int _itemsWidth = 0;
|
||||
int _itemsHeight = 0;
|
||||
|
|
|
@ -1555,7 +1555,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
const auto lnkIsVoice = document->isVoiceMessage();
|
||||
const auto lnkIsAudio = document->isAudioFile();
|
||||
if (document->loaded() && document->isGifv()) {
|
||||
if (!cAutoPlayGif()) {
|
||||
if (!document->session().settings().autoplayGifs()) {
|
||||
_menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
|
||||
openContextGif(itemId);
|
||||
});
|
||||
|
@ -2384,6 +2384,18 @@ bool HistoryInner::elementIntersectsRange(
|
|||
return (top < till && bottom > from);
|
||||
}
|
||||
|
||||
bool HistoryInner::elementStartStickerLoop(
|
||||
not_null<const Element*> view) const {
|
||||
return _controller->session().settings().loopAnimatedStickers()
|
||||
|| !_animatedStickersPlayed.contains(view->data()->fullId());
|
||||
}
|
||||
|
||||
void HistoryInner::elementStickerLoopStarted(not_null<const Element*> view) {
|
||||
if (!_controller->session().settings().loopAnimatedStickers()) {
|
||||
_animatedStickersPlayed.emplace(view->data()->fullId());
|
||||
}
|
||||
}
|
||||
|
||||
auto HistoryInner::getSelectionState() const
|
||||
-> HistoryView::TopBarWidget::SelectedState {
|
||||
auto result = HistoryView::TopBarWidget::SelectedState {};
|
||||
|
@ -3234,6 +3246,18 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
|
|||
? Instance->elementIntersectsRange(view, from, till)
|
||||
: false;
|
||||
}
|
||||
bool elementStartStickerLoop(
|
||||
not_null<const Element*> view) override {
|
||||
return Instance
|
||||
? Instance->elementStartStickerLoop(view)
|
||||
: true;
|
||||
}
|
||||
void elementStickerLoopStarted(
|
||||
not_null<const Element*> view) override {
|
||||
if (Instance) {
|
||||
Instance->elementStickerLoopStarted(view);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ public:
|
|||
not_null<const Element*> view,
|
||||
int from,
|
||||
int till) const;
|
||||
bool elementStartStickerLoop(not_null<const Element*> view) const;
|
||||
void elementStickerLoopStarted(not_null<const Element*> view);
|
||||
|
||||
void updateBotInfo(bool recount = true);
|
||||
|
||||
|
@ -330,6 +332,8 @@ private:
|
|||
style::cursor _cursor = style::cur_default;
|
||||
SelectedItems _selected;
|
||||
|
||||
base::flat_set<FullMsgId> _animatedStickersPlayed;
|
||||
|
||||
MouseAction _mouseAction = MouseAction::None;
|
||||
TextSelectType _mouseSelectType = TextSelectType::Letters;
|
||||
QPoint _dragStartPosition;
|
||||
|
|
|
@ -1639,7 +1639,7 @@ void HistoryWidget::showHistory(
|
|||
cancelTypingAction();
|
||||
}
|
||||
|
||||
if (!cAutoPlayGif()) {
|
||||
if (!session().settings().autoplayGifs()) {
|
||||
session().data().stopAutoplayAnimations();
|
||||
}
|
||||
clearReplyReturns();
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "layout.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "media/player/media_player_instance.h"
|
||||
|
@ -228,6 +229,10 @@ QSize HistoryGif::videoSize() const {
|
|||
}
|
||||
}
|
||||
|
||||
bool HistoryGif::autoplayEnabled() const {
|
||||
return history()->session().settings().autoplayGifs();
|
||||
}
|
||||
|
||||
void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
|
@ -238,7 +243,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, crl::
|
|||
auto selected = (selection == FullSelection);
|
||||
|
||||
if (loaded
|
||||
&& cAutoPlayGif()
|
||||
&& autoplayEnabled()
|
||||
&& !_gif
|
||||
&& !_gif.isBad()
|
||||
&& !activeRoundPlayer()) {
|
||||
|
@ -370,7 +375,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, crl::
|
|||
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
|
||||
}
|
||||
|
||||
if (radial || (!reader && !player && (_gif.isBad() || (!loaded && !_data->loading()) || !cAutoPlayGif()))) {
|
||||
if (radial || (!reader && !player && (_gif.isBad() || (!loaded && !_data->loading()) || !autoplayEnabled()))) {
|
||||
auto radialOpacity = (radial && loaded && item->id > 0) ? _animation->radial.opacity() : 1.;
|
||||
auto inner = QRect(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||
p.setPen(Qt::NoPen);
|
||||
|
@ -852,7 +857,7 @@ void HistoryGif::playAnimation(bool autoplay) {
|
|||
return;
|
||||
} else if (_gif && autoplay) {
|
||||
return;
|
||||
} else if (_gif && cAutoPlayGif()) {
|
||||
} else if (_gif && autoplayEnabled()) {
|
||||
Core::App().showDocument(_data, _parent->data());
|
||||
return;
|
||||
}
|
||||
|
@ -860,7 +865,7 @@ void HistoryGif::playAnimation(bool autoplay) {
|
|||
if (_gif) {
|
||||
stopAnimation();
|
||||
} else if (_data->loaded(DocumentData::FilePathResolve::Checked)) {
|
||||
if (!cAutoPlayGif()) {
|
||||
if (!autoplayEnabled()) {
|
||||
history()->owner().stopAutoplayAnimations();
|
||||
}
|
||||
setClipReader(Media::Clip::MakeReader(
|
||||
|
|
|
@ -85,6 +85,7 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool autoplayEnabled() const;
|
||||
void playAnimation(bool autoplay) override;
|
||||
QSize countOptimalSize() override;
|
||||
QSize countCurrentSize(int newWidth) override;
|
||||
|
|
|
@ -122,7 +122,11 @@ void HistorySticker::unloadLottie() {
|
|||
_parent->data()->history()->owner().unregisterHeavyViewPart(_parent);
|
||||
}
|
||||
|
||||
void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void HistorySticker::draw(
|
||||
Painter &p,
|
||||
const QRect &r,
|
||||
TextSelection selection,
|
||||
crl::time ms) const {
|
||||
auto sticker = _data->sticker();
|
||||
if (!sticker) return;
|
||||
|
||||
|
@ -197,19 +201,24 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, c
|
|||
if (selected) {
|
||||
request.colored = st::msgStickerOverlay->c;
|
||||
}
|
||||
const auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
|
||||
if (!paused) {
|
||||
_lottie->markFrameShown();
|
||||
}
|
||||
const auto frame = _lottie->frame(request);
|
||||
const auto size = frame.size() / cIntRetinaFactor();
|
||||
const auto frame = _lottie->frameInfo(request);
|
||||
const auto size = frame.image.size() / cIntRetinaFactor();
|
||||
p.drawImage(
|
||||
QRect(
|
||||
QPoint(
|
||||
usex + (usew - size.width()) / 2,
|
||||
(minHeight() - size.height()) / 2),
|
||||
size),
|
||||
frame);
|
||||
frame.image);
|
||||
|
||||
const auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
|
||||
if (!paused
|
||||
&& (frame.index != 0
|
||||
|| _parent->delegate()->elementStartStickerLoop(_parent))
|
||||
&& _lottie->markFrameShown()
|
||||
&& !frame.index) {
|
||||
_parent->delegate()->elementStickerLoopStarted(_parent);
|
||||
}
|
||||
}
|
||||
if (!inWebPage) {
|
||||
auto fullRight = usex + usew;
|
||||
|
|
|
@ -162,12 +162,12 @@ void AddDocumentActions(
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (document->loaded() && document->isGifv()) {
|
||||
if (!cAutoPlayGif()) {
|
||||
menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
|
||||
OpenGif(contextId);
|
||||
});
|
||||
}
|
||||
if (document->loaded()
|
||||
&& document->isGifv()
|
||||
&& !document->session().settings().autoplayGifs()) {
|
||||
menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
|
||||
OpenGif(contextId);
|
||||
});
|
||||
}
|
||||
if (document->sticker()
|
||||
&& document->sticker()->set.type() != mtpc_inputStickerSetEmpty) {
|
||||
|
|
|
@ -84,6 +84,15 @@ bool SimpleElementDelegate::elementIntersectsRange(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SimpleElementDelegate::elementStartStickerLoop(
|
||||
not_null<const Element*> view) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SimpleElementDelegate::elementStickerLoopStarted(
|
||||
not_null<const Element*> view) {
|
||||
}
|
||||
|
||||
TextSelection UnshiftItemSelection(
|
||||
TextSelection selection,
|
||||
uint16 byLength) {
|
||||
|
|
|
@ -50,6 +50,9 @@ public:
|
|||
not_null<const Element*> view,
|
||||
int from,
|
||||
int till) = 0;
|
||||
virtual bool elementStartStickerLoop(not_null<const Element*> view) = 0;
|
||||
virtual void elementStickerLoopStarted(
|
||||
not_null<const Element*> view) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -69,6 +72,10 @@ public:
|
|||
not_null<const Element*> view,
|
||||
int from,
|
||||
int till) override;
|
||||
bool elementStartStickerLoop(
|
||||
not_null<const Element*> view) override;
|
||||
void elementStickerLoopStarted(not_null<const Element*> view) override;
|
||||
|
||||
};
|
||||
|
||||
TextSelection UnshiftItemSelection(
|
||||
|
|
|
@ -1141,6 +1141,17 @@ bool ListWidget::elementIntersectsRange(
|
|||
return (top < till && bottom > from);
|
||||
}
|
||||
|
||||
bool ListWidget::elementStartStickerLoop(not_null<const Element*> view) {
|
||||
return _controller->session().settings().loopAnimatedStickers()
|
||||
|| !_animatedStickersPlayed.contains(view->data()->fullId());
|
||||
}
|
||||
|
||||
void ListWidget::elementStickerLoopStarted(not_null<const Element*> view) {
|
||||
if (!_controller->session().settings().loopAnimatedStickers()) {
|
||||
_animatedStickersPlayed.emplace(view->data()->fullId());
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::saveState(not_null<ListMemento*> memento) {
|
||||
memento->setAroundPosition(_aroundPosition);
|
||||
auto state = countScrollState();
|
||||
|
|
|
@ -184,12 +184,15 @@ public:
|
|||
bool elementUnderCursor(not_null<const Element*> view) override;
|
||||
void elementAnimationAutoplayAsync(
|
||||
not_null<const Element*> view) override;
|
||||
crl::time elementHighlightTime(not_null<const Element*> element) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
int from,
|
||||
int till) override;
|
||||
bool elementStartStickerLoop(not_null<const Element*> view) override;
|
||||
void elementStickerLoopStarted(not_null<const Element*> view) override;
|
||||
|
||||
~ListWidget();
|
||||
|
||||
|
@ -441,6 +444,7 @@ private:
|
|||
int _itemsWidth = 0;
|
||||
int _itemsHeight = 0;
|
||||
int _itemAverageHeight = 0;
|
||||
base::flat_set<FullMsgId> _animatedStickersPlayed;
|
||||
|
||||
int _minHeight = 0;
|
||||
int _visibleTop = 0;
|
||||
|
|
|
@ -54,7 +54,6 @@ void PrepareSupportMode() {
|
|||
Global::SetDesktopNotify(false);
|
||||
Global::SetSoundNotify(false);
|
||||
Auth().settings().autoDownload() = Full::FullDisabled();
|
||||
cSetAutoPlayGif(false);
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
|
||||
|
|
|
@ -228,4 +228,19 @@ QImage Animation::frame(const FrameRequest &request) const {
|
|||
return PrepareFrameByRequest(frame, !changed);
|
||||
}
|
||||
|
||||
auto Animation::frameInfo(const FrameRequest &request) const -> FrameInfo {
|
||||
Expects(_state != nullptr);
|
||||
|
||||
const auto frame = _state->frameForPaint();
|
||||
const auto changed = (frame->request != request);
|
||||
if (changed) {
|
||||
frame->request = request;
|
||||
_player->updateFrameRequest(this, request);
|
||||
}
|
||||
return {
|
||||
PrepareFrameByRequest(frame, !changed),
|
||||
frame->index % _state->framesCount()
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Lottie
|
||||
|
|
|
@ -10,7 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lottie/lottie_common.h"
|
||||
#include "base/weak_ptr.h"
|
||||
|
||||
class QImage;
|
||||
#include <QtGui/QImage>
|
||||
|
||||
class QString;
|
||||
class QByteArray;
|
||||
|
||||
|
@ -39,6 +40,11 @@ std::unique_ptr<rlottie::Animation> CreateFromContent(
|
|||
|
||||
class Animation final : public base::has_weak_ptr {
|
||||
public:
|
||||
struct FrameInfo {
|
||||
QImage image;
|
||||
int index = 0;
|
||||
};
|
||||
|
||||
Animation(
|
||||
not_null<Player*> player,
|
||||
const QByteArray &content,
|
||||
|
@ -55,6 +61,7 @@ public:
|
|||
[[nodiscard]] bool ready() const;
|
||||
[[nodiscard]] QImage frame() const;
|
||||
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||
[[nodiscard]] FrameInfo frameInfo(const FrameRequest &request) const;
|
||||
|
||||
private:
|
||||
void initDone(details::InitData &&data);
|
||||
|
|
|
@ -210,12 +210,46 @@ void FrameRendererObject::queueGenerateFrames() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
Information SharedState::CalculateInformation(
|
||||
Quality quality,
|
||||
rlottie::Animation *animation,
|
||||
Cache *cache) {
|
||||
Expects(animation != nullptr || cache != nullptr);
|
||||
|
||||
auto width = size_t(0);
|
||||
auto height = size_t(0);
|
||||
if (animation) {
|
||||
animation->size(width, height);
|
||||
} else {
|
||||
width = cache->originalSize().width();
|
||||
height = cache->originalSize().height();
|
||||
}
|
||||
const auto rate = animation
|
||||
? GetLottieFrameRate(animation, quality)
|
||||
: cache->frameRate();
|
||||
const auto count = animation
|
||||
? GetLottieFramesCount(animation, quality)
|
||||
: cache->framesCount();
|
||||
|
||||
auto result = Information();
|
||||
result.size = QSize(
|
||||
(width > 0 && width <= kMaxSize) ? int(width) : 0,
|
||||
(height > 0 && height <= kMaxSize) ? int(height) : 0);
|
||||
result.frameRate = (rate > 0 && rate <= kMaxFrameRate) ? int(rate) : 0;
|
||||
result.framesCount = (count > 0 && count <= kMaxFramesCount)
|
||||
? int(count)
|
||||
: 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
SharedState::SharedState(
|
||||
std::unique_ptr<rlottie::Animation> animation,
|
||||
const FrameRequest &request,
|
||||
Quality quality)
|
||||
: _animation(std::move(animation))
|
||||
, _quality(quality) {
|
||||
: _info(CalculateInformation(quality, animation.get(), nullptr))
|
||||
, _quality(quality)
|
||||
, _animation(std::move(animation)) {
|
||||
construct(request);
|
||||
}
|
||||
|
||||
|
@ -225,15 +259,15 @@ SharedState::SharedState(
|
|||
std::unique_ptr<Cache> cache,
|
||||
const FrameRequest &request,
|
||||
Quality quality)
|
||||
: _content(content)
|
||||
, _animation(std::move(animation))
|
||||
: _info(CalculateInformation(quality, animation.get(), cache.get()))
|
||||
, _quality(quality)
|
||||
, _cache(std::move(cache)) {
|
||||
, _cache(std::move(cache))
|
||||
, _animation(std::move(animation))
|
||||
, _content(content) {
|
||||
construct(request);
|
||||
}
|
||||
|
||||
void SharedState::construct(const FrameRequest &request) {
|
||||
calculateProperties();
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
@ -243,39 +277,20 @@ void SharedState::construct(const FrameRequest &request) {
|
|||
return;
|
||||
}
|
||||
if (_cache) {
|
||||
_cache->init(_size, _frameRate, _framesCount, request);
|
||||
_cache->init(
|
||||
_info.size,
|
||||
_info.frameRate,
|
||||
_info.framesCount,
|
||||
request);
|
||||
}
|
||||
renderFrame(cover, request, 0);
|
||||
init(std::move(cover), request);
|
||||
}
|
||||
|
||||
void SharedState::calculateProperties() {
|
||||
Expects(_animation != nullptr || _cache != nullptr);
|
||||
|
||||
auto width = size_t(0);
|
||||
auto height = size_t(0);
|
||||
if (_animation) {
|
||||
_animation->size(width, height);
|
||||
} else {
|
||||
width = _cache->originalSize().width();
|
||||
height = _cache->originalSize().height();
|
||||
}
|
||||
const auto rate = _animation
|
||||
? GetLottieFrameRate(_animation.get(), _quality)
|
||||
: _cache->frameRate();
|
||||
const auto count = _animation
|
||||
? GetLottieFramesCount(_animation.get(), _quality)
|
||||
: _cache->framesCount();
|
||||
|
||||
_size = QSize(
|
||||
(width > 0 && width <= kMaxSize) ? int(width) : 0,
|
||||
(height > 0 && height <= kMaxSize) ? int(height) : 0);
|
||||
_frameRate = (rate > 0 && rate <= kMaxFrameRate) ? int(rate) : 0;
|
||||
_framesCount = (count > 0 && count <= kMaxFramesCount) ? int(count) : 0;
|
||||
}
|
||||
|
||||
bool SharedState::isValid() const {
|
||||
return (_framesCount > 0) && (_frameRate > 0) && !_size.isEmpty();
|
||||
return (_info.framesCount > 0)
|
||||
&& (_info.frameRate > 0)
|
||||
&& !_info.size.isEmpty();
|
||||
}
|
||||
|
||||
void SharedState::renderFrame(
|
||||
|
@ -286,7 +301,9 @@ void SharedState::renderFrame(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto size = request.box.isEmpty() ? _size : request.size(_size);
|
||||
const auto size = request.box.isEmpty()
|
||||
? _info.size
|
||||
: request.size(_info.size);
|
||||
if (!GoodStorageForFrame(image, size)) {
|
||||
image = CreateFrameStorage(size);
|
||||
}
|
||||
|
@ -339,9 +356,12 @@ bool IsRendered(not_null<const Frame*> frame) {
|
|||
void SharedState::renderNextFrame(
|
||||
not_null<Frame*> frame,
|
||||
const FrameRequest &request) {
|
||||
Expects(_framesCount > 0);
|
||||
Expects(_info.framesCount > 0);
|
||||
|
||||
renderFrame(frame->original, request, (++_frameIndex) % _framesCount);
|
||||
renderFrame(
|
||||
frame->original,
|
||||
request,
|
||||
(++_frameIndex) % _info.framesCount);
|
||||
frame->request = request;
|
||||
PrepareFrameByRequest(frame);
|
||||
frame->index = _frameIndex;
|
||||
|
@ -392,7 +412,7 @@ auto SharedState::renderNextFrame(const FrameRequest &request)
|
|||
crl::time SharedState::countFrameDisplayTime(int index) const {
|
||||
return _started
|
||||
+ _delay
|
||||
+ crl::time(1000) * (_skippedFrames + index) / _frameRate;
|
||||
+ crl::time(1000) * (_skippedFrames + index) / _info.frameRate;
|
||||
}
|
||||
|
||||
int SharedState::counter() const {
|
||||
|
@ -416,14 +436,7 @@ not_null<const Frame*> SharedState::getFrame(int index) const {
|
|||
}
|
||||
|
||||
Information SharedState::information() const {
|
||||
if (!isValid()) {
|
||||
return {};
|
||||
}
|
||||
auto result = Information();
|
||||
result.frameRate = _frameRate;
|
||||
result.size = _size;
|
||||
result.framesCount = _framesCount;
|
||||
return result;
|
||||
return isValid() ? _info : Information();
|
||||
}
|
||||
|
||||
not_null<Frame*> SharedState::frameForPaint() {
|
||||
|
@ -434,6 +447,10 @@ not_null<Frame*> SharedState::frameForPaint() {
|
|||
return result;
|
||||
}
|
||||
|
||||
int SharedState::framesCount() const {
|
||||
return _info.framesCount;
|
||||
}
|
||||
|
||||
crl::time SharedState::nextFrameDisplayTime() const {
|
||||
const auto frameDisplayTime = [&](int counter) {
|
||||
const auto next = (counter + 1) % (2 * kFramesCount);
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
[[nodiscard]] bool initialized() const;
|
||||
|
||||
[[nodiscard]] not_null<Frame*> frameForPaint();
|
||||
[[nodiscard]] int framesCount() const;
|
||||
[[nodiscard]] crl::time nextFrameDisplayTime() const;
|
||||
void addTimelineDelay(crl::time delayed, int skippedFrames = 0);
|
||||
void markFrameDisplayed(crl::time now);
|
||||
|
@ -88,8 +89,12 @@ public:
|
|||
~SharedState();
|
||||
|
||||
private:
|
||||
static Information CalculateInformation(
|
||||
Quality quality,
|
||||
rlottie::Animation *animation,
|
||||
Cache *cache);
|
||||
|
||||
void construct(const FrameRequest &request);
|
||||
void calculateProperties();
|
||||
bool isValid() const;
|
||||
void init(QImage cover, const FrameRequest &request);
|
||||
void renderNextFrame(
|
||||
|
@ -100,10 +105,6 @@ private:
|
|||
[[nodiscard]] not_null<const Frame*> getFrame(int index) const;
|
||||
[[nodiscard]] int counter() const;
|
||||
|
||||
QByteArray _content;
|
||||
std::unique_ptr<rlottie::Animation> _animation;
|
||||
Quality _quality = Quality::Default;
|
||||
|
||||
// crl::queue changes 0,2,4,6 to 1,3,5,7.
|
||||
// main thread changes 1,3,5,7 to 2,4,6,0.
|
||||
static constexpr auto kCounterUninitialized = -1;
|
||||
|
@ -121,11 +122,13 @@ private:
|
|||
|
||||
int _frameIndex = 0;
|
||||
int _skippedFrames = 0;
|
||||
int _framesCount = 0;
|
||||
int _frameRate = 0;
|
||||
QSize _size;
|
||||
const Information _info;
|
||||
const Quality _quality = Quality::Default;
|
||||
|
||||
std::unique_ptr<Cache> _cache;
|
||||
const std::unique_ptr<Cache> _cache;
|
||||
|
||||
std::unique_ptr<rlottie::Animation> _animation;
|
||||
const QByteArray _content;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -369,7 +369,7 @@ void MultiPlayer::addTimelineDelay(crl::time delayed) {
|
|||
_delay += delayed;
|
||||
}
|
||||
|
||||
void MultiPlayer::markFrameShown() {
|
||||
bool MultiPlayer::markFrameShown() {
|
||||
if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
|
||||
_nextFrameTime = kTimeUnknown;
|
||||
}
|
||||
|
@ -381,7 +381,9 @@ void MultiPlayer::markFrameShown() {
|
|||
}
|
||||
if (count) {
|
||||
_renderer->frameShown();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Lottie
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
void updateFrameRequest(
|
||||
not_null<const Animation*> animation,
|
||||
const FrameRequest &request) override;
|
||||
void markFrameShown() override;
|
||||
bool markFrameShown() override;
|
||||
void checkStep() override;
|
||||
|
||||
not_null<Animation*> append(
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
virtual void updateFrameRequest(
|
||||
not_null<const Animation*> animation,
|
||||
const FrameRequest &request) = 0;
|
||||
virtual void markFrameShown() = 0;
|
||||
virtual bool markFrameShown() = 0;
|
||||
virtual void checkStep() = 0;
|
||||
|
||||
virtual ~Player() = default;
|
||||
|
|
|
@ -79,6 +79,11 @@ QImage SinglePlayer::frame(const FrameRequest &request) const {
|
|||
return _animation.frame(request);
|
||||
}
|
||||
|
||||
Animation::FrameInfo SinglePlayer::frameInfo(
|
||||
const FrameRequest &request) const {
|
||||
return _animation.frameInfo(request);
|
||||
}
|
||||
|
||||
void SinglePlayer::checkStep() {
|
||||
if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
|
||||
return;
|
||||
|
@ -128,7 +133,7 @@ void SinglePlayer::updateFrameRequest(
|
|||
_renderer->updateFrameRequest(_state, request);
|
||||
}
|
||||
|
||||
void SinglePlayer::markFrameShown() {
|
||||
bool SinglePlayer::markFrameShown() {
|
||||
Expects(_state != nullptr);
|
||||
|
||||
if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
|
||||
|
@ -136,7 +141,9 @@ void SinglePlayer::markFrameShown() {
|
|||
}
|
||||
if (_state->markFrameShown()) {
|
||||
_renderer->frameShown();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Lottie
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
void updateFrameRequest(
|
||||
not_null<const Animation*> animation,
|
||||
const FrameRequest &request) override;
|
||||
void markFrameShown() override;
|
||||
bool markFrameShown() override;
|
||||
void checkStep() override;
|
||||
|
||||
rpl::producer<Update, Error> updates() const;
|
||||
|
@ -57,6 +57,8 @@ public:
|
|||
[[nodiscard]] bool ready() const;
|
||||
[[nodiscard]] QImage frame() const;
|
||||
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||
[[nodiscard]] Animation::FrameInfo frameInfo(
|
||||
const FrameRequest &request) const;
|
||||
|
||||
private:
|
||||
void checkNextFrameAvailability();
|
||||
|
|
|
@ -49,7 +49,7 @@ Settings::Variables::Variables()
|
|||
|
||||
QByteArray Settings::serialize() const {
|
||||
const auto autoDownload = _variables.autoDownload.serialize();
|
||||
auto size = sizeof(qint32) * 23;
|
||||
auto size = sizeof(qint32) * 30;
|
||||
for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) {
|
||||
size += Serialize::stringSize(i.key()) + Serialize::stringSize(i.value());
|
||||
}
|
||||
|
@ -99,6 +99,8 @@ QByteArray Settings::serialize() const {
|
|||
stream << qint32(_variables.notifyAboutPinned.current() ? 1 : 0);
|
||||
stream << qint32(_variables.archiveInMainMenu.current() ? 1 : 0);
|
||||
stream << qint32(_variables.skipArchiveInSearch.current() ? 1 : 0);
|
||||
stream << qint32(_variables.autoplayGifs ? 1 : 0);
|
||||
stream << qint32(_variables.loopAnimatedStickers ? 1 : 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -139,6 +141,8 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
|
|||
qint32 notifyAboutPinned = _variables.notifyAboutPinned.current() ? 1 : 0;
|
||||
qint32 archiveInMainMenu = _variables.archiveInMainMenu.current() ? 1 : 0;
|
||||
qint32 skipArchiveInSearch = _variables.skipArchiveInSearch.current() ? 1 : 0;
|
||||
qint32 autoplayGifs = _variables.autoplayGifs ? 1 : 0;
|
||||
qint32 loopAnimatedStickers = _variables.loopAnimatedStickers ? 1 : 0;
|
||||
|
||||
stream >> selectorTab;
|
||||
stream >> lastSeenWarningSeen;
|
||||
|
@ -230,6 +234,10 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
|
|||
if (!stream.atEnd()) {
|
||||
stream >> skipArchiveInSearch;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> autoplayGifs;
|
||||
stream >> loopAnimatedStickers;
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Settings::constructFromSerialized()"));
|
||||
|
@ -303,6 +311,8 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
|
|||
_variables.notifyAboutPinned = (notifyAboutPinned == 1);
|
||||
_variables.archiveInMainMenu = (archiveInMainMenu == 1);
|
||||
_variables.skipArchiveInSearch = (skipArchiveInSearch == 1);
|
||||
_variables.autoplayGifs = (autoplayGifs == 1);
|
||||
_variables.loopAnimatedStickers = (loopAnimatedStickers == 1);
|
||||
}
|
||||
|
||||
void Settings::setSupportChatsTimeSlice(int slice) {
|
||||
|
|
|
@ -230,6 +230,18 @@ public:
|
|||
void setExeLaunchWarning(bool warning) {
|
||||
_variables.exeLaunchWarning = warning;
|
||||
}
|
||||
bool autoplayGifs() const {
|
||||
return _variables.autoplayGifs;
|
||||
}
|
||||
void setAutoplayGifs(bool value) {
|
||||
_variables.autoplayGifs = value;
|
||||
}
|
||||
bool loopAnimatedStickers() const {
|
||||
return _variables.loopAnimatedStickers;
|
||||
}
|
||||
void setLoopAnimatedStickers(bool value) {
|
||||
_variables.loopAnimatedStickers = value;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Variables {
|
||||
|
@ -264,6 +276,8 @@ private:
|
|||
rpl::variable<bool> archiveInMainMenu = false;
|
||||
rpl::variable<bool> notifyAboutPinned = true;
|
||||
rpl::variable<bool> skipArchiveInSearch = false;
|
||||
bool autoplayGifs = true;
|
||||
bool loopAnimatedStickers = true;
|
||||
|
||||
static constexpr auto kDefaultSupportChatsLimitSlice
|
||||
= 7 * 24 * 60 * 60;
|
||||
|
|
|
@ -123,6 +123,7 @@ void LoaderMtproto::sendNext() {
|
|||
|
||||
const auto usedFileReference = _location.fileReference();
|
||||
const auto id = _sender.request(MTPupload_GetFile(
|
||||
MTP_flags(0),
|
||||
_location.tl(Auth().userId()),
|
||||
MTP_int(offset),
|
||||
MTP_int(kPartSize)
|
||||
|
|
|
@ -72,4 +72,3 @@ int gOtherOnline = 0;
|
|||
int32 gAutoDownloadPhoto = 0; // all auto download
|
||||
int32 gAutoDownloadAudio = 0;
|
||||
int32 gAutoDownloadGif = 0;
|
||||
bool gAutoPlayGif = true;
|
||||
|
|
|
@ -158,7 +158,6 @@ DeclareSetting(float64, RetinaFactor);
|
|||
DeclareSetting(int32, IntRetinaFactor);
|
||||
|
||||
DeclareSetting(int, OtherOnline);
|
||||
DeclareSetting(bool, AutoPlayGif);
|
||||
|
||||
constexpr auto kInterfaceScaleAuto = 0;
|
||||
constexpr auto kInterfaceScaleMin = 100;
|
||||
|
|
|
@ -424,21 +424,36 @@ void SetupPerformance(
|
|||
not_null<Ui::VerticalLayout*> container) {
|
||||
SetupAnimations(container);
|
||||
|
||||
const auto session = &controller->session();
|
||||
AddButton(
|
||||
container,
|
||||
tr::lng_settings_autoplay_gifs(),
|
||||
st::settingsButton
|
||||
)->toggleOn(
|
||||
rpl::single(cAutoPlayGif())
|
||||
rpl::single(session->settings().autoplayGifs())
|
||||
)->toggledValue(
|
||||
) | rpl::filter([](bool enabled) {
|
||||
return (enabled != cAutoPlayGif());
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != session->settings().autoplayGifs());
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
cSetAutoPlayGif(enabled);
|
||||
if (!cAutoPlayGif()) {
|
||||
controller->session().data().stopAutoplayAnimations();
|
||||
session->settings().setAutoplayGifs(enabled);
|
||||
if (!enabled) {
|
||||
session->data().stopAutoplayAnimations();
|
||||
}
|
||||
Local::writeUserSettings();
|
||||
session->saveSettingsDelayed();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
tr::lng_settings_loop_stickers(),
|
||||
st::settingsButton
|
||||
)->toggleOn(
|
||||
rpl::single(session->settings().loopAnimatedStickers())
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return enabled != session->settings().loopAnimatedStickers();
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
session->settings().setLoopAnimatedStickers(enabled);
|
||||
session->saveSettingsDelayed();
|
||||
}, container->lifetime());
|
||||
}
|
||||
|
||||
|
|
|
@ -580,7 +580,7 @@ enum {
|
|||
dbiAutoDownloadOld = 0x34,
|
||||
dbiSavedGifsLimit = 0x35,
|
||||
dbiShowingSavedGifsOld = 0x36,
|
||||
dbiAutoPlay = 0x37,
|
||||
dbiAutoPlayOld = 0x37,
|
||||
dbiAdaptiveForWide = 0x38,
|
||||
dbiHiddenPinnedMessages = 0x39,
|
||||
dbiRecentEmoji = 0x3a,
|
||||
|
@ -1104,12 +1104,12 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
|||
set(Type::VideoMessage, gif);
|
||||
} break;
|
||||
|
||||
case dbiAutoPlay: {
|
||||
case dbiAutoPlayOld: {
|
||||
qint32 gif;
|
||||
stream >> gif;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
cSetAutoPlayGif(gif == 1);
|
||||
GetStoredSessionSettings().setAutoplayGifs(gif == 1);
|
||||
} break;
|
||||
|
||||
case dbiDialogsMode: {
|
||||
|
@ -2087,7 +2087,6 @@ void _writeUserSettings() {
|
|||
data.stream << quint32(dbiVideoVolume) << qint32(qRound(Global::VideoVolume() * 1e6));
|
||||
data.stream << quint32(dbiDialogsMode) << qint32(Global::DialogsModeEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsMode());
|
||||
data.stream << quint32(dbiModerateMode) << qint32(Global::ModerateModeEnabled() ? 1 : 0);
|
||||
data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0);
|
||||
data.stream << quint32(dbiUseExternalVideoPlayer) << qint32(cUseExternalVideoPlayer());
|
||||
data.stream << quint32(dbiCacheSettings) << qint64(_cacheTotalSizeLimit) << qint32(_cacheTotalTimeLimit) << qint64(_cacheBigFileTotalSizeLimit) << qint32(_cacheBigFileTotalTimeLimit);
|
||||
if (!userData.isEmpty()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue