mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Start emoji interactions playback.
This commit is contained in:
parent
b6fafdd8f7
commit
15f83892a1
9 changed files with 263 additions and 14 deletions
|
@ -100,7 +100,7 @@ void EmojiInteractions::start(not_null<const HistoryView::Element*> view) {
|
||||||
auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
||||||
auto nearest = kTimeNever;
|
auto nearest = kTimeNever;
|
||||||
auto waitingForDownload = false;
|
auto waitingForDownload = false;
|
||||||
for (auto &[id, animations] : _animations) {
|
for (auto &[item, animations] : _animations) {
|
||||||
auto lastStartedAt = crl::time();
|
auto lastStartedAt = crl::time();
|
||||||
for (auto &animation : animations) {
|
for (auto &animation : animations) {
|
||||||
if (animation.startedAt) {
|
if (animation.startedAt) {
|
||||||
|
@ -111,11 +111,7 @@ auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
||||||
break;
|
break;
|
||||||
} else if (!lastStartedAt || lastStartedAt + kMinDelay <= now) {
|
} else if (!lastStartedAt || lastStartedAt + kMinDelay <= now) {
|
||||||
animation.startedAt = now;
|
animation.startedAt = now;
|
||||||
|
_playRequests.fire({ item, animation.media });
|
||||||
// #TODO interactions
|
|
||||||
//const auto sticker = std::make_unique<HistoryView::Sticker>(
|
|
||||||
// view,
|
|
||||||
// document);
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
nearest = std::min(nearest, lastStartedAt + kMinDelay);
|
nearest = std::min(nearest, lastStartedAt + kMinDelay);
|
||||||
|
@ -174,8 +170,8 @@ void EmojiInteractions::sendAccumulated(
|
||||||
auto EmojiInteractions::checkAccumulated(crl::time now) -> CheckResult {
|
auto EmojiInteractions::checkAccumulated(crl::time now) -> CheckResult {
|
||||||
auto nearest = kTimeNever;
|
auto nearest = kTimeNever;
|
||||||
for (auto i = begin(_animations); i != end(_animations);) {
|
for (auto i = begin(_animations); i != end(_animations);) {
|
||||||
auto &[id, animations] = *i;
|
auto &[item, animations] = *i;
|
||||||
sendAccumulated(now, id, animations);
|
sendAccumulated(now, item, animations);
|
||||||
if (animations.empty()) {
|
if (animations.empty()) {
|
||||||
i = _animations.erase(i);
|
i = _animations.erase(i);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -26,12 +26,22 @@ class Element;
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
|
||||||
|
struct EmojiInteractionPlayRequest {
|
||||||
|
not_null<HistoryItem*> item;
|
||||||
|
std::shared_ptr<Data::DocumentMedia> media;
|
||||||
|
};
|
||||||
|
|
||||||
class EmojiInteractions final {
|
class EmojiInteractions final {
|
||||||
public:
|
public:
|
||||||
explicit EmojiInteractions(not_null<Main::Session*> session);
|
explicit EmojiInteractions(not_null<Main::Session*> session);
|
||||||
~EmojiInteractions();
|
~EmojiInteractions();
|
||||||
|
|
||||||
|
using PlayRequest = EmojiInteractionPlayRequest;
|
||||||
|
|
||||||
void start(not_null<const HistoryView::Element*> view);
|
void start(not_null<const HistoryView::Element*> view);
|
||||||
|
[[nodiscard]] rpl::producer<PlayRequest> playRequests() const {
|
||||||
|
return _playRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Animation {
|
struct Animation {
|
||||||
|
@ -63,6 +73,7 @@ private:
|
||||||
not_null<HistoryItem*>,
|
not_null<HistoryItem*>,
|
||||||
std::vector<Animation>> _animations;
|
std::vector<Animation>> _animations;
|
||||||
base::Timer _checkTimer;
|
base::Timer _checkTimer;
|
||||||
|
rpl::event_stream<PlayRequest> _playRequests;
|
||||||
|
|
||||||
bool _waitingForDownload = false;
|
bool _waitingForDownload = false;
|
||||||
rpl::lifetime _downloadCheckLifetime;
|
rpl::lifetime _downloadCheckLifetime;
|
||||||
|
|
|
@ -60,11 +60,12 @@ auto LottieFromDocument(
|
||||||
Method &&method,
|
Method &&method,
|
||||||
not_null<Data::DocumentMedia*> media,
|
not_null<Data::DocumentMedia*> media,
|
||||||
uint8 keyShift,
|
uint8 keyShift,
|
||||||
QSize box) {
|
QSize box,
|
||||||
|
int cacheAreaLimit) {
|
||||||
const auto document = media->owner();
|
const auto document = media->owner();
|
||||||
const auto data = media->bytes();
|
const auto data = media->bytes();
|
||||||
const auto filepath = document->filepath();
|
const auto filepath = document->filepath();
|
||||||
if (box.width() * box.height() > kDontCacheLottieAfterArea) {
|
if (box.width() * box.height() > cacheAreaLimit) {
|
||||||
// Don't use frame caching for large stickers.
|
// Don't use frame caching for large stickers.
|
||||||
return method(
|
return method(
|
||||||
Lottie::ReadContent(data, filepath),
|
Lottie::ReadContent(data, filepath),
|
||||||
|
@ -113,9 +114,12 @@ std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||||
replacements,
|
replacements,
|
||||||
std::move(renderer));
|
std::move(renderer));
|
||||||
};
|
};
|
||||||
|
const auto limit = (sizeTag == StickerLottieSize::EmojiInteraction)
|
||||||
|
? (3 * kDontCacheLottieAfterArea)
|
||||||
|
: kDontCacheLottieAfterArea;
|
||||||
const auto tag = replacements ? replacements->tag : uint8(0);
|
const auto tag = replacements ? replacements->tag : uint8(0);
|
||||||
const auto keyShift = ((tag << 4) & 0xF0) | (uint8(sizeTag) & 0x0F);
|
const auto keyShift = ((tag << 4) & 0xF0) | (uint8(sizeTag) & 0x0F);
|
||||||
return LottieFromDocument(method, media, uint8(keyShift), box);
|
return LottieFromDocument(method, media, uint8(keyShift), box, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
||||||
|
@ -126,7 +130,8 @@ not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
||||||
const auto method = [&](auto &&...args) {
|
const auto method = [&](auto &&...args) {
|
||||||
return player->append(std::forward<decltype(args)>(args)...);
|
return player->append(std::forward<decltype(args)>(args)...);
|
||||||
};
|
};
|
||||||
return LottieFromDocument(method, media, uint8(sizeTag), box);
|
const auto limit = kDontCacheLottieAfterArea;
|
||||||
|
return LottieFromDocument(method, media, uint8(sizeTag), box, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasLottieThumbnail(
|
bool HasLottieThumbnail(
|
||||||
|
|
|
@ -44,6 +44,7 @@ enum class StickerLottieSize : uchar {
|
||||||
StickersFooter,
|
StickersFooter,
|
||||||
SetsListThumbnail,
|
SetsListThumbnail,
|
||||||
InlineResults,
|
InlineResults,
|
||||||
|
EmojiInteraction,
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/history_view_service_message.h"
|
#include "history/view/history_view_service_message.h"
|
||||||
#include "history/view/history_view_cursor_state.h"
|
#include "history/view/history_view_cursor_state.h"
|
||||||
#include "history/view/history_view_context_menu.h"
|
#include "history/view/history_view_context_menu.h"
|
||||||
|
#include "history/view/history_view_emoji_interactions.h"
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
#include "ui/chat/chat_style.h"
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
@ -160,6 +161,8 @@ HistoryInner::HistoryInner(
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _peer(history->peer)
|
, _peer(history->peer)
|
||||||
, _history(history)
|
, _history(history)
|
||||||
|
, _emojiInteractions(std::make_unique<HistoryView::EmojiInteractions>(
|
||||||
|
&controller->session()))
|
||||||
, _migrated(history->migrateFrom())
|
, _migrated(history->migrateFrom())
|
||||||
, _pathGradient(
|
, _pathGradient(
|
||||||
HistoryView::MakePathShiftGradient(
|
HistoryView::MakePathShiftGradient(
|
||||||
|
@ -195,6 +198,21 @@ HistoryInner::HistoryInner(
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
using PlayRequest = ChatHelpers::EmojiInteractionPlayRequest;
|
||||||
|
_controller->emojiInteractions().playRequests(
|
||||||
|
) | rpl::filter([=](const PlayRequest &request) {
|
||||||
|
return (request.item->history() == _history);
|
||||||
|
}) | rpl::start_with_next([=](const PlayRequest &request) {
|
||||||
|
if (const auto view = request.item->mainView()) {
|
||||||
|
_emojiInteractions->play(request, view);
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
_emojiInteractions->updateRequests(
|
||||||
|
) | rpl::start_with_next([=](QRect rect) {
|
||||||
|
update(rect.translated(0, _historyPaddingTop));
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
session().data().itemRemoved(
|
session().data().itemRemoved(
|
||||||
) | rpl::start_with_next(
|
) | rpl::start_with_next(
|
||||||
[this](auto item) { itemRemoved(item); },
|
[this](auto item) { itemRemoved(item); },
|
||||||
|
@ -834,6 +852,9 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
p.setOpacity(1.);
|
||||||
|
p.translate(0, _historyPaddingTop);
|
||||||
|
_emojiInteractions->paint(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2357,6 +2378,10 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) {
|
||||||
const auto till = _visibleAreaBottom + pages * visibleAreaHeight;
|
const auto till = _visibleAreaBottom + pages * visibleAreaHeight;
|
||||||
session().data().unloadHeavyViewParts(ElementDelegate(), from, till);
|
session().data().unloadHeavyViewParts(ElementDelegate(), from, till);
|
||||||
checkHistoryActivation();
|
checkHistoryActivation();
|
||||||
|
|
||||||
|
_emojiInteractions->visibleAreaUpdated(
|
||||||
|
_visibleAreaTop - _historyPaddingTop,
|
||||||
|
_visibleAreaBottom - _historyPaddingTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryInner::displayScrollDate() const {
|
bool HistoryInner::displayScrollDate() const {
|
||||||
|
@ -2454,7 +2479,12 @@ void HistoryInner::updateSize() {
|
||||||
_botAbout->rect = QRect(descAtX, descAtY, _botAbout->width + st::msgPadding.left() + st::msgPadding.right(), descH - st::msgMargin.top() - st::msgMargin.bottom());
|
_botAbout->rect = QRect(descAtX, descAtY, _botAbout->width + st::msgPadding.left() + st::msgPadding.right(), descH - st::msgMargin.top() - st::msgMargin.bottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
_historyPaddingTop = newHistoryPaddingTop;
|
if (_historyPaddingTop != newHistoryPaddingTop) {
|
||||||
|
_historyPaddingTop = newHistoryPaddingTop;
|
||||||
|
_emojiInteractions->visibleAreaUpdated(
|
||||||
|
_visibleAreaTop - _historyPaddingTop,
|
||||||
|
_visibleAreaBottom - _historyPaddingTop);
|
||||||
|
}
|
||||||
|
|
||||||
int newHeight = _historyPaddingTop + itemsHeight + st::historyPaddingBottom;
|
int newHeight = _historyPaddingTop + itemsHeight + st::historyPaddingBottom;
|
||||||
if (width() != _scroll->width() || height() != newHeight) {
|
if (width() != _scroll->width() || height() != newHeight) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ class CloudImageView;
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
class ElementDelegate;
|
class ElementDelegate;
|
||||||
|
class EmojiInteractions;
|
||||||
struct TextState;
|
struct TextState;
|
||||||
struct StateRequest;
|
struct StateRequest;
|
||||||
enum class CursorState : char;
|
enum class CursorState : char;
|
||||||
|
@ -354,6 +355,7 @@ private:
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
const not_null<PeerData*> _peer;
|
const not_null<PeerData*> _peer;
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
const std::unique_ptr<HistoryView::EmojiInteractions> _emojiInteractions;
|
||||||
std::shared_ptr<Ui::ChatTheme> _theme;
|
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||||
|
|
||||||
History *_migrated = nullptr;
|
History *_migrated = nullptr;
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "history/view/history_view_emoji_interactions.h"
|
||||||
|
|
||||||
|
#include "history/view/history_view_element.h"
|
||||||
|
#include "history/view/media/history_view_sticker.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "chat_helpers/emoji_interactions.h"
|
||||||
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
|
#include "lottie/lottie_common.h"
|
||||||
|
#include "lottie/lottie_single_player.h"
|
||||||
|
#include "base/random.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kSizeMultiplier = 3;
|
||||||
|
|
||||||
|
[[nodiscard]] QPoint GenerateRandomShift(QSize emoji) {
|
||||||
|
// Random shift in [-0.08 ... 0.08] of animated emoji size.
|
||||||
|
const auto maxShift = emoji * 2 / 25;
|
||||||
|
return {
|
||||||
|
base::RandomIndex(maxShift.width() * 2 + 1) - maxShift.width(),
|
||||||
|
base::RandomIndex(maxShift.height() * 2 + 1) - maxShift.height(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
EmojiInteractions::EmojiInteractions(not_null<Main::Session*> session)
|
||||||
|
: _session(session) {
|
||||||
|
_session->data().viewRemoved(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return !_plays.empty();
|
||||||
|
}) | rpl::start_with_next([=](not_null<const Element*> view) {
|
||||||
|
_plays.erase(ranges::remove(_plays, view, &Play::view), end(_plays));
|
||||||
|
}, _lifetime);
|
||||||
|
|
||||||
|
_emojiSize = Sticker::EmojiSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmojiInteractions::~EmojiInteractions() = default;
|
||||||
|
|
||||||
|
void EmojiInteractions::play(
|
||||||
|
ChatHelpers::EmojiInteractionPlayRequest request,
|
||||||
|
not_null<Element*> view) {
|
||||||
|
const auto top = view->block()->y() + view->y();
|
||||||
|
const auto bottom = top + view->height();
|
||||||
|
if (_visibleTop >= bottom
|
||||||
|
|| _visibleBottom <= top
|
||||||
|
|| _visibleTop == _visibleBottom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto lottie = ChatHelpers::LottiePlayerFromDocument(
|
||||||
|
request.media.get(),
|
||||||
|
nullptr,
|
||||||
|
ChatHelpers::StickerLottieSize::EmojiInteraction,
|
||||||
|
_emojiSize * kSizeMultiplier * style::DevicePixelRatio(),
|
||||||
|
Lottie::Quality::High);
|
||||||
|
const auto shift = GenerateRandomShift(_emojiSize);
|
||||||
|
lottie->updates(
|
||||||
|
) | rpl::start_with_next([=](Lottie::Update update) {
|
||||||
|
v::match(update.data, [&](const Lottie::Information &information) {
|
||||||
|
}, [&](const Lottie::DisplayFrameRequest &request) {
|
||||||
|
const auto rect = computeRect(view).translated(shift);
|
||||||
|
if (rect.y() + rect.height() >= _visibleTop
|
||||||
|
&& rect.y() <= _visibleBottom) {
|
||||||
|
_updateRequests.fire_copy(rect);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, lottie->lifetime());
|
||||||
|
_plays.push_back({
|
||||||
|
.view = view,
|
||||||
|
.lottie = std::move(lottie),
|
||||||
|
.shift = shift,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiInteractions::visibleAreaUpdated(
|
||||||
|
int visibleTop,
|
||||||
|
int visibleBottom) {
|
||||||
|
_visibleTop = visibleTop;
|
||||||
|
_visibleBottom = visibleBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect EmojiInteractions::computeRect(not_null<Element*> view) const {
|
||||||
|
const auto fullWidth = view->width();
|
||||||
|
const auto shift = (_emojiSize.width() * kSizeMultiplier) / 40;
|
||||||
|
const auto skip = (view->hasFromPhoto() ? st::msgPhotoSkip : 0)
|
||||||
|
+ st::msgMargin.left();
|
||||||
|
const auto rightAligned = view->hasOutLayout()
|
||||||
|
&& !view->delegate()->elementIsChatWide();
|
||||||
|
const auto left = rightAligned
|
||||||
|
? (fullWidth - skip + shift - _emojiSize.width() * kSizeMultiplier)
|
||||||
|
: (skip - shift);
|
||||||
|
const auto viewTop = view->block()->y() + view->y() + view->marginTop();
|
||||||
|
const auto top = viewTop - _emojiSize.height();
|
||||||
|
return QRect(QPoint(left, top), _emojiSize * kSizeMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiInteractions::paint(QPainter &p) {
|
||||||
|
const auto factor = style::DevicePixelRatio();
|
||||||
|
for (auto &play : _plays) {
|
||||||
|
if (!play.lottie->ready()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto request = Lottie::FrameRequest();
|
||||||
|
request.box = _emojiSize * kSizeMultiplier * factor;
|
||||||
|
const auto rightAligned = play.view->hasOutLayout()
|
||||||
|
&& !play.view->delegate()->elementIsChatWide();
|
||||||
|
if (!rightAligned) {
|
||||||
|
// #TODO interactions mirror
|
||||||
|
request.colored = st::msgStickerOverlay->c;
|
||||||
|
}
|
||||||
|
const auto frame = play.lottie->frameInfo(request);
|
||||||
|
if (frame.index + 1 == play.lottie->information().framesCount) {
|
||||||
|
play.finished = true;
|
||||||
|
}
|
||||||
|
const auto rect = computeRect(play.view);
|
||||||
|
p.drawImage(
|
||||||
|
QRect(rect.topLeft() + play.shift, frame.image.size() / factor),
|
||||||
|
frame.image);
|
||||||
|
play.lottie->markFrameShown();
|
||||||
|
}
|
||||||
|
_plays.erase(ranges::remove(_plays, true, &Play::finished), end(_plays));
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QRect> EmojiInteractions::updateRequests() const {
|
||||||
|
return _updateRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ChatHelpers {
|
||||||
|
struct EmojiInteractionPlayRequest;
|
||||||
|
} // namespace ChatHelpers
|
||||||
|
|
||||||
|
namespace Lottie {
|
||||||
|
class SinglePlayer;
|
||||||
|
} // namespace Lottie
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
class Session;
|
||||||
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
class Element;
|
||||||
|
|
||||||
|
class EmojiInteractions final {
|
||||||
|
public:
|
||||||
|
explicit EmojiInteractions(not_null<Main::Session*> session);
|
||||||
|
~EmojiInteractions();
|
||||||
|
|
||||||
|
void play(
|
||||||
|
ChatHelpers::EmojiInteractionPlayRequest request,
|
||||||
|
not_null<Element*> view);
|
||||||
|
void visibleAreaUpdated(int visibleTop, int visibleBottom);
|
||||||
|
|
||||||
|
void paint(QPainter &p);
|
||||||
|
[[nodiscard]] rpl::producer<QRect> updateRequests() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Play {
|
||||||
|
not_null<Element*> view;
|
||||||
|
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||||
|
QPoint shift;
|
||||||
|
bool finished = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] QRect computeRect(not_null<Element*> view) const;
|
||||||
|
|
||||||
|
const not_null<Main::Session*> _session;
|
||||||
|
|
||||||
|
int _visibleTop = 0;
|
||||||
|
int _visibleBottom = 0;
|
||||||
|
QSize _emojiSize;
|
||||||
|
|
||||||
|
std::vector<Play> _plays;
|
||||||
|
rpl::event_stream<QRect> _updateRequests;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
|
@ -1 +1 @@
|
||||||
Subproject commit 25294ef8da339f23e87d3cf0dbe8f29491712cfc
|
Subproject commit a8ffe6cb920ca400de03127cbf5bc5b5ed32aff4
|
Loading…
Add table
Reference in a new issue