diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 7a254c51a..a3bef4bd3 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -27,6 +27,7 @@ void SetupSwipeHandler( const auto threshold = style::ConvertFloatScale(kThresholdWidth); struct State { base::unique_qptr filter; + Ui::Animations::Simple animationReach; Ui::Animations::Simple animationEnd; SwipeHandlerFinishData finishByTopData; std::optional orientation; @@ -41,6 +42,7 @@ void SetupSwipeHandler( const auto updateRatio = [=](float64 ratio) { update({ .ratio = std::clamp(ratio, 0., 1.), + .reachRatio = state->animationReach.value(0.), .translation = (-std::clamp(ratio, 0., 1.5) * threshold), .msgBareId = state->finishByTopData.msgBareId, .cursorTop = state->cursorTop, @@ -82,6 +84,9 @@ void SetupSwipeHandler( scroll->scrolls() | rpl::start_with_next([=] { processEnd(nullptr); }, state->lifetime); + const auto animationReachCallback = [=] { + updateRatio((state->startAt - state->lastAt).x() / threshold); + }; const auto filter = [=](not_null e) { if (e->type() == QEvent::Leave && state->orientation) { processEnd(nullptr); @@ -124,8 +129,15 @@ void SetupSwipeHandler( const auto ratio = delta.x() / threshold; updateRatio(ratio); constexpr auto kResetReachedOn = 0.95; + constexpr auto kBounceDuration = crl::time(500); if (!state->reached && ratio >= 1.) { state->reached = true; + state->animationReach.stop(); + state->animationReach.start( + animationReachCallback, + 0., + 1., + kBounceDuration); base::Platform::Haptic(); } else if (state->reached && ratio < kResetReachedOn) { diff --git a/Telegram/SourceFiles/history/history_view_swipe_data.h b/Telegram/SourceFiles/history/history_view_swipe_data.h index c42b146b8..a08ef8e2c 100644 --- a/Telegram/SourceFiles/history/history_view_swipe_data.h +++ b/Telegram/SourceFiles/history/history_view_swipe_data.h @@ -11,6 +11,7 @@ namespace HistoryView { struct ChatPaintGestureHorizontalData { float64 ratio = 0.; + float64 reachRatio = 0.; float64 translation = 0.; int64 msgBareId = 0; int cursorTop = 0; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index b5b0dea66..fb6a5175b 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "payments/payments_reaction_process.h" // TryAddingPaidReaction. #include "ui/text/text_options.h" #include "ui/painter.h" +#include "window/themes/window_theme.h" // IsNightMode. #include "window/window_session_controller.h" #include "apiwrap.h" #include "styles/style_chat.h" @@ -1491,18 +1492,31 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.translate(-context.gestureHorizontal.translation, 0); constexpr auto kShiftRatio = 1.5; + constexpr auto kBouncePart = 0.25; + constexpr auto kStrokeWidth = 2.; + constexpr auto kWaveWidth = 10.; + const auto reachRatio = context.gestureHorizontal.reachRatio; const auto size = st::historyFastShareSize; - const auto rect = QRect( + const auto rect = QRectF( width() - (size * kShiftRatio) * context.gestureHorizontal.ratio, g.y() + (g.height() - size) / 2, size, size); const auto center = rect::center(rect); - const auto spanAngle = -context.gestureHorizontal.ratio + const auto spanAngle = context.gestureHorizontal.ratio * arc::kFullLength; - const auto strokeWidth = style::ConvertFloatScale(2.); - auto pen = QPen(context.st->msgServiceBg()); - pen.setWidthF(strokeWidth); + const auto strokeWidth = style::ConvertFloatScale(kStrokeWidth); + + const auto reachScale = std::clamp( + (reachRatio > kBouncePart) + ? (kBouncePart * 2 - reachRatio) + : reachRatio, + 0., + 1.); + auto pen = Window::Theme::IsNightMode() + ? QPen(anim::with_alpha(context.st->msgServiceFg()->c, 0.3)) + : QPen(context.st->msgServiceBg()); + pen.setWidthF(strokeWidth - (1. * (reachScale / kBouncePart))); const auto arcRect = rect - Margins(strokeWidth); p.save(); { @@ -1510,15 +1524,34 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.setPen(Qt::NoPen); p.setBrush(context.st->msgServiceBg()); p.setOpacity(context.gestureHorizontal.ratio); + p.translate(center); + if (reachScale) { + p.scale(-(1. + 1. * reachScale), (1. + 1. * reachScale)); + } else { + p.scale(-1., 1.); + } + p.translate(-center); + // All the next draws are mirrored. p.drawEllipse(rect); + context.st->historyFastShareIcon().paintInCenter( + p, + QRect( + base::SafeRound(rect.x()), + base::SafeRound(rect.y()), + base::SafeRound(rect.width()), + base::SafeRound(rect.height()))); p.setPen(pen); p.setBrush(Qt::NoBrush); p.drawArc(arcRect, arc::kQuarterLength, spanAngle); - p.drawArc(arcRect, arc::kQuarterLength, spanAngle); - p.translate(center); - p.scale(-1., 1.); - p.translate(-center); - context.st->historyFastShareIcon().paintInCenter(p, rect); + // p.drawArc(arcRect, arc::kQuarterLength, spanAngle); + if (reachRatio) { + const auto w = style::ConvertFloatScale(kWaveWidth); + p.setOpacity(context.gestureHorizontal.ratio - reachRatio); + p.drawArc( + arcRect + Margins(reachRatio * reachRatio * w), + arc::kQuarterLength, + spanAngle); + } } p.restore(); }