mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Limit amount of playing interactions.
This commit is contained in:
parent
15f83892a1
commit
bc2f96251f
6 changed files with 98 additions and 5 deletions
|
@ -590,6 +590,8 @@ PRIVATE
|
|||
history/view/history_view_cursor_state.h
|
||||
history/view/history_view_element.cpp
|
||||
history/view/history_view_element.h
|
||||
history/view/history_view_emoji_interactions.cpp
|
||||
history/view/history_view_emoji_interactions.h
|
||||
history/view/history_view_empty_list_bubble.cpp
|
||||
history/view/history_view_empty_list_bubble.h
|
||||
history/view/history_view_group_call_tracker.cpp
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace {
|
|||
|
||||
constexpr auto kMinDelay = crl::time(200);
|
||||
constexpr auto kAccumulateDelay = crl::time(1000);
|
||||
constexpr auto kMaxDelay = 2 * crl::time(1000);
|
||||
constexpr auto kTimeNever = std::numeric_limits<crl::time>::max();
|
||||
constexpr auto kVersion = 1;
|
||||
|
||||
|
@ -102,6 +103,14 @@ auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
|||
auto waitingForDownload = false;
|
||||
for (auto &[item, animations] : _animations) {
|
||||
auto lastStartedAt = crl::time();
|
||||
|
||||
// Erase too old requests.
|
||||
const auto i = ranges::find_if(animations, [&](const Animation &a) {
|
||||
return !a.startedAt && (a.scheduledAt + kMaxDelay <= now);
|
||||
});
|
||||
if (i != end(animations)) {
|
||||
animations.erase(i, end(animations));
|
||||
}
|
||||
for (auto &animation : animations) {
|
||||
if (animation.startedAt) {
|
||||
lastStartedAt = animation.startedAt;
|
||||
|
@ -111,7 +120,11 @@ auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
|||
break;
|
||||
} else if (!lastStartedAt || lastStartedAt + kMinDelay <= now) {
|
||||
animation.startedAt = now;
|
||||
_playRequests.fire({ item, animation.media });
|
||||
_playRequests.fire({
|
||||
item,
|
||||
animation.media,
|
||||
animation.scheduledAt,
|
||||
});
|
||||
break;
|
||||
} else {
|
||||
nearest = std::min(nearest, lastStartedAt + kMinDelay);
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace ChatHelpers {
|
|||
struct EmojiInteractionPlayRequest {
|
||||
not_null<HistoryItem*> item;
|
||||
std::shared_ptr<Data::DocumentMedia> media;
|
||||
crl::time shouldHaveStartedAt = 0;
|
||||
};
|
||||
|
||||
class EmojiInteractions final {
|
||||
|
|
|
@ -203,9 +203,9 @@ HistoryInner::HistoryInner(
|
|||
_controller->emojiInteractions().playRequests(
|
||||
) | rpl::filter([=](const PlayRequest &request) {
|
||||
return (request.item->history() == _history);
|
||||
}) | rpl::start_with_next([=](const PlayRequest &request) {
|
||||
}) | rpl::start_with_next([=](PlayRequest &&request) {
|
||||
if (const auto view = request.item->mainView()) {
|
||||
_emojiInteractions->play(request, view);
|
||||
_emojiInteractions->play(std::move(request), view);
|
||||
}
|
||||
}, lifetime());
|
||||
_emojiInteractions->updateRequests(
|
||||
|
|
|
@ -26,6 +26,11 @@ namespace {
|
|||
|
||||
constexpr auto kSizeMultiplier = 3;
|
||||
|
||||
constexpr auto kMaxPlays = 5;
|
||||
constexpr auto kMaxPlaysWithSmallDelay = 3;
|
||||
constexpr auto kSmallDelay = crl::time(200);
|
||||
constexpr auto kDropDelayedAfterDelay = crl::time(2000);
|
||||
|
||||
[[nodiscard]] QPoint GenerateRandomShift(QSize emoji) {
|
||||
// Random shift in [-0.08 ... 0.08] of animated emoji size.
|
||||
const auto maxShift = emoji * 2 / 25;
|
||||
|
@ -54,6 +59,17 @@ EmojiInteractions::~EmojiInteractions() = default;
|
|||
void EmojiInteractions::play(
|
||||
ChatHelpers::EmojiInteractionPlayRequest request,
|
||||
not_null<Element*> view) {
|
||||
if (_plays.empty()) {
|
||||
play(view, std::move(request.media));
|
||||
} else {
|
||||
_delayed.push_back({ view, request.media, crl::now() });
|
||||
checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::play(
|
||||
not_null<Element*> view,
|
||||
std::shared_ptr<Data::DocumentMedia> media) {
|
||||
const auto top = view->block()->y() + view->y();
|
||||
const auto bottom = top + view->height();
|
||||
if (_visibleTop >= bottom
|
||||
|
@ -62,7 +78,7 @@ void EmojiInteractions::play(
|
|||
return;
|
||||
}
|
||||
auto lottie = ChatHelpers::LottiePlayerFromDocument(
|
||||
request.media.get(),
|
||||
media.get(),
|
||||
nullptr,
|
||||
ChatHelpers::StickerLottieSize::EmojiInteraction,
|
||||
_emojiSize * kSizeMultiplier * style::DevicePixelRatio(),
|
||||
|
@ -123,7 +139,13 @@ void EmojiInteractions::paint(QPainter &p) {
|
|||
request.colored = st::msgStickerOverlay->c;
|
||||
}
|
||||
const auto frame = play.lottie->frameInfo(request);
|
||||
if (frame.index + 1 == play.lottie->information().framesCount) {
|
||||
play.frame = frame.index;
|
||||
if (!play.framesCount) {
|
||||
const auto &information = play.lottie->information();
|
||||
play.framesCount = information.framesCount;
|
||||
play.frameRate = information.frameRate;
|
||||
}
|
||||
if (play.frame + 1 == play.framesCount) {
|
||||
play.finished = true;
|
||||
}
|
||||
const auto rect = computeRect(play.view);
|
||||
|
@ -133,6 +155,43 @@ void EmojiInteractions::paint(QPainter &p) {
|
|||
play.lottie->markFrameShown();
|
||||
}
|
||||
_plays.erase(ranges::remove(_plays, true, &Play::finished), end(_plays));
|
||||
checkDelayed();
|
||||
}
|
||||
|
||||
void EmojiInteractions::checkDelayed() {
|
||||
if (_delayed.empty() || _plays.size() >= kMaxPlays) {
|
||||
return;
|
||||
}
|
||||
auto withTooLittleDelay = false;
|
||||
auto withHalfPlayed = false;
|
||||
for (const auto &play : _plays) {
|
||||
if (!play.framesCount
|
||||
|| !play.frameRate
|
||||
|| !play.frame
|
||||
|| (play.frame * crl::time(1000)
|
||||
< kSmallDelay * play.frameRate)) {
|
||||
withTooLittleDelay = true;
|
||||
break;
|
||||
} else if (play.frame * 2 > play.framesCount) {
|
||||
withHalfPlayed = true;
|
||||
}
|
||||
}
|
||||
if (withTooLittleDelay) {
|
||||
return;
|
||||
} else if (_plays.size() >= kMaxPlaysWithSmallDelay && !withHalfPlayed) {
|
||||
return;
|
||||
}
|
||||
const auto now = crl::now();
|
||||
const auto i = ranges::find_if(_delayed, [&](const Delayed &delayed) {
|
||||
return (delayed.shouldHaveStartedAt + kDropDelayedAfterDelay > now);
|
||||
});
|
||||
if (i == end(_delayed)) {
|
||||
_delayed.clear();
|
||||
return;
|
||||
}
|
||||
auto good = std::move(*i);
|
||||
_delayed.erase(begin(_delayed), i + 1);
|
||||
play(good.view, std::move(good.media));
|
||||
}
|
||||
|
||||
rpl::producer<QRect> EmojiInteractions::updateRequests() const {
|
||||
|
|
|
@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace ChatHelpers {
|
||||
struct EmojiInteractionPlayRequest;
|
||||
} // namespace ChatHelpers
|
||||
|
@ -41,11 +45,24 @@ private:
|
|||
not_null<Element*> view;
|
||||
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
QPoint shift;
|
||||
int frame = 0;
|
||||
int framesCount = 0;
|
||||
int frameRate = 0;
|
||||
bool finished = false;
|
||||
};
|
||||
struct Delayed {
|
||||
not_null<Element*> view;
|
||||
std::shared_ptr<Data::DocumentMedia> media;
|
||||
crl::time shouldHaveStartedAt = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] QRect computeRect(not_null<Element*> view) const;
|
||||
|
||||
void play(
|
||||
not_null<Element*> view,
|
||||
std::shared_ptr<Data::DocumentMedia> media);
|
||||
void checkDelayed();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
int _visibleTop = 0;
|
||||
|
@ -53,6 +70,7 @@ private:
|
|||
QSize _emojiSize;
|
||||
|
||||
std::vector<Play> _plays;
|
||||
std::vector<Delayed> _delayed;
|
||||
rpl::event_stream<QRect> _updateRequests;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
|
Loading…
Add table
Reference in a new issue