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_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_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?";
"lng_record_lock_discard" = "Discard";
"lng_will_be_notified" = "Members will 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->setEscFilter([=]() -> bool {
return _replyToId || (_nonEmptySelection && _list);
});
_voiceRecordBar->setSendButtonGeometryValue(_send->geometryValue());
@ -1629,7 +1626,7 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
? _history->localEditDraft()
: _history->localDraft();
auto fieldAvailable = canWriteMessage()
&& !_voiceRecordBar->preventDraftApply();
&& !_voiceRecordBar->isActive();
if (!draft || (!_history->localEditDraft() && !fieldAvailable)) {
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
clearFieldText(0, fieldHistoryAction);
@ -3099,7 +3096,7 @@ void HistoryWidget::send(Api::SendOptions options) {
return;
}
if (_voiceRecordBar && _voiceRecordBar->isListenState()) {
if (_voiceRecordBar->isListenState()) {
_voiceRecordBar->requestToSendWithOptions(options);
return;
}
@ -3915,8 +3912,8 @@ void HistoryWidget::setTabbedPanel(std::unique_ptr<TabbedPanel> panel) {
}
bool HistoryWidget::preventsClose(Fn<void()> &&continueCallback) const {
if (isRecording()) {
_voiceRecordBar->showDiscardRecordingBox(std::move(continueCallback));
if (_voiceRecordBar->isActive()) {
_voiceRecordBar->showDiscardBox(std::move(continueCallback));
return true;
}
return false;
@ -5648,7 +5645,7 @@ void HistoryWidget::editMessage(FullMsgId itemId) {
}
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)));
return;
}
@ -6122,6 +6119,8 @@ void HistoryWidget::escape() {
_fieldAutocomplete->hideAnimated();
} else if (_replyToId && _field->getTextWithTags().text.isEmpty()) {
cancelReply();
} else if (auto &voice = _voiceRecordBar; voice->isActive()) {
voice->showDiscardBox(nullptr, anim::type::normal);
} else {
_cancelRequests.fire({});
}

View File

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

View File

@ -1070,7 +1070,6 @@ void VoiceRecordBar::init() {
_lock->locks(
) | rpl::start_with_next([=] {
installClickOutsideFilter();
_level->setType(VoiceRecordButton::Type::Send);
_level->clicks(
@ -1173,10 +1172,6 @@ void VoiceRecordBar::visibilityAnimate(bool show, Fn<void()> &&callback) {
_showAnimation.start(std::move(animationCallback), from, to, duration);
}
void VoiceRecordBar::setEscFilter(Fn<bool()> &&callback) {
_escFilter = std::move(callback);
}
void VoiceRecordBar::setStartRecordingFilter(Fn<bool()> &&callback) {
_startRecordingFilter = std::move(callback);
}
@ -1227,6 +1222,9 @@ void VoiceRecordBar::startRecording() {
}, [=] {
stop(false);
}, _recordingLifetime);
_recordingLifetime.add([=] {
_recording = false;
});
};
visibilityAnimate(true, std::move(appearanceCallback));
show();
@ -1287,7 +1285,6 @@ void VoiceRecordBar::stop(bool send) {
void VoiceRecordBar::finish() {
_recordingLifetime.destroy();
_lockShowing = false;
_recording = false;
_inField = false;
_redCircleProgress = 0.;
_recordingSamples = 0;
@ -1411,7 +1408,7 @@ bool VoiceRecordBar::isRecording() const {
return _recording.current();
}
bool VoiceRecordBar::preventDraftApply() const {
bool VoiceRecordBar::isActive() const {
return isRecording() || isListenState();
}
@ -1419,7 +1416,7 @@ void VoiceRecordBar::hideAnimated() {
if (isHidden()) {
return;
}
visibilityAnimate(false, [=] { hide(); });
visibilityAnimate(false, [=] { hideFast(); });
}
void VoiceRecordBar::finishAnimating() {
@ -1494,77 +1491,6 @@ void VoiceRecordBar::orderControls() {
_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() {
auto keyFilterCallback = [=](not_null<QEvent*> e) {
using Result = base::EventFilterResult;
@ -1577,7 +1503,6 @@ void VoiceRecordBar::installListenStateFilter() {
const auto keyEvent = static_cast<QKeyEvent*>(e.get());
const auto key = keyEvent->key();
const auto isSpace = (key == Qt::Key_Space);
const auto isEsc = (key == Qt::Key_Escape);
const auto isEnter = (key == Qt::Key_Enter
|| key == Qt::Key_Return);
if (isSpace && !keyEvent->isAutoRepeat() && _listen) {
@ -1588,14 +1513,6 @@ void VoiceRecordBar::installListenStateFilter() {
requestToSendWithOptions({});
return Result::Cancel;
}
if (isEsc) {
if (_escFilter && _escFilter()) {
return Result::Continue;
} else {
hideAnimated();
return Result::Cancel;
}
}
return Result::Continue;
}
default: return Result::Continue;
@ -1610,19 +1527,27 @@ void VoiceRecordBar::installListenStateFilter() {
std::move(keyFilter));
}
void VoiceRecordBar::showDiscardRecordingBox(Fn<void()> &&callback) {
if (!isRecording()) {
void VoiceRecordBar::showDiscardBox(
Fn<void()> &&callback,
anim::type animated) {
if (!isActive()) {
return;
}
auto sure = [=, callback = std::move(callback)](Fn<void()> &&close) {
hideFast();
if (animated == anim::type::instant) {
hideFast();
} else {
hideAnimated();
}
close();
if (callback) {
callback();
}
};
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),
st::attentionBoxButton,
std::move(sure)));

View File

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