Improved VoiceRecordBar support in ComposeControls.

This commit is contained in:
23rd 2020-10-11 21:35:09 +03:00 committed by John Preston
parent 6ed7615653
commit ad4bf9b5c8
7 changed files with 110 additions and 18 deletions

View file

@ -730,6 +730,8 @@ void HistoryWidget::initVoiceRecordBar() {
return _replyToId || (_nonEmptySelection && _list); return _replyToId || (_nonEmptySelection && _list);
}); });
_voiceRecordBar->setSendButtonGeometryValue(_send->geometryValue());
_voiceRecordBar->startRecordingRequests( _voiceRecordBar->startRecordingRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
const auto error = _peer const auto error = _peer

View file

@ -494,7 +494,7 @@ MessageToEdit FieldHeader::queryToEdit() {
} }
ComposeControls::ComposeControls( ComposeControls::ComposeControls(
not_null<QWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<Window::SessionController*> window, not_null<Window::SessionController*> window,
Mode mode) Mode mode)
: _parent(parent) : _parent(parent)
@ -520,6 +520,7 @@ ComposeControls::ComposeControls(
&_window->session().data())) &_window->session().data()))
, _voiceRecordBar(std::make_unique<VoiceRecordBar>( , _voiceRecordBar(std::make_unique<VoiceRecordBar>(
_wrap.get(), _wrap.get(),
parent,
window, window,
_send, _send,
st::historySendSize.height())) st::historySendSize.height()))
@ -671,6 +672,7 @@ void ComposeControls::showFinished() {
_tabbedPanel->hideFast(); _tabbedPanel->hideFast();
} }
updateWrappingVisibility(); updateWrappingVisibility();
_voiceRecordBar->orderControls();
} }
void ComposeControls::showForGrab() { void ComposeControls::showForGrab() {
@ -928,6 +930,30 @@ void ComposeControls::initVoiceRecordBar() {
} }
_voiceRecordBar->startRecording(); _voiceRecordBar->startRecording();
}, _wrap->lifetime()); }, _wrap->lifetime());
{
auto geometry = rpl::merge(
_wrap->geometryValue(),
_send->geometryValue()
) | rpl::map([=](QRect geometry) {
auto r = _send->geometry();
r.setY(r.y() + _wrap->y());
return r;
});
_voiceRecordBar->setSendButtonGeometryValue(std::move(geometry));
}
{
auto bottom = _wrap->geometryValue(
) | rpl::map([=](QRect geometry) {
return geometry.y() - st::historyRecordLockPosition.y();
});
_voiceRecordBar->setLockBottom(std::move(bottom));
}
_voiceRecordBar->setEscFilter([=] {
return (isEditingMessage() || replyingToMessage());
});
} }
void ComposeControls::updateWrappingVisibility() { void ComposeControls::updateWrappingVisibility() {
@ -1311,4 +1337,12 @@ FullMsgId ComposeControls::replyingToMessage() const {
return _header->replyingToMessage(); return _header->replyingToMessage();
} }
bool ComposeControls::isLockPresent() const {
return _voiceRecordBar->isLockPresent();
}
rpl::producer<bool> ComposeControls::lockShowStarts() const {
return _voiceRecordBar->lockShowStarts();
}
} // namespace HistoryView } // namespace HistoryView

View file

