mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Added appearance animation to VoiceRecordBar.
This commit is contained in:
parent
e7454e3849
commit
5c006002b6
3 changed files with 77 additions and 45 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 }};
|
||||||
|
|
Loading…
Add table
Reference in a new issue