From a19e3ca3dcf503d3f0da8a7f7379c46a834f3892 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 7 Nov 2020 21:02:08 +0300 Subject: [PATCH] Added initial ability to send recorded voice data from listen state. --- .../SourceFiles/history/history_widget.cpp | 6 ++ .../history_view_compose_controls.cpp | 6 ++ .../history_view_voice_record_bar.cpp | 84 +++++++++++++++---- .../controls/history_view_voice_record_bar.h | 6 +- 4 files changed, 86 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b9b47f9184..23cf33d08c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -804,6 +804,11 @@ void HistoryWidget::initVoiceRecordBar() { updateUnreadMentionsVisibility(); }, lifetime()); + _voiceRecordBar->updateSendButtonTypeRequests( + ) | rpl::start_with_next([=] { + updateSendButtonType(); + }, lifetime()); + _voiceRecordBar->hideFast(); } @@ -3639,6 +3644,7 @@ bool HistoryWidget::isMuteUnmute() const { bool HistoryWidget::showRecordButton() const { return Media::Capture::instance()->available() + && !_voiceRecordBar->isListenState() && !HasSendText(_field) && !readyToForward() && !_editMsgId; 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 fdd5d198d1..f2961d993f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -994,6 +994,7 @@ void ComposeControls::orderControls() { bool ComposeControls::showRecordButton() const { return ::Media::Capture::instance()->available() + && !_voiceRecordBar->isListenState() && !HasSendText(_field) //&& !readyToForward() && !isEditingMessage(); @@ -1533,6 +1534,11 @@ void ComposeControls::initVoiceRecordBar() { _voiceRecordBar->setEscFilter([=] { return (isEditingMessage() || replyingToMessage()); }); + + _voiceRecordBar->updateSendButtonTypeRequests( + ) | rpl::start_with_next([=] { + updateSendButtonType(); + }, _wrap->lifetime()); } void ComposeControls::updateWrappingVisibility() { 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 ec98faa410..4f3ac5146a 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 @@ -78,10 +78,11 @@ class ListenWrap final { public: ListenWrap( not_null parent, - const ::Media::Capture::Result &data); + ::Media::Capture::Result &&data); void requestPaintProgress(float64 progress); rpl::producer<> stopRequests() const; + ::Media::Capture::Result *data() const; rpl::lifetime &lifetime(); @@ -90,7 +91,8 @@ private: not_null _parent; - const std::unique_ptr _voiceData; + const std::unique_ptr<::Media::Capture::Result> _data; + // const std::unique_ptr _voiceData; const style::IconButton &_stDelete; base::unique_qptr _delete; @@ -102,9 +104,10 @@ private: ListenWrap::ListenWrap( not_null parent, - const ::Media::Capture::Result &data) + ::Media::Capture::Result &&data) : _parent(parent) -, _voiceData(ProcessCaptureResult(data)) +, _data(std::make_unique<::Media::Capture::Result>(std::move(data))) +// , _voiceData(ProcessCaptureResult(_data)) , _stDelete(st::historyRecordDelete) , _delete(base::make_unique_q(parent, _stDelete)) { init(); @@ -137,6 +140,10 @@ rpl::producer<> ListenWrap::stopRequests() const { return _delete->clicks() | rpl::to_empty; } +::Media::Capture::Result *ListenWrap::data() const { + return _data.get(); +} + rpl::lifetime &ListenWrap::lifetime() { return _lifetime; } @@ -533,11 +540,9 @@ void VoiceRecordBar::init() { _lock->stops( ) | rpl::start_with_next([=] { ::Media::Capture::instance()->startedChanges( - ) | rpl::filter([](auto capturing) { - return !capturing; + ) | rpl::filter([=](auto capturing) { + return !capturing && _listen; }) | rpl::take(1) | rpl::start_with_next([=] { - Assert(_listen != nullptr); - _lockShowing = false; const auto to = 1.; @@ -605,6 +610,50 @@ void VoiceRecordBar::init() { _startTimer.cancel(); } }, lifetime()); + + _listenChanges.events( + ) | rpl::filter([=] { + return _listen != nullptr; + }) | rpl::start_with_next([=] { + _listen->stopRequests( + ) | rpl::take(1) | rpl::start_with_next([=] { + visibilityAnimate(false, [=] { hide(); }); + }, _listen->lifetime()); + + _listen->lifetime().add([=] { _listenChanges.fire({}); }); + + auto filterCallback = [=](not_null e) { + using Result = base::EventFilterResult; + if (_send->type() != Ui::SendButton::Type::Send + && _send->type() != Ui::SendButton::Type::Schedule) { + return Result::Continue; + } + switch(e->type()) { + case QEvent::MouseButtonRelease: { + auto callback = [=] { + const auto data = _listen->data(); + _sendVoiceRequests.fire({ + data->bytes, + data->waveform, + Duration(data->samples) }); + hide(); + }; + visibilityAnimate(false, std::move(callback)); + _send->clearState(); + return Result::Cancel; + } + default: return Result::Continue; + } + }; + + auto filter = base::install_event_filter( + _send.get(), + std::move(filterCallback)); + + _listen->lifetime().make_state>( + std::move(filter)); + + }, lifetime()); } void VoiceRecordBar::activeAnimate(bool active) { @@ -783,8 +832,10 @@ void VoiceRecordBar::stopRecording(StopType type) { instance()->stop(); return; } - instance()->stop(crl::guard(this, [=](const Result &data) { + instance()->stop(crl::guard(this, [=](Result &&data) { if (data.bytes.isEmpty()) { + // Close everything. + stop(false); return; } @@ -793,11 +844,8 @@ void VoiceRecordBar::stopRecording(StopType type) { if (type == StopType::Send) { _sendVoiceRequests.fire({ data.bytes, data.waveform, duration }); } else if (type == StopType::Listen) { - _listen = std::make_unique(this, data); - _listen->stopRequests( - ) | rpl::take(1) | rpl::start_with_next([=] { - visibilityAnimate(false, [=] { hide(); }); - }, _listen->lifetime()); + _listen = std::make_unique(this, std::move(data)); + _listenChanges.fire({}); _lockShowing = false; } @@ -879,10 +927,18 @@ rpl::producer VoiceRecordBar::lockShowStarts() const { return _lockShowing.changes(); } +rpl::producer<> VoiceRecordBar::updateSendButtonTypeRequests() const { + return _listenChanges.events(); +} + bool VoiceRecordBar::isLockPresent() const { return _lockShowing.current(); } +bool VoiceRecordBar::isListenState() const { + return _listen != nullptr; +} + bool VoiceRecordBar::isTypeRecord() const { return (_send->type() == Ui::SendButton::Type::Record); } 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 fe4d50f86a..1df1477756 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 @@ -57,6 +57,7 @@ public: [[nodiscard]] rpl::producer sendVoiceRequests() const; [[nodiscard]] rpl::producer recordingStateChanges() const; [[nodiscard]] rpl::producer lockShowStarts() const; + [[nodiscard]] rpl::producer<> updateSendButtonTypeRequests() const; void setLockBottom(rpl::producer &&bottom); void setSendButtonGeometryValue(rpl::producer &&geometry); @@ -65,6 +66,7 @@ public: [[nodiscard]] bool isRecording() const; [[nodiscard]] bool isLockPresent() const; + [[nodiscard]] bool isListenState() const; private: enum class StopType { @@ -117,6 +119,7 @@ private: rpl::event_stream _sendActionUpdates; rpl::event_stream _sendVoiceRequests; + rpl::event_stream<> _listenChanges; int _centerY = 0; QRect _redCircleRect; @@ -130,6 +133,7 @@ private: rpl::variable _recording = false; rpl::variable _inField = false; + rpl::variable _lockShowing = false; int _recordingSamples = 0; float64 _redCircleProgress = 0.; @@ -137,8 +141,6 @@ private: rpl::lifetime _recordingLifetime; - rpl::variable _lockShowing = false; - Ui::Animations::Simple _showLockAnimation; Ui::Animations::Simple _showListenAnimation; Ui::Animations::Simple _activeAnimation;