@ -78,7 +78,7 @@ public:
}; };
ComposeControls( ComposeControls(
not_null<QWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<Window::SessionController*> window, not_null<Window::SessionController*> window,
Mode mode); Mode mode);
~ComposeControls(); ~ComposeControls();
@ -135,6 +135,9 @@ public:
void clear(); void clear();
void hidePanelsAnimated(); void hidePanelsAnimated();
[[nodiscard]] rpl::producer<bool> lockShowStarts() const;
[[nodiscard]] bool isLockPresent() const;
private: private:
enum class TextUpdateEvent { enum class TextUpdateEvent {
//SaveDraft = (1 << 0), //SaveDraft = (1 << 0),

View file

@ -156,8 +156,15 @@ bool RecordLevel::recordingAnimationCallback(crl::time now) {
} }
void RecordLevel::init() { void RecordLevel::init() {
const auto hasProgress = [](auto value) { return value != 0.; };
// Do not allow the widget to be shown from the outside.
shownValue( shownValue(
) | rpl::start_with_next([=](bool shown) { ) | rpl::start_with_next([=](bool shown) {
const auto shouldShown = hasProgress(_showProgress.current());
if (shown != shouldShown) {
setVisible(shouldShown);
}
}, lifetime()); }, lifetime());
paintRequest( paintRequest(
@ -170,9 +177,7 @@ void RecordLevel::init() {
}, lifetime()); }, lifetime());
_showProgress.changes( _showProgress.changes(
) | rpl::map([](auto value) { ) | rpl::map(hasProgress) | rpl::distinct_until_changed(
return value != 0.;
}) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool show) { ) | rpl::start_with_next([=](bool show) {
setVisible(show); setVisible(show);
setMouseTracking(show); setMouseTracking(show);
@ -395,21 +400,31 @@ rpl::producer<> RecordLock::locks() const {
VoiceRecordBar::VoiceRecordBar( VoiceRecordBar::VoiceRecordBar(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<Ui::RpWidget*> sectionWidget,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
std::shared_ptr<Ui::SendButton> send, std::shared_ptr<Ui::SendButton> send,
int recorderHeight) int recorderHeight)
: RpWidget(parent) : RpWidget(parent)
, _sectionWidget(sectionWidget)
, _controller(controller) , _controller(controller)
, _send(send) , _send(send)
, _lock(std::make_unique<RecordLock>(parent)) , _lock(std::make_unique<RecordLock>(sectionWidget))
, _level(std::make_unique<RecordLevel>( , _level(std::make_unique<RecordLevel>(
parent, sectionWidget,
_controller->widget()->leaveEvents())) _controller->widget()->leaveEvents()))
, _cancelFont(st::historyRecordFont) { , _cancelFont(st::historyRecordFont) {
resize(QSize(parent->width(), recorderHeight)); resize(QSize(parent->width(), recorderHeight));
init(); init();
} }
VoiceRecordBar::VoiceRecordBar(
not_null<Ui::RpWidget*> parent,
not_null<Window::SessionController*> controller,
std::shared_ptr<Ui::SendButton> send,
int recorderHeight)
: VoiceRecordBar(parent, parent, controller, send, recorderHeight) {
}
VoiceRecordBar::~VoiceRecordBar() { VoiceRecordBar::~VoiceRecordBar() {
if (isRecording()) { if (isRecording()) {
stopRecording(false); stopRecording(false);
@ -444,11 +459,6 @@ void VoiceRecordBar::updateLockGeometry() {
_lock->moveToRight(right, _lock->y()); _lock->moveToRight(right, _lock->y());
} }
void VoiceRecordBar::updateLevelGeometry() {
const auto center = (_send->width() - _level->width()) / 2;
_level->moveToRight(st::historySendRight + center, y() + center);
}
void VoiceRecordBar::init() { void VoiceRecordBar::init() {
hide(); hide();
// Keep VoiceRecordBar behind SendButton. // Keep VoiceRecordBar behind SendButton.
@ -459,8 +469,7 @@ void VoiceRecordBar::init() {
return e->type() == QEvent::ZOrderChange; return e->type() == QEvent::ZOrderChange;
}) | rpl::to_empty }) | rpl::to_empty
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
stackUnder(_send.get()); orderControls();
_level->raise();
}, lifetime()); }, lifetime());
sizeValue( sizeValue(
@ -484,7 +493,6 @@ void VoiceRecordBar::init() {
} }
updateMessageGeometry(); updateMessageGeometry();
updateLockGeometry(); updateLockGeometry();
updateLevelGeometry();
}, lifetime()); }, lifetime());
paintRequest( paintRequest(
@ -606,7 +614,16 @@ void VoiceRecordBar::setLockBottom(rpl::producer<int> &&bottom) {
bottom bottom
) | rpl::start_with_next([=](int value) { ) | rpl::start_with_next([=](int value) {
_lock->moveToLeft(_lock->x(), value - _lock->height()); _lock->moveToLeft(_lock->x(), value - _lock->height());
updateLevelGeometry(); }, lifetime());
}
void VoiceRecordBar::setSendButtonGeometryValue(
rpl::producer<QRect> &&geometry) {
std::move(
geometry
) | rpl::start_with_next([=](QRect r) {
const auto center = (r.width() - _level->width()) / 2;
_level->moveToLeft(r.x() + center, r.y() + center);
}, lifetime()); }, lifetime());
} }
@ -660,7 +677,7 @@ void VoiceRecordBar::startRecording() {
? inField ? inField
: _level->inCircle(_level->mapFromGlobal(globalPos)); : _level->inCircle(_level->mapFromGlobal(globalPos));
if (_showLockAnimation.animating()) { if (_showLockAnimation.animating() || !hasDuration()) {
return; return;
} }
computeAndSetLockProgress(mouse->globalPos()); computeAndSetLockProgress(mouse->globalPos());
@ -813,6 +830,10 @@ bool VoiceRecordBar::isTypeRecord() const {
return (_send->type() == Ui::SendButton::Type::Record); return (_send->type() == Ui::SendButton::Type::Record);
} }
bool VoiceRecordBar::hasDuration() const {
return _recordingSamples > 0;
}
float64 VoiceRecordBar::activeAnimationRatio() const { float64 VoiceRecordBar::activeAnimationRatio() const {
return _activeAnimation.value(_inField.current() ? 1. : 0.); return _activeAnimation.value(_inField.current() ? 1. : 0.);
} }
@ -837,6 +858,12 @@ void VoiceRecordBar::computeAndSetLockProgress(QPoint globalPos) {
_lock->requestPaintProgress(std::clamp(progress, 0., 1.)); _lock->requestPaintProgress(std::clamp(progress, 0., 1.));
} }
void VoiceRecordBar::orderControls() {
stackUnder(_send.get());
_level->raise();
_lock->raise();
}
void VoiceRecordBar::installClickOutsideFilter() { void VoiceRecordBar::installClickOutsideFilter() {
const auto box = _recordingLifetime.make_state<QPointer<ConfirmBox>>(); const auto box = _recordingLifetime.make_state<QPointer<ConfirmBox>>();
const auto showBox = [=] { const auto showBox = [=] {

View file

@ -30,6 +30,12 @@ public:
using SendActionUpdate = Controls::SendActionUpdate; using SendActionUpdate = Controls::SendActionUpdate;
using VoiceToSend = Controls::VoiceToSend; using VoiceToSend = Controls::VoiceToSend;
VoiceRecordBar(
not_null<Ui::RpWidget*> parent,
not_null<Ui::RpWidget*> sectionWidget,
not_null<Window::SessionController*> controller,
std::shared_ptr<Ui::SendButton> send,
int recorderHeight);
VoiceRecordBar( VoiceRecordBar(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
@ -40,6 +46,8 @@ public:
void startRecording(); void startRecording();
void finishAnimating(); void finishAnimating();
void orderControls();
[[nodiscard]] rpl::producer<SendActionUpdate> sendActionUpdates() const; [[nodiscard]] rpl::producer<SendActionUpdate> sendActionUpdates() const;
[[nodiscard]] rpl::producer<VoiceToSend> sendVoiceRequests() const; [[nodiscard]] rpl::producer<VoiceToSend> sendVoiceRequests() const;
[[nodiscard]] rpl::producer<bool> recordingStateChanges() const; [[nodiscard]] rpl::producer<bool> recordingStateChanges() const;
@ -47,6 +55,7 @@ public:
[[nodiscard]] rpl::producer<bool> lockShowStarts() const; [[nodiscard]] rpl::producer<bool> lockShowStarts() const;
void setLockBottom(rpl::producer<int> &&bottom); void setLockBottom(rpl::producer<int> &&bottom);
void setSendButtonGeometryValue(rpl::producer<QRect> &&geometry);
void setEscFilter(Fn<bool()> &&callback); void setEscFilter(Fn<bool()> &&callback);
[[nodiscard]] bool isRecording() const; [[nodiscard]] bool isRecording() const;
@ -57,7 +66,6 @@ private:
void updateMessageGeometry(); void updateMessageGeometry();
void updateLockGeometry(); void updateLockGeometry();
void updateLevelGeometry();
void recordError(); void recordError();
void recordUpdated(quint16 level, int samples); void recordUpdated(quint16 level, int samples);
@ -78,6 +86,7 @@ private:
void installClickOutsideFilter(); void installClickOutsideFilter();
bool isTypeRecord() const; bool isTypeRecord() const;
bool hasDuration() const;
void activeAnimate(bool active); void activeAnimate(bool active);
float64 showAnimationRatio() const; float64 showAnimationRatio() const;
@ -87,6 +96,7 @@ private:
QString cancelMessage() const; QString cancelMessage() const;
const not_null<Ui::RpWidget*> _sectionWidget;
const not_null<Window::SessionController*> _controller; const not_null<Window::SessionController*> _controller;
const std::shared_ptr<Ui::SendButton> _send; const std::shared_ptr<Ui::SendButton> _send;
const std::unique_ptr<RecordLock> _lock; const std::unique_ptr<RecordLock> _lock;

View file

@ -507,6 +507,11 @@ void RepliesWidget::setupComposeControls() {
Unexpected("action in MimeData hook."); Unexpected("action in MimeData hook.");
}); });
_composeControls->lockShowStarts(
) | rpl::start_with_next([=] {
updateScrollDownVisibility();
}, lifetime());
_composeControls->finishAnimating(); _composeControls->finishAnimating();
} }
@ -1213,6 +1218,9 @@ void RepliesWidget::updateScrollDownVisibility() {
} }
const auto scrollDownIsVisible = [&]() -> std::optional<bool> { const auto scrollDownIsVisible = [&]() -> std::optional<bool> {
if (_composeControls->isLockPresent()) {
return false;
}
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
if (top < _scroll->scrollTopMax() || _replyReturn) { if (top < _scroll->scrollTopMax() || _replyReturn) {
return true; return true;

View file

@ -253,6 +253,11 @@ void ScheduledWidget::setupComposeControls() {
} }
Unexpected("action in MimeData hook."); Unexpected("action in MimeData hook.");
}); });
_composeControls->lockShowStarts(
) | rpl::start_with_next([=] {
updateScrollDownVisibility();
}, lifetime());
} }
void ScheduledWidget::chooseAttach() { void ScheduledWidget::chooseAttach() {
@ -820,6 +825,9 @@ void ScheduledWidget::updateScrollDownVisibility() {
} }
const auto scrollDownIsVisible = [&]() -> std::optional<bool> { const auto scrollDownIsVisible = [&]() -> std::optional<bool> {
if (_composeControls->isLockPresent()) {
return false;
}
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
if (top < _scroll->scrollTopMax()) { if (top < _scroll->scrollTopMax()) {
return true; return true;