From 8f42cd9b09533e7a36d35bf6b922a90da44e012e Mon Sep 17 00:00:00 2001 From: RadRussianRus Date: Sun, 11 Sep 2022 03:49:51 +0300 Subject: [PATCH] [Improvement] Allow to copy from bot response and poll solution modals --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/api/api_bot.cpp | 3 +- .../history/view/media/history_view_poll.cpp | 32 ++- .../history/view/media/history_view_poll.h | 2 +- .../kotato/boxes/kotato_confirm_box.cpp | 215 ++++++++++++++++++ .../kotato/boxes/kotato_confirm_box.h | 73 ++++++ 6 files changed, 319 insertions(+), 8 deletions(-) create mode 100644 Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.cpp create mode 100644 Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 84526d572..dc0b55166 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1023,6 +1023,8 @@ PRIVATE iv/iv_delegate_impl.h iv/iv_instance.cpp iv/iv_instance.h + kotato/boxes/kotato_confirm_box.cpp + kotato/boxes/kotato_confirm_box.h kotato/boxes/kotato_fonts_box.cpp kotato/boxes/kotato_fonts_box.h kotato/boxes/kotato_radio_box.cpp diff --git a/Telegram/SourceFiles/api/api_bot.cpp b/Telegram/SourceFiles/api/api_bot.cpp index 862bf5a45..496d8aaf9 100644 --- a/Telegram/SourceFiles/api/api_bot.cpp +++ b/Telegram/SourceFiles/api/api_bot.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/choose_peer_box.h" #include "lang/lang_keys.h" #include "core/core_cloud_password.h" +#include "kotato/boxes/kotato_confirm_box.h" #include "core/click_handler_types.h" #include "data/data_changes.h" #include "data/data_peer.h" @@ -115,7 +116,7 @@ void SendBotCallbackData( if (!show->valid()) { return; } else if (showAlert) { - show->showBox(Ui::MakeInformBox(message)); + show->showBox(Box(message)); } else { if (withPassword) { show->hideLayer(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index 6f924fc2e..a766080c8 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/ripple_animation.h" #include "ui/effects/fireworks_animation.h" #include "ui/toast/toast.h" +#include "kotato/boxes/kotato_confirm_box.h" #include "ui/painter.h" #include "data/data_media_types.h" #include "data/data_poll.h" @@ -454,8 +455,12 @@ void Poll::checkQuizAnswered() { } } -void Poll::showSolution() const { +void Poll::showSolution(bool inBox) const { if (!_poll->solution.text.isEmpty()) { + if (inBox) { + Ui::show(Box(_poll->solution)); + return; + } solutionToggled(true); _parent->delegate()->elementShowTooltip( _poll->solution, @@ -1021,7 +1026,7 @@ void Poll::paintShowSolution( } if (!_showSolutionLink) { _showSolutionLink = std::make_shared( - crl::guard(this, [=] { showSolution(); })); + crl::guard(this, [=] { showSolution(true); })); } const auto stm = context.messageStyle(); const auto &icon = stm->historyQuizExplain; @@ -1176,7 +1181,11 @@ void Poll::paintRadio( auto pen = regular->p; pen.setWidth(radio.thickness); p.setPen(pen); - p.drawEllipse(rect); + if (_flags & PollData::Flag::MultiChoice) { + p.drawRoundedRect(rect, st::buttonRadius, st::buttonRadius); + } else { + p.drawEllipse(rect); + } } if (checkmark > 0.) { const auto removeFull = (radio.diameter / 2 - radio.thickness); @@ -1186,7 +1195,13 @@ void Poll::paintRadio( pen.setWidth(radio.thickness); p.setPen(pen); p.setBrush(color); - p.drawEllipse(rect.marginsRemoved({ removeNow, removeNow, removeNow, removeNow })); + if (_flags & PollData::Flag::MultiChoice) { + p.drawRoundedRect( + rect.marginsRemoved({ removeNow, removeNow, removeNow, removeNow }), + st::buttonRadius, st::buttonRadius); + } else { + p.drawEllipse(rect.marginsRemoved({ removeNow, removeNow, removeNow, removeNow })); + } const auto &icon = stm->historyPollChosen; icon.paint(p, left + (radio.diameter - icon.width()) / 2, top + (radio.diameter - icon.height()) / 2, width()); } @@ -1272,8 +1287,13 @@ void Poll::paintFilling( : stm->historyPollChoiceRight; const auto cleft = aleft - st::historyPollPercentSkip - icon.width(); const auto ctop = ftop - (icon.height() - thickness) / 2; - p.drawEllipse(cleft, ctop, icon.width(), icon.height()); - + if (_flags & PollData::Flag::MultiChoice) { + p.drawRoundedRect( + QRect{ cleft, ctop, icon.width(), icon.height() }, + st::buttonRadius, st::buttonRadius); + } else { + p.drawEllipse(cleft, ctop, icon.width(), icon.height()); + } const auto paintContent = [&](QPainter &p) { icon.paint(p, cleft, ctop, width); }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.h b/Telegram/SourceFiles/history/view/media/history_view_poll.h index ea919b539..51dc4dd61 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.h +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.h @@ -177,7 +177,7 @@ private: void sendMultiOptions(); void showResults(); void checkQuizAnswered(); - void showSolution() const; + void showSolution(bool inBox = false) const; void solutionToggled( bool solutionShown, anim::type animated = anim::type::normal) const; diff --git a/Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.cpp b/Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.cpp new file mode 100644 index 000000000..7f5eeff8e --- /dev/null +++ b/Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.cpp @@ -0,0 +1,215 @@ +/* +This file is part of Kotatogram Desktop, +the unofficial app based on Telegram Desktop. + +For license and copyright information please follow this link: +https://github.com/kotatogram/kotatogram-desktop/blob/dev/LEGAL +*/ +#include "kotato/boxes/kotato_confirm_box.h" + +#include "lang/lang_keys.h" +#include "ui/widgets/labels.h" +#include "styles/style_layers.h" +#include "styles/style_boxes.h" + +namespace Kotato { + +ConfirmBox::ConfirmBox( + QWidget*, + const QString &text, + FnMut confirmedCallback, + FnMut cancelledCallback) +: _confirmText(tr::lng_box_ok(tr::now)) +, _cancelText(tr::lng_cancel(tr::now)) +, _confirmStyle(st::defaultBoxButton) +, _text(this, st::boxLabel) +, _confirmedCallback(std::move(confirmedCallback)) +, _cancelledCallback(std::move(cancelledCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + QWidget*, + const QString &text, + const QString &confirmText, + FnMut confirmedCallback, + FnMut cancelledCallback) +: _confirmText(confirmText) +, _cancelText(tr::lng_cancel(tr::now)) +, _confirmStyle(st::defaultBoxButton) +, _text(this, st::boxLabel) +, _confirmedCallback(std::move(confirmedCallback)) +, _cancelledCallback(std::move(cancelledCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + QWidget*, + const TextWithEntities &text, + const QString &confirmText, + FnMut confirmedCallback, + FnMut cancelledCallback) +: _confirmText(confirmText) +, _cancelText(tr::lng_cancel(tr::now)) +, _confirmStyle(st::defaultBoxButton) +, _text(this, st::boxLabel) +, _confirmedCallback(std::move(confirmedCallback)) +, _cancelledCallback(std::move(cancelledCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + QWidget*, + const QString &text, + const QString &confirmText, + const style::RoundButton &confirmStyle, + FnMut confirmedCallback, + FnMut cancelledCallback) +: _confirmText(confirmText) +, _cancelText(tr::lng_cancel(tr::now)) +, _confirmStyle(confirmStyle) +, _text(this, st::boxLabel) +, _confirmedCallback(std::move(confirmedCallback)) +, _cancelledCallback(std::move(cancelledCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + QWidget*, + const QString &text, + const QString &confirmText, + const QString &cancelText, + FnMut confirmedCallback, + FnMut cancelledCallback) +: _confirmText(confirmText) +, _cancelText(cancelText) +, _confirmStyle(st::defaultBoxButton) +, _text(this, st::boxLabel) +, _confirmedCallback(std::move(confirmedCallback)) +, _cancelledCallback(std::move(cancelledCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + QWidget*, + const QString &text, + const QString &confirmText, + const style::RoundButton &confirmStyle, + const QString &cancelText, + FnMut confirmedCallback, + FnMut cancelledCallback) +: _confirmText(confirmText) +, _cancelText(cancelText) +, _confirmStyle(st::defaultBoxButton) +, _text(this, st::boxLabel) +, _confirmedCallback(std::move(confirmedCallback)) +, _cancelledCallback(std::move(cancelledCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + const InformBoxTag &, + const QString &text, + const QString &doneText, + Fn closedCallback) +: _confirmText(doneText) +, _confirmStyle(st::defaultBoxButton) +, _informative(true) +, _text(this, st::boxLabel) +, _confirmedCallback(generateInformCallback(closedCallback)) +, _cancelledCallback(generateInformCallback(closedCallback)) { + init(text); +} + +ConfirmBox::ConfirmBox( + const InformBoxTag &, + const TextWithEntities &text, + const QString &doneText, + Fn closedCallback) +: _confirmText(doneText) +, _confirmStyle(st::defaultBoxButton) +, _informative(true) +, _text(this, st::boxLabel) +, _confirmedCallback(generateInformCallback(closedCallback)) +, _cancelledCallback(generateInformCallback(closedCallback)) { + init(text); +} + +FnMut ConfirmBox::generateInformCallback( + Fn closedCallback) { + return crl::guard(this, [=] { + closeBox(); + if (closedCallback) { + closedCallback(); + } + }); +} + +void ConfirmBox::init(const QString &text) { + _text->setText(text); +} + +void ConfirmBox::init(const TextWithEntities &text) { + _text->setMarkedText(text); +} + +void ConfirmBox::prepare() { + addButton( + rpl::single(_confirmText), + [=] { confirmed(); }, + _confirmStyle); + if (!_informative) { + addButton( + rpl::single(_cancelText), + [=] { _cancelled = true; closeBox(); }); + } + + boxClosing() | rpl::start_with_next([=] { + if (!_confirmed && (!_strictCancel || _cancelled)) { + if (auto callback = std::move(_cancelledCallback)) { + callback(); + } + } + }, lifetime()); + + _text->setSelectable(true); + _text->setLinksTrusted(); + + setDimensions(st::boxWidth, st::boxPadding.top() + _text->height() + st::boxPadding.bottom()); +} + +void ConfirmBox::resizeEvent(QResizeEvent *e) { + BoxContent::resizeEvent(e); + _text->moveToLeft(st::boxPadding.left(), st::boxPadding.top()); +} + +void ConfirmBox::confirmed() { + if (!_confirmed) { + _confirmed = true; + if (auto callback = std::move(_confirmedCallback)) { + callback(); + } + } +} + +void ConfirmBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + confirmed(); + } else { + BoxContent::keyPressEvent(e); + } +} + +InformBox::InformBox(QWidget*, const QString &text, Fn closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, tr::lng_box_ok(tr::now), std::move(closedCallback)) { +} + +InformBox::InformBox(QWidget*, const QString &text, const QString &doneText, Fn closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) { +} + +InformBox::InformBox(QWidget*, const TextWithEntities &text, Fn closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, tr::lng_box_ok(tr::now), std::move(closedCallback)) { +} + +InformBox::InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) { +} + +} // namespace Kotato \ No newline at end of file diff --git a/Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.h b/Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.h new file mode 100644 index 000000000..f1004b4aa --- /dev/null +++ b/Telegram/SourceFiles/kotato/boxes/kotato_confirm_box.h @@ -0,0 +1,73 @@ +/* +This file is part of Kotatogram Desktop, +the unofficial app based on Telegram Desktop. + +For license and copyright information please follow this link: +https://github.com/kotatogram/kotatogram-desktop/blob/dev/LEGAL +*/ +#pragma once + +#include "boxes/abstract_box.h" + +namespace Ui { +class FlatLabel; +} // namespace Ui + +namespace Kotato { +class InformBox; +class ConfirmBox : public Ui::BoxContent { +public: + ConfirmBox(QWidget*, const QString &text, FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget*, const QString &text, const QString &confirmText, FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget*, const TextWithEntities &text, const QString &confirmText, FnMut confirmedCallback = nullptr, FnMut cancelledCallback = nullptr); + + // If strict cancel is set the cancelledCallback is only called if the cancel button was pressed. + void setStrictCancel(bool strictCancel) { + _strictCancel = strictCancel; + } + +protected: + void prepare() override; + + void resizeEvent(QResizeEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + +private: + struct InformBoxTag { + }; + ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn closedCallback); + ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const QString &doneText, Fn closedCallback); + FnMut generateInformCallback(Fn closedCallback); + friend class InformBox; + + void confirmed(); + void init(const QString &text); + void init(const TextWithEntities &text); + + QString _confirmText; + QString _cancelText; + const style::RoundButton &_confirmStyle; + bool _informative = false; + + object_ptr _text; + + bool _confirmed = false; + bool _cancelled = false; + bool _strictCancel = false; + FnMut _confirmedCallback; + FnMut _cancelledCallback; + +}; + +class InformBox : public ConfirmBox { +public: + InformBox(QWidget*, const QString &text, Fn closedCallback = nullptr); + InformBox(QWidget*, const QString &text, const QString &doneText, Fn closedCallback = nullptr); + InformBox(QWidget*, const TextWithEntities &text, Fn closedCallback = nullptr); + InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn closedCallback = nullptr); + +}; +} // namespace Kotato \ No newline at end of file