Added ability to use application while recording voice message.

This commit is contained in:
23rd 2020-12-13 18:58:42 +03:00 committed by John Preston
parent dc7a754418
commit 77775b5f7c
5 changed files with 36 additions and 112 deletions

View file

@ -1345,6 +1345,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_record_cancel" = "Release outside this field to cancel"; "lng_record_cancel" = "Release outside this field to cancel";
"lng_record_lock_cancel" = "Click outside of the circle to cancel"; "lng_record_lock_cancel" = "Click outside of the circle to cancel";
"lng_record_lock_cancel_sure" = "Are you sure you want to stop recording and discard your voice message?"; "lng_record_lock_cancel_sure" = "Are you sure you want to stop recording and discard your voice message?";
"lng_record_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?";
"lng_record_lock_discard" = "Discard"; "lng_record_lock_discard" = "Discard";
"lng_will_be_notified" = "Members will be notified when you post"; "lng_will_be_notified" = "Members will be notified when you post";
"lng_wont_be_notified" = "Members will not be notified when you post"; "lng_wont_be_notified" = "Members will not be notified when you post";

View file

@ -757,9 +757,6 @@ void HistoryWidget::initVoiceRecordBar() {
}); });
_voiceRecordBar->setLockBottom(std::move(scrollHeight)); _voiceRecordBar->setLockBottom(std::move(scrollHeight));
} }
_voiceRecordBar->setEscFilter([=]() -> bool {
return _replyToId || (_nonEmptySelection && _list);
});
_voiceRecordBar->setSendButtonGeometryValue(_send->geometryValue()); _voiceRecordBar->setSendButtonGeometryValue(_send->geometryValue());
@ -1629,7 +1626,7 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
? _history->localEditDraft() ? _history->localEditDraft()
: _history->localDraft(); : _history->localDraft();
auto fieldAvailable = canWriteMessage() auto fieldAvailable = canWriteMessage()
&& !_voiceRecordBar->preventDraftApply(); && !_voiceRecordBar->isActive();
if (!draft || (!_history->localEditDraft() && !fieldAvailable)) { if (!draft || (!_history->localEditDraft() && !fieldAvailable)) {
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0); auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
clearFieldText(0, fieldHistoryAction); clearFieldText(0, fieldHistoryAction);
@ -3099,7 +3096,7 @@ void HistoryWidget::send(Api::SendOptions options) {
return; return;
} }
if (_voiceRecordBar && _voiceRecordBar->isListenState()) { if (_voiceRecordBar->isListenState()) {
_voiceRecordBar->requestToSendWithOptions(options); _voiceRecordBar->requestToSendWithOptions(options);
return; return;
} }
@ -3915,8 +3912,8 @@ void HistoryWidget::setTabbedPanel(std::unique_ptr<TabbedPanel> panel) {
} }
bool HistoryWidget::preventsClose(Fn<void()> &&continueCallback) const { bool HistoryWidget::preventsClose(Fn<void()> &&continueCallback) const {
if (isRecording()) { if (_voiceRecordBar->isActive()) {
_voiceRecordBar->showDiscardRecordingBox(std::move(continueCallback)); _voiceRecordBar->showDiscardBox(std::move(continueCallback));
return true; return true;
} }
return false; return false;
@ -5648,7 +5645,7 @@ void HistoryWidget::editMessage(FullMsgId itemId) {
} }
void HistoryWidget::editMessage(not_null<HistoryItem*> item) { void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
if (_voiceRecordBar && _voiceRecordBar->isListenState()) { if (_voiceRecordBar->isListenState()) {
Ui::show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now))); Ui::show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
return; return;
} }
@ -6122,6 +6119,8 @@ void HistoryWidget::escape() {
_fieldAutocomplete->hideAnimated(); _fieldAutocomplete->hideAnimated();
} else if (_replyToId && _field->getTextWithTags().text.isEmpty()) { } else if (_replyToId && _field->getTextWithTags().text.isEmpty()) {
cancelReply(); cancelReply();
} else if (auto &voice = _voiceRecordBar; voice->isActive()) {
voice->showDiscardBox(nullptr, anim::type::normal);
} else { } else {
_cancelRequests.fire({}); _cancelRequests.fire({});
} }

