/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "settings/business/settings_chatbots.h" #include "core/application.h" #include "data/business/data_business_chatbots.h" #include "data/data_session.h" #include "data/data_user.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "settings/business/settings_recipients_helper.h" #include "ui/text/text_utilities.h" #include "ui/widgets/fields/input_field.h" #include "ui/widgets/buttons.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/vertical_list.h" #include "window/window_session_controller.h" #include "styles/style_layers.h" #include "styles/style_settings.h" namespace Settings { namespace { enum class LookupState { Empty, Loading, Ready, }; struct BotState { UserData *bot = nullptr; LookupState state = LookupState::Empty; }; class Chatbots : public BusinessSection { public: Chatbots( QWidget *parent, not_null controller); ~Chatbots(); [[nodiscard]] rpl::producer title() override; const Ui::RoundRect *bottomSkipRounding() const override { return &_bottomSkipRounding; } private: void setupContent(not_null controller); void save(); Ui::RoundRect _bottomSkipRounding; rpl::variable _recipients; rpl::variable _usernameValue; rpl::variable _botValue; rpl::variable _repliesAllowed = true; }; [[nodiscard]] rpl::producer DebouncedValue( not_null field) { return rpl::single(field->getLastText()); } [[nodiscard]] rpl::producer LookupBot( not_null session, rpl::producer usernameChanges) { return rpl::never(); } [[nodiscard]] object_ptr MakeBotPreview( not_null parent, rpl::producer state, Fn resetBot) { return object_ptr(parent.get()); } Chatbots::Chatbots( QWidget *parent, not_null controller) : BusinessSection(parent, controller) , _bottomSkipRounding(st::boxRadius, st::boxDividerBg) { setupContent(controller); } Chatbots::~Chatbots() { if (!Core::Quitting()) { save(); } } rpl::producer Chatbots::title() { return tr::lng_chatbots_title(); } void Chatbots::setupContent( not_null controller) { using namespace rpl::mappers; const auto content = Ui::CreateChild(this); const auto current = controller->session().data().chatbots().current(); _recipients = current.recipients; _repliesAllowed = current.repliesAllowed; AddDividerTextWithLottie(content, { .lottie = u"robot"_q, .lottieSize = st::settingsCloudPasswordIconSize, .lottieMargins = st::peerAppearanceIconPadding, .showFinished = showFinishes(), .about = tr::lng_chatbots_about( lt_link, tr::lng_chatbots_about_link( ) | Ui::Text::ToLink(u"internal:about_business_chatbots"_q), Ui::Text::WithEntities), .aboutMargins = st::peerAppearanceCoverLabelMargin, }); const auto username = content->add( object_ptr( content, st::settingsChatbotsUsername, tr::lng_chatbots_placeholder(), (current.bot ? current.bot->session().createInternalLink( current.bot->username()) : QString())), st::settingsChatbotsUsernameMargins); _usernameValue = DebouncedValue(username); _botValue = rpl::single(BotState{ current.bot, current.bot ? LookupState::Ready : LookupState::Empty }) | rpl::then( LookupBot(&controller->session(), _usernameValue.changes()) ); const auto resetBot = [=] { username->setText(QString()); username->setFocus(); }; content->add(object_ptr>( content, MakeBotPreview(content, _botValue.value(), resetBot))); Ui::AddDividerText( content, tr::lng_chatbots_add_about(), st::peerAppearanceDividerTextMargin); AddBusinessRecipientsSelector(content, { .controller = controller, .title = tr::lng_chatbots_access_title(), .data = &_recipients, }); Ui::AddSkip(content, st::settingsChatbotsAccessSkip); Ui::AddDividerText( content, tr::lng_chatbots_exclude_about(), st::peerAppearanceDividerTextMargin); Ui::AddSkip(content); Ui::AddSubsectionTitle(content, tr::lng_chatbots_permissions_title()); content->add(object_ptr( content, tr::lng_chatbots_reply(), st::settingsButtonNoIcon ))->toggleOn(_repliesAllowed.value())->toggledChanges( ) | rpl::start_with_next([=](bool value) { _repliesAllowed = value; }, content->lifetime()); Ui::AddSkip(content); Ui::AddDividerText( content, tr::lng_chatbots_reply_about(), st::settingsChatbotsBottomTextMargin, RectPart::Top); Ui::ResizeFitChild(this, content); } void Chatbots::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)); } }; controller()->session().data().chatbots().save({ .bot = _botValue.current().bot, .recipients = _recipients.current(), .repliesAllowed = _repliesAllowed.current(), }, [=](QString error) { show->showToast(error); }); } } // namespace Type ChatbotsId() { return Chatbots::Id(); } } // namespace Settings