From cab22c07a5c6a33db8e61c8ed68f1f67ca891d38 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 11 Oct 2020 14:39:43 +0300 Subject: [PATCH] Replaced recording animation with simple red circle animation. --- .../history_view_voice_record_bar.cpp | 71 +++++++++---------- .../controls/history_view_voice_record_bar.h | 10 ++- Telegram/SourceFiles/ui/chat/chat.style | 3 +- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index 0cc7349556..5724baf44a 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -405,10 +405,7 @@ VoiceRecordBar::VoiceRecordBar( , _level(std::make_unique( parent, _controller->widget()->leaveEvents())) -, _cancelFont(st::historyRecordFont) -, _recordingAnimation([=](crl::time now) { - return recordingAnimationCallback(now); -}) { +, _cancelFont(st::historyRecordFont) { resize(QSize(parent->width(), recorderHeight)); init(); } @@ -470,8 +467,8 @@ void VoiceRecordBar::init() { ) | rpl::start_with_next([=](QSize size) { _centerY = size.height() / 2; { - const auto maxD = st::historyRecordSignalMax * 2; - const auto point = _centerY - st::historyRecordSignalMax; + const auto maxD = st::historyRecordSignalRadius * 2; + const auto point = _centerY - st::historyRecordSignalRadius; _redCircleRect = { point, point, maxD, maxD }; } { @@ -494,7 +491,7 @@ void VoiceRecordBar::init() { ) | rpl::start_with_next([=](const QRect &clip) { Painter p(this); if (_showAnimation.animating()) { - p.setOpacity(_showAnimation.value(1.)); + p.setOpacity(showAnimationRatio()); } p.fillRect(clip, st::historyComposeAreaBg); @@ -502,12 +499,13 @@ void VoiceRecordBar::init() { // The message should be painted first to avoid flickering. drawMessage(p, activeAnimationRatio()); } - if (clip.intersects(_redCircleRect)) { - drawRecording(p); - } if (clip.intersects(_durationRect)) { drawDuration(p); } + if (clip.intersects(_redCircleRect)) { + // Should be the last to be drawn. + drawRedCircle(p); + } }, lifetime()); _inField.changes( @@ -635,6 +633,7 @@ void VoiceRecordBar::startRecording() { // Show the lock widget after the first successful update. *shown = true; _lockShowing = true; + startRedCircleAnimation(); } recordUpdated(update.level, update.samples); }, [=] { @@ -673,26 +672,8 @@ void VoiceRecordBar::startRecording() { }, _recordingLifetime); } -bool VoiceRecordBar::recordingAnimationCallback(crl::time now) { - const auto dt = anim::Disabled() - ? 1. - : ((now - _recordingAnimation.started()) - / float64(kRecordingUpdateDelta)); - if (dt >= 1.) { - _recordingLevel.finish(); - } else { - _recordingLevel.update(dt, anim::linear); - } - if (!anim::Disabled()) { - update(_redCircleRect); - } - return (dt < 1.); -} - void VoiceRecordBar::recordUpdated(quint16 level, int samples) { _level->requestPaintLevel(level); - _recordingLevel.start(level); - _recordingAnimation.start(); _recordingSamples = samples; if (samples < 0 || samples >= kMaxSamples) { stop(samples > 0 && _inField.current()); @@ -711,8 +692,7 @@ void VoiceRecordBar::stop(bool send) { stopRecording(send); - _recordingLevel = anim::value(); - _recordingAnimation.stop(); + _redCircleProgress = 0.; _inField = false; @@ -754,17 +734,31 @@ void VoiceRecordBar::drawDuration(Painter &p) { p.drawText(_durationRect, style::al_left, duration); } -void VoiceRecordBar::drawRecording(Painter &p) { +void VoiceRecordBar::startRedCircleAnimation() { + if (anim::Disabled()) { + return; + } + const auto animation = _recordingLifetime + .make_state(); + animation->init([=](crl::time now) { + const auto diffTime = now - animation->started(); + _redCircleProgress = std::abs(std::sin(diffTime / 400.)); + update(_redCircleRect); + return true; + }); + animation->start(); +} + +void VoiceRecordBar::drawRedCircle(Painter &p) { PainterHighQualityEnabler hq(p); p.setPen(Qt::NoPen); p.setBrush(st::historyRecordSignalColor); - const auto min = st::historyRecordSignalMin; - const auto max = st::historyRecordSignalMax; - const auto delta = std::min(_recordingLevel.current() / 0x4000, 1.); - const auto radii = qRound(min + (delta * (max - min))); + p.setOpacity(1. - _redCircleProgress); + const int radii = st::historyRecordSignalRadius * showAnimationRatio(); const auto center = _redCircleRect.center() + QPoint(1, 1); p.drawEllipse(center, radii, radii); + p.setOpacity(1.); } void VoiceRecordBar::drawMessage(Painter &p, float64 recordActive) { @@ -795,7 +789,6 @@ bool VoiceRecordBar::isRecording() const { } void VoiceRecordBar::finishAnimating() { - _recordingAnimation.stop(); _showAnimation.stop(); } @@ -829,6 +822,12 @@ float64 VoiceRecordBar::activeAnimationRatio() const { return _activeAnimation.value(_inField.current() ? 1. : 0.); } +float64 VoiceRecordBar::showAnimationRatio() const { + // There is no reason to set the final value to zero, + // because at zero this widget is hidden. + return _showAnimation.value(1.); +} + QString VoiceRecordBar::cancelMessage() const { return _lock->isLocked() ? tr::lng_record_lock_cancel(tr::now) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h index 79f08ac60f..e9d4d67ced 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h @@ -70,15 +70,17 @@ private: bool showRecordButton() const; void drawDuration(Painter &p); - void drawRecording(Painter &p); + void drawRedCircle(Painter &p); void drawMessage(Painter &p, float64 recordActive); void updateOverStates(QPoint pos); + void startRedCircleAnimation(); void installClickOutsideFilter(); bool isTypeRecord() const; void activeAnimate(bool active); + float64 showAnimationRatio() const; float64 activeAnimationRatio() const; void computeAndSetLockProgress(QPoint globalPos); @@ -105,6 +107,7 @@ private: rpl::variable _recording = false; rpl::variable _inField = false; int _recordingSamples = 0; + float64 _redCircleProgress = 0.; const style::font &_cancelFont; @@ -113,13 +116,8 @@ private: rpl::variable _lockShowing = false; Ui::Animations::Simple _showLockAnimation; - - // This can animate for a very long time (like in music playing), - // so it should be a Basic, not a Simple animation. - Ui::Animations::Basic _recordingAnimation; Ui::Animations::Simple _activeAnimation; Ui::Animations::Simple _showAnimation; - anim::value _recordingLevel; }; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 743831fb11..f37fead111 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -337,8 +337,7 @@ historyRecordVoiceCancel: icon {{ "send_control_record_active", attentionButtonF historyRecordVoiceRippleBgActive: lightButtonBgOver; historyRecordVoiceRippleBgCancel: attentionButtonBgRipple; historyRecordSignalColor: attentionButtonFg; -historyRecordSignalMin: 5px; -historyRecordSignalMax: 12px; +historyRecordSignalRadius: 5px; historyRecordCancel: windowSubTextFg; historyRecordCancelActive: windowActiveTextFg; historyRecordFont: font(13px);