mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Added initial ability to send recorded voice data from listen state.
This commit is contained in:
parent
647cbc5464
commit
a19e3ca3dc
4 changed files with 86 additions and 16 deletions
|
@ -804,6 +804,11 @@ void HistoryWidget::initVoiceRecordBar() {
|
||||||
updateUnreadMentionsVisibility();
|
updateUnreadMentionsVisibility();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
_voiceRecordBar->updateSendButtonTypeRequests(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateSendButtonType();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_voiceRecordBar->hideFast();
|
_voiceRecordBar->hideFast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3639,6 +3644,7 @@ bool HistoryWidget::isMuteUnmute() const {
|
||||||
|
|
||||||
bool HistoryWidget::showRecordButton() const {
|
bool HistoryWidget::showRecordButton() const {
|
||||||
return Media::Capture::instance()->available()
|
return Media::Capture::instance()->available()
|
||||||
|
&& !_voiceRecordBar->isListenState()
|
||||||
&& !HasSendText(_field)
|
&& !HasSendText(_field)
|
||||||
&& !readyToForward()
|
&& !readyToForward()
|
||||||
&& !_editMsgId;
|
&& !_editMsgId;
|
||||||
|
|
|
@ -994,6 +994,7 @@ void ComposeControls::orderControls() {
|
||||||
|
|
||||||
bool ComposeControls::showRecordButton() const {
|
bool ComposeControls::showRecordButton() const {
|
||||||
return ::Media::Capture::instance()->available()
|
return ::Media::Capture::instance()->available()
|
||||||
|
&& !_voiceRecordBar->isListenState()
|
||||||
&& !HasSendText(_field)
|
&& !HasSendText(_field)
|
||||||
//&& !readyToForward()
|
//&& !readyToForward()
|
||||||
&& !isEditingMessage();
|
&& !isEditingMessage();
|
||||||
|
@ -1533,6 +1534,11 @@ void ComposeControls::initVoiceRecordBar() {
|
||||||
_voiceRecordBar->setEscFilter([=] {
|
_voiceRecordBar->setEscFilter([=] {
|
||||||
return (isEditingMessage() || replyingToMessage());
|
return (isEditingMessage() || replyingToMessage());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_voiceRecordBar->updateSendButtonTypeRequests(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateSendButtonType();
|
||||||
|
}, _wrap->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComposeControls::updateWrappingVisibility() {
|
void ComposeControls::updateWrappingVisibility() {
|
||||||
|
|
|
@ -78,10 +78,11 @@ class ListenWrap final {
|
||||||
public:
|
public:
|
||||||
ListenWrap(
|
ListenWrap(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
const ::Media::Capture::Result &data);
|
::Media::Capture::Result &&data);
|
||||||
|
|
||||||
void requestPaintProgress(float64 progress);
|
void requestPaintProgress(float64 progress);
|
||||||
rpl::producer<> stopRequests() const;
|
rpl::producer<> stopRequests() const;
|
||||||
|
::Media::Capture::Result *data() const;
|
||||||
|
|
||||||
rpl::lifetime &lifetime();
|
rpl::lifetime &lifetime();
|
||||||
|
|
||||||
|
@ -90,7 +91,8 @@ private:
|
||||||
|
|
||||||
not_null<Ui::RpWidget*> _parent;
|
not_null<Ui::RpWidget*> _parent;
|
||||||
|
|
||||||
const std::unique_ptr<VoiceData> _voiceData;
|
const std::unique_ptr<::Media::Capture::Result> _data;
|
||||||
|
// const std::unique_ptr<VoiceData> _voiceData;
|
||||||
const style::IconButton &_stDelete;
|
const style::IconButton &_stDelete;
|
||||||
base::unique_qptr<Ui::IconButton> _delete;
|
base::unique_qptr<Ui::IconButton> _delete;
|
||||||
|
|
||||||
|
@ -102,9 +104,10 @@ private:
|
||||||
|
|
||||||
ListenWrap::ListenWrap(
|
ListenWrap::ListenWrap(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
const ::Media::Capture::Result &data)
|
::Media::Capture::Result &&data)
|
||||||
: _parent(parent)
|
: _parent(parent)
|
||||||
, _voiceData(ProcessCaptureResult(data))
|
, _data(std::make_unique<::Media::Capture::Result>(std::move(data)))
|
||||||
|
// , _voiceData(ProcessCaptureResult(_data))
|
||||||
, _stDelete(st::historyRecordDelete)
|
, _stDelete(st::historyRecordDelete)
|
||||||
, _delete(base::make_unique_q<Ui::IconButton>(parent, _stDelete)) {
|
, _delete(base::make_unique_q<Ui::IconButton>(parent, _stDelete)) {
|
||||||
init();
|
init();
|
||||||
|
@ -137,6 +140,10 @@ rpl::producer<> ListenWrap::stopRequests() const {
|
||||||
return _delete->clicks() | rpl::to_empty;
|
return _delete->clicks() | rpl::to_empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::Media::Capture::Result *ListenWrap::data() const {
|
||||||
|
return _data.get();
|
||||||
|
}
|
||||||
|
|
||||||
rpl::lifetime &ListenWrap::lifetime() {
|
rpl::lifetime &ListenWrap::lifetime() {
|
||||||
return _lifetime;
|
return _lifetime;
|
||||||
}
|
}
|
||||||
|
@ -533,11 +540,9 @@ void VoiceRecordBar::init() {
|
||||||
_lock->stops(
|
_lock->stops(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
::Media::Capture::instance()->startedChanges(
|
::Media::Capture::instance()->startedChanges(
|
||||||
) | rpl::filter([](auto capturing) {
|
) | rpl::filter([=](auto capturing) {
|
||||||
return !capturing;
|
return !capturing && _listen;
|
||||||
}) | rpl::take(1) | rpl::start_with_next([=] {
|
}) | rpl::take(1) | rpl::start_with_next([=] {
|
||||||
Assert(_listen != nullptr);
|
|
||||||
|
|
||||||
_lockShowing = false;
|
_lockShowing = false;
|
||||||
|
|
||||||
const auto to = 1.;
|
const auto to = 1.;
|
||||||
|
@ -605,6 +610,50 @@ void VoiceRecordBar::init() {
|
||||||
_startTimer.cancel();
|
_startTimer.cancel();
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, 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<QEvent*> 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<base::unique_qptr<QObject>>(
|
||||||
|
std::move(filter));
|
||||||
|
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceRecordBar::activeAnimate(bool active) {
|
void VoiceRecordBar::activeAnimate(bool active) {
|
||||||
|
@ -783,8 +832,10 @@ void VoiceRecordBar::stopRecording(StopType type) {
|
||||||
instance()->stop();
|
instance()->stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance()->stop(crl::guard(this, [=](const Result &data) {
|
instance()->stop(crl::guard(this, [=](Result &&data) {
|
||||||
if (data.bytes.isEmpty()) {
|
if (data.bytes.isEmpty()) {
|
||||||
|
// Close everything.
|
||||||
|
stop(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,11 +844,8 @@ void VoiceRecordBar::stopRecording(StopType type) {
|
||||||
if (type == StopType::Send) {
|
if (type == StopType::Send) {
|
||||||
_sendVoiceRequests.fire({ data.bytes, data.waveform, duration });
|
_sendVoiceRequests.fire({ data.bytes, data.waveform, duration });
|
||||||
} else if (type == StopType::Listen) {
|
} else if (type == StopType::Listen) {
|
||||||
_listen = std::make_unique<ListenWrap>(this, data);
|
_listen = std::make_unique<ListenWrap>(this, std::move(data));
|
||||||
_listen->stopRequests(
|
_listenChanges.fire({});
|
||||||
) | rpl::take(1) | rpl::start_with_next([=] {
|
|
||||||
visibilityAnimate(false, [=] { hide(); });
|
|
||||||
}, _listen->lifetime());
|
|
||||||
|
|
||||||
_lockShowing = false;
|
_lockShowing = false;
|
||||||
}
|
}
|
||||||
|
@ -879,10 +927,18 @@ rpl::producer<bool> VoiceRecordBar::lockShowStarts() const {
|
||||||
return _lockShowing.changes();
|
return _lockShowing.changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> VoiceRecordBar::updateSendButtonTypeRequests() const {
|
||||||
|
return _listenChanges.events();
|
||||||
|
}
|
||||||
|
|
||||||
bool VoiceRecordBar::isLockPresent() const {
|
bool VoiceRecordBar::isLockPresent() const {
|
||||||
return _lockShowing.current();
|
return _lockShowing.current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VoiceRecordBar::isListenState() const {
|
||||||
|
return _listen != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool VoiceRecordBar::isTypeRecord() const {
|
bool VoiceRecordBar::isTypeRecord() const {
|
||||||
return (_send->type() == Ui::SendButton::Type::Record);
|
return (_send->type() == Ui::SendButton::Type::Record);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
[[nodiscard]] rpl::producer<VoiceToSend> sendVoiceRequests() const;
|
[[nodiscard]] rpl::producer<VoiceToSend> sendVoiceRequests() const;
|
||||||
[[nodiscard]] rpl::producer<bool> recordingStateChanges() const;
|
[[nodiscard]] rpl::producer<bool> recordingStateChanges() const;
|
||||||
[[nodiscard]] rpl::producer<bool> lockShowStarts() const;
|
[[nodiscard]] rpl::producer<bool> lockShowStarts() const;
|
||||||
|
[[nodiscard]] rpl::producer<> updateSendButtonTypeRequests() const;
|
||||||
|
|
||||||
void setLockBottom(rpl::producer<int> &&bottom);
|
void setLockBottom(rpl::producer<int> &&bottom);
|
||||||
void setSendButtonGeometryValue(rpl::producer<QRect> &&geometry);
|
void setSendButtonGeometryValue(rpl::producer<QRect> &&geometry);
|
||||||
|
@ -65,6 +66,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] bool isRecording() const;
|
[[nodiscard]] bool isRecording() const;
|
||||||
[[nodiscard]] bool isLockPresent() const;
|
[[nodiscard]] bool isLockPresent() const;
|
||||||
|
[[nodiscard]] bool isListenState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class StopType {
|
enum class StopType {
|
||||||
|
@ -117,6 +119,7 @@ private:
|
||||||
|
|
||||||
rpl::event_stream<SendActionUpdate> _sendActionUpdates;
|
rpl::event_stream<SendActionUpdate> _sendActionUpdates;
|
||||||
rpl::event_stream<VoiceToSend> _sendVoiceRequests;
|
rpl::event_stream<VoiceToSend> _sendVoiceRequests;
|
||||||
|
rpl::event_stream<> _listenChanges;
|
||||||
|
|
||||||
int _centerY = 0;
|
int _centerY = 0;
|
||||||
QRect _redCircleRect;
|
QRect _redCircleRect;
|
||||||
|
@ -130,6 +133,7 @@ private:
|
||||||
|
|
||||||
rpl::variable<bool> _recording = false;
|
rpl::variable<bool> _recording = false;
|
||||||
rpl::variable<bool> _inField = false;
|
rpl::variable<bool> _inField = false;
|
||||||
|
rpl::variable<bool> _lockShowing = false;
|
||||||
int _recordingSamples = 0;
|
int _recordingSamples = 0;
|
||||||
float64 _redCircleProgress = 0.;
|
float64 _redCircleProgress = 0.;
|
||||||
|
|
||||||
|
@ -137,8 +141,6 @@ private:
|
||||||
|
|
||||||
rpl::lifetime _recordingLifetime;
|
rpl::lifetime _recordingLifetime;
|
||||||
|
|
||||||
rpl::variable<bool> _lockShowing = false;
|
|
||||||
|
|
||||||
Ui::Animations::Simple _showLockAnimation;
|
Ui::Animations::Simple _showLockAnimation;
|
||||||
Ui::Animations::Simple _showListenAnimation;
|
Ui::Animations::Simple _showListenAnimation;
|
||||||
Ui::Animations::Simple _activeAnimation;
|
Ui::Animations::Simple _activeAnimation;
|
||||||
|
|
Loading…
Add table
Reference in a new issue