From fd76b44dbdf150d91761946e6f853390f9035c67 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 4 Oct 2020 00:46:03 +0300 Subject: [PATCH] Replaced voice record processing with VoiceRecordBar in ComposeControls. --- .../history_view_compose_controls.cpp | 273 +++--------------- .../controls/history_view_compose_controls.h | 32 +- 2 files changed, 57 insertions(+), 248 deletions(-) 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 0020e99446..21c8e5e935 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/confirm_box.h" #include "history/history.h" #include "history/history_item.h" +#include "history/view/controls/history_view_voice_record_bar.h" #include "history/view/history_view_webpage_preview.h" #include "inline_bots/inline_results_widget.h" #include "lang/lang_keys.h" @@ -57,6 +58,7 @@ using MessageToEdit = ComposeControls::MessageToEdit; using VoiceToSend = ComposeControls::VoiceToSend; using SendActionUpdate = ComposeControls::SendActionUpdate; using SetHistoryArgs = ComposeControls::SetHistoryArgs; +using VoiceRecordBar = HistoryView::Controls::VoiceRecordBar; [[nodiscard]] auto ShowWebPagePreview(WebPageData *page) { return page && (page->pendingTill >= 0); @@ -500,7 +502,7 @@ ComposeControls::ComposeControls( , _mode(mode) , _wrap(std::make_unique(parent)) , _writeRestricted(std::make_unique(parent)) -, _send(Ui::CreateChild(_wrap.get())) +, _send(std::make_shared(_wrap.get())) , _attachToggle(Ui::CreateChild( _wrap.get(), st::historyAttach)) @@ -516,18 +518,16 @@ ComposeControls::ComposeControls( , _header(std::make_unique( _wrap.get(), &_window->session().data())) -, _textUpdateEvents(TextUpdateEvent::SendTyping) -, _recordCancelWidth(st::historyRecordFont->width(tr::lng_record_cancel(tr::now))) -, _recordingAnimation([=](crl::time now) { - return recordingAnimationCallback(now); -}) { +, _voiceRecordBar(std::make_unique( + _wrap.get(), + window, + _send, + st::historySendSize.height())) +, _textUpdateEvents(TextUpdateEvent::SendTyping) { init(); } ComposeControls::~ComposeControls() { - if (_recording) { - stopRecording(false); - } setTabbedPanel(nullptr); } @@ -579,91 +579,13 @@ int ComposeControls::heightCurrent() const { } bool ComposeControls::focus() { - if (_recording) { + if (_voiceRecordBar->isRecording()) { return false; } _field->setFocus(); return true; } -void ComposeControls::updateControlsVisibility() { - if (_recording) { - _field->hide(); - _tabbedSelectorToggle->hide(); - //_botKeyboardShow->hide(); - //_botKeyboardHide->hide(); - //_botCommandStart->hide(); - _attachToggle->hide(); - //if (_silent) { - // _silent->hide(); - //} - //if (_scheduled) { - // _scheduled->hide(); - //} - //if (_kbShown) { - // _kbScroll->show(); - //} else { - // _kbScroll->hide(); - //} - } else { - _field->show(); - //if (_kbShown) { - // _kbScroll->show(); - // _tabbedSelectorToggle->hide(); - // _botKeyboardHide->show(); - // _botKeyboardShow->hide(); - // _botCommandStart->hide(); - //} else if (_kbReplyTo) { - // _kbScroll->hide(); - // _tabbedSelectorToggle->show(); - // _botKeyboardHide->hide(); - // _botKeyboardShow->hide(); - // _botCommandStart->hide(); - //} else { - // _kbScroll->hide(); - // _tabbedSelectorToggle->show(); - // _botKeyboardHide->hide(); - // if (_keyboard->hasMarkup()) { - // _botKeyboardShow->show(); - // _botCommandStart->hide(); - // } else { - // _botKeyboardShow->hide(); - // if (_cmdStartShown) { - // _botCommandStart->show(); - // } else { - // _botCommandStart->hide(); - // } - // } - //} - _tabbedSelectorToggle->show(); - _attachToggle->show(); - //if (_silent) { - // _silent->show(); - //} - //if (_scheduled) { - // _scheduled->show(); - //} - //updateFieldPlaceholder(); - } - -} - -bool ComposeControls::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()) { - _wrap->update(_attachToggle->geometry()); - } - return (dt < 1.); -} - rpl::producer<> ComposeControls::cancelRequests() const { return _cancelRequests.events(); } @@ -693,7 +615,7 @@ rpl::producer<> ComposeControls::sendRequests() const { } rpl::producer ComposeControls::sendVoiceRequests() const { - return _sendVoiceRequests.events(); + return _voiceRecordBar->sendVoiceRequests(); } rpl::producer ComposeControls::editRequests() const { @@ -792,6 +714,7 @@ void ComposeControls::init() { initTabbedSelector(); initSendButton(); initWriteRestriction(); + initVoiceRecordBar(); _wrap->sizeValue( ) | rpl::start_with_next([=](QSize size) { @@ -841,99 +764,12 @@ void ComposeControls::init() { cancelEditMessage(); }, _wrap->lifetime()); } + + orderControls(); } -void ComposeControls::recordDone( - QByteArray result, - VoiceWaveform waveform, - int samples) { - if (result.isEmpty()) { - return; - } - - Window::ActivateWindow(_window); - const auto duration = samples / ::Media::Player::kDefaultFrequency; - _sendVoiceRequests.fire({ result, waveform, duration }); -} - -void ComposeControls::recordUpdated(quint16 level, int samples) { - if (!_recording) { - return; - } - - _recordingLevel.start(level); - _recordingAnimation.start(); - _recordingSamples = samples; - if (samples < 0 || samples >= ::Media::Player::kDefaultFrequency * AudioVoiceMsgMaxLength) { - stopRecording(samples > 0 && _inField); - } - Core::App().updateNonIdle(); - _wrap->update(); - _sendActionUpdates.fire({ Api::SendProgressType::RecordVoice }); -} - -void ComposeControls::recordStartCallback() { - using namespace ::Media::Capture; - const auto error = _history - ? Data::RestrictionError(_history->peer, ChatRestriction::f_send_media) - : std::nullopt; - if (error) { - Ui::show(Box(*error)); - return; - } else if (_showSlowmodeError && _showSlowmodeError()) { - return; - } else if (!instance()->available()) { - return; - } - - instance()->start(); - instance()->updated( - ) | rpl::start_with_next_error([=](const Update &update) { - recordUpdated(update.level, update.samples); - }, [=] { - stopRecording(false); - }, _recordingLifetime); - - _recording = _inField = true; - updateControlsVisibility(); - _window->widget()->setInnerFocus(); - - _wrap->update(); - - _send->setRecordActive(true); -} - -void ComposeControls::recordStopCallback(bool active) { - stopRecording(active); -} - -void ComposeControls::recordUpdateCallback(QPoint globalPos) { - updateOverStates(_wrap->mapFromGlobal(globalPos)); -} - -void ComposeControls::stopRecording(bool send) { - if (send) { - ::Media::Capture::instance()->stop(crl::guard(_wrap.get(), [=]( - const ::Media::Capture::Result &result) { - recordDone(result.bytes, result.waveform, result.samples); - })); - } else { - ::Media::Capture::instance()->stop(); - } - - _recordingLevel = anim::value(); - _recordingAnimation.stop(); - - _recordingLifetime.destroy(); - _recording = false; - _recordingSamples = 0; - _sendActionUpdates.fire({ Api::SendProgressType::RecordVoice, -1 }); - - updateControlsVisibility(); - _window->widget()->setInnerFocus(); - - _wrap->update(); - _send->setRecordActive(false); +void ComposeControls::orderControls() { + _send->raise(); } bool ComposeControls::showRecordButton() const { @@ -943,30 +779,6 @@ bool ComposeControls::showRecordButton() const { && !isEditingMessage(); } -void ComposeControls::drawRecording(Painter &p, float64 recordActive) { - p.setPen(Qt::NoPen); - p.setBrush(st::historyRecordSignalColor); - - auto delta = qMin(_recordingLevel.current() / 0x4000, 1.); - auto d = 2 * qRound(st::historyRecordSignalMin + (delta * (st::historyRecordSignalMax - st::historyRecordSignalMin))); - { - PainterHighQualityEnabler hq(p); - p.drawEllipse(_attachToggle->x() + (_tabbedSelectorToggle->width() - d) / 2, _attachToggle->y() + (_attachToggle->height() - d) / 2, d, d); - } - - auto duration = Ui::FormatDurationText(_recordingSamples / ::Media::Player::kDefaultFrequency); - p.setFont(st::historyRecordFont); - - p.setPen(st::historyRecordDurationFg); - p.drawText(_attachToggle->x() + _tabbedSelectorToggle->width(), _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, duration); - - int32 left = _attachToggle->x() + _tabbedSelectorToggle->width() + st::historyRecordFont->width(duration) + ((_send->width() - st::historyRecordVoice.width()) / 2); - int32 right = _wrap->width() - _send->width(); - - p.setPen(anim::pen(st::historyRecordCancel, st::historyRecordCancelActive, 1. - recordActive)); - p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, tr::lng_record_cancel(tr::now)); -} - void ComposeControls::drawRestrictedWrite(Painter &p, const QString &error) { p.fillRect(_writeRestricted->rect(), st::historyReplyBg); @@ -1023,7 +835,9 @@ void ComposeControls::fieldChanged() { } rpl::producer ComposeControls::sendActionUpdates() const { - return _sendActionUpdates.events(); + return rpl::merge( + _sendActionUpdates.events(), + _voiceRecordBar->sendActionUpdates()); } void ComposeControls::initTabbedSelector() { @@ -1093,6 +907,29 @@ void ComposeControls::initWriteRestriction() { }, _wrap->lifetime()); } +void ComposeControls::initVoiceRecordBar() { + _voiceRecordBar->recordingStateChanges( + ) | rpl::start_with_next([=](bool active) { + _field->setVisible(!active); + }, _wrap->lifetime()); + + _voiceRecordBar->startRecordingRequests( + ) | rpl::start_with_next([=] { + const auto error = _history + ? Data::RestrictionError( + _history->peer, + ChatRestriction::f_send_media) + : std::nullopt; + if (error) { + Ui::show(Box(*error)); + return; + } else if (_showSlowmodeError && _showSlowmodeError()) { + return; + } + _voiceRecordBar->startRecording(); + }, _wrap->lifetime()); +} + void ComposeControls::updateWrappingVisibility() { const auto restricted = _writeRestriction.current().has_value(); _writeRestricted->setVisible(restricted); @@ -1124,16 +961,11 @@ void ComposeControls::updateSendButtonType() { _send->setSlowmodeDelay(delay); _send->setDisabled(_sendDisabledBySlowmode.current() && (type == Type::Send || type == Type::Record)); - - _send->setRecordStartCallback([=] { recordStartCallback(); }); - _send->setRecordStopCallback([=](bool active) { recordStopCallback(active); }); - _send->setRecordUpdateCallback([=](QPoint globalPos) { recordUpdateCallback(globalPos); }); - _send->setRecordAnimationCallback([=] { _wrap->update(); }); } void ComposeControls::finishAnimating() { _send->finishAnimating(); - _recordingAnimation.stop(); + _voiceRecordBar->finishAnimating(); } void ComposeControls::updateControlsGeometry(QSize size) { @@ -1165,6 +997,11 @@ void ComposeControls::updateControlsGeometry(QSize size) { _send->moveToRight(right, buttonsTop); right += _send->width(); _tabbedSelectorToggle->moveToRight(right, buttonsTop); + + _voiceRecordBar->resizeToWidth(size.width()); + _voiceRecordBar->moveToLeft( + 0, + size.height() - _voiceRecordBar->height()); } void ComposeControls::updateOuterGeometry(QRect rect) { @@ -1178,24 +1015,10 @@ void ComposeControls::updateOuterGeometry(QRect rect) { } } -void ComposeControls::updateOverStates(QPoint pos) { - const auto inField = _wrap->rect().contains(pos); - if (inField != _inField && _recording) { - _inField = inField; - _send->setRecordActive(_inField); - } -} - void ComposeControls::paintBackground(QRect clip) { Painter p(_wrap.get()); p.fillRect(clip, st::historyComposeAreaBg); - if (!_field->isHidden() || _recording) { - //drawField(p, clip); - if (!_send->isHidden() && _recording) { - drawRecording(p, _send->recordActiveRatio()); - } - } } void ComposeControls::escape() { 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 0bea191060..3d642ab5d8 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -56,6 +56,10 @@ enum class SendProgressType; namespace HistoryView { +namespace Controls { +class VoiceRecordBar; +} // namespace Controls + class FieldHeader; class ComposeControls final { @@ -145,6 +149,7 @@ private: void initSendButton(); void initWebpageProcess(); void initWriteRestriction(); + void initVoiceRecordBar(); void updateSendButtonType(); void updateHeight(); void updateWrappingVisibility(); @@ -153,6 +158,8 @@ private: void updateOuterGeometry(QRect rect); void paintBackground(QRect clip); + void orderControls(); + void escape(); void fieldChanged(); void toggleTabbedSelectorMode(); @@ -161,18 +168,7 @@ private: void setTextFromEditingMessage(not_null item); - void recordUpdated(quint16 level, int samples); - void recordDone(QByteArray result, VoiceWaveform waveform, int samples); - - bool recordingAnimationCallback(crl::time now); - void stopRecording(bool send); - - void recordStartCallback(); - void recordStopCallback(bool active); - void recordUpdateCallback(QPoint globalPos); - bool showRecordButton() const; - void drawRecording(Painter &p, float64 recordActive); void drawRestrictedWrite(Painter &p, const QString &error); void updateOverStates(QPoint pos); @@ -188,7 +184,7 @@ private: const std::unique_ptr _wrap; const std::unique_ptr _writeRestricted; - const not_null _send; + const std::shared_ptr _send; const not_null _attachToggle; const not_null _tabbedSelectorToggle; const not_null _field; @@ -197,32 +193,22 @@ private: friend class FieldHeader; const std::unique_ptr _header; + const std::unique_ptr _voiceRecordBar; rpl::event_stream<> _cancelRequests; rpl::event_stream _fileChosen; rpl::event_stream _photoChosen; rpl::event_stream _inlineResultChosen; rpl::event_stream _sendActionUpdates; - rpl::event_stream _sendVoiceRequests; TextWithTags _localSavedText; TextUpdateEvents _textUpdateEvents; - bool _recording = false; - bool _inField = false; //bool _inReplyEditForward = false; //bool _inClickable = false; - int _recordingSamples = 0; - int _recordCancelWidth; - rpl::lifetime _recordingLifetime; rpl::lifetime _uploaderSubscriptions; - // 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; - anim::value _recordingLevel; - Fn _raiseEmojiSuggestions; };