mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Implement craft success animation.
This commit is contained in:
@@ -337,6 +337,8 @@ PRIVATE
|
|||||||
boxes/star_gift_auction_box.h
|
boxes/star_gift_auction_box.h
|
||||||
boxes/star_gift_box.cpp
|
boxes/star_gift_box.cpp
|
||||||
boxes/star_gift_box.h
|
boxes/star_gift_box.h
|
||||||
|
boxes/star_gift_cover_box.cpp
|
||||||
|
boxes/star_gift_cover_box.h
|
||||||
boxes/star_gift_craft_animation.cpp
|
boxes/star_gift_craft_animation.cpp
|
||||||
boxes/star_gift_craft_animation.h
|
boxes/star_gift_craft_animation.h
|
||||||
boxes/star_gift_craft_box.cpp
|
boxes/star_gift_craft_box.cpp
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "boxes/star_gift_cover_box.h"
|
||||||
#include "data/data_star_gift.h"
|
#include "data/data_star_gift.h"
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
@@ -65,31 +66,6 @@ void ShowStarGiftBox(
|
|||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<PeerData*> peer);
|
not_null<PeerData*> peer);
|
||||||
|
|
||||||
struct UniqueGiftCoverArgs {
|
|
||||||
rpl::producer<QString> pretitle;
|
|
||||||
rpl::producer<TextWithEntities> subtitle;
|
|
||||||
Fn<void()> subtitleClick;
|
|
||||||
bool subtitleLinkColored = false;
|
|
||||||
bool subtitleOutlined = false;
|
|
||||||
rpl::producer<CreditsAmount> resalePrice;
|
|
||||||
Fn<void()> resaleClick;
|
|
||||||
bool attributesInfo = false;
|
|
||||||
Fn<void(
|
|
||||||
std::optional<Data::UniqueGift> now,
|
|
||||||
std::optional<Data::UniqueGift> next,
|
|
||||||
float64 progress)> repaintedHook;
|
|
||||||
std::shared_ptr<Data::GiftUpgradeSpinner> upgradeSpinner;
|
|
||||||
};
|
|
||||||
struct UniqueGiftCover {
|
|
||||||
Data::UniqueGift values;
|
|
||||||
bool spinner = false;
|
|
||||||
bool force = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
void AddUniqueGiftCover(
|
|
||||||
not_null<VerticalLayout*> container,
|
|
||||||
rpl::producer<UniqueGiftCover> data,
|
|
||||||
UniqueGiftCoverArgs &&args);
|
|
||||||
void AddWearGiftCover(
|
void AddWearGiftCover(
|
||||||
not_null<VerticalLayout*> container,
|
not_null<VerticalLayout*> container,
|
||||||
const Data::UniqueGift &data,
|
const Data::UniqueGift &data,
|
||||||
@@ -124,8 +100,6 @@ void ShowOfferBuyBox(
|
|||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
std::shared_ptr<Data::UniqueGift> unique);
|
std::shared_ptr<Data::UniqueGift> unique);
|
||||||
|
|
||||||
void GiftReleasedByHandler(not_null<PeerData*> peer);
|
|
||||||
|
|
||||||
struct StarGiftUpgradeArgs {
|
struct StarGiftUpgradeArgs {
|
||||||
not_null<Window::SessionController*> controller;
|
not_null<Window::SessionController*> controller;
|
||||||
Data::StarGift stargift;
|
Data::StarGift stargift;
|
||||||
@@ -196,4 +170,9 @@ void SendGiftBox(
|
|||||||
const Info::PeerGifts::GiftDescriptor &descriptor,
|
const Info::PeerGifts::GiftDescriptor &descriptor,
|
||||||
rpl::producer<Data::GiftAuctionState> auctionState);
|
rpl::producer<Data::GiftAuctionState> auctionState);
|
||||||
|
|
||||||
|
[[nodiscard]] Data::CreditsHistoryEntry EntryForUpgradedGift(
|
||||||
|
const std::shared_ptr<Data::GiftUpgradeResult> &gift,
|
||||||
|
uint64 nextToUpgradeStickerId = 0,
|
||||||
|
Fn<void()> nextToUpgradeShow = nullptr);
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
#include "data/data_star_gift.h"
|
||||||
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
struct UniqueGift;
|
||||||
|
struct GiftUpgradeSpinner;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class RpWidget;
|
||||||
|
class VerticalLayout;
|
||||||
|
|
||||||
|
struct UniqueGiftCoverArgs {
|
||||||
|
rpl::producer<QString> pretitle;
|
||||||
|
rpl::producer<TextWithEntities> subtitle;
|
||||||
|
Fn<void()> subtitleClick;
|
||||||
|
bool subtitleLinkColored = false;
|
||||||
|
bool subtitleOutlined = false;
|
||||||
|
rpl::producer<CreditsAmount> resalePrice;
|
||||||
|
Fn<void()> resaleClick;
|
||||||
|
bool attributesInfo = false;
|
||||||
|
Fn<void(
|
||||||
|
std::optional<Data::UniqueGift> now,
|
||||||
|
std::optional<Data::UniqueGift> next,
|
||||||
|
float64 progress)> repaintedHook;
|
||||||
|
std::shared_ptr<Data::GiftUpgradeSpinner> upgradeSpinner;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UniqueGiftCover {
|
||||||
|
Data::UniqueGift values;
|
||||||
|
bool spinner = false;
|
||||||
|
bool force = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetupResalePriceButton(
|
||||||
|
not_null<RpWidget*> parent,
|
||||||
|
rpl::producer<QColor> background,
|
||||||
|
rpl::producer<CreditsAmount> price,
|
||||||
|
Fn<void()> click);
|
||||||
|
|
||||||
|
void GiftReleasedByHandler(not_null<PeerData*> peer);
|
||||||
|
|
||||||
|
class UniqueGiftCoverWidget final : public RpWidget {
|
||||||
|
public:
|
||||||
|
UniqueGiftCoverWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
rpl::producer<UniqueGiftCover> data,
|
||||||
|
UniqueGiftCoverArgs &&args);
|
||||||
|
~UniqueGiftCoverWidget();
|
||||||
|
|
||||||
|
struct PaintContext {
|
||||||
|
int width = 0;
|
||||||
|
int patternAreaHeight = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CraftContext {
|
||||||
|
QSize initial;
|
||||||
|
QColor initialBg;
|
||||||
|
float64 fadeInProgress = 0.;
|
||||||
|
float64 expandProgress = 0.;
|
||||||
|
};
|
||||||
|
[[nodiscard]] QRect prepareCraftFrame(
|
||||||
|
QImage &canvas,
|
||||||
|
const CraftContext &context);
|
||||||
|
|
||||||
|
[[nodiscard]] QColor backgroundColor() const;
|
||||||
|
[[nodiscard]] QColor foregroundColor() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BackdropView;
|
||||||
|
struct PatternView;
|
||||||
|
struct ModelView;
|
||||||
|
struct GiftView;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
[[nodiscard]] QImage prepareBackdrop(
|
||||||
|
BackdropView &backdrop,
|
||||||
|
const PaintContext &context);
|
||||||
|
void paintBackdrop(
|
||||||
|
QPainter &p,
|
||||||
|
BackdropView &backdrop,
|
||||||
|
const PaintContext &context);
|
||||||
|
void paintPattern(
|
||||||
|
QPainter &p,
|
||||||
|
PatternView &pattern,
|
||||||
|
const BackdropView &backdrop,
|
||||||
|
const PaintContext &context,
|
||||||
|
float64 shown);
|
||||||
|
bool paintModel(
|
||||||
|
QPainter &p,
|
||||||
|
ModelView &model,
|
||||||
|
const PaintContext &context,
|
||||||
|
float64 scale = 1.,
|
||||||
|
bool paused = false);
|
||||||
|
bool paintGift(
|
||||||
|
QPainter &p,
|
||||||
|
GiftView &gift,
|
||||||
|
const PaintContext &context,
|
||||||
|
float64 shown);
|
||||||
|
|
||||||
|
void paintSpinnerAnimation(QPainter &p, const PaintContext &context);
|
||||||
|
void paintNormalAnimation(
|
||||||
|
QPainter &p,
|
||||||
|
const PaintContext &context,
|
||||||
|
float64 progress);
|
||||||
|
|
||||||
|
struct State;
|
||||||
|
const std::unique_ptr<State> _state;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] object_ptr<UniqueGiftCoverWidget> MakeUniqueGiftCover(
|
||||||
|
QWidget *parent,
|
||||||
|
rpl::producer<UniqueGiftCover> data,
|
||||||
|
UniqueGiftCoverArgs &&args);
|
||||||
|
|
||||||
|
void AddUniqueGiftCover(
|
||||||
|
not_null<VerticalLayout*> container,
|
||||||
|
rpl::producer<UniqueGiftCover> data,
|
||||||
|
UniqueGiftCoverArgs &&args);
|
||||||
|
|
||||||
|
} // namespace Ui
|
||||||
@@ -8,7 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "boxes/star_gift_craft_animation.h"
|
#include "boxes/star_gift_craft_animation.h"
|
||||||
|
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
|
#include "boxes/star_gift_box.h"
|
||||||
|
#include "boxes/star_gift_cover_box.h"
|
||||||
|
#include "chat_helpers/compose/compose_show.h"
|
||||||
#include "chat_helpers/stickers_lottie.h"
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
|
#include "data/data_credits.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
@@ -16,10 +20,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "info/peer_gifts/info_peer_gifts_common.h"
|
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||||
#include "lottie/lottie_common.h"
|
#include "lottie/lottie_common.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "settings/settings_credits_graphics.h"
|
||||||
|
#include "ui/boxes/boost_box.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
|
#include "ui/layers/generic_box.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "ui/top_background_gradient.h"
|
#include "ui/top_background_gradient.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_credits.h"
|
#include "styles/style_credits.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
@@ -38,6 +46,9 @@ constexpr auto kFailurePlayerStopFrame = 120;
|
|||||||
constexpr auto kFailurePlayerFps = 60;
|
constexpr auto kFailurePlayerFps = 60;
|
||||||
constexpr auto kFailurePlayerFadeOutFrames = 10;
|
constexpr auto kFailurePlayerFadeOutFrames = 10;
|
||||||
constexpr auto kFailureScaleDuration = crl::time(200);
|
constexpr auto kFailureScaleDuration = crl::time(200);
|
||||||
|
constexpr auto kSuccessFadeInDuration = crl::time(300);
|
||||||
|
constexpr auto kSuccessExpandDuration = crl::time(400);
|
||||||
|
constexpr auto kSuccessExpandStart = crl::time(100);
|
||||||
|
|
||||||
struct Rotation {
|
struct Rotation {
|
||||||
float64 x = 0.;
|
float64 x = 0.;
|
||||||
@@ -53,6 +64,10 @@ struct Rotation {
|
|||||||
|
|
||||||
using RotationFn = Fn<Rotation(Rotation initial, crl::time t)>;
|
using RotationFn = Fn<Rotation(Rotation initial, crl::time t)>;
|
||||||
|
|
||||||
|
[[nodiscard]] int Slowing() {
|
||||||
|
return anim::SlowMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] RotationFn DecayingRotation(Rotation impulse, float64 decay) {
|
[[nodiscard]] RotationFn DecayingRotation(Rotation impulse, float64 decay) {
|
||||||
const auto lambda = -std::log(decay) / kFrameDuration;
|
const auto lambda = -std::log(decay) / kFrameDuration;
|
||||||
return [=](Rotation initial, crl::time t) {
|
return [=](Rotation initial, crl::time t) {
|
||||||
@@ -284,16 +299,22 @@ const auto kGiftAnimations = std::array<GiftAnimationConfig, 7>{{ {
|
|||||||
|
|
||||||
void PaintCubeFace(
|
void PaintCubeFace(
|
||||||
QPainter &p,
|
QPainter &p,
|
||||||
const QImage &face,
|
|
||||||
const std::array<QPointF, 4> &corners,
|
const std::array<QPointF, 4> &corners,
|
||||||
|
const QImage &face,
|
||||||
|
QSize faceSize = QSize(),
|
||||||
|
const QRect &source = QRect(),
|
||||||
int rotation = 0) {
|
int rotation = 0) {
|
||||||
if (face.isNull()) {
|
if (face.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ratio = style::DevicePixelRatio();
|
const auto ratio = style::DevicePixelRatio();
|
||||||
const auto w = face.width() / ratio;
|
const auto origin = source.isEmpty() ? face.size() : source.size();
|
||||||
const auto h = face.height() / ratio;
|
if (faceSize.isEmpty()) {
|
||||||
|
faceSize = origin / ratio;
|
||||||
|
}
|
||||||
|
const auto w = faceSize.width();
|
||||||
|
const auto h = faceSize.height();
|
||||||
|
|
||||||
const auto srcRect = QPolygonF({
|
const auto srcRect = QPolygonF({
|
||||||
QPointF(0, 0),
|
QPointF(0, 0),
|
||||||
@@ -328,7 +349,12 @@ void PaintCubeFace(
|
|||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
p.save();
|
p.save();
|
||||||
p.setTransform(transform, true);
|
p.setTransform(transform, true);
|
||||||
p.drawImage(QRectF(0, 0, w, h), face);
|
const auto delta = source.isEmpty()
|
||||||
|
? QPointF()
|
||||||
|
: QPointF(
|
||||||
|
((origin.width() / ratio) - faceSize.width()) / 2.,
|
||||||
|
((origin.height() / ratio) - faceSize.height()) / 2.);
|
||||||
|
p.drawImage(QRectF(-delta, QSizeF(origin) / ratio), face, source);
|
||||||
p.restore();
|
p.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,10 +441,10 @@ void PaintCubeFirstFlight(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FailureAnimation> SetupFailureAnimation(
|
std::unique_ptr<CraftFailAnimation> SetupFailureAnimation(
|
||||||
not_null<RpWidget*> canvas,
|
not_null<RpWidget*> canvas,
|
||||||
not_null<CraftAnimationState*> state) {
|
not_null<CraftAnimationState*> state) {
|
||||||
auto result = std::make_unique<FailureAnimation>();
|
auto result = std::make_unique<CraftFailAnimation>();
|
||||||
const auto raw = result.get();
|
const auto raw = result.get();
|
||||||
|
|
||||||
const auto document
|
const auto document
|
||||||
@@ -460,21 +486,22 @@ std::unique_ptr<FailureAnimation> SetupFailureAnimation(
|
|||||||
|
|
||||||
void FailureAnimationCheck(
|
void FailureAnimationCheck(
|
||||||
not_null<CraftAnimationState*> state,
|
not_null<CraftAnimationState*> state,
|
||||||
not_null<RpWidget*> canvas) {
|
not_null<RpWidget*> canvas,
|
||||||
|
crl::time now) {
|
||||||
const auto animation = state->failureAnimation.get();
|
const auto animation = state->failureAnimation.get();
|
||||||
if (!animation) {
|
if (!animation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
const auto elapsed = (now - state->animationStartTime);
|
||||||
const auto elapsed = (crl::now() - state->animationStartTime);
|
const auto failureDuration = (1000 * kFailurePlayerStopFrame)
|
||||||
const auto failureAnimationDuration = (1000 * kFailurePlayerStopFrame)
|
|
||||||
/ kFailurePlayerFps;
|
/ kFailurePlayerFps;
|
||||||
if (!animation->playerStarted
|
const auto playerStartTime = state->animationDuration - failureDuration;
|
||||||
&& elapsed >= config.duration - failureAnimationDuration) {
|
if (!animation->playerStarted && elapsed >= playerStartTime) {
|
||||||
animation->playerStarted = true;
|
animation->playerStarted = true;
|
||||||
}
|
}
|
||||||
if (!animation->scaleStarted
|
const auto playerScaleStart = state->animationDuration
|
||||||
&& elapsed >= config.duration - kFailureScaleDuration) {
|
- kFailureScaleDuration;
|
||||||
|
if (!animation->scaleStarted && elapsed >= playerScaleStart) {
|
||||||
animation->scaleStarted = true;
|
animation->scaleStarted = true;
|
||||||
animation->scaleAnimation.start([=] {
|
animation->scaleAnimation.start([=] {
|
||||||
canvas->update();
|
canvas->update();
|
||||||
@@ -537,6 +564,41 @@ void FailureAnimationCheck(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QRect PrepareCraftFrame(
|
||||||
|
not_null<CraftAnimationState*> state,
|
||||||
|
int faceIndex,
|
||||||
|
crl::time now) {
|
||||||
|
Expects(state->successAnimation != nullptr);
|
||||||
|
|
||||||
|
const auto &shared = state->shared.get();
|
||||||
|
const auto success = state->successAnimation.get();
|
||||||
|
const auto elapsed = now - state->animationStartTime;
|
||||||
|
const auto end = state->animationDuration * Slowing();
|
||||||
|
const auto left = end - elapsed;
|
||||||
|
const auto fadeDuration = kSuccessFadeInDuration * Slowing();
|
||||||
|
const auto fadeInProgress = std::clamp(
|
||||||
|
(1. - (left / float64(fadeDuration))),
|
||||||
|
0.,
|
||||||
|
1.);
|
||||||
|
const auto expandStart = kSuccessExpandStart * Slowing();
|
||||||
|
const auto expanding = kSuccessExpandDuration * Slowing();
|
||||||
|
const auto expandProgress = std::clamp(
|
||||||
|
(expandStart - left) / float64(expanding),
|
||||||
|
0.,
|
||||||
|
1.);
|
||||||
|
if (expandProgress == 1. && !success->finished) {
|
||||||
|
success->finished = true;
|
||||||
|
}
|
||||||
|
const auto expanded = anim::easeOutCubic(1., expandProgress);
|
||||||
|
success->expanded = expanded;
|
||||||
|
return success->widget->prepareCraftFrame(success->frame, {
|
||||||
|
.initial = shared->forgeRect.size(),
|
||||||
|
.initialBg = shared->forgeSides[faceIndex].bg,
|
||||||
|
.fadeInProgress = fadeInProgress,
|
||||||
|
.expandProgress = expanded,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void PaintCube(
|
void PaintCube(
|
||||||
QPainter &p,
|
QPainter &p,
|
||||||
not_null<CraftAnimationState*> state,
|
not_null<CraftAnimationState*> state,
|
||||||
@@ -545,7 +607,8 @@ void PaintCube(
|
|||||||
float64 size) {
|
float64 size) {
|
||||||
const auto shared = state->shared.get();
|
const auto shared = state->shared.get();
|
||||||
|
|
||||||
FailureAnimationCheck(state, canvas);
|
const auto now = crl::now();
|
||||||
|
FailureAnimationCheck(state, canvas, now);
|
||||||
|
|
||||||
const auto totalScale = FailureAnimationScale(state);
|
const auto totalScale = FailureAnimationScale(state);
|
||||||
const auto showCube = (totalScale > 0.);
|
const auto showCube = (totalScale > 0.);
|
||||||
@@ -565,13 +628,12 @@ void PaintCube(
|
|||||||
&& state->currentPhaseIndex >= 0) {
|
&& state->currentPhaseIndex >= 0) {
|
||||||
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
||||||
const auto elapsed = (crl::now() - state->animationStartTime);
|
const auto elapsed = (crl::now() - state->animationStartTime);
|
||||||
if (elapsed >= config.revealTime * anim::SlowMultiplier()) {
|
if (elapsed >= config.revealTime * Slowing()) {
|
||||||
state->nextFaceRevealed = true;
|
state->nextFaceRevealed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto craftFailed = state->craftResult.has_value()
|
const auto craftResult = state->successAnimation.get();
|
||||||
&& !state->craftResult->get();
|
|
||||||
|
|
||||||
auto paintFailure = Fn<void()>();
|
auto paintFailure = Fn<void()>();
|
||||||
for (const auto faceIndex : faces) {
|
for (const auto faceIndex : faces) {
|
||||||
@@ -587,7 +649,9 @@ void PaintCube(
|
|||||||
|
|
||||||
const auto thisFaceRevealed = state->nextFaceRevealed
|
const auto thisFaceRevealed = state->nextFaceRevealed
|
||||||
&& (faceIndex == state->nextFaceIndex);
|
&& (faceIndex == state->nextFaceIndex);
|
||||||
|
auto faceSize = shared->forgeRect.size();
|
||||||
auto faceImage = shared->forgeSides[faceIndex].frame;
|
auto faceImage = shared->forgeSides[faceIndex].frame;
|
||||||
|
auto faceSource = QRect();
|
||||||
auto faceRotation = thisFaceRevealed
|
auto faceRotation = thisFaceRevealed
|
||||||
? state->nextFaceRotation
|
? state->nextFaceRotation
|
||||||
: 0;
|
: 0;
|
||||||
@@ -596,6 +660,7 @@ void PaintCube(
|
|||||||
if (i != state->currentlyFlying
|
if (i != state->currentlyFlying
|
||||||
&& state->giftToSide[i].face == faceIndex
|
&& state->giftToSide[i].face == faceIndex
|
||||||
&& shared->corners[i].giftButton) {
|
&& shared->corners[i].giftButton) {
|
||||||
|
faceSize = QSize(); // Take from the frame.
|
||||||
faceImage = shared->corners[i].gift(1.);
|
faceImage = shared->corners[i].gift(1.);
|
||||||
faceRotation = state->giftToSide[i].rotation;
|
faceRotation = state->giftToSide[i].rotation;
|
||||||
break;
|
break;
|
||||||
@@ -603,7 +668,13 @@ void PaintCube(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (thisFaceRevealed && state->allGiftsLanded) {
|
if (thisFaceRevealed && state->allGiftsLanded) {
|
||||||
if (craftFailed) {
|
const auto coverWidget = craftResult
|
||||||
|
? craftResult->widget
|
||||||
|
: nullptr;
|
||||||
|
if (coverWidget) {
|
||||||
|
faceSource = PrepareCraftFrame(state, faceIndex, now);
|
||||||
|
faceImage = craftResult->frame;
|
||||||
|
} else {
|
||||||
const auto maybeOpacity = FailureAnimationPrepareFrame(
|
const auto maybeOpacity = FailureAnimationPrepareFrame(
|
||||||
state,
|
state,
|
||||||
canvas,
|
canvas,
|
||||||
@@ -616,8 +687,10 @@ void PaintCube(
|
|||||||
}
|
}
|
||||||
PaintCubeFace(
|
PaintCubeFace(
|
||||||
p,
|
p,
|
||||||
state->failureAnimation->frame,
|
|
||||||
*corners,
|
*corners,
|
||||||
|
state->failureAnimation->frame,
|
||||||
|
faceSize,
|
||||||
|
faceSource,
|
||||||
faceRotation);
|
faceRotation);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -626,7 +699,13 @@ void PaintCube(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (showCube) {
|
if (showCube) {
|
||||||
PaintCubeFace(p, faceImage, *corners, faceRotation);
|
PaintCubeFace(
|
||||||
|
p,
|
||||||
|
*corners,
|
||||||
|
faceImage,
|
||||||
|
faceSize,
|
||||||
|
faceSource,
|
||||||
|
faceRotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -784,7 +863,7 @@ void PaintFlyingGiftWithQuad(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto frame = corner.gift(progress);
|
const auto frame = corner.gift(progress);
|
||||||
PaintCubeFace(p, frame, corners, 0);
|
PaintCubeFace(p, corners, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintFlyingGift(
|
void PaintFlyingGift(
|
||||||
@@ -1054,6 +1133,7 @@ void LandCurrentGift(not_null<CraftAnimationState*> state, crl::time now) {
|
|||||||
state->currentPhaseIndex = configIndex;
|
state->currentPhaseIndex = configIndex;
|
||||||
state->currentPhaseFinished = false;
|
state->currentPhaseFinished = false;
|
||||||
state->animationStartTime = now;
|
state->animationStartTime = now;
|
||||||
|
state->animationDuration = config.duration;
|
||||||
state->nextFaceIndex = config.targetFaceIndex;
|
state->nextFaceIndex = config.targetFaceIndex;
|
||||||
state->nextFaceRotation = config.targetFaceRotation;
|
state->nextFaceRotation = config.targetFaceRotation;
|
||||||
state->nextFaceRevealed = false;
|
state->nextFaceRevealed = false;
|
||||||
@@ -1211,7 +1291,7 @@ void CraftState::paint(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CraftState::updateForGiftCount(int count) {
|
void CraftState::updateForGiftCount(int count, Fn<void()> repaint) {
|
||||||
for (auto i = 4; i != 0;) {
|
for (auto i = 4; i != 0;) {
|
||||||
auto &cover = covers[--i];
|
auto &cover = covers[--i];
|
||||||
const auto shown = (i < count);
|
const auto shown = (i < count);
|
||||||
@@ -1219,11 +1299,11 @@ void CraftState::updateForGiftCount(int count) {
|
|||||||
cover.shown = shown;
|
cover.shown = shown;
|
||||||
const auto from = shown ? 0. : 1.;
|
const auto from = shown ? 0. : 1.;
|
||||||
const auto to = shown ? 1. : 0.;
|
const auto to = shown ? 1. : 0.;
|
||||||
cover.shownAnimation.start([this] {
|
cover.shownAnimation.start(
|
||||||
if (repaint) {
|
repaint,
|
||||||
repaint();
|
from,
|
||||||
}
|
to,
|
||||||
}, from, to, st::fadeWrapDuration);
|
st::fadeWrapDuration);
|
||||||
coversAnimate = true;
|
coversAnimate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1256,10 +1336,20 @@ CraftState::EmptySide CraftState::prepareEmptySide(int index) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StartCraftAnimation(
|
void StartCraftAnimation(
|
||||||
not_null<VerticalLayout*> container,
|
not_null<GenericBox*> box,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
std::shared_ptr<CraftState> shared,
|
std::shared_ptr<CraftState> shared,
|
||||||
Fn<void(CraftResultCallback)> startRequest,
|
Fn<void(CraftResultCallback)> startRequest,
|
||||||
Fn<void()> closeOnFail) {
|
Fn<void()> closeParent) {
|
||||||
|
const auto container = box->verticalLayout();
|
||||||
|
const auto closeOnFail = crl::guard(box, [=] {
|
||||||
|
if (const auto onstack = closeParent) {
|
||||||
|
onstack();
|
||||||
|
}
|
||||||
|
box->closeBox();
|
||||||
|
show->showToast("failed");// tr::lng_gift_craft_failed(tr::now));
|
||||||
|
});
|
||||||
|
|
||||||
while (container->count() > 0) {
|
while (container->count() > 0) {
|
||||||
delete container->widgetAt(0);
|
delete container->widgetAt(0);
|
||||||
}
|
}
|
||||||
@@ -1270,8 +1360,10 @@ void StartCraftAnimation(
|
|||||||
const auto height = shared->containerHeight;
|
const auto height = shared->containerHeight;
|
||||||
const auto craftingHeight = shared->craftingBottom - shared->craftingTop;
|
const auto craftingHeight = shared->craftingBottom - shared->craftingTop;
|
||||||
state->shared = std::move(shared);
|
state->shared = std::move(shared);
|
||||||
|
state->shared->craftingStarted = true;
|
||||||
|
|
||||||
raw->resize(container->width(), height);
|
const auto craftingSize = QSize(container->width(), height);
|
||||||
|
raw->resize(craftingSize);
|
||||||
|
|
||||||
for (auto &corner : state->shared->corners) {
|
for (auto &corner : state->shared->corners) {
|
||||||
if (corner.giftButton) {
|
if (corner.giftButton) {
|
||||||
@@ -1290,15 +1382,41 @@ void StartCraftAnimation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto shared = state->shared.get();
|
const auto shared = state->shared.get();
|
||||||
|
const auto success = state->successAnimation.get();
|
||||||
const auto slideProgress = state->slideOutAnimation.value(1.);
|
const auto slideProgress = state->slideOutAnimation.value(1.);
|
||||||
shared->paint(p, raw->size(), craftingHeight, slideProgress);
|
if (slideProgress < 1.) {
|
||||||
|
shared->paint(p, craftingSize, craftingHeight, slideProgress);
|
||||||
|
} else {
|
||||||
|
if (shared->craftBg.isNull()) {
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
shared->craftBg = QImage(
|
||||||
|
craftingSize * ratio,
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
shared->craftBg.setDevicePixelRatio(ratio);
|
||||||
|
shared->craftBg.fill(Qt::transparent);
|
||||||
|
|
||||||
|
auto q = QPainter(&shared->craftBg);
|
||||||
|
shared->paint(q, craftingSize, craftingHeight, 1.);
|
||||||
|
}
|
||||||
|
if (success && success->hiding) {
|
||||||
|
p.setOpacity(1. - success->heightAnimation.value(1.));
|
||||||
|
}
|
||||||
|
p.drawImage(0, 0, shared->craftBg);
|
||||||
|
if (success && success->hiding) {
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shared->craftingOffsetY = (shared->containerHeight / 2.)
|
shared->craftingOffsetY = (shared->containerHeight / 2.)
|
||||||
- shared->craftingAreaCenterY;
|
- shared->craftingAreaCenterY;
|
||||||
if (slideProgress < 1.) {
|
if (slideProgress < 1.) {
|
||||||
shared->craftingOffsetY *= slideProgress;
|
shared->craftingOffsetY *= slideProgress;
|
||||||
PaintSlideOutPhase(p, shared, raw->size(), slideProgress);
|
PaintSlideOutPhase(p, shared, craftingSize, slideProgress);
|
||||||
} else {
|
} else {
|
||||||
|
if (success) {
|
||||||
|
const auto target = success->coverShift;
|
||||||
|
shared->craftingOffsetY -= target * success->expanded;
|
||||||
|
}
|
||||||
const auto cubeSize = float64(shared->forgeRect.width());
|
const auto cubeSize = float64(shared->forgeRect.width());
|
||||||
const auto cubeCenter = QPointF(shared->forgeRect.topLeft())
|
const auto cubeCenter = QPointF(shared->forgeRect.topLeft())
|
||||||
+ QPointF(cubeSize, cubeSize) / 2.
|
+ QPointF(cubeSize, cubeSize) / 2.
|
||||||
@@ -1426,13 +1544,14 @@ void StartCraftAnimation(
|
|||||||
state->continuousAnimation.init([=](crl::time now) {
|
state->continuousAnimation.init([=](crl::time now) {
|
||||||
if (state->currentPhaseIndex >= 0) {
|
if (state->currentPhaseIndex >= 0) {
|
||||||
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
||||||
const auto elapsed = (now - state->animationStartTime)
|
const auto elapsed = state->currentPhaseFinished
|
||||||
/ anim::SlowMultiplier();
|
? (config.duration * Slowing())
|
||||||
|
: (now - state->animationStartTime);
|
||||||
const auto initial = Rotation{
|
const auto initial = Rotation{
|
||||||
state->initialRotationX,
|
state->initialRotationX,
|
||||||
state->initialRotationY,
|
state->initialRotationY,
|
||||||
};
|
};
|
||||||
const auto r = config.rotation(initial, elapsed);
|
const auto r = config.rotation(initial, elapsed / Slowing());
|
||||||
state->rotationX = r.x;
|
state->rotationX = r.x;
|
||||||
state->rotationY = r.y;
|
state->rotationY = r.y;
|
||||||
}
|
}
|
||||||
@@ -1449,42 +1568,67 @@ void StartCraftAnimation(
|
|||||||
&& state->giftsLanded > 0
|
&& state->giftsLanded > 0
|
||||||
&& state->giftsLanded < state->totalGifts
|
&& state->giftsLanded < state->totalGifts
|
||||||
&& state->currentPhaseIndex >= 0) {
|
&& state->currentPhaseIndex >= 0) {
|
||||||
|
const auto elapsed = now - state->animationStartTime;
|
||||||
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
const auto start = state->animationDuration - kFlightDuration;
|
||||||
const auto elapsed = (now - state->animationStartTime)
|
if (elapsed >= start * Slowing()) {
|
||||||
/ anim::SlowMultiplier();
|
|
||||||
const auto flightStartTime = config.duration - kFlightDuration;
|
|
||||||
if (elapsed >= flightStartTime) {
|
|
||||||
StartGiftFlightToFace(state, raw, state->nextFaceIndex);
|
StartGiftFlightToFace(state, raw, state->nextFaceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto success = state->successAnimation.get();
|
||||||
if (!state->currentPhaseFinished
|
if (!state->currentPhaseFinished
|
||||||
&& !state->flightAnimation.animating()
|
&& !state->flightAnimation.animating()
|
||||||
&& state->currentlyFlying < 0
|
&& state->currentlyFlying < 0
|
||||||
&& state->giftsLanded >= state->totalGifts
|
&& state->giftsLanded >= state->totalGifts
|
||||||
&& state->totalGifts > 0
|
&& state->totalGifts > 0
|
||||||
&& state->currentPhaseIndex >= 0) {
|
&& state->currentPhaseIndex >= 0) {
|
||||||
|
const auto elapsed = now - state->animationStartTime;
|
||||||
const auto &config = kGiftAnimations[state->currentPhaseIndex];
|
if (elapsed >= state->animationDuration * Slowing()) {
|
||||||
const auto elapsed = (now - state->animationStartTime)
|
|
||||||
/ anim::SlowMultiplier();
|
|
||||||
if (elapsed >= config.duration) {
|
|
||||||
state->currentPhaseFinished = true;
|
state->currentPhaseFinished = true;
|
||||||
|
if (success) {
|
||||||
|
const auto wasContent = box->height();
|
||||||
|
const auto wasTotal = box->parentWidget()->height();
|
||||||
|
const auto wasButtons = wasTotal - wasContent;
|
||||||
|
|
||||||
|
container->clear();
|
||||||
|
container->add(std::move(success->owned));
|
||||||
|
|
||||||
|
box->setStyle(st::giftBox);
|
||||||
|
|
||||||
|
const auto entry = EntryForUpgradedGift(
|
||||||
|
*state->craftResult);
|
||||||
|
Settings::GenericCreditsEntryBody(box, show, entry);
|
||||||
|
container->resizeToWidth(st::boxWideWidth);
|
||||||
|
|
||||||
|
const auto nowContent = box->height();
|
||||||
|
const auto nowTotal = box->parentWidget()->height();
|
||||||
|
const auto nowButtons = nowTotal - nowContent;
|
||||||
|
|
||||||
|
box->animateHeightFrom(
|
||||||
|
wasContent + wasButtons - nowButtons);
|
||||||
|
success->hiding = true;
|
||||||
|
const auto duration = kSuccessExpandDuration
|
||||||
|
- kSuccessExpandStart;
|
||||||
|
success->heightAnimation.start([=] {
|
||||||
|
const auto height = anim::interpolate(
|
||||||
|
craftingSize.height(),
|
||||||
|
success->coverHeight,
|
||||||
|
success->heightAnimation.value(1.));
|
||||||
|
raw->resize(craftingSize.width(), height);
|
||||||
|
}, 0., 1., duration, anim::easeOutCubic);
|
||||||
|
|
||||||
|
raw->setParent(box->parentWidget());
|
||||||
|
raw->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (success->finished) {
|
||||||
|
state->continuousAnimation.stop();
|
||||||
|
raw->hide();
|
||||||
|
|
||||||
const auto hasMoreFlights = (state->giftsLanded < state->totalGifts);
|
StartFireworks(box->parentWidget());
|
||||||
const auto isFlying = state->flightAnimation.animating();
|
}
|
||||||
const auto isAnimating = !state->currentPhaseFinished;
|
return true;
|
||||||
const auto isLoadingShown = state->loadingShownAnimation.animating();
|
|
||||||
const auto isFailureAnimation = state->failureAnimation != nullptr;
|
|
||||||
|
|
||||||
return hasMoreFlights
|
|
||||||
|| isFlying
|
|
||||||
|| isAnimating
|
|
||||||
|| isLoadingShown
|
|
||||||
|| isFailureAnimation;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
container->add(std::move(canvas));
|
container->add(std::move(canvas));
|
||||||
@@ -1496,6 +1640,27 @@ void StartCraftAnimation(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state->craftResult = std::move(result);
|
state->craftResult = std::move(result);
|
||||||
|
if (const auto result = state->craftResult->get()) {
|
||||||
|
state->successAnimation = std::make_unique<
|
||||||
|
CraftDoneAnimation
|
||||||
|
>(CraftDoneAnimation{
|
||||||
|
.owned = MakeUniqueGiftCover(
|
||||||
|
container,
|
||||||
|
rpl::single(UniqueGiftCover{ *result->info.unique }),
|
||||||
|
{}),
|
||||||
|
});
|
||||||
|
const auto success = state->successAnimation.get();
|
||||||
|
|
||||||
|
const auto raw = success->owned.get();
|
||||||
|
success->widget = raw;
|
||||||
|
raw->hide();
|
||||||
|
raw->resizeToWidth(st::boxWideWidth);
|
||||||
|
SendPendingMoveResizeEvents(raw);
|
||||||
|
|
||||||
|
const auto fullHeight = state->shared->containerHeight;
|
||||||
|
success->coverHeight = raw->height();
|
||||||
|
success->coverShift = (fullHeight - raw->height()) / 2;
|
||||||
|
}
|
||||||
tryStartFlying();
|
tryStartFlying();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/object_ptr.h"
|
||||||
#include "base/unique_qptr.h"
|
#include "base/unique_qptr.h"
|
||||||
#include "data/data_star_gift.h"
|
#include "data/data_star_gift.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
#include "ui/text/text_custom_emoji.h"
|
#include "ui/text/text_custom_emoji.h"
|
||||||
|
|
||||||
|
namespace ChatHelpers {
|
||||||
|
class Show;
|
||||||
|
} // namespace ChatHelpers
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
@@ -27,7 +32,9 @@ class GiftButton;
|
|||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
class GenericBox;
|
||||||
class VerticalLayout;
|
class VerticalLayout;
|
||||||
|
class UniqueGiftCoverWidget;
|
||||||
|
|
||||||
using CraftResultCallback = Fn<void(std::shared_ptr<Data::GiftUpgradeResult>)>;
|
using CraftResultCallback = Fn<void(std::shared_ptr<Data::GiftUpgradeResult>)>;
|
||||||
|
|
||||||
@@ -56,7 +63,8 @@ struct CraftState {
|
|||||||
QColor button1;
|
QColor button1;
|
||||||
QColor button2;
|
QColor button2;
|
||||||
bool coversAnimate = false;
|
bool coversAnimate = false;
|
||||||
Fn<void()> repaint;
|
bool craftingStarted = false;
|
||||||
|
QImage craftBg;
|
||||||
|
|
||||||
QImage topPart;
|
QImage topPart;
|
||||||
QRect topPartRect;
|
QRect topPartRect;
|
||||||
@@ -98,8 +106,12 @@ struct CraftState {
|
|||||||
int craftingAreaCenterY = 0;
|
int craftingAreaCenterY = 0;
|
||||||
int craftingOffsetY = 0;
|
int craftingOffsetY = 0;
|
||||||
|
|
||||||
void paint(QPainter &p, QSize size, int craftingHeight, float64 slideProgress = 0.);
|
void paint(
|
||||||
void updateForGiftCount(int count);
|
QPainter &p,
|
||||||
|
QSize size,
|
||||||
|
int craftingHeight,
|
||||||
|
float64 slideProgress = 0.);
|
||||||
|
void updateForGiftCount(int count, Fn<void()> repaint);
|
||||||
[[nodiscard]] EmptySide prepareEmptySide(int index) const;
|
[[nodiscard]] EmptySide prepareEmptySide(int index) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -108,7 +120,20 @@ struct FacePlacement {
|
|||||||
int rotation = 0;
|
int rotation = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FailureAnimation {
|
struct CraftDoneAnimation {
|
||||||
|
object_ptr<UniqueGiftCoverWidget> owned;
|
||||||
|
UniqueGiftCoverWidget *widget = nullptr;
|
||||||
|
Animations::Simple shownAnimation;
|
||||||
|
Animations::Simple heightAnimation;
|
||||||
|
QImage frame;
|
||||||
|
int coverHeight = 0;
|
||||||
|
int coverShift = 0;
|
||||||
|
float64 expanded = 0.;
|
||||||
|
bool finished = false;
|
||||||
|
bool hiding = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CraftFailAnimation {
|
||||||
std::unique_ptr<HistoryView::StickerPlayer> player;
|
std::unique_ptr<HistoryView::StickerPlayer> player;
|
||||||
QImage frame;
|
QImage frame;
|
||||||
DocumentData *document = nullptr;
|
DocumentData *document = nullptr;
|
||||||
@@ -138,6 +163,7 @@ struct CraftAnimationState {
|
|||||||
|
|
||||||
int currentPhaseIndex = -1;
|
int currentPhaseIndex = -1;
|
||||||
crl::time animationStartTime = 0;
|
crl::time animationStartTime = 0;
|
||||||
|
crl::time animationDuration = 0;
|
||||||
float64 initialRotationX = 0.;
|
float64 initialRotationX = 0.;
|
||||||
float64 initialRotationY = 0.;
|
float64 initialRotationY = 0.;
|
||||||
int nextFaceIndex = 0;
|
int nextFaceIndex = 0;
|
||||||
@@ -152,13 +178,15 @@ struct CraftAnimationState {
|
|||||||
crl::time loadingStartedTime = 0;
|
crl::time loadingStartedTime = 0;
|
||||||
bool loadingFadingOut = false;
|
bool loadingFadingOut = false;
|
||||||
|
|
||||||
std::unique_ptr<FailureAnimation> failureAnimation;
|
std::unique_ptr<CraftDoneAnimation> successAnimation;
|
||||||
|
std::unique_ptr<CraftFailAnimation> failureAnimation;
|
||||||
};
|
};
|
||||||
|
|
||||||
void StartCraftAnimation(
|
void StartCraftAnimation(
|
||||||
not_null<VerticalLayout*> container,
|
not_null<GenericBox*> box,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
std::shared_ptr<CraftState> state,
|
std::shared_ptr<CraftState> state,
|
||||||
Fn<void(CraftResultCallback)> startRequest,
|
Fn<void(CraftResultCallback)> startRequest,
|
||||||
Fn<void()> closeOnFail);
|
Fn<void()> closeParent);
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ AbstractButton *MakeRemoveButton(
|
|||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
rpl::producer<std::vector<GiftForCraft>> chosen,
|
rpl::producer<std::vector<GiftForCraft>> chosen,
|
||||||
rpl::producer<QColor> edgeColor) {
|
rpl::producer<QColor> edgeColor) {
|
||||||
const auto width = st::boxWidth;
|
const auto width = st::boxWideWidth;
|
||||||
|
|
||||||
const auto buttonPadding = st::craftPreviewPadding;
|
const auto buttonPadding = st::craftPreviewPadding;
|
||||||
const auto buttonSize = st::giftBoxGiftTiny;
|
const auto buttonSize = st::giftBoxGiftTiny;
|
||||||
@@ -805,6 +805,7 @@ void ShowSelectGiftBox(
|
|||||||
|
|
||||||
void Craft(
|
void Craft(
|
||||||
not_null<GenericBox*> box,
|
not_null<GenericBox*> box,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
std::shared_ptr<CraftState> state,
|
std::shared_ptr<CraftState> state,
|
||||||
const std::vector<GiftForCraft> &gifts,
|
const std::vector<GiftForCraft> &gifts,
|
||||||
Fn<void()> closeParent) {
|
Fn<void()> closeParent) {
|
||||||
@@ -818,7 +819,7 @@ void Craft(
|
|||||||
base::call_delayed(delay, box, [=] {
|
base::call_delayed(delay, box, [=] {
|
||||||
const auto shouldSucceed = true;// (base::RandomIndex(5) != 0);
|
const auto shouldSucceed = true;// (base::RandomIndex(5) != 0);
|
||||||
const auto count = int(giftsCopy.size());
|
const auto count = int(giftsCopy.size());
|
||||||
if (shouldSucceed && !count) {
|
if (shouldSucceed && count > 0) {
|
||||||
const auto &chosen = giftsCopy[base::RandomIndex(count)];
|
const auto &chosen = giftsCopy[base::RandomIndex(count)];
|
||||||
auto info = Data::StarGift{
|
auto info = Data::StarGift{
|
||||||
.id = chosen.unique->initialGiftId,
|
.id = chosen.unique->initialGiftId,
|
||||||
@@ -836,21 +837,12 @@ void Craft(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto container = box->verticalLayout();
|
|
||||||
const auto show = box->uiShow();
|
|
||||||
const auto closeOnFail = crl::guard(box, [=] {
|
|
||||||
if (const auto onstack = closeParent) {
|
|
||||||
onstack();
|
|
||||||
}
|
|
||||||
box->closeBox();
|
|
||||||
show->showToast(tr::lng_gift_craft_failed(tr::now));
|
|
||||||
});
|
|
||||||
StartCraftAnimation(
|
StartCraftAnimation(
|
||||||
container,
|
box,
|
||||||
|
std::move(show),
|
||||||
std::move(state),
|
std::move(state),
|
||||||
std::move(startRequest),
|
std::move(startRequest),
|
||||||
closeOnFail);
|
closeParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MakeCraftContent(
|
void MakeCraftContent(
|
||||||
@@ -924,10 +916,11 @@ void MakeCraftContent(
|
|||||||
|
|
||||||
const auto raw = box->verticalLayout();
|
const auto raw = box->verticalLayout();
|
||||||
|
|
||||||
state->craftState->repaint = [=] { raw->update(); };
|
|
||||||
state->chosen.value(
|
state->chosen.value(
|
||||||
) | rpl::on_next([=](const std::vector<GiftForCraft> &gifts) {
|
) | rpl::on_next([=](const std::vector<GiftForCraft> &gifts) {
|
||||||
state->craftState->updateForGiftCount(int(gifts.size()));
|
state->craftState->updateForGiftCount(int(gifts.size()), [=] {
|
||||||
|
raw->update();
|
||||||
|
});
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
|
|
||||||
const auto title = state->title = raw->add(
|
const auto title = state->title = raw->add(
|
||||||
@@ -1031,6 +1024,9 @@ void MakeCraftContent(
|
|||||||
|
|
||||||
raw->paintOn([=](QPainter &p) {
|
raw->paintOn([=](QPainter &p) {
|
||||||
const auto &cs = state->craftState;
|
const auto &cs = state->craftState;
|
||||||
|
if (cs->craftingStarted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto wasButton1 = cs->button1;
|
const auto wasButton1 = cs->button1;
|
||||||
const auto wasButton2 = cs->button2;
|
const auto wasButton2 = cs->button2;
|
||||||
cs->paint(p, raw->size(), craftingHeight);
|
cs->paint(p, raw->size(), craftingHeight);
|
||||||
@@ -1101,7 +1097,12 @@ void MakeCraftContent(
|
|||||||
cs->bottomPartY = aboutPos.y();
|
cs->bottomPartY = aboutPos.y();
|
||||||
cs->containerHeight = raw->height();
|
cs->containerHeight = raw->height();
|
||||||
|
|
||||||
Craft(box, state->craftState, state->chosen.current(), closeParent);
|
Craft(
|
||||||
|
box,
|
||||||
|
controller->uiShow(),
|
||||||
|
state->craftState,
|
||||||
|
state->chosen.current(),
|
||||||
|
closeParent);
|
||||||
};
|
};
|
||||||
button->setClickedCallback(startCrafting);
|
button->setClickedCallback(startCrafting);
|
||||||
|
|
||||||
@@ -1137,7 +1138,7 @@ void ShowGiftCraftBoxInternal(
|
|||||||
bool autoStartCraft) {
|
bool autoStartCraft) {
|
||||||
controller->show(Box([=](not_null<GenericBox*> box) {
|
controller->show(Box([=](not_null<GenericBox*> box) {
|
||||||
box->setStyle(st::giftCraftBox);
|
box->setStyle(st::giftCraftBox);
|
||||||
box->setWidth(st::boxWidth);
|
box->setWidth(st::boxWideWidth);
|
||||||
box->setNoContentMargin(true);
|
box->setNoContentMargin(true);
|
||||||
MakeCraftContent(
|
MakeCraftContent(
|
||||||
box,
|
box,
|
||||||
|
|||||||
@@ -1488,6 +1488,13 @@ void GenericCreditsEntryBox(
|
|||||||
GenericCreditsEntryBody(box, show, e, s, nullptr, st);
|
GenericCreditsEntryBody(box, show, e, s, nullptr, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenericCreditsEntryBody(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
const Data::CreditsHistoryEntry &e) {
|
||||||
|
GenericCreditsEntryBody(box, std::move(show), e, {}, nullptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
void GenericCreditsEntryBody(
|
void GenericCreditsEntryBody(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ void GenericCreditsEntryBox(
|
|||||||
const Data::CreditsHistoryEntry &e,
|
const Data::CreditsHistoryEntry &e,
|
||||||
const Data::SubscriptionEntry &s,
|
const Data::SubscriptionEntry &s,
|
||||||
CreditsEntryBoxStyleOverrides st = {});
|
CreditsEntryBoxStyleOverrides st = {});
|
||||||
|
void GenericCreditsEntryBody(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
const Data::CreditsHistoryEntry &e);
|
||||||
void GenericCreditsEntryBody(
|
void GenericCreditsEntryBody(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
|||||||
@@ -604,7 +604,7 @@ craftPattern: IconEmoji {
|
|||||||
padding: margins(0px, 0px, 0px, 0px);
|
padding: margins(0px, 0px, 0px, 0px);
|
||||||
}
|
}
|
||||||
craftAddIcon: icon {{ "settings/plus", windowFgActive }};
|
craftAddIcon: icon {{ "settings/plus", windowFgActive }};
|
||||||
craftPreviewPadding: margins(24px, 12px, 18px, 8px);
|
craftPreviewPadding: margins(24px, 12px, 40px, 8px);
|
||||||
craftForge: icon{{ "chat/filled_forge-48x48", windowFg }};
|
craftForge: icon{{ "chat/filled_forge-48x48", windowFg }};
|
||||||
craftForgePadding: 12px;
|
craftForgePadding: 12px;
|
||||||
craftForgePercent: CraftRadialPercent {
|
craftForgePercent: CraftRadialPercent {
|
||||||
|
|||||||
@@ -1683,9 +1683,9 @@ SessionController::SessionController(
|
|||||||
});
|
});
|
||||||
|
|
||||||
#if _DEBUG // TEST: Auto-open craft box on startup
|
#if _DEBUG // TEST: Auto-open craft box on startup
|
||||||
constexpr auto kGiftsCount = 4;
|
constexpr auto kGiftsCount = 1;
|
||||||
crl::on_main(this, [=] {
|
crl::on_main(this, [=] {
|
||||||
if (rand() % 2 == 0) {
|
if (rand() % 2 < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto user = session->user();
|
const auto user = session->user();
|
||||||
|
|||||||
Reference in New Issue
Block a user