diff --git a/Telegram/SourceFiles/data/business/data_business_chatbots.cpp b/Telegram/SourceFiles/data/business/data_business_chatbots.cpp index 26dd216870..89215a2e00 100644 --- a/Telegram/SourceFiles/data/business/data_business_chatbots.cpp +++ b/Telegram/SourceFiles/data/business/data_business_chatbots.cpp @@ -27,7 +27,7 @@ rpl::producer Chatbots::value() const { return _settings.value(); } -void Chatbots::save(ChatbotsSettings settings) { +void Chatbots::save(ChatbotsSettings settings, Fn fail) { _settings = settings; } diff --git a/Telegram/SourceFiles/data/business/data_business_chatbots.h b/Telegram/SourceFiles/data/business/data_business_chatbots.h index 13b8a894bd..da088c394b 100644 --- a/Telegram/SourceFiles/data/business/data_business_chatbots.h +++ b/Telegram/SourceFiles/data/business/data_business_chatbots.h @@ -30,7 +30,7 @@ public: [[nodiscard]] rpl::producer changes() const; [[nodiscard]] rpl::producer value() const; - void save(ChatbotsSettings settings); + void save(ChatbotsSettings settings, Fn fail); private: const not_null _session; diff --git a/Telegram/SourceFiles/data/business/data_business_info.cpp b/Telegram/SourceFiles/data/business/data_business_info.cpp index bd75f4af73..43ef345e69 100644 --- a/Telegram/SourceFiles/data/business/data_business_info.cpp +++ b/Telegram/SourceFiles/data/business/data_business_info.cpp @@ -118,20 +118,31 @@ BusinessInfo::BusinessInfo(not_null owner) BusinessInfo::~BusinessInfo() = default; -void BusinessInfo::saveWorkingHours(WorkingHours data) { - auto details = _owner->session().user()->businessDetails(); - if (details.hours == data) { +void BusinessInfo::saveWorkingHours( + WorkingHours data, + Fn fail) { + const auto session = &_owner->session(); + auto details = session->user()->businessDetails(); + const auto &was = details.hours; + if (was == data) { return; } using Flag = MTPaccount_UpdateBusinessWorkHours::Flag; - _owner->session().api().request(MTPaccount_UpdateBusinessWorkHours( + session->api().request(MTPaccount_UpdateBusinessWorkHours( MTP_flags(data ? Flag::f_business_work_hours : Flag()), ToMTP(data) - )).send(); + )).fail([=](const MTP::Error &error) { + auto details = session->user()->businessDetails(); + details.hours = was; + session->user()->setBusinessDetails(std::move(details)); + if (fail) { + fail(error.type()); + } + }).send(); details.hours = std::move(data); - _owner->session().user()->setBusinessDetails(std::move(details)); + session->user()->setBusinessDetails(std::move(details)); } void BusinessInfo::applyAwaySettings(AwaySettings data) { @@ -142,15 +153,25 @@ void BusinessInfo::applyAwaySettings(AwaySettings data) { _awaySettingsChanged.fire({}); } -void BusinessInfo::saveAwaySettings(AwaySettings data) { - if (_awaySettings == data) { +void BusinessInfo::saveAwaySettings( + AwaySettings data, + Fn fail) { + const auto &was = _awaySettings; + if (was == data) { return; } using Flag = MTPaccount_UpdateBusinessAwayMessage::Flag; - _owner->session().api().request(MTPaccount_UpdateBusinessAwayMessage( + const auto session = &_owner->session(); + session->api().request(MTPaccount_UpdateBusinessAwayMessage( MTP_flags(data ? Flag::f_message : Flag()), data ? ToMTP(data) : MTPInputBusinessAwayMessage() - )).send(); + )).fail([=](const MTP::Error &error) { + _awaySettings = was; + _awaySettingsChanged.fire({}); + if (fail) { + fail(error.type()); + } + }).send(); _awaySettings = std::move(data); _awaySettingsChanged.fire({}); @@ -176,15 +197,25 @@ void BusinessInfo::applyGreetingSettings(GreetingSettings data) { _greetingSettingsChanged.fire({}); } -void BusinessInfo::saveGreetingSettings(GreetingSettings data) { - if (_greetingSettings == data) { +void BusinessInfo::saveGreetingSettings( + GreetingSettings data, + Fn fail) { + const auto &was = _greetingSettings; + if (was == data) { return; } using Flag = MTPaccount_UpdateBusinessGreetingMessage::Flag; - _owner->session().api().request(MTPaccount_UpdateBusinessGreetingMessage( - MTP_flags(data ? Flag::f_message : Flag()), - data ? ToMTP(data) : MTPInputBusinessGreetingMessage() - )).send(); + _owner->session().api().request( + MTPaccount_UpdateBusinessGreetingMessage( + MTP_flags(data ? Flag::f_message : Flag()), + data ? ToMTP(data) : MTPInputBusinessGreetingMessage()) + ).fail([=](const MTP::Error &error) { + _greetingSettings = was; + _greetingSettingsChanged.fire({}); + if (fail) { + fail(error.type()); + } + }).send(); _greetingSettings = std::move(data); _greetingSettingsChanged.fire({}); diff --git a/Telegram/SourceFiles/data/business/data_business_info.h b/Telegram/SourceFiles/data/business/data_business_info.h index e572d27571..3b747eb0f2 100644 --- a/Telegram/SourceFiles/data/business/data_business_info.h +++ b/Telegram/SourceFiles/data/business/data_business_info.h @@ -20,15 +20,17 @@ public: void preload(); - void saveWorkingHours(WorkingHours data); + void saveWorkingHours(WorkingHours data, Fn fail); - void saveAwaySettings(AwaySettings data); + void saveAwaySettings(AwaySettings data, Fn fail); void applyAwaySettings(AwaySettings data); [[nodiscard]] AwaySettings awaySettings() const; [[nodiscard]] bool awaySettingsLoaded() const; [[nodiscard]] rpl::producer<> awaySettingsChanged() const; - void saveGreetingSettings(GreetingSettings data); + void saveGreetingSettings( + GreetingSettings data, + Fn fail); void applyGreetingSettings(GreetingSettings data); [[nodiscard]] GreetingSettings greetingSettings() const; [[nodiscard]] bool greetingSettingsLoaded() const; diff --git a/Telegram/SourceFiles/settings/business/settings_away_message.cpp b/Telegram/SourceFiles/settings/business/settings_away_message.cpp index ae600e0de6..4953bbdbd6 100644 --- a/Telegram/SourceFiles/settings/business/settings_away_message.cpp +++ b/Telegram/SourceFiles/settings/business/settings_away_message.cpp @@ -213,7 +213,9 @@ void AwayMessage::setupContent( const auto current = info->awaySettings(); const auto disabled = (current.schedule.type == AwayScheduleType::Never); - _recipients = current.recipients; + _recipients = disabled + ? Data::BusinessRecipients{ .allButExcluded = true } + : current.recipients; auto initialSchedule = disabled ? AwaySchedule{ .type = AwayScheduleType::Always, } : current.schedule; @@ -340,14 +342,25 @@ void AwayMessage::setupContent( } void AwayMessage::save() { + const auto show = controller()->uiShow(); const auto session = &controller()->session(); + const auto fail = [=](QString error) { + if (error == u"BUSINESS_RECIPIENTS_EMPTY"_q) { + AssertIsDebug(); + show->showToast(u"Please choose at least one recipient."_q); + //tr::lng_greeting_recipients_empty(tr::now)); + } else if (error != u"SHORTCUT_INVALID"_q) { + show->showToast(error); + } + }; session->data().businessInfo().saveAwaySettings( _enabled.current() ? Data::AwaySettings{ .recipients = _recipients.current(), .schedule = _schedule.current(), .shortcutId = LookupShortcutId(session, u"away"_q), .offlineOnly = _offlineOnly.current(), - } : Data::AwaySettings()); + } : Data::AwaySettings(), + fail); } } // namespace diff --git a/Telegram/SourceFiles/settings/business/settings_chatbots.cpp b/Telegram/SourceFiles/settings/business/settings_chatbots.cpp index 18d9c9545f..d9879f470e 100644 --- a/Telegram/SourceFiles/settings/business/settings_chatbots.cpp +++ b/Telegram/SourceFiles/settings/business/settings_chatbots.cpp @@ -189,12 +189,20 @@ void Chatbots::setupContent( } void Chatbots::save() { - const auto settings = Data::ChatbotsSettings{ + const auto show = controller()->uiShow(); + const auto session = &controller()->session(); + const auto fail = [=](QString error) { + if (error == u"BUSINESS_RECIPIENTS_EMPTY"_q) { + AssertIsDebug(); + show->showToast(u"Please choose at least one recipient."_q); + //tr::lng_greeting_recipients_empty(tr::now)); + } + }; + controller()->session().data().chatbots().save({ .bot = _botValue.current().bot, .recipients = _recipients.current(), .repliesAllowed = _repliesAllowed.current(), - }; - controller()->session().data().chatbots().save(settings); + }, [=](QString error) { show->showToast(error); }); } } // namespace diff --git a/Telegram/SourceFiles/settings/business/settings_greeting.cpp b/Telegram/SourceFiles/settings/business/settings_greeting.cpp index e16cc6477b..6db47a7a01 100644 --- a/Telegram/SourceFiles/settings/business/settings_greeting.cpp +++ b/Telegram/SourceFiles/settings/business/settings_greeting.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "settings/business/settings_shortcut_messages.h" #include "settings/business/settings_recipients_helper.h" +#include "ui/boxes/time_picker_box.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" @@ -73,92 +74,22 @@ void EditPeriodBox( not_null box, int days, Fn save) { - auto values = base::flat_set{ 7, 14, 21, 28 }; - if (!values.contains(days)) { - values.emplace(days); + auto values = std::vector{ 7, 14, 21, 28 }; + if (!ranges::contains(values, days)) { + values.push_back(days); + ranges::sort(values); } - const auto startIndex = int(values.find(days) - begin(values)); - const auto content = box->addRow(object_ptr( - box, - st::settingsWorkingHoursPicker)); - - const auto font = st::boxTextFont; - const auto itemHeight = st::settingsWorkingHoursPickerItemHeight; - auto paintCallback = [=]( - QPainter &p, - int index, - float64 y, - float64 distanceFromCenter, - int outerWidth) { - const auto r = QRectF(0, y, outerWidth, itemHeight); - const auto progress = std::abs(distanceFromCenter); - const auto revProgress = 1. - progress; - p.save(); - p.translate(r.center()); - constexpr auto kMinYScale = 0.2; - const auto yScale = kMinYScale - + (1. - kMinYScale) * anim::easeOutCubic(1., revProgress); - p.scale(1., yScale); - p.translate(-r.center()); - p.setOpacity(revProgress); - p.setFont(font); - p.setPen(st::defaultFlatLabel.textFg); - p.drawText( - r, - tr::lng_days(tr::now, lt_count, *(values.begin() + index)), - style::al_center); - p.restore(); - }; - - const auto picker = Ui::CreateChild( - content, - std::move(paintCallback), - int(values.size()), - itemHeight, - startIndex); - - content->sizeValue( - ) | rpl::start_with_next([=](const QSize &s) { - picker->resize(s.width(), s.height()); - picker->moveToLeft((s.width() - picker->width()) / 2, 0); - }, content->lifetime()); - - content->paintRequest( - ) | rpl::start_with_next([=](const QRect &r) { - auto p = QPainter(content); - - p.fillRect(r, Qt::transparent); - - const auto lineRect = QRect( - 0, - content->height() / 2, - content->width(), - st::defaultInputField.borderActive); - p.fillRect(lineRect.translated(0, itemHeight / 2), st::activeLineFg); - p.fillRect(lineRect.translated(0, -itemHeight / 2), st::activeLineFg); - }, content->lifetime()); - - base::install_event_filter(content, [=](not_null e) { - if ((e->type() == QEvent::MouseButtonPress) - || (e->type() == QEvent::MouseButtonRelease) - || (e->type() == QEvent::MouseMove)) { - picker->handleMouseEvent(static_cast(e.get())); - } else if (e->type() == QEvent::Wheel) { - picker->handleWheelEvent(static_cast(e.get())); - } - return base::EventFilterResult::Continue; - }); - base::install_event_filter(box, [=](not_null e) { - if (e->type() == QEvent::KeyPress) { - picker->handleKeyEvent(static_cast(e.get())); - } - return base::EventFilterResult::Continue; - }); + const auto phrases = ranges::views::all( + values + ) | ranges::views::transform([](int days) { + return tr::lng_days(tr::now, lt_count, days); + }) | ranges::to_vector; + const auto take = TimePickerBox(box, values, phrases, days); box->addButton(tr::lng_settings_save(), [=] { const auto weak = Ui::MakeWeak(box); - save(*(begin(values) + picker->index())); + save(take()); if (const auto strong = weak.data()) { strong->closeBox(); } @@ -187,7 +118,9 @@ void Greeting::setupContent( const auto current = info->greetingSettings(); const auto disabled = !current.noActivityDays; - _recipients = current.recipients; + _recipients = disabled + ? Data::BusinessRecipients{ .allButExcluded = true } + : current.recipients; _noActivityDays = disabled ? kDefaultNoActivityDays : current.noActivityDays; @@ -326,13 +259,24 @@ void Greeting::setupContent( } void Greeting::save() { + const auto show = controller()->uiShow(); const auto session = &controller()->session(); + const auto fail = [=](QString error) { + if (error == u"BUSINESS_RECIPIENTS_EMPTY"_q) { + AssertIsDebug(); + show->showToast(u"Please choose at least one recipient."_q); + //tr::lng_greeting_recipients_empty(tr::now)); + } else if (error != u"SHORTCUT_INVALID"_q) { + show->showToast(error); + } + }; session->data().businessInfo().saveGreetingSettings( _enabled.current() ? Data::GreetingSettings{ .recipients = _recipients.current(), .noActivityDays = _noActivityDays.current(), .shortcutId = LookupShortcutId(session, u"hello"_q), - } : Data::GreetingSettings()); + } : Data::GreetingSettings(), + fail); } } // namespace diff --git a/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp b/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp index 53fb228ba9..d45d94750c 100644 --- a/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp +++ b/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp @@ -41,7 +41,6 @@ public: private: void setupContent(not_null controller); - void save(); rpl::variable _count; @@ -54,11 +53,7 @@ QuickReplies::QuickReplies( setupContent(controller); } -QuickReplies::~QuickReplies() { - if (!Core::Quitting()) { - save(); - } -} +QuickReplies::~QuickReplies() = default; rpl::producer QuickReplies::title() { return tr::lng_replies_title(); @@ -160,9 +155,6 @@ void QuickReplies::setupContent( Ui::ResizeFitChild(this, content); } -void QuickReplies::save() { -} - } // namespace Type QuickRepliesId() { diff --git a/Telegram/SourceFiles/settings/business/settings_working_hours.cpp b/Telegram/SourceFiles/settings/business/settings_working_hours.cpp index 42865a2c07..39ef6e793c 100644 --- a/Telegram/SourceFiles/settings/business/settings_working_hours.cpp +++ b/Telegram/SourceFiles/settings/business/settings_working_hours.cpp @@ -673,8 +673,10 @@ void WorkingHours::setupContent( } void WorkingHours::save() { + const auto show = controller()->uiShow(); controller()->session().data().businessInfo().saveWorkingHours( - _enabled.current() ? _hours.current() : Data::WorkingHours()); + _enabled.current() ? _hours.current() : Data::WorkingHours(), + [=](QString error) { show->showToast(error); }); } } // namespace