| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /*
- 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_quick_replies.h"
- #include "boxes/premium_preview_box.h"
- #include "core/application.h"
- #include "data/business/data_shortcut_messages.h"
- #include "data/data_session.h"
- #include "lang/lang_keys.h"
- #include "main/main_account.h"
- #include "main/main_session.h"
- #include "settings/business/settings_recipients_helper.h"
- #include "settings/business/settings_shortcut_messages.h"
- #include "ui/layers/generic_box.h"
- #include "ui/text/text_utilities.h"
- #include "ui/widgets/buttons.h"
- #include "ui/widgets/fields/input_field.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_chat_helpers.h"
- #include "styles/style_layers.h"
- #include "styles/style_settings.h"
- namespace Settings {
- namespace {
- constexpr auto kShortcutLimit = 32;
- class QuickReplies : public BusinessSection<QuickReplies> {
- public:
- QuickReplies(
- QWidget *parent,
- not_null<Window::SessionController*> controller);
- ~QuickReplies();
- [[nodiscard]] rpl::producer<QString> title() override;
- private:
- void setupContent(not_null<Window::SessionController*> controller);
- rpl::variable<int> _count;
- };
- QuickReplies::QuickReplies(
- QWidget *parent,
- not_null<Window::SessionController*> controller)
- : BusinessSection(parent, controller) {
- setupContent(controller);
- }
- QuickReplies::~QuickReplies() = default;
- rpl::producer<QString> QuickReplies::title() {
- return tr::lng_replies_title();
- }
- void QuickReplies::setupContent(
- not_null<Window::SessionController*> controller) {
- using namespace rpl::mappers;
- const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
- AddDividerTextWithLottie(content, {
- .lottie = u"writing"_q,
- .lottieSize = st::settingsCloudPasswordIconSize,
- .lottieMargins = st::peerAppearanceIconPadding,
- .showFinished = showFinishes(),
- .about = tr::lng_replies_about(Ui::Text::WithEntities),
- .aboutMargins = st::peerAppearanceCoverLabelMargin,
- });
- Ui::AddSkip(content);
- const auto addWrap = content->add(
- object_ptr<Ui::VerticalLayout>(content));
- const auto owner = &controller->session().data();
- const auto messages = &owner->shortcutMessages();
- rpl::combine(
- _count.value(),
- ShortcutsLimitValue(&controller->session())
- ) | rpl::start_with_next([=](int count, int limit) {
- while (addWrap->count()) {
- delete addWrap->widgetAt(0);
- }
- if (count < limit) {
- const auto add = addWrap->add(object_ptr<Ui::SettingsButton>(
- addWrap,
- tr::lng_replies_add(),
- st::settingsButtonNoIcon
- ));
- add->setClickedCallback([=] {
- if (!controller->session().premium()) {
- ShowPremiumPreviewToBuy(
- controller,
- PremiumFeature::QuickReplies);
- return;
- }
- const auto submit = [=](QString name, Fn<void()> close) {
- const auto id = messages->emplaceShortcut(name);
- showOther(ShortcutMessagesId(id));
- close();
- };
- controller->show(Box(
- EditShortcutNameBox,
- QString(),
- crl::guard(this, submit)));
- });
- if (count > 0) {
- AddSkip(addWrap);
- AddDivider(addWrap);
- AddSkip(addWrap);
- }
- }
- if (const auto width = content->width()) {
- content->resizeToWidth(width);
- }
- }, lifetime());
- const auto inner = content->add(
- object_ptr<Ui::VerticalLayout>(content));
- rpl::single(rpl::empty) | rpl::then(
- messages->shortcutsChanged()
- ) | rpl::start_with_next([=] {
- auto old = inner->count();
- const auto &shortcuts = messages->shortcuts();
- for (const auto &[_, shortcut]
- : shortcuts.list | ranges::views::reverse) {
- if (!shortcut.count) {
- continue;
- }
- const auto name = shortcut.name;
- AddButtonWithLabel(
- inner,
- rpl::single('/' + name),
- tr::lng_forum_messages(
- lt_count,
- rpl::single(1. * shortcut.count)),
- st::settingsButtonNoIcon
- )->setClickedCallback([=] {
- const auto id = messages->emplaceShortcut(name);
- showOther(ShortcutMessagesId(id));
- });
- if (old) {
- delete inner->widgetAt(0);
- --old;
- }
- }
- while (old--) {
- delete inner->widgetAt(0);
- }
- _count = inner->count();
- }, content->lifetime());
- Ui::ResizeFitChild(this, content);
- }
- [[nodiscard]] bool ValidShortcutName(const QString &name) {
- if (name.isEmpty() || name.size() > kShortcutLimit) {
- return false;
- }
- for (const auto &ch : name) {
- if (!ch.isLetterOrNumber()
- && (ch != QChar('_'))
- && (ch.unicode() != 0x200c)
- && (ch.unicode() != 0x00b7)
- && (ch.unicode() < 0x0d80 || ch.unicode() > 0x0dff)) {
- return false;
- }
- }
- return true;
- }
- } // namespace
- Type QuickRepliesId() {
- return QuickReplies::Id();
- }
- void EditShortcutNameBox(
- not_null<Ui::GenericBox*> box,
- QString name,
- Fn<void(QString, Fn<void()>)> submit) {
- name = name.trimmed();
- const auto editing = !name.isEmpty();
- box->setTitle(editing
- ? tr::lng_replies_edit_title()
- : tr::lng_replies_add_title());
- box->addRow(object_ptr<Ui::FlatLabel>(
- box,
- (editing
- ? tr::lng_replies_edit_about()
- : tr::lng_replies_add_shortcut()),
- st::settingsAddReplyLabel));
- const auto field = box->addRow(object_ptr<Ui::InputField>(
- box,
- st::settingsAddReplyField,
- tr::lng_replies_add_placeholder(),
- name));
- box->setFocusCallback([=] {
- field->setFocusFast();
- });
- field->selectAll();
- field->setMaxLength(kShortcutLimit * 2);
- Ui::AddLengthLimitLabel(field, kShortcutLimit);
- const auto callback = [=] {
- const auto name = field->getLastText().trimmed();
- if (!ValidShortcutName(name)) {
- field->showError();
- } else {
- submit(name, [weak = Ui::MakeWeak(box)] {
- if (const auto strong = weak.data()) {
- strong->closeBox();
- }
- });
- }
- };
- field->submits(
- ) | rpl::start_with_next(callback, field->lifetime());
- box->addButton(tr::lng_settings_save(), callback);
- box->addButton(tr::lng_cancel(), [=] {
- box->closeBox();
- });
- }
- } // namespace Settings
|