View file

@ -1567,10 +1567,6 @@ void ComposeControls::initVoiceRecordBar() {
_voiceRecordBar->setLockBottom(std::move(bottom)); _voiceRecordBar->setLockBottom(std::move(bottom));
} }
_voiceRecordBar->setEscFilter([=] {
return (isEditingMessage() || replyingToMessage());
});
_voiceRecordBar->updateSendButtonTypeRequests( _voiceRecordBar->updateSendButtonTypeRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
updateSendButtonType(); updateSendButtonType();
@ -1716,7 +1712,11 @@ void ComposeControls::paintBackground(QRect clip) {
} }
void ComposeControls::escape() { void ComposeControls::escape() {
_cancelRequests.fire({}); if (auto &voice = _voiceRecordBar; !voice->isActive()) {
voice->showDiscardBox(nullptr, anim::type::normal);
} else {
_cancelRequests.fire({});
}
} }
bool ComposeControls::pushTabbedSelectorToThirdSection( bool ComposeControls::pushTabbedSelectorToThirdSection(
@ -2139,8 +2139,8 @@ bool ComposeControls::isRecording() const {
} }
bool ComposeControls::preventsClose(Fn<void()> &&continueCallback) const { bool ComposeControls::preventsClose(Fn<void()> &&continueCallback) const {
if (isRecording()) { if (_voiceRecordBar->isActive()) {
_voiceRecordBar->showDiscardRecordingBox(std::move(continueCallback)); _voiceRecordBar->showDiscardBox(std::move(continueCallback));
return true; return true;
} }
return false; return false;

View file

@ -1070,7 +1070,6 @@ void VoiceRecordBar::init() {
_lock->locks( _lock->locks(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
installClickOutsideFilter();
_level->setType(VoiceRecordButton::Type::Send); _level->setType(VoiceRecordButton::Type::Send);
_level->clicks( _level->clicks(
@ -1173,10 +1172,6 @@ void VoiceRecordBar::visibilityAnimate(bool show, Fn<void()> &&callback) {
_showAnimation.start(std::move(animationCallback), from, to, duration); _showAnimation.start(std::move(animationCallback), from, to, duration);
} }
void VoiceRecordBar::setEscFilter(Fn<bool()> &&callback) {
_escFilter = std::move(callback);
}
void VoiceRecordBar::setStartRecordingFilter(Fn<bool()> &&callback) { void VoiceRecordBar::setStartRecordingFilter(Fn<bool()> &&callback) {
_startRecordingFilter = std::move(callback); _startRecordingFilter = std::move(callback);
} }
@ -1227,6 +1222,9 @@ void VoiceRecordBar::startRecording() {
}, [=] { }, [=] {
stop(false); stop(false);
}, _recordingLifetime); }, _recordingLifetime);
_recordingLifetime.add([=] {
_recording = false;
});
}; };
visibilityAnimate(true, std::move(appearanceCallback)); visibilityAnimate(true, std::move(appearanceCallback));
show(); show();
@ -1287,7 +1285,6 @@ void VoiceRecordBar::stop(bool send) {
void VoiceRecordBar::finish() { void VoiceRecordBar::finish() {
_recordingLifetime.destroy(); _recordingLifetime.destroy();
_lockShowing = false; _lockShowing = false;
_recording = false;
_inField = false; _inField = false;
_redCircleProgress = 0.; _redCircleProgress = 0.;
_recordingSamples = 0; _recordingSamples = 0;
@ -1411,7 +1408,7 @@ bool VoiceRecordBar::isRecording() const {
return _recording.current(); return _recording.current();
} }
bool VoiceRecordBar::preventDraftApply() const { bool VoiceRecordBar::isActive() const {
return isRecording() || isListenState(); return isRecording() || isListenState();
} }
@ -1419,7 +1416,7 @@ void VoiceRecordBar::hideAnimated() {
if (isHidden()) { if (isHidden()) {
return; return;
} }
visibilityAnimate(false, [=] { hide(); }); visibilityAnimate(false, [=] { hideFast(); });
} }
void VoiceRecordBar::finishAnimating() { void VoiceRecordBar::finishAnimating() {
@ -1494,77 +1491,6 @@ void VoiceRecordBar::orderControls() {
_lock->raise(); _lock->raise();
} }
void VoiceRecordBar::installClickOutsideFilter() {
const auto box = _recordingLifetime.make_state<QPointer<ConfirmBox>>();
const auto showBox = [=] {
if (*box) {
return;
}
auto sure = [=](Fn<void()> &&close) {
stop(false);
close();
};
*box = Ui::show(Box<ConfirmBox>(
tr::lng_record_lock_cancel_sure(tr::now),
tr::lng_record_lock_discard(tr::now),
st::attentionBoxButton,
std::move(sure)));
};
const auto computeResult = [=](not_null<QEvent*> e) {
using Type = FilterType;
if (!_lock->isLocked()) {
return Type::Continue;
}
const auto type = e->type();
const auto noBox = !(*box);
if (type == QEvent::KeyPress) {
const auto key = static_cast<QKeyEvent*>(e.get())->key();
const auto isEsc = (key == Qt::Key_Escape);
const auto isEnter = (key == Qt::Key_Enter
|| key == Qt::Key_Return);
if (noBox) {
if (isEnter) {
stop(true);
return Type::Cancel;
} else if (isEsc && (_escFilter && _escFilter())) {
return Type::Continue;
}
return Type::ShowBox;
}
return (isEsc || isEnter) ? Type::Continue : Type::ShowBox;
} else if (type == QEvent::ContextMenu || type == QEvent::Shortcut) {
return Type::ShowBox;
} else if (type == QEvent::MouseButtonPress) {
return Type::Continue;
// return (noBox && !_inField.current() && !_lock->underMouse())
// ? Type::ShowBox
// : Type::Continue;
}
return Type::Continue;
};
auto filterCallback = [=](not_null<QEvent*> e) {
using Result = base::EventFilterResult;
switch(computeResult(e)) {
case FilterType::ShowBox: {
showBox();
return Result::Cancel;
}
case FilterType::Continue: return Result::Continue;
case FilterType::Cancel: return Result::Cancel;
default: return Result::Continue;
}
};
auto filter = base::install_event_filter(
QCoreApplication::instance(),
std::move(filterCallback));
_recordingLifetime.make_state<base::unique_qptr<QObject>>(
std::move(filter));
}
void VoiceRecordBar::installListenStateFilter() { void VoiceRecordBar::installListenStateFilter() {
auto keyFilterCallback = [=](not_null<QEvent*> e) { auto keyFilterCallback = [=](not_null<QEvent*> e) {
using Result = base::EventFilterResult; using Result = base::EventFilterResult;
@ -1577,7 +1503,6 @@ void VoiceRecordBar::installListenStateFilter() {
const auto keyEvent = static_cast<QKeyEvent*>(e.get()); const auto keyEvent = static_cast<QKeyEvent*>(e.get());
const auto key = keyEvent->key(); const auto key = keyEvent->key();
const auto isSpace = (key == Qt::Key_Space); const auto isSpace = (key == Qt::Key_Space);
const auto isEsc = (key == Qt::Key_Escape);
const auto isEnter = (key == Qt::Key_Enter const auto isEnter = (key == Qt::Key_Enter
|| key == Qt::Key_Return); || key == Qt::Key_Return);
if (isSpace && !keyEvent->isAutoRepeat() && _listen) { if (isSpace && !keyEvent->isAutoRepeat() && _listen) {
@ -1588,14 +1513,6 @@ void VoiceRecordBar::installListenStateFilter() {
requestToSendWithOptions({}); requestToSendWithOptions({});
return Result::Cancel; return Result::Cancel;
} }
if (isEsc) {
if (_escFilter && _escFilter()) {
return Result::Continue;
} else {
hideAnimated();
return Result::Cancel;
}
}
return Result::Continue; return Result::Continue;
} }
default: return Result::Continue; default: return Result::Continue;
@ -1610,19 +1527,27 @@ void VoiceRecordBar::installListenStateFilter() {
std::move(keyFilter)); std::move(keyFilter));
} }
void VoiceRecordBar::showDiscardRecordingBox(Fn<void()> &&callback) { void VoiceRecordBar::showDiscardBox(
if (!isRecording()) { Fn<void()> &&callback,
anim::type animated) {
if (!isActive()) {
return; return;
} }
auto sure = [=, callback = std::move(callback)](Fn<void()> &&close) { auto sure = [=, callback = std::move(callback)](Fn<void()> &&close) {
hideFast(); if (animated == anim::type::instant) {
hideFast();
} else {
hideAnimated();
}
close(); close();
if (callback) { if (callback) {
callback(); callback();
} }
}; };
Ui::show(Box<ConfirmBox>( Ui::show(Box<ConfirmBox>(
tr::lng_record_lock_cancel_sure(tr::now), (isListenState()
? tr::lng_record_listen_cancel_sure
: tr::lng_record_lock_cancel_sure)(tr::now),
tr::lng_record_lock_discard(tr::now), tr::lng_record_lock_discard(tr::now),
st::attentionBoxButton, st::attentionBoxButton,
std::move(sure))); std::move(sure)));

View file

@ -47,7 +47,9 @@ public:
int recorderHeight); int recorderHeight);
~VoiceRecordBar(); ~VoiceRecordBar();
void showDiscardRecordingBox(Fn<void()> &&callback); void showDiscardBox(
Fn<void()> &&callback,
anim::type animated = anim::type::instant);
void startRecording(); void startRecording();
void finishAnimating(); void finishAnimating();
@ -68,13 +70,12 @@ public:
void setLockBottom(rpl::producer<int> &&bottom); void setLockBottom(rpl::producer<int> &&bottom);
void setSendButtonGeometryValue(rpl::producer<QRect> &&geometry); void setSendButtonGeometryValue(rpl::producer<QRect> &&geometry);
void setEscFilter(Fn<bool()> &&callback);
void setStartRecordingFilter(Fn<bool()> &&callback); void setStartRecordingFilter(Fn<bool()> &&callback);
[[nodiscard]] bool isRecording() const; [[nodiscard]] bool isRecording() const;
[[nodiscard]] bool isLockPresent() const; [[nodiscard]] bool isLockPresent() const;
[[nodiscard]] bool isListenState() const; [[nodiscard]] bool isListenState() const;
[[nodiscard]] bool preventDraftApply() const; [[nodiscard]] bool isActive() const;
private: private:
enum class StopType { enum class StopType {
@ -102,7 +103,6 @@ private:
void drawMessage(Painter &p, float64 recordActive); void drawMessage(Painter &p, float64 recordActive);
void startRedCircleAnimation(); void startRedCircleAnimation();
void installClickOutsideFilter();
void installListenStateFilter(); void installListenStateFilter();
bool isTypeRecord() const; bool isTypeRecord() const;
@ -137,7 +137,6 @@ private:
Ui::Text::String _message; Ui::Text::String _message;
Fn<bool()> _escFilter;
Fn<bool()> _startRecordingFilter; Fn<bool()> _startRecordingFilter;
rpl::variable<bool> _recording = false; rpl::variable<bool> _recording = false;