diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 086802bfaf..b6dddb9802 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1342,7 +1342,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_broadcast_silent_ph" = "Silent broadcast..."; "lng_send_anonymous_ph" = "Send anonymously..."; "lng_record_cancel" = "Release outside this field to cancel"; -"lng_record_lock_cancel" = "Click outside of microphone button to cancel"; +"lng_record_lock_cancel" = "Click outside of circle to cancel"; "lng_record_lock_cancel_sure" = "Are you sure you want to stop recording and discard your voice message?"; "lng_record_lock_discard" = "Discard"; "lng_will_be_notified" = "Members will be notified when you post"; 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 186a09c9ed..d16acb2d06 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 @@ -1074,6 +1074,7 @@ void VoiceRecordBar::init() { _lock->locks( ) | rpl::start_with_next([=] { installClickOutsideFilter(); + _level->setType(VoiceRecordButton::Type::Send); _level->clicks( ) | rpl::start_with_next([=] { @@ -1102,7 +1103,8 @@ void VoiceRecordBar::init() { TextParseOptions{ TextParseMultiline, 0, 0, direction }); updateMessageGeometry(); - update(_messageRect); + // Update a whole widget to clear a previous text. + update(); }, lifetime()); _send->events( diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.cpp index 64ef1e235e..a8bcc70361 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.cpp @@ -213,8 +213,6 @@ private: void initEnterIdleAnimation(rpl::producer animationTicked); void initFlingAnimation(rpl::producer animationTicked); - Ui::Animations::Simple _flingAnimation; - const std::unique_ptr _circleBezier; const float _rotationOffset; @@ -652,6 +650,10 @@ void VoiceRecordButton::requestPaintLevel(quint16 level) { void VoiceRecordButton::init() { const auto hasProgress = [](auto value) { return value != 0.; }; + const auto stateChangedAnimation = + lifetime().make_state(); + const auto currentState = lifetime().make_state(_state.current()); + paintRequest( ) | rpl::start_with_next([=](const QRect &clip) { Painter p(this); @@ -674,8 +676,29 @@ void VoiceRecordButton::init() { if (!complete) { p.setOpacity(progress); } - st::historyRecordVoiceActive.paintInCenter(p, rect()); + // Paint icon. + { + const auto stateProgress = stateChangedAnimation->value(0.); + const auto scale = (std::cos(M_PI * 2 * stateProgress) + 1.) * .5; + p.translate(_center, _center); + if (scale < 1.) { + p.scale(scale, scale); + } + const auto state = *currentState; + const auto icon = (state == Type::Send) + ? st::historySendIcon + : st::historyRecordVoiceActive; + const auto position = (state == Type::Send) + ? st::historyRecordSendIconPosition + : QPoint(0, 0); + icon.paint( + p, + -icon.width() / 2 + position.x(), + -icon.height() / 2 + position.y(), + 0, + st::historyRecordVoiceFgActiveIcon->c); + } }, lifetime()); rpl::merge( @@ -689,6 +712,7 @@ void VoiceRecordButton::init() { _recordingAnimation.stop(); _showProgress = 0.; _recordCircle->reset(); + _state = Type::Record; } else { if (!_recordingAnimation.animating()) { _recordingAnimation.start(); @@ -701,6 +725,19 @@ void VoiceRecordButton::init() { ) | rpl::start_with_next([=](bool active) { setPointerCursor(active); }, lifetime()); + + _state.changes( + ) | rpl::start_with_next([=](Type newState) { + const auto to = 1.; + auto callback = [=](float64 value) { + if (value >= (to * .5)) { + *currentState = newState; + } + update(); + }; + const auto duration = st::historyRecordVoiceDuration * 2; + stateChangedAnimation->start(std::move(callback), 0., to, duration); + }, lifetime()); } rpl::producer VoiceRecordButton::actives() const { @@ -745,4 +782,8 @@ void VoiceRecordButton::requestPaintColor(float64 progress) { update(); } +void VoiceRecordButton::setType(Type state) { + _state = state; +} + } // namespace HistoryView::Controls diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.h b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.h index 27d0068eba..beb96d0d47 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_button.h @@ -22,6 +22,13 @@ public: rpl::producer<> leaveWindowEventProducer); ~VoiceRecordButton(); + enum class Type { + Send, + Record, + }; + + void setType(Type state); + void requestPaintColor(float64 progress); void requestPaintProgress(float64 progress); void requestPaintLevel(quint16 level); @@ -41,6 +48,7 @@ private: rpl::variable _showProgress = 0.; rpl::variable _colorProgress = 0.; rpl::variable _inCircle = false; + rpl::variable _state = Type::Record; // This can animate for a very long time (like in music playing), // so it should be a Basic, not a Simple animation. diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index efdd96ce66..f7ca7a9724 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -336,6 +336,7 @@ historyRecordVoiceDuration: 120; historyRecordVoice: icon {{ "send_control_record", historyRecordVoiceFg }}; historyRecordVoiceOver: icon {{ "send_control_record", historyRecordVoiceFgOver }}; historyRecordVoiceActive: icon {{ "send_control_record_active", historyRecordVoiceFgActiveIcon }}; +historyRecordSendIconPosition: point(2px, 0px); historyRecordVoiceRippleBgActive: lightButtonBgOver; historyRecordSignalRadius: 5px; historyRecordCancel: windowSubTextFg;