Add 'Loop animated stickers' setting.

This commit is contained in:
John Preston 2019-08-01 12:42:24 +01:00
parent abf49e1672
commit 708b1d7ad4
31 changed files with 285 additions and 105 deletions

View File

@ -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?";

View File

@ -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), [=] {

View File

@ -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;

View File

@ -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);
}
}
};

View File

@ -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;

View File

@ -1639,7 +1639,7 @@ void HistoryWidget::showHistory(
cancelTypingAction();
}
if (!cAutoPlayGif()) {
if (!session().settings().autoplayGifs()) {
session().data().stopAutoplayAnimations();
}
clearReplyReturns();

View File

@ -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(

View File

@ -85,6 +85,7 @@ protected:
}
private:
[[nodiscard]] bool autoplayEnabled() const;
void playAnimation(bool autoplay) override;
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;

View File

@ -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;

View File

@ -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) {

View File

@ -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) {

View File

@ -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(

View File

@ -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();

View File

@ -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;

View File

@ -54,7 +54,6 @@ void PrepareSupportMode() {
Global::SetDesktopNotify(false);
Global::SetSoundNotify(false);
Auth().settings().autoDownload() = Full::FullDisabled();
cSetAutoPlayGif(false);
Local::writeUserSettings();
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
};

View File

@ -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

View File

@ -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(

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -72,4 +72,3 @@ int gOtherOnline = 0;
int32 gAutoDownloadPhoto = 0; // all auto download
int32 gAutoDownloadAudio = 0;
int32 gAutoDownloadGif = 0;
bool gAutoPlayGif = true;

View File

@ -158,7 +158,6 @@ DeclareSetting(float64, RetinaFactor);
DeclareSetting(int32, IntRetinaFactor);
DeclareSetting(int, OtherOnline);
DeclareSetting(bool, AutoPlayGif);
constexpr auto kInterfaceScaleAuto = 0;
constexpr auto kInterfaceScaleMin = 100;

View File

@ -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());
}

View File

@ -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()) {