Added appearance animation to VoiceRecordBar.

This commit is contained in:
23rd 2020-10-04 21:19:34 +03:00 committed by John Preston
parent e7454e3849
commit 5c006002b6
3 changed files with 77 additions and 45 deletions

View file

@ -90,6 +90,7 @@ void VoiceRecordBar::init() {
paintRequest( paintRequest(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
Painter p(this); Painter p(this);
p.setOpacity(_showAnimation.value(1.));
p.fillRect(rect(), st::historyComposeAreaBg); p.fillRect(rect(), st::historyComposeAreaBg);
drawRecording(p, activeAnimationRatio()); drawRecording(p, activeAnimationRatio());
@ -116,28 +117,46 @@ void VoiceRecordBar::activeAnimate(bool active) {
} }
} }
void VoiceRecordBar::startRecording() { void VoiceRecordBar::visibilityAnimate(bool show, Fn<void()> &&callback) {
using namespace ::Media::Capture; const auto to = show ? 1. : 0.;
if (!instance()->available()) { const auto from = show ? 0. : 1.;
return; const auto duration = st::historyRecordVoiceShowDuration;
} auto animationCallback = [=, callback = std::move(callback)](auto value) {
show(); update();
_recording = true; if ((show && value == 1.) || (!show && value == 0.)) {
if (callback) {
callback();
}
}
};
_showAnimation.start(std::move(animationCallback), from, to, duration);
}
instance()->start(); void VoiceRecordBar::startRecording() {
instance()->updated( auto appearanceCallback = [=] {
) | rpl::start_with_next_error([=](const Update &update) { Expects(!_showAnimation.animating());
recordUpdated(update.level, update.samples);
}, [=] { using namespace ::Media::Capture;
stopRecording(false); if (!instance()->available()) {
}, _recordingLifetime); stop(false);
return;
}
_recording = true;
instance()->start();
instance()->updated(
) | rpl::start_with_next_error([=](const Update &update) {
recordUpdated(update.level, update.samples);
}, [=] {
stop(false);
}, _recordingLifetime);
};
visibilityAnimate(true, std::move(appearanceCallback));
show();
_inField = true; _inField = true;
_controller->widget()->setInnerFocus(); _controller->widget()->setInnerFocus();
update();
activeAnimate(true);
_send->events( _send->events(
) | rpl::filter([=](not_null<QEvent*> e) { ) | rpl::filter([=](not_null<QEvent*> e) {
return isTypeRecord() return isTypeRecord()
@ -149,7 +168,7 @@ void VoiceRecordBar::startRecording() {
const auto mouse = static_cast<QMouseEvent*>(e.get()); const auto mouse = static_cast<QMouseEvent*>(e.get());
_inField = rect().contains(mapFromGlobal(mouse->globalPos())); _inField = rect().contains(mapFromGlobal(mouse->globalPos()));
} else if (type == QEvent::MouseButtonRelease) { } else if (type == QEvent::MouseButtonRelease) {
stopRecording(_inField.current()); stop(_inField.current());
} }
}, _recordingLifetime); }, _recordingLifetime);
} }
@ -175,44 +194,51 @@ void VoiceRecordBar::recordUpdated(quint16 level, int samples) {
_recordingAnimation.start(); _recordingAnimation.start();
_recordingSamples = samples; _recordingSamples = samples;
if (samples < 0 || samples >= kMaxSamples) { if (samples < 0 || samples >= kMaxSamples) {
stopRecording(samples > 0 && _inField.current()); stop(samples > 0 && _inField.current());
} }
Core::App().updateNonIdle(); Core::App().updateNonIdle();
update(); update();
_sendActionUpdates.fire({ Api::SendProgressType::RecordVoice }); _sendActionUpdates.fire({ Api::SendProgressType::RecordVoice });
} }
void VoiceRecordBar::stop(bool send) {
auto disappearanceCallback = [=] {
Expects(!_showAnimation.animating());
hide();
_recording = false;
stopRecording(send);
_recordingLevel = anim::value();
_recordingAnimation.stop();
_inField = false;
_recordingLifetime.destroy();
_recordingSamples = 0;
_sendActionUpdates.fire({ Api::SendProgressType::RecordVoice, -1 });
_controller->widget()->setInnerFocus();
};
visibilityAnimate(false, std::move(disappearanceCallback));
}
void VoiceRecordBar::stopRecording(bool send) { void VoiceRecordBar::stopRecording(bool send) {
hide();
_recording = false;
using namespace ::Media::Capture; using namespace ::Media::Capture;
if (send) { if (!send) {
instance()->stop(crl::guard(this, [=](const Result &data) {
if (data.bytes.isEmpty()) {
return;
}
Window::ActivateWindow(_controller);
const auto duration = Duration(data.samples);
_sendVoiceRequests.fire({ data.bytes, data.waveform, duration });
}));
} else {
instance()->stop(); instance()->stop();
return;
} }
instance()->stop(crl::guard(this, [=](const Result &data) {
if (data.bytes.isEmpty()) {
return;
}
_recordingLevel = anim::value(); Window::ActivateWindow(_controller);
_recordingAnimation.stop(); const auto duration = Duration(data.samples);
_sendVoiceRequests.fire({ data.bytes, data.waveform, duration });
_inField = false; }));
_recordingLifetime.destroy();
_recordingSamples = 0;
_sendActionUpdates.fire({ Api::SendProgressType::RecordVoice, -1 });
_controller->widget()->setInnerFocus();
update();
} }
void VoiceRecordBar::drawRecording(Painter &p, float64 recordActive) { void VoiceRecordBar::drawRecording(Painter &p, float64 recordActive) {
@ -276,6 +302,7 @@ bool VoiceRecordBar::isRecording() const {
void VoiceRecordBar::finishAnimating() { void VoiceRecordBar::finishAnimating() {
_recordingAnimation.stop(); _recordingAnimation.stop();
_showAnimation.stop();
} }
rpl::producer<bool> VoiceRecordBar::recordingStateChanges() const { rpl::producer<bool> VoiceRecordBar::recordingStateChanges() const {

View file

@ -53,7 +53,10 @@ private:
void recordUpdated(quint16 level, int samples); void recordUpdated(quint16 level, int samples);
bool recordingAnimationCallback(crl::time now); bool recordingAnimationCallback(crl::time now);
void stop(bool send);
void stopRecording(bool send); void stopRecording(bool send);
void visibilityAnimate(bool show, Fn<void()> &&callback);
void recordStopCallback(bool active); void recordStopCallback(bool active);
void recordUpdateCallback(QPoint globalPos); void recordUpdateCallback(QPoint globalPos);
@ -90,6 +93,7 @@ private:
// so it should be a Basic, not a Simple animation. // so it should be a Basic, not a Simple animation.
Ui::Animations::Basic _recordingAnimation; Ui::Animations::Basic _recordingAnimation;
Ui::Animations::Simple _activeAnimation; Ui::Animations::Simple _activeAnimation;
Ui::Animations::Simple _showAnimation;
anim::value _recordingLevel; anim::value _recordingLevel;
}; };

View file

@ -328,6 +328,7 @@ historyScheduledToggle: IconButton(historyAttach) {
historyRecordVoiceFg: historyComposeIconFg; historyRecordVoiceFg: historyComposeIconFg;
historyRecordVoiceFgOver: historyComposeIconFgOver; historyRecordVoiceFgOver: historyComposeIconFgOver;
historyRecordVoiceFgActive: windowBgActive; historyRecordVoiceFgActive: windowBgActive;
historyRecordVoiceShowDuration: 120;
historyRecordVoiceDuration: 120; historyRecordVoiceDuration: 120;
historyRecordVoice: icon {{ "send_control_record", historyRecordVoiceFg }}; historyRecordVoice: icon {{ "send_control_record", historyRecordVoiceFg }};
historyRecordVoiceOver: icon {{ "send_control_record", historyRecordVoiceFgOver }}; historyRecordVoiceOver: icon {{ "send_control_record", historyRecordVoiceFgOver }};