Clear hidden animated stickers.

This commit is contained in:
John Preston 2019-05-14 12:50:44 +03:00
parent 236513943c
commit 7ee16ba45c
23 changed files with 233 additions and 130 deletions

View File

@ -756,31 +756,3 @@ bool BackgroundPreviewBox::Start(
HistoryView::Context BackgroundPreviewBox::elementContext() {
return HistoryView::Context::ContactPreview;
}
std::unique_ptr<HistoryView::Element> BackgroundPreviewBox::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>(delegate(), message);
}
std::unique_ptr<HistoryView::Element> BackgroundPreviewBox::elementCreate(
not_null<HistoryService*> message) {
Unexpected("Service message in BackgroundPreviewBox.");
}
bool BackgroundPreviewBox::elementUnderCursor(
not_null<const Element*> view) {
return false;
}
void BackgroundPreviewBox::elementAnimationAutoplayAsync(
not_null<const Element*> element) {
}
crl::time BackgroundPreviewBox::elementHighlightTime(
not_null<const Element*> element) {
return crl::time(0);
}
bool BackgroundPreviewBox::elementInSelectionMode() {
return false;
}

View File

@ -21,7 +21,7 @@ class Checkbox;
class BackgroundPreviewBox
: public BoxContent
, private HistoryView::ElementDelegate {
, private HistoryView::SimpleElementDelegate {
public:
BackgroundPreviewBox(QWidget*, const Data::WallPaper &paper);
@ -38,16 +38,6 @@ private:
using Element = HistoryView::Element;
not_null<HistoryView::ElementDelegate*> delegate();
HistoryView::Context elementContext() override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
not_null<const Element*> element) override;
crl::time elementHighlightTime(
not_null<const Element*> element) override;
bool elementInSelectionMode() override;
void apply();
void share();

View File

@ -1251,6 +1251,58 @@ void Session::sendHistoryChangeNotifications() {
}
}
void Session::registerHeavyViewPart(not_null<ViewElement*> view) {
_heavyViewParts.emplace(view);
}
void Session::unregisterHeavyViewPart(not_null<ViewElement*> view) {
_heavyViewParts.remove(view);
}
void Session::unloadHeavyViewParts(
not_null<HistoryView::ElementDelegate*> delegate) {
if (_heavyViewParts.empty()) {
return;
}
const auto remove = ranges::count(_heavyViewParts, delegate, [](not_null<ViewElement*> element) {
return element->delegate();
});
if (remove == _heavyViewParts.size()) {
for (const auto view : base::take(_heavyViewParts)) {
view->unloadHeavyPart();
}
} else {
auto remove = std::vector<not_null<ViewElement*>>();
for (const auto view : _heavyViewParts) {
if (view->delegate() == delegate) {
remove.push_back(view);
}
}
for (const auto view : remove) {
view->unloadHeavyPart();
}
}
}
void Session::unloadHeavyViewParts(
not_null<HistoryView::ElementDelegate*> delegate,
int from,
int till) {
if (_heavyViewParts.empty()) {
return;
}
auto remove = std::vector<not_null<ViewElement*>>();
for (const auto view : _heavyViewParts) {
if (view->delegate() == delegate
&& !delegate->elementIntersectsRange(view, from, till)) {
remove.push_back(view);
}
}
for (const auto view : remove) {
view->unloadHeavyPart();
}
}
void Session::removeMegagroupParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user) {

View File

@ -30,6 +30,7 @@ enum class NewMessageType;
namespace HistoryView {
struct Group;
class Element;
class ElementDelegate;
} // namespace HistoryView
class AuthSession;
@ -198,6 +199,15 @@ public:
[[nodiscard]] rpl::producer<not_null<History*>> historyChanged() const;
void sendHistoryChangeNotifications();
void registerHeavyViewPart(not_null<ViewElement*> view);
void unregisterHeavyViewPart(not_null<ViewElement*> view);
void unloadHeavyViewParts(
not_null<HistoryView::ElementDelegate*> delegate);
void unloadHeavyViewParts(
not_null<HistoryView::ElementDelegate*> delegate,
int from,
int till);
using MegagroupParticipant = std::tuple<
not_null<ChannelData*>,
not_null<UserData*>>;
@ -909,6 +919,8 @@ private:
not_null<const HistoryItem*>,
std::vector<not_null<ViewElement*>>> _views;
base::flat_set<not_null<ViewElement*>> _heavyViewParts;
PeerData *_proxyPromoted = nullptr;
NotifySettings _defaultUserNotifySettings;

View File

@ -525,6 +525,17 @@ bool InnerWidget::elementInSelectionMode() {
return false;
}
bool InnerWidget::elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) {
Expects(view->delegate() == this);
const auto top = itemTop(view);
const auto bottom = top + view->height();
return (top < till && bottom > from);
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter));
memento->setAdmins(std::move(_admins));

