mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Show animation on story reaction sending.
This commit is contained in:
parent
41eac3692c
commit
ff835ec76c
8 changed files with 100 additions and 8 deletions
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/painter.h"
|
||||
#include "history/history_item.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -667,12 +668,30 @@ ChosenReaction Selector::lookupChosen(const Data::ReactionId &id) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Selector::preloadAllRecentsAnimations() {
|
||||
const auto preload = [&](DocumentData *document) {
|
||||
const auto view = document
|
||||
? document->activeMediaView()
|
||||
: nullptr;
|
||||
if (view) {
|
||||
view->checkStickerLarge();
|
||||
}
|
||||
};
|
||||
for (const auto &reaction : _reactions.recent) {
|
||||
if (!reaction.id.custom()) {
|
||||
preload(reaction.centerIcon);
|
||||
}
|
||||
preload(reaction.aroundAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
void Selector::expand() {
|
||||
if (_expandScheduled) {
|
||||
return;
|
||||
}
|
||||
_expandScheduled = true;
|
||||
_willExpand.fire({});
|
||||
preloadAllRecentsAnimations();
|
||||
const auto parent = parentWidget()->geometry();
|
||||
const auto extents = extentsForShadow();
|
||||
const auto heightLimit = _reactions.customAllowed
|
||||
|
|
|
@ -131,6 +131,7 @@ private:
|
|||
void createList();
|
||||
void finishExpand();
|
||||
ChosenReaction lookupChosen(const Data::ReactionId &id) const;
|
||||
void preloadAllRecentsAnimations();
|
||||
|
||||
const style::EmojiPan &_st;
|
||||
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||
|
|
|
@ -11,11 +11,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/power_save_blocker.h"
|
||||
#include "base/qt_signal_producer.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/view/reactions/history_view_reactions_strip.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/stories/media_stories_caption_full_view.h"
|
||||
#include "media/stories/media_stories_delegate.h"
|
||||
|
@ -28,8 +31,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/stories/media_stories_share.h"
|
||||
#include "media/stories/media_stories_view.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/effects/emoji_fly_animation.h"
|
||||
#include "ui/effects/message_sending_animation_common.h"
|
||||
#include "ui/effects/reaction_fly_animation.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "styles/style_media_view.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_boxes.h" // UserpicButton
|
||||
|
@ -171,8 +177,14 @@ Controller::Controller(not_null<Delegate*> delegate)
|
|||
}, _lifetime);
|
||||
|
||||
_reactions->chosen(
|
||||
) | rpl::start_with_next([=](const Data::ReactionId &id) {
|
||||
_replyArea->sendReaction(id);
|
||||
) | rpl::start_with_next([=](HistoryView::Reactions::ChosenReaction id) {
|
||||
startReactionAnimation(id.id, {
|
||||
.type = Ui::MessageSendingAnimationFrom::Type::Emoji,
|
||||
.globalStartGeometry = id.globalGeometry,
|
||||
.frame = id.icon,
|
||||
});
|
||||
_replyArea->sendReaction(id.id);
|
||||
unfocusReply();
|
||||
}, _lifetime);
|
||||
|
||||
_delegate->storiesLayerShown(
|
||||
|
@ -1062,4 +1074,32 @@ void Controller::updatePowerSaveBlocker(const Player::TrackState &state) {
|
|||
[=] { return _wrap->window()->windowHandle(); });
|
||||
}
|
||||
|
||||
void Controller::startReactionAnimation(
|
||||
Data::ReactionId id,
|
||||
Ui::MessageSendingAnimationFrom from) {
|
||||
Expects(shown());
|
||||
|
||||
auto args = Ui::ReactionFlyAnimationArgs{
|
||||
.id = id,
|
||||
.flyIcon = from.frame,
|
||||
.flyFrom = _wrap->mapFromGlobal(from.globalStartGeometry),
|
||||
.scaleOutDuration = st::fadeWrapDuration * 2,
|
||||
};
|
||||
_reactionAnimation = std::make_unique<Ui::EmojiFlyAnimation>(
|
||||
_wrap,
|
||||
&shownUser()->owner().reactions(),
|
||||
std::move(args),
|
||||
[=] { _reactionAnimation->repaint(); },
|
||||
Data::CustomEmojiSizeTag::Isolated);
|
||||
const auto layer = _reactionAnimation->layer();
|
||||
_wrap->paintRequest() | rpl::start_with_next([=] {
|
||||
if (!_reactionAnimation->paintBadgeFrame(_wrap.get())) {
|
||||
InvokeQueued(layer, [=] {
|
||||
_reactionAnimation = nullptr;
|
||||
_wrap->update();
|
||||
});
|
||||
}
|
||||
}, layer->lifetime());
|
||||
}
|
||||
|
||||
} // namespace Media::Stories
|
||||
|
|
|
@ -21,6 +21,7 @@ struct FileChosen;
|
|||
|
||||
namespace Data {
|
||||
struct FileOrigin;
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
|
@ -29,6 +30,8 @@ class CachedIconFactory;
|
|||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
struct MessageSendingAnimationFrom;
|
||||
class EmojiFlyAnimation;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Main {
|
||||
|
@ -183,6 +186,10 @@ private:
|
|||
void checkMoveByDelta();
|
||||
void loadMoreToList();
|
||||
|
||||
void startReactionAnimation(
|
||||
Data::ReactionId id,
|
||||
Ui::MessageSendingAnimationFrom from);
|
||||
|
||||
const not_null<Delegate*> _delegate;
|
||||
|
||||
rpl::variable<std::optional<Layout>> _layout;
|
||||
|
@ -226,6 +233,7 @@ private:
|
|||
std::unique_ptr<Sibling> _siblingRight;
|
||||
|
||||
std::unique_ptr<base::PowerSaveBlocker> _powerSaveBlocker;
|
||||
std::unique_ptr<Ui::EmojiFlyAnimation> _reactionAnimation;
|
||||
|
||||
Main::Session *_session = nullptr;
|
||||
rpl::lifetime _sessionLifetime;
|
||||
|
|
|
@ -143,7 +143,7 @@ void Reactions::create() {
|
|||
_selector->chosen(
|
||||
) | rpl::start_with_next([=](
|
||||
HistoryView::Reactions::ChosenReaction reaction) {
|
||||
_chosen.fire_copy(reaction.id);
|
||||
_chosen.fire_copy(reaction);
|
||||
hide();
|
||||
}, _selector->lifetime());
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ struct ReactionId;
|
|||
|
||||
namespace HistoryView::Reactions {
|
||||
class Selector;
|
||||
struct ChosenReaction;
|
||||
} // namespace HistoryView::Reactions
|
||||
|
||||
namespace Ui {
|
||||
|
@ -30,10 +31,11 @@ public:
|
|||
explicit Reactions(not_null<Controller*> controller);
|
||||
~Reactions();
|
||||
|
||||
using Chosen = HistoryView::Reactions::ChosenReaction;
|
||||
[[nodiscard]] rpl::producer<bool> expandedValue() const {
|
||||
return _expanded.value();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<Data::ReactionId> chosen() const {
|
||||
[[nodiscard]] rpl::producer<Chosen> chosen() const {
|
||||
return _chosen.events();
|
||||
}
|
||||
|
||||
|
@ -54,7 +56,7 @@ private:
|
|||
std::unique_ptr<Ui::RpWidget> _parent;
|
||||
std::unique_ptr<HistoryView::Reactions::Selector> _selector;
|
||||
std::vector<std::unique_ptr<Hiding>> _hiding;
|
||||
rpl::event_stream<Data::ReactionId> _chosen;
|
||||
rpl::event_stream<Chosen> _chosen;
|
||||
Ui::Animations::Simple _showing;
|
||||
rpl::variable<float64> _shownValue;
|
||||
rpl::variable<bool> _expanded;
|
||||
|
|
|
@ -67,7 +67,8 @@ ReactionFlyAnimation::ReactionFlyAnimation(
|
|||
Data::CustomEmojiSizeTag customSizeTag)
|
||||
: _owner(owner)
|
||||
, _repaint(std::move(repaint))
|
||||
, _flyFrom(args.flyFrom) {
|
||||
, _flyFrom(args.flyFrom)
|
||||
, _scaleOutDuration(args.scaleOutDuration) {
|
||||
const auto &list = owner->list(::Data::Reactions::Type::All);
|
||||
auto centerIcon = (DocumentData*)nullptr;
|
||||
auto aroundAnimation = (DocumentData*)nullptr;
|
||||
|
@ -135,7 +136,26 @@ QRect ReactionFlyAnimation::paintGetArea(
|
|||
const QColor &colored,
|
||||
QRect clip,
|
||||
crl::time now) const {
|
||||
if (_flyIcon.isNull()) {
|
||||
const auto scale = [&] {
|
||||
const auto rate = _effect ? _effect->frameRate() : 0.;
|
||||
if (!_scaleOutDuration || !rate) {
|
||||
return 1.;
|
||||
}
|
||||
const auto left = _effect->framesCount() - _effect->frameIndex();
|
||||
const auto duration = left * 1000. / rate;
|
||||
return (duration < _scaleOutDuration)
|
||||
? (duration / double(_scaleOutDuration))
|
||||
: 1.;
|
||||
}();
|
||||
if (scale < 1.) {
|
||||
const auto delta = ((1. - scale) / 2.) * target.size();
|
||||
target = QRect(
|
||||
target.topLeft() + QPoint(delta.width(), delta.height()),
|
||||
target.size() * scale);
|
||||
}
|
||||
if (!_valid) {
|
||||
return QRect();
|
||||
} else if (_flyIcon.isNull()) {
|
||||
const auto wide = QRect(
|
||||
target.topLeft() - QPoint(target.width(), target.height()) / 2,
|
||||
target.size() * 2);
|
||||
|
|
|
@ -27,6 +27,7 @@ struct ReactionFlyAnimationArgs {
|
|||
::Data::ReactionId id;
|
||||
QImage flyIcon;
|
||||
QRect flyFrom;
|
||||
crl::time scaleOutDuration = 0;
|
||||
|
||||
[[nodiscard]] ReactionFlyAnimationArgs translated(QPoint point) const;
|
||||
};
|
||||
|
@ -102,6 +103,7 @@ private:
|
|||
QRect _flyFrom;
|
||||
float64 _centerSizeMultiplier = 0.;
|
||||
int _customSize = 0;
|
||||
crl::time _scaleOutDuration = 0;
|
||||
bool _valid = false;
|
||||
|
||||
mutable Parabolic _cached;
|
||||
|
|
Loading…
Add table
Reference in a new issue