Show recording progress.

This commit is contained in:
John Preston 2024-10-18 15:17:29 +04:00
parent f74dd3ca1e
commit e59e4afd3e
4 changed files with 105 additions and 20 deletions

View file

@ -1534,13 +1534,11 @@ void VoiceRecordBar::init() {
if (_startRecordingFilter && _startRecordingFilter()) {
return;
}
_recordingTipRequired = true;
_recordingTipRequire = crl::now();
_recordingVideo = (_send->type() == Ui::SendButton::Type::Round);
_startTimer.callOnce(st::universalDuration);
} else if (e->type() == QEvent::MouseButtonRelease) {
if (base::take(_recordingTipRequired)) {
_recordingTipRequests.fire({});
}
checkTipRequired();
_startTimer.cancel();
}
}, lifetime());
@ -1694,7 +1692,6 @@ void VoiceRecordBar::startRecording() {
}
instance()->updated(
) | rpl::start_with_next_error([=](const Update &update) {
_recordingTipRequired = (update.samples < kMinSamples);
recordUpdated(update.level, update.samples);
}, [=] {
stop(false);
@ -1702,10 +1699,9 @@ void VoiceRecordBar::startRecording() {
if (_videoRecorder) {
_videoRecorder->updated(
) | rpl::start_with_next_error([=](const Update &update) {
_recordingTipRequired = (update.samples < kMinSamples);
recordUpdated(update.level, update.samples);
if (update.finished) {
stop(true);
stop(update.samples >= kMinSamples);
}
}, [=] {
stop(false);
@ -1742,14 +1738,22 @@ void VoiceRecordBar::startRecording() {
}
computeAndSetLockProgress(mouse->globalPos());
} else if (type == QEvent::MouseButtonRelease) {
if (base::take(_recordingTipRequired)) {
_recordingTipRequests.fire({});
}
checkTipRequired();
stop(_inField.current());
}
}, _recordingLifetime);
}
void VoiceRecordBar::checkTipRequired() {
const auto require = base::take(_recordingTipRequire);
const auto duration = st::universalDuration
+ (kMinSamples * crl::time(1000)
/ ::Media::Player::kDefaultFrequency);
if (require && (require + duration > crl::now())) {
_recordingTipRequests.fire({});
}
}
void VoiceRecordBar::recordUpdated(quint16 level, int samples) {
_level->requestPaintLevel(level);
_recordingSamples = samples;

View file

@ -124,6 +124,7 @@ private:
void updateTTLGeometry(TTLAnimationType type, float64 progress);
void recordUpdated(quint16 level, int samples);
void checkTipRequired();
void stop(bool send);
void stopRecording(StopType type, bool ttlBeforeHide = false);
@ -192,7 +193,7 @@ private:
float64 _redCircleProgress = 0.;
rpl::event_stream<> _recordingTipRequests;
bool _recordingTipRequired = false;
crl::time _recordingTipRequire = 0;
bool _lockFromBottom = false;
std::unique_ptr<Ui::RoundVideoRecorder> _videoRecorder;

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ffmpeg/ffmpeg_utility.h"
#include "media/audio/media_audio_capture.h"
#include "ui/image/image_prepare.h"
#include "ui/arc_angles.h"
#include "ui/painter.h"
#include "ui/rp_widget.h"
#include "webrtc/webrtc_video_track.h"
@ -703,10 +704,14 @@ Fn<void(Media::Capture::Chunk)> RoundVideoRecorder::audioChunkProcessor() {
};
}
auto RoundVideoRecorder::updated() const
auto RoundVideoRecorder::updated()
-> rpl::producer<Update, rpl::empty_error> {
return _private.producer_on_main([](const Private &that) {
return that.updated();
}) | rpl::before_next([=](const Update &update) {
const auto duration = (update.samples * crl::time(1000))
/ kAudioFrequency;
progressTo(duration / (1. * kMaxDuration));
});
}
@ -725,6 +730,19 @@ void RoundVideoRecorder::hide(Fn<void(RoundVideoResult)> done) {
}
}
void RoundVideoRecorder::progressTo(float64 progress) {
if (_progress == progress) {
return;
}
_progressAnimation.start(
[=] { _preview->update(); },
progress,
_progress,
kUpdateEach);
_progress = progress;
_preview->update();
}
void RoundVideoRecorder::prepareFrame() {
if (_frameOriginal.isNull() || _preparedIndex == _lastAddedIndex) {
return;
@ -755,29 +773,82 @@ void RoundVideoRecorder::prepareFrame() {
_framePrepared.setDevicePixelRatio(ratio);
}
void RoundVideoRecorder::createImages() {
const auto ratio = style::DevicePixelRatio();
_framePrepared = QImage(
QSize(_side, _side) * ratio,
QImage::Format_ARGB32_Premultiplied);
_framePrepared.fill(Qt::transparent);
_framePrepared.setDevicePixelRatio(ratio);
auto p = QPainter(&_framePrepared);
auto hq = PainterHighQualityEnabler(p);
p.setPen(Qt::NoPen);
p.setBrush(Qt::black);
p.drawEllipse(0, 0, _side, _side);
const auto side = _side + 2 * _extent;
_shadow = QImage(
QSize(side, side) * ratio,
QImage::Format_ARGB32_Premultiplied);
_shadow.fill(Qt::transparent);
_shadow.setDevicePixelRatio(ratio);
auto sp = QPainter(&_shadow);
auto shq = PainterHighQualityEnabler(sp);
QRadialGradient gradient(
QPointF(_extent + _side / 2, _extent + _side / 2),
_side / 2 + _extent);
gradient.setColorAt(0, QColor(0, 0, 0, 128));
gradient.setColorAt(0.8, QColor(0, 0, 0, 64));
gradient.setColorAt(1, QColor(0, 0, 0, 0));
sp.setPen(Qt::NoPen);
sp.fillRect(0, 0, side, side, gradient);
sp.end();
}
void RoundVideoRecorder::setup() {
const auto raw = _preview.get();
_side = style::ConvertScale(kSide * 3 / 4);
_progressStroke = st::radialLine;
_extent = _progressStroke * 8;
createImages();
_descriptor.container->sizeValue(
) | rpl::start_with_next([=](QSize outer) {
const auto side = _side + 2 * _extent;
raw->setGeometry(
style::centerrect(
QRect(QPoint(), outer),
QRect(0, 0, _side, _side)));
QRect(0, 0, side, side)));
}, raw->lifetime());
raw->paintRequest() | rpl::start_with_next([=] {
prepareFrame();
auto p = QPainter(raw);
if (!_framePrepared.isNull()) {
p.drawImage(QRect(0, 0, _side, _side), _framePrepared);
} else {
p.drawImage(raw->rect(), _shadow);
const auto inner = QRect(_extent, _extent, _side, _side);
p.drawImage(inner, _framePrepared);
if (_progress > 0.) {
auto hq = PainterHighQualityEnabler(p);
p.setPen(Qt::NoPen);
p.setBrush(QColor(0, 0, 0));
p.drawEllipse(0, 0, _side, _side);
p.setPen(QPen(
Qt::white,
_progressStroke,
Qt::SolidLine,
Qt::RoundCap));
p.setBrush(Qt::NoBrush);
const auto add = _progressStroke * 3 / 2.;
const auto full = arc::kFullLength;
const auto length = int(base::SafeRound(
_progressAnimation.value(_progress) * full));
p.drawArc(
QRectF(inner).marginsAdded({ add, add, add, add }),
(full / 4) - length,
length);
}
}, raw->lifetime());

View file

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/effects/animations.h"
#include <crl/crl_object_on_queue.h>
namespace Media::Capture {
@ -51,22 +53,29 @@ public:
void hide(Fn<void(RoundVideoResult)> done = nullptr);
using Update = Media::Capture::Update;
[[nodiscard]] rpl::producer<Update, rpl::empty_error> updated() const;
[[nodiscard]] rpl::producer<Update, rpl::empty_error> updated();
private:
class Private;
void setup();
void prepareFrame();
void createImages();
void progressTo(float64 progress);
const RoundVideoRecorderDescriptor _descriptor;
std::unique_ptr<RpWidget> _preview;
crl::object_on_queue<Private> _private;
Ui::Animations::Simple _progressAnimation;
float64 _progress = 0.;
QImage _frameOriginal;
QImage _framePrepared;
QImage _shadow;
int _lastAddedIndex = 0;
int _preparedIndex = 0;
int _side = 0;
int _progressStroke = 0;
int _extent = 0;
bool _paused = false;
};