From bb64285c3ac4c32acdf0a60d8a75bd64cc06de7f Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 24 Jan 2020 17:45:05 +0300 Subject: [PATCH] Always show Create button, show error messages. Fixes #7058, fixes #7059. --- Telegram/Resources/langs/lang.strings | 3 + .../SourceFiles/boxes/create_poll_box.cpp | 113 +++++++++++------- Telegram/SourceFiles/boxes/create_poll_box.h | 10 ++ 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f37d4c4e02..49d1973684 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2204,6 +2204,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_polls_create_multiple_choice" = "Multiple Answers"; "lng_polls_create_quiz_mode" = "Quiz Mode"; "lng_polls_create_button" = "Create"; +"lng_polls_choose_question" = "Please enter a question."; +"lng_polls_choose_answers" = "Please enter at least two options."; +"lng_polls_choose_correct" = "Please choose the correct answer."; "lng_polls_poll_results_title" = "Poll results"; "lng_polls_quiz_results_title" = "Quiz results"; diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp index 1d9b433bfe..a8b3f3d186 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.cpp +++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp @@ -48,8 +48,9 @@ public: not_null session, bool chooseCorrectEnabled); + [[nodiscard]] bool hasOptions() const; [[nodiscard]] bool isValid() const; - [[nodiscard]] rpl::producer isValidChanged() const; + [[nodiscard]] bool hasCorrect() const; [[nodiscard]] std::vector toPollAnswers() const; void focusFirst(); @@ -139,8 +140,10 @@ private: int _position = 0; std::vector> _list; std::vector> _destroyed; - rpl::variable _valid = false; rpl::variable _usedCount = 0; + bool _hasOptions = false; + bool _isValid = false; + bool _hasCorrect = false; rpl::event_stream> _scrollToWidget; rpl::event_stream<> _backspaceInFront; @@ -470,12 +473,16 @@ bool Options::full() const { return (_list.size() == kMaxOptionsCount); } -bool Options::isValid() const { - return _valid.current(); +bool Options::hasOptions() const { + return _hasOptions; } -rpl::producer Options::isValidChanged() const { - return _valid.changes(); +bool Options::isValid() const { + return _isValid; +} + +bool Options::hasCorrect() const { + return _hasCorrect; } rpl::producer Options::usedCount() const { @@ -696,10 +703,11 @@ void Options::removeDestroyed(not_null option) { void Options::validateState() { checkLastOption(); - _valid = (ranges::count_if(_list, &Option::isGood) > 1) - && (ranges::find_if(_list, &Option::isTooLong) == end(_list)) - && (!_chooseCorrectGroup - || ranges::find_if(_list, &Option::isCorrect) != end(_list)); + _hasOptions = (ranges::count_if(_list, &Option::isGood) > 1); + _isValid = _hasOptions + && (ranges::find_if(_list, &Option::isTooLong) == end(_list)); + _hasCorrect = ranges::find_if(_list, &Option::isCorrect) != end(_list); + const auto lastEmpty = !_list.empty() && _list.back()->isEmpty(); _usedCount = _list.size() - (lastEmpty ? 1 : 0); } @@ -789,7 +797,7 @@ object_ptr CreatePollBox::setupContent() { using namespace Settings; const auto id = rand_value(); - const auto valid = lifetime().make_state>(); + const auto error = lifetime().make_state(Error::Question); auto result = object_ptr(this); const auto container = result.data(); @@ -910,8 +918,41 @@ object_ptr CreatePollBox::setupContent() { | (quiz->checked() ? Flag::Quiz : Flag(0))); return result; }; - const auto send = [=](Api::SendOptions options) { - _submitRequests.fire({ collectResult(), options }); + const auto collectError = [=] { + if (isValidQuestion()) { + *error &= ~Error::Question; + } else { + *error |= Error::Question; + } + if (!options->hasOptions()) { + *error |= Error::Options; + } else if (!options->isValid()) { + *error |= Error::Other; + } else { + *error &= ~(Error::Options | Error::Other); + } + if (quiz->checked() && !options->hasCorrect()) { + *error |= Error::Correct; + } else { + *error &= ~Error::Correct; + } + }; + const auto showError = [=](const QString &text) { + Ui::Toast::Show(text); + }; + const auto send = [=](Api::SendOptions sendOptions) { + collectError(); + if (*error & Error::Question) { + showError(tr::lng_polls_choose_question(tr::now)); + question->setFocus(); + } else if (*error & Error::Options) { + showError(tr::lng_polls_choose_answers(tr::now)); + options->focusFirst(); + } else if (*error & Error::Correct) { + showError(tr::lng_polls_choose_correct(tr::now)); + } else if (!*error) { + _submitRequests.fire({ collectResult(), sendOptions }); + } }; const auto sendSilent = [=] { auto options = Api::SendOptions(); @@ -926,36 +967,6 @@ object_ptr CreatePollBox::setupContent() { send), Ui::LayerOption::KeepOther); }; - const auto updateValid = [=] { - valid->fire(isValidQuestion() && options->isValid()); - }; - connect(question, &Ui::InputField::changed, [=] { - updateValid(); - }); - valid->events_starting_with( - false - ) | rpl::distinct_until_changed( - ) | rpl::start_with_next([=](bool valid) { - clearButtons(); - if (valid) { - const auto submit = addButton( - tr::lng_polls_create_button(), - [=] { send({}); }); - if (_sendType == Api::SendType::Normal) { - SetupSendMenuAndShortcuts( - submit.data(), - [=] { return SendMenuType::Scheduled; }, - sendSilent, - sendScheduled); - } - } - addButton(tr::lng_cancel(), [=] { closeBox(); }); - }, lifetime()); - - options->isValidChanged( - ) | rpl::start_with_next([=] { - updateValid(); - }, lifetime()); options->scrollToWidget( ) | rpl::start_with_next([=](not_null widget) { @@ -967,6 +978,22 @@ object_ptr CreatePollBox::setupContent() { FocusAtEnd(question); }, lifetime()); + const auto submit = addButton( + tr::lng_polls_create_button(), + [=] { send({}); }); + if (_sendType == Api::SendType::Normal) { + const auto sendMenuType = [=] { + collectError(); + return *error ? SendMenuType::Disabled : SendMenuType::Scheduled; + }; + SetupSendMenuAndShortcuts( + submit.data(), + sendMenuType, + sendSilent, + sendScheduled); + } + addButton(tr::lng_cancel(), [=] { closeBox(); }); + return result; } diff --git a/Telegram/SourceFiles/boxes/create_poll_box.h b/Telegram/SourceFiles/boxes/create_poll_box.h index e1c5c0760c..f05b1dce1e 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.h +++ b/Telegram/SourceFiles/boxes/create_poll_box.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/abstract_box.h" #include "api/api_common.h" #include "data/data_poll.h" +#include "base/flags.h" struct PollData; @@ -44,6 +45,15 @@ protected: void prepare() override; private: + enum class Error { + Question = 0x01, + Options = 0x02, + Correct = 0x04, + Other = 0x08, + }; + friend constexpr inline bool is_flag_type(Error) { return true; } + using Errors = base::flags; + object_ptr setupContent(); not_null setupQuestion( not_null container);