diff --git a/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp b/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp index 4efc961e92..32d28dbcd4 100644 --- a/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp @@ -85,18 +85,19 @@ using RotationFn = Fn; struct GiftAnimationConfig { RotationFn rotation; crl::time duration = 0; + crl::time revealTime = 0; int nextFaceIndex = 0; int nextFaceRotation = 0; }; const auto kGiftAnimations = std::array{{ - { DecayingRotationFinal({ 4.1, -8.2 }, 0.98, { 1, -2 }, 2200), 2200, 1, 180 }, - { DecayingRotation({ 3.2, -5.9 }, 0.97), 1200, 4, 180 }, - { DecayingRotationFinal({ 6.2, 7.8 }, 0.98, { 2, 1 }, 2200), 2200, 1, 0 }, - { DecayingRotation({ 7.0, 4.5 }, 0.97), 1200, 5, 0 }, - { DecayingRotationFinal({ -6.5, 5.0 }, 0.98, { 0, 1 }, 2200), 2200, 1, 0 }, - { DecayingRotation({ -2.5, 3.5 }, 0.98), 1200, 2, 180 }, - { DecayingRotationFinal({ -4.4, -8.2 }, 0.98, { 0, -1.5 }, 2200), 2200, 3, 0 }, + { DecayingRotationFinal({ 4.1, -8.2 }, 0.98, { 1, -2 }, 2200), 2200, 600, 1, 180 }, + { DecayingRotation({ 3.2, -5.9 }, 0.97), 1200, 0, 4, 180 }, + { DecayingRotationFinal({ 6.2, 7.8 }, 0.98, { 2, 1 }, 2200), 2200, 1000, 1, 0 }, + { DecayingRotation({ 7.0, 4.5 }, 0.97), 1200, 200, 5, 0 }, + { DecayingRotationFinal({ -6.5, 5.0 }, 0.98, { 0, 1 }, 2200), 2200, 800, 1, 0 }, + { DecayingRotation({ -2.5, 3.5 }, 0.98), 1200, 200, 2, 180 }, + { DecayingRotationFinal({ -4.4, -8.2 }, 0.98, { 0, -1.5 }, 2200), 2200, 600, 3, 0 }, }}; [[nodiscard]] int GetFrontFaceAtRotation(float64 rotationX, float64 rotationY) { @@ -465,10 +466,13 @@ void PaintCube( const auto faces = GetVisibleCubeFaces(animState->rotationX, animState->rotationY); - if (!animState->nextFaceRotationApplied - && animState->nextFaceRotation != 0 - && !ranges::contains(faces, animState->nextFaceIndex)) { - animState->nextFaceRotationApplied = true; + if (!animState->nextFaceRevealed + && animState->currentConfigIndex >= 0) { + const auto &config = kGiftAnimations[animState->currentConfigIndex]; + const auto elapsed = (crl::now() - animState->animationStartTime); + if (elapsed >= config.revealTime * anim::SlowMultiplier()) { + animState->nextFaceRevealed = true; + } } for (const auto faceIndex : faces) { @@ -482,9 +486,10 @@ void PaintCube( continue; } - auto faceImage = shared->forgeImages[faceIndex]; - auto faceRotation = (animState->nextFaceRotationApplied - && faceIndex == animState->nextFaceIndex) + const auto thisFaceRevealed = animState->nextFaceRevealed + && (faceIndex == animState->nextFaceIndex); + auto faceImage = shared->forgeSides[faceIndex].frame; + auto faceRotation = thisFaceRevealed ? animState->nextFaceRotation : 0; @@ -498,10 +503,28 @@ void PaintCube( } } - if (!faceImage.isNull()) { - PaintCubeFace(p, faceImage, *corners, faceRotation); + if (thisFaceRevealed && animState->allGiftsLanded) { + if (shared->finalSide.frame.isNull()) { + shared->finalSide = shared->forgeSides[faceIndex]; + shared->finalSide.frame.fill(shared->finalSide.bg); + + auto p = QPainter(&shared->finalSide.frame); + const auto side = shared->finalSide.frame.width() / 6; + p.setPen(Qt::NoPen); + p.setBrush(Qt::red); + p.drawEllipse(side, side, side, side); + } + faceImage = shared->finalSide.frame; } + + PaintCubeFace(p, faceImage, *corners, faceRotation); } + + const auto elapsed = (crl::now() - animState->animationStartTime) + / anim::SlowMultiplier(); + p.setPen(Qt::white); + p.setFont(st::semiboldFont); + p.drawText(0, st::semiboldFont->ascent, QString::number(elapsed, 'f', 2)); } struct GiftFlightPosition { @@ -887,7 +910,9 @@ void LandCurrentGift(CraftAnimationState *animState, crl::time now) { } const auto giftNumber = ++animState->giftsLanded; - const auto isLastGift = (giftNumber >= animState->totalGifts); + const auto isLastGift + = animState->allGiftsLanded + = (giftNumber >= animState->totalGifts); const auto configIndex = (giftNumber - 1) * 2 + (isLastGift ? 0 : 1); Assert(configIndex < 7); @@ -902,7 +927,7 @@ void LandCurrentGift(CraftAnimationState *animState, crl::time now) { animState->animationStartTime = now; animState->nextFaceIndex = config.nextFaceIndex; animState->nextFaceRotation = config.nextFaceRotation; - animState->nextFaceRotationApplied = false; + animState->nextFaceRevealed = false; } void PaintLoadingAnimation(QPainter &p, CraftAnimationState *animState) { @@ -1065,13 +1090,14 @@ void CraftState::updateForGiftCount(int count) { } } -QImage CraftState::prepareForgeImage(int index) const { +CraftState::EmptySide CraftState::prepareEmptySide(int index) const { const auto size = forgeRect.size(); const auto ratio = style::DevicePixelRatio(); auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); - result.fill(anim::color(forgeBg1, forgeBg2, index / 5.)); + const auto bg = anim::color(forgeBg1, forgeBg2, index / 5.); + result.fill(bg); auto p = QPainter(&result); st::craftForge.paintInCenter(p, QRect(QPoint(), size), st::white->c); @@ -1087,7 +1113,7 @@ QImage CraftState::prepareForgeImage(int index) const { p.end(); - return result; + return { .bg = bg, .frame = result }; } void StartCraftAnimation( diff --git a/Telegram/SourceFiles/boxes/star_gift_craft_animation.h b/Telegram/SourceFiles/boxes/star_gift_craft_animation.h index 54bf293229..4aab84a72b 100644 --- a/Telegram/SourceFiles/boxes/star_gift_craft_animation.h +++ b/Telegram/SourceFiles/boxes/star_gift_craft_animation.h @@ -77,7 +77,12 @@ struct CraftState { QColor forgeBg2; QImage forgePercent; - std::array forgeImages; + struct EmptySide { + QColor bg; + QImage frame; + }; + std::array forgeSides; + EmptySide finalSide; int containerHeight = 0; int craftingTop = 0; @@ -87,7 +92,7 @@ struct CraftState { void paint(QPainter &p, QSize size, int craftingHeight, float64 slideProgress = 0.); void updateForGiftCount(int count); - [[nodiscard]] QImage prepareForgeImage(int index) const; + [[nodiscard]] EmptySide prepareEmptySide(int index) const; }; @@ -109,6 +114,7 @@ struct CraftAnimationState { int currentlyFlying = -1; int giftsLanded = 0; int totalGifts = 0; + bool allGiftsLanded = false; std::array giftToSide; Animations::Simple flightAnimation; @@ -118,7 +124,7 @@ struct CraftAnimationState { float64 initialRotationY = 0.; int nextFaceIndex = 0; int nextFaceRotation = 0; - bool nextFaceRotationApplied = false; + bool nextFaceRevealed = false; std::optional> flightTargetCorners; diff --git a/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp b/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp index 0a2774abc4..78d1c8d7b4 100644 --- a/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp @@ -505,7 +505,7 @@ AbstractButton *MakeRemoveButton( QColor(overlayBg.red(), overlayBg.green(), overlayBg.blue()), overlayBg.alphaF()); for (auto i = 0; i != 6; ++i) { - craftState->forgeImages[i] = craftState->prepareForgeImage(i); + craftState->forgeSides[i] = craftState->prepareEmptySide(i); } }; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index ce2bc1614f..bdf47943ef 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1685,6 +1685,7 @@ SessionController::SessionController( #if _DEBUG // TEST: Auto-open craft box on startup constexpr auto kGiftsCount = 4; crl::on_main(this, [=] { + return; const auto user = session->user(); session->api().request(MTPpayments_GetSavedStarGifts( MTP_flags(MTPpayments_GetSavedStarGifts::Flag::f_exclude_unlimited),