View File

@ -89,6 +89,10 @@ public:
crl::time elementHighlightTime(
not_null<const HistoryView::Element*> element) override;
bool elementInSelectionMode() override;
bool elementIntersectsRange(
not_null<const HistoryView::Element*> view,
int from,
int till) override;
~InnerWidget();

View File

@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kScrollDateHideTimeout = 1000;
constexpr auto kUnloadHeavyPartsPages = 3;
// Helper binary search for an item in a list that is not completely
// above the given top of the visible area or below the given bottom of the visible area
@ -76,6 +77,8 @@ int BinarySearchBlocksOrItems(const T &list, int edge) {
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
HistoryInner *HistoryInner::Instance = nullptr;
class HistoryInner::BotAbout : public ClickHandlerHost {
public:
BotAbout(not_null<HistoryInner*> parent, not_null<BotInfo*> info);
@ -127,6 +130,8 @@ HistoryInner::HistoryInner(
, _scroll(scroll)
, _scrollDateCheck([this] { scrollDateCheck(); })
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
Instance = this;
_touchSelectTimer.setSingleShot(true);
connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect()));
@ -2097,6 +2102,7 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) {
auto scrolledUp = (top < _visibleAreaTop);
_visibleAreaTop = top;
_visibleAreaBottom = bottom;
const auto visibleAreaHeight = bottom - top;
// if history has pending resize events we should not update scrollTopItem
if (hasPendingResizedItems()) {
@ -2130,6 +2136,12 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) {
} else {
scrollDateHideByTimer();
}
// Unload lottie animations.
const auto pages = kUnloadHeavyPartsPages;
const auto from = _visibleAreaTop - pages * visibleAreaHeight;
const auto till = _visibleAreaBottom + pages * visibleAreaHeight;
Auth().data().unloadHeavyViewParts(ElementDelegate(), from, till);
}
bool HistoryInner::displayScrollDate() const {
@ -2243,6 +2255,9 @@ void HistoryInner::leaveEventHook(QEvent *e) {
}
HistoryInner::~HistoryInner() {
if (Instance == this) {
Instance = nullptr;
}
delete _menu;
_mouseAction = MouseAction::None;
}
@ -2345,6 +2360,18 @@ bool HistoryInner::inSelectionMode() const {
return false;
}
bool HistoryInner::elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) const {
const auto top = itemTop(view);
if (top < 0) {
return false;
}
const auto bottom = top + view->height();
return (top < till && bottom > from);
}
auto HistoryInner::getSelectionState() const
-> HistoryView::TopBarWidget::SelectedState {
auto result = HistoryView::TopBarWidget::SelectedState {};
@ -3179,7 +3206,15 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
return crl::time(0);
}
bool elementInSelectionMode() override {
return App::main()->historyInSelectionMode();
return Instance ? Instance->inSelectionMode() : false;
}
bool elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) override {
return Instance
? Instance->elementIntersectsRange(view, from, till)
: false;
}
};

View File

@ -73,6 +73,10 @@ public:
MessageIdsList getSelectedItems() const;
void selectItem(not_null<HistoryItem*> item);
bool inSelectionMode() const;
bool elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) const;
void updateBotInfo(bool recount = true);
@ -296,6 +300,8 @@ private:
// Does any of the shown histories has this flag set.
bool hasPendingResizedItems() const;
static HistoryInner *Instance;
not_null<Window::Controller*> _controller;
const not_null<PeerData*> _peer;

View File

