diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 1ad11462f1..f02f1eb310 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -730,6 +730,8 @@ void HistoryWidget::initVoiceRecordBar() { return _replyToId || (_nonEmptySelection && _list); }); + _voiceRecordBar->setSendButtonGeometryValue(_send->geometryValue()); + _voiceRecordBar->startRecordingRequests( ) | rpl::start_with_next([=] { const auto error = _peer diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 21c8e5e935..69b8f1fe0c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -494,7 +494,7 @@ MessageToEdit FieldHeader::queryToEdit() { } ComposeControls::ComposeControls( - not_null parent, + not_null parent, not_null window, Mode mode) : _parent(parent) @@ -520,6 +520,7 @@ ComposeControls::ComposeControls( &_window->session().data())) , _voiceRecordBar(std::make_unique( _wrap.get(), + parent, window, _send, st::historySendSize.height())) @@ -671,6 +672,7 @@ void ComposeControls::showFinished() { _tabbedPanel->hideFast(); } updateWrappingVisibility(); + _voiceRecordBar->orderControls(); } void ComposeControls::showForGrab() { @@ -928,6 +930,30 @@ void ComposeControls::initVoiceRecordBar() { } _voiceRecordBar->startRecording(); }, _wrap->lifetime()); + + { + auto geometry = rpl::merge( + _wrap->geometryValue(), + _send->geometryValue() + ) | rpl::map([=](QRect geometry) { + auto r = _send->geometry(); + r.setY(r.y() + _wrap->y()); + return r; + }); + _voiceRecordBar->setSendButtonGeometryValue(std::move(geometry)); + } + + { + auto bottom = _wrap->geometryValue( + ) | rpl::map([=](QRect geometry) { + return geometry.y() - st::historyRecordLockPosition.y(); + }); + _voiceRecordBar->setLockBottom(std::move(bottom)); + } + + _voiceRecordBar->setEscFilter([=] { + return (isEditingMessage() || replyingToMessage()); + }); } void ComposeControls::updateWrappingVisibility() { @@ -1311,4 +1337,12 @@ FullMsgId ComposeControls::replyingToMessage() const { return _header->replyingToMessage(); } +bool ComposeControls::isLockPresent() const { + return _voiceRecordBar->isLockPresent(); +} + +rpl::producer ComposeControls::lockShowStarts() const { + return _voiceRecordBar->lockShowStarts(); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index 3d642ab5d8..5df22827dd 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -78,7 +78,7 @@ public: }; ComposeControls( - not_null parent, + not_null parent, not_null window, Mode mode); ~ComposeControls(); @@ -135,6 +135,9 @@ public: void clear(); void hidePanelsAnimated(); + [[nodiscard]] rpl::producer lockShowStarts() const; + [[nodiscard]] bool isLockPresent() const; + private: enum class TextUpdateEvent { //SaveDraft = (1 << 0), 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 d87e563fb1..78b769c3eb 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 @@ -156,8 +156,15 @@ bool RecordLevel::recordingAnimationCallback(crl::time now) { } void RecordLevel::init() { + const auto hasProgress = [](auto value) { return value != 0.; }; + + // Do not allow the widget to be shown from the outside. shownValue( ) | rpl::start_with_next([=](bool shown) { + const auto shouldShown = hasProgress(_showProgress.current()); + if (shown != shouldShown) { + setVisible(shouldShown); + } }, lifetime()); paintRequest( @@ -170,9 +177,7 @@ void RecordLevel::init() { }, lifetime()); _showProgress.changes( - ) | rpl::map([](auto value) { - return value != 0.; - }) | rpl::distinct_until_changed( + ) | rpl::map(hasProgress) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](bool show) { setVisible(show); setMouseTracking(show); @@ -395,21 +400,31 @@ rpl::producer<> RecordLock::locks() const { VoiceRecordBar::VoiceRecordBar( not_null parent, + not_null sectionWidget, not_null controller, std::shared_ptr send, int recorderHeight) : RpWidget(parent) +, _sectionWidget(sectionWidget) , _controller(controller) , _send(send) -, _lock(std::make_unique(parent)) +, _lock(std::make_unique(sectionWidget)) , _level(std::make_unique( - parent, + sectionWidget, _controller->widget()->leaveEvents())) , _cancelFont(st::historyRecordFont) { resize(QSize(parent->width(), recorderHeight)); init(); } +VoiceRecordBar::VoiceRecordBar( + not_null parent, + not_null controller, + std::shared_ptr send, + int recorderHeight) +: VoiceRecordBar(parent, parent, controller, send, recorderHeight) { +} + VoiceRecordBar::~VoiceRecordBar() { if (isRecording()) { stopRecording(false); @@ -444,11 +459,6 @@ void VoiceRecordBar::updateLockGeometry() { _lock->moveToRight(right, _lock->y()); } -void VoiceRecordBar::updateLevelGeometry() { - const auto center = (_send->width() - _level->width()) / 2; - _level->moveToRight(st::historySendRight + center, y() + center); -} - void VoiceRecordBar::init() { hide(); // Keep VoiceRecordBar behind SendButton. @@ -459,8 +469,7 @@ void VoiceRecordBar::init() { return e->type() == QEvent::ZOrderChange; }) | rpl::to_empty ) | rpl::start_with_next([=] { - stackUnder(_send.get()); - _level->raise(); + orderControls(); }, lifetime()); sizeValue( @@ -484,7 +493,6 @@ void VoiceRecordBar::init() { } updateMessageGeometry(); updateLockGeometry(); - updateLevelGeometry(); }, lifetime()); paintRequest( @@ -606,7 +614,16 @@ void VoiceRecordBar::setLockBottom(rpl::producer &&bottom) { bottom ) | rpl::start_with_next([=](int value) { _lock->moveToLeft(_lock->x(), value - _lock->height()); - updateLevelGeometry(); + }, lifetime()); +} + +void VoiceRecordBar::setSendButtonGeometryValue( + rpl::producer &&geometry) { + std::move( + geometry + ) | rpl::start_with_next([=](QRect r) { + const auto center = (r.width() - _level->width()) / 2; + _level->moveToLeft(r.x() + center, r.y() + center); }, lifetime()); } @@ -660,7 +677,7 @@ void VoiceRecordBar::startRecording() { ? inField : _level->inCircle(_level->mapFromGlobal(globalPos)); - if (_showLockAnimation.animating()) { + if (_showLockAnimation.animating() || !hasDuration()) { return; } computeAndSetLockProgress(mouse->globalPos()); @@ -813,6 +830,10 @@ bool VoiceRecordBar::isTypeRecord() const { return (_send->type() == Ui::SendButton::Type::Record); } +bool VoiceRecordBar::hasDuration() const { + return _recordingSamples > 0; +} + float64 VoiceRecordBar::activeAnimationRatio() const { return _activeAnimation.value(_inField.current() ? 1. : 0.); } @@ -837,6 +858,12 @@ void VoiceRecordBar::computeAndSetLockProgress(QPoint globalPos) { _lock->requestPaintProgress(std::clamp(progress, 0., 1.)); } +void VoiceRecordBar::orderControls() { + stackUnder(_send.get()); + _level->raise(); + _lock->raise(); +} + void VoiceRecordBar::installClickOutsideFilter() { const auto box = _recordingLifetime.make_state>(); const auto showBox = [=] { 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 e9d4d67ced..bd1b953560 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 @@ -30,6 +30,12 @@ public: using SendActionUpdate = Controls::SendActionUpdate; using VoiceToSend = Controls::VoiceToSend; + VoiceRecordBar( + not_null parent, + not_null sectionWidget, + not_null controller, + std::shared_ptr send, + int recorderHeight); VoiceRecordBar( not_null parent, not_null controller, @@ -40,6 +46,8 @@ public: void startRecording(); void finishAnimating(); + void orderControls(); + [[nodiscard]] rpl::producer sendActionUpdates() const; [[nodiscard]] rpl::producer sendVoiceRequests() const; [[nodiscard]] rpl::producer recordingStateChanges() const; @@ -47,6 +55,7 @@ public: [[nodiscard]] rpl::producer lockShowStarts() const; void setLockBottom(rpl::producer &&bottom); + void setSendButtonGeometryValue(rpl::producer &&geometry); void setEscFilter(Fn &&callback); [[nodiscard]] bool isRecording() const; @@ -57,7 +66,6 @@ private: void updateMessageGeometry(); void updateLockGeometry(); - void updateLevelGeometry(); void recordError(); void recordUpdated(quint16 level, int samples); @@ -78,6 +86,7 @@ private: void installClickOutsideFilter(); bool isTypeRecord() const; + bool hasDuration() const; void activeAnimate(bool active); float64 showAnimationRatio() const; @@ -87,6 +96,7 @@ private: QString cancelMessage() const; + const not_null _sectionWidget; const not_null _controller; const std::shared_ptr _send; const std::unique_ptr _lock; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index b3170d8cf0..af7297e634 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -507,6 +507,11 @@ void RepliesWidget::setupComposeControls() { Unexpected("action in MimeData hook."); }); + _composeControls->lockShowStarts( + ) | rpl::start_with_next([=] { + updateScrollDownVisibility(); + }, lifetime()); + _composeControls->finishAnimating(); } @@ -1213,6 +1218,9 @@ void RepliesWidget::updateScrollDownVisibility() { } const auto scrollDownIsVisible = [&]() -> std::optional { + if (_composeControls->isLockPresent()) { + return false; + } const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; if (top < _scroll->scrollTopMax() || _replyReturn) { return true; diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 0afcc8d930..4367b4d5c7 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -253,6 +253,11 @@ void ScheduledWidget::setupComposeControls() { } Unexpected("action in MimeData hook."); }); + + _composeControls->lockShowStarts( + ) | rpl::start_with_next([=] { + updateScrollDownVisibility(); + }, lifetime()); } void ScheduledWidget::chooseAttach() { @@ -820,6 +825,9 @@ void ScheduledWidget::updateScrollDownVisibility() { } const auto scrollDownIsVisible = [&]() -> std::optional { + if (_composeControls->isLockPresent()) { + return false; + } const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; if (top < _scroll->scrollTopMax()) { return true;