@ -850,10 +850,6 @@ int HistoryWidget::itemTopForHighlight(
return qMax(itemTop - (heightLeft / 2), 0);
}
bool HistoryWidget::inSelectionMode() const {
return _list ? _list->inSelectionMode() : false;
}
void HistoryWidget::start() {
Auth().data().stickersUpdated(
) | rpl::start_with_next([this] {
@ -1643,6 +1639,9 @@ void HistoryWidget::showHistory(
_showAtMsgId = showAtMsgId;
_historyInited = false;
// Unload lottie animations.
Auth().data().unloadHeavyViewParts(HistoryInner::ElementDelegate());
if (peerId) {
_peer = Auth().data().peer(peerId);
_channel = peerToChannel(_peer->id);

View File

@ -186,7 +186,6 @@ public:
void enqueueMessageHighlight(not_null<HistoryView::Element*> view);
crl::time highlightStartTime(not_null<const HistoryItem*> item) const;
bool inSelectionMode() const;
MessageIdsList getSelectedItems() const;
void itemEdited(HistoryItem *item);

View File

@ -220,6 +220,9 @@ public:
return true;
}
virtual void unloadHeavyPart() {
}
// Should be called only by Data::Session.
virtual void updateSharedContactUserId(UserId userId) {
}

View File

@ -39,7 +39,9 @@ HistorySticker::HistorySticker(
}
}
HistorySticker::~HistorySticker() = default;
HistorySticker::~HistorySticker() {
unloadLottie();
}
QSize HistorySticker::countOptimalSize() {
auto sticker = _data->sticker();
@ -93,9 +95,14 @@ QSize HistorySticker::countCurrentSize(int newWidth) {
}
void HistorySticker::setupLottie() {
if (_lottie) {
return;
}
_lottie = _data->data().isEmpty()
? Lottie::FromFile(_data->filepath())
: Lottie::FromData(_data->data());
_parent->data()->history()->owner().registerHeavyViewPart(_parent);
_lottie->updates(
) | rpl::start_with_next_error([=](Lottie::Update update) {
update.data.match([&](const Lottie::Information &information) {
@ -107,6 +114,14 @@ void HistorySticker::setupLottie() {
}, _lifetime);
}
void HistorySticker::unloadLottie() {
if (!_lottie) {
return;
}
_lottie = nullptr;
_parent->data()->history()->owner().unregisterHeavyViewPart(_parent);
}
void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
if (!_lottie && _data->filename().endsWith(qstr(".json"))) {
if (_data->loaded()) {

View File

@ -55,6 +55,10 @@ public:
return true;
}
void unloadHeavyPart() override {
unloadLottie();
}
private:
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;
@ -64,6 +68,7 @@ private:
int additionalWidth() const;
void setupLottie();
void unloadLottie();
int _pixw = 1;
int _pixh = 1;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_element.h"
#include "history/view/history_view_service_message.h"
#include "history/view/history_view_message.h"
#include "history/history_item_components.h"
#include "history/history_item.h"
#include "history/media/history_media.h"
@ -47,6 +48,42 @@ bool IsAttachedToPreviousInSavedMessages(
} // namespace
std::unique_ptr<HistoryView::Element> SimpleElementDelegate::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>(this, message);
}
std::unique_ptr<HistoryView::Element> SimpleElementDelegate::elementCreate(
not_null<HistoryService*> message) {
return std::make_unique<HistoryView::Service>(this, message);
}
bool SimpleElementDelegate::elementUnderCursor(
not_null<const Element*> view) {
return false;
}
void SimpleElementDelegate::elementAnimationAutoplayAsync(
not_null<const Element*> element) {
}
crl::time SimpleElementDelegate::elementHighlightTime(
not_null<const Element*> element) {
return crl::time(0);
}
bool SimpleElementDelegate::elementInSelectionMode() {
return false;
}
bool SimpleElementDelegate::elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) {
return true;
}
TextSelection UnshiftItemSelection(
TextSelection selection,
uint16 byLength) {
@ -526,6 +563,12 @@ bool Element::hasVisibleText() const {
return false;
}
void Element::unloadHeavyPart() {
if (_media) {
_media->unloadHeavyPart();
}
}
HistoryBlock *Element::block() {
return _block;
}

View File

@ -46,9 +46,31 @@ public:
virtual crl::time elementHighlightTime(
not_null<const Element*> element) = 0;
virtual bool elementInSelectionMode() = 0;
virtual bool elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) = 0;
};
class SimpleElementDelegate : public ElementDelegate {
public:
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
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;
};
TextSelection UnshiftItemSelection(
TextSelection selection,
uint16 byLength);
@ -232,6 +254,8 @@ public:
virtual TimeId displayedEditDate() const;
virtual bool hasVisibleText() const;
virtual void unloadHeavyPart();
// Legacy blocks structure.
HistoryBlock *block();
const HistoryBlock *block() const;

View File

@ -1126,6 +1126,17 @@ bool ListWidget::elementInSelectionMode() {
return hasSelectedItems() || !_dragSelected.empty();
}
bool ListWidget::elementIntersectsRange(
not_null<const Element*> view,
int from,
int till) {
Expects(view->delegate() == this);
const auto top = itemTop(view);
const auto bottom = top + view->height();
return (top < till && bottom > from);
}
void ListWidget::saveState(not_null<ListMemento*> memento) {
memento->setAroundPosition(_aroundPosition);
auto state = countScrollState();

View File

@ -180,6 +180,10 @@ public:
not_null<const Element*> view) 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;
~ListWidget();

View File

@ -967,10 +967,6 @@ crl::time MainWidget::highlightStartTime(not_null<const HistoryItem*> item) cons
return _history->highlightStartTime(item);
}
bool MainWidget::historyInSelectionMode() const {
return _history->inSelectionMode();
}
MsgId MainWidget::currentReplyToIdFor(not_null<History*> history) const {
if (_history->history() == history) {
return _history->replyToId();

View File

@ -199,7 +199,6 @@ public:
// While HistoryInner is not HistoryView::ListWidget.
crl::time highlightStartTime(not_null<const HistoryItem*> item) const;
bool historyInSelectionMode() const;
MsgId currentReplyToIdFor(not_null<History*> history) const;

View File

@ -682,36 +682,6 @@ HistoryView::Context ForwardsPrivacyController::elementContext() {
return HistoryView::Context::ContactPreview;
}
auto ForwardsPrivacyController::elementCreate(
not_null<HistoryMessage*> message)
-> std::unique_ptr<HistoryView::Element> {
return std::make_unique<HistoryView::Message>(delegate(), message);
}
auto ForwardsPrivacyController::elementCreate(
not_null<HistoryService*> message)
-> std::unique_ptr<HistoryView::Element> {
Unexpected("Service message in ForwardsPrivacyController.");
}
bool ForwardsPrivacyController::elementUnderCursor(
not_null<const Element*> view) {
return false;
}
void ForwardsPrivacyController::elementAnimationAutoplayAsync(
not_null<const Element*> element) {
}
crl::time ForwardsPrivacyController::elementHighlightTime(
not_null<const Element*> element) {
return crl::time(0);
}
bool ForwardsPrivacyController::elementInSelectionMode() {
return false;
}
ApiWrap::Privacy::Key ProfilePhotoPrivacyController::key() {
return Key::ProfilePhoto;
}

View File

@ -109,7 +109,7 @@ public:
class ForwardsPrivacyController
: public EditPrivacyBox::Controller
, private HistoryView::ElementDelegate {
, private HistoryView::SimpleElementDelegate {
public:
using Option = EditPrivacyBox::Option;
using Exception = EditPrivacyBox::Exception;
@ -132,16 +132,6 @@ private:
using Element = HistoryView::Element;
not_null<HistoryView::ElementDelegate*> delegate();
HistoryView::Context elementContext() override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
not_null<const Element*> element) override;
crl::time elementHighlightTime(
not_null<const Element*> element) override;
bool elementInSelectionMode() override;
static void PaintForwardedTooltip(
Painter &p,

View File

@ -577,31 +577,4 @@ HistoryView::Context ConfirmContactBox::elementContext() {
return HistoryView::Context::ContactPreview;
}
std::unique_ptr<HistoryView::Element> ConfirmContactBox::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>(this, message);
}
std::unique_ptr<HistoryView::Element> ConfirmContactBox::elementCreate(
not_null<HistoryService*> message) {
return std::make_unique<HistoryView::Service>(this, message);
}
bool ConfirmContactBox::elementUnderCursor(not_null<const Element*> view) {
return false;
}
void ConfirmContactBox::elementAnimationAutoplayAsync(
not_null<const Element*> element) {
}
crl::time ConfirmContactBox::elementHighlightTime(
not_null<const Element*> element) {
return crl::time(0);
}
bool ConfirmContactBox::elementInSelectionMode() {
return false;
}
} // namespace Support

View File

@ -59,7 +59,7 @@ private:
class ConfirmContactBox
: public BoxContent
, public HistoryView::ElementDelegate {
, public HistoryView::SimpleElementDelegate {
public:
ConfirmContactBox(
QWidget*,
@ -69,16 +69,6 @@ public:
using Element = HistoryView::Element;
HistoryView::Context elementContext() override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
not_null<const Element*> element) override;
crl::time elementHighlightTime(
not_null<const Element*> element) override;
bool elementInSelectionMode() override;
protected:
void prepare() override;