Improve recipients selection in business features.

This commit is contained in:
John Preston 2024-03-07 17:02:32 +04:00
parent e3f6c189a7
commit 00dcf11691
14 changed files with 109 additions and 49 deletions

View File

@ -2285,6 +2285,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_chatbots_remove" = "Remove Bot"; "lng_chatbots_remove" = "Remove Bot";
"lng_chatbots_not_found" = "Chatbot not found."; "lng_chatbots_not_found" = "Chatbot not found.";
"lng_chatbots_add" = "Add"; "lng_chatbots_add" = "Add";
"lng_chatbots_info_url" = "https://telegram.org/privacy";
"lng_boost_channel_button" = "Boost Channel"; "lng_boost_channel_button" = "Boost Channel";
"lng_boost_group_button" = "Boost Group"; "lng_boost_group_button" = "Boost Group";

View File

@ -669,17 +669,6 @@ bool ShowSearchTagsPromo(
return true; return true;
} }
bool ShowAboutBusinessChatbots(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
controller->showToast(u"Cool feature, yeah.."_q); AssertIsDebug();
return true;
}
void ExportTestChatTheme( void ExportTestChatTheme(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<const Data::CloudTheme*> theme) { not_null<const Data::CloudTheme*> theme) {
@ -1048,10 +1037,6 @@ const std::vector<LocalUrlHandler> &InternalUrlHandlers() {
u"about_tags"_q, u"about_tags"_q,
ShowSearchTagsPromo ShowSearchTagsPromo
}, },
{
u"about_business_chatbots"_q,
ShowAboutBusinessChatbots
},
}; };
return Result; return Result;
} }

View File

@ -30,6 +30,10 @@ struct BusinessChats {
BusinessChatTypes types; BusinessChatTypes types;
std::vector<not_null<UserData*>> list; std::vector<not_null<UserData*>> list;
[[nodiscard]] bool empty() const {
return !types && list.empty();
}
friend inline bool operator==( friend inline bool operator==(
const BusinessChats &a, const BusinessChats &a,
const BusinessChats &b) = default; const BusinessChats &b) = default;
@ -193,7 +197,7 @@ enum class AwayScheduleType : uchar {
}; };
struct AwaySchedule { struct AwaySchedule {
AwayScheduleType type = AwayScheduleType::Always; AwayScheduleType type = AwayScheduleType::Never;
WorkingInterval customInterval; WorkingInterval customInterval;
friend inline bool operator==( friend inline bool operator==(

View File

@ -109,20 +109,20 @@ void BusinessInfo::saveAwaySettings(
const auto &was = _awaySettings; const auto &was = _awaySettings;
if (was == data) { if (was == data) {
return; return;
} else if (!data || data.shortcutId) {
using Flag = MTPaccount_UpdateBusinessAwayMessage::Flag;
const auto session = &_owner->session();
session->api().request(MTPaccount_UpdateBusinessAwayMessage(
MTP_flags(data ? Flag::f_message : Flag()),
data ? ToMTP(data) : MTPInputBusinessAwayMessage()
)).fail([=](const MTP::Error &error) {
_awaySettings = was;
_awaySettingsChanged.fire({});
if (fail) {
fail(error.type());
}
}).send();
} }
using Flag = MTPaccount_UpdateBusinessAwayMessage::Flag;
const auto session = &_owner->session();
session->api().request(MTPaccount_UpdateBusinessAwayMessage(
MTP_flags(data ? Flag::f_message : Flag()),
data ? ToMTP(data) : MTPInputBusinessAwayMessage()
)).fail([=](const MTP::Error &error) {
_awaySettings = was;
_awaySettingsChanged.fire({});
if (fail) {
fail(error.type());
}
}).send();
_awaySettings = std::move(data); _awaySettings = std::move(data);
_awaySettingsChanged.fire({}); _awaySettingsChanged.fire({});
} }
@ -153,20 +153,20 @@ void BusinessInfo::saveGreetingSettings(
const auto &was = _greetingSettings; const auto &was = _greetingSettings;
if (was == data) { if (was == data) {
return; return;
} else if (!data || data.shortcutId) {
using Flag = MTPaccount_UpdateBusinessGreetingMessage::Flag;
_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();
} }
using Flag = MTPaccount_UpdateBusinessGreetingMessage::Flag;
_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); _greetingSettings = std::move(data);
_greetingSettingsChanged.fire({}); _greetingSettingsChanged.fire({});
} }

View File

@ -101,6 +101,12 @@ public:
} }
virtual void fillTopBarMenu(const Ui::Menu::MenuCallback &addAction); virtual void fillTopBarMenu(const Ui::Menu::MenuCallback &addAction);
[[nodiscard]] virtual bool closeByOutsideClick() const {
return true;
}
virtual void checkBeforeClose(Fn<void()> close) {
close();
}
[[nodiscard]] virtual rpl::producer<QString> title() = 0; [[nodiscard]] virtual rpl::producer<QString> title() = 0;
[[nodiscard]] virtual rpl::producer<QString> subtitle() { [[nodiscard]] virtual rpl::producer<QString> subtitle() {
return nullptr; return nullptr;

View File

@ -410,8 +410,10 @@ void WrapWidget::setupTopBarMenuToggle() {
} }
void WrapWidget::checkBeforeClose(Fn<void()> close) { void WrapWidget::checkBeforeClose(Fn<void()> close) {
_controller->parentController()->hideLayer(); _content->checkBeforeClose(crl::guard(this, [=] {
close(); _controller->parentController()->hideLayer();
close();
}));
} }
void WrapWidget::addTopBarMenuButton() { void WrapWidget::addTopBarMenuButton() {
@ -438,7 +440,7 @@ void WrapWidget::addTopBarMenuButton() {
} }
bool WrapWidget::closeByOutsideClick() const { bool WrapWidget::closeByOutsideClick() const {
return true; return _content->closeByOutsideClick();
} }
void WrapWidget::addProfileCallsButton() { void WrapWidget::addProfileCallsButton() {
@ -872,8 +874,12 @@ void WrapWidget::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape || e->key() == Qt::Key_Back) { if (e->key() == Qt::Key_Escape || e->key() == Qt::Key_Back) {
if (hasStackHistory() || wrap() != Wrap::Layer) { if (hasStackHistory() || wrap() != Wrap::Layer) {
checkBeforeClose([=] { _controller->showBackFromStack(); }); checkBeforeClose([=] { _controller->showBackFromStack(); });
return; } else {
checkBeforeClose([=] {
_controller->parentController()->hideSpecialLayer();
});
} }
return;
} }
SectionWidget::keyPressEvent(e); SectionWidget::keyPressEvent(e);
} }

View File

@ -232,6 +232,14 @@ rpl::producer<bool> Widget::desiredShadowVisibility() const {
: rpl::single(true); : rpl::single(true);
} }
bool Widget::closeByOutsideClick() const {
return _inner->closeByOutsideClick();;
}
void Widget::checkBeforeClose(Fn<void()> close) {
_inner->checkBeforeClose(std::move(close));
}
rpl::producer<QString> Widget::title() { rpl::producer<QString> Widget::title() {
return _inner->title(); return _inner->title();
} }

View File

@ -76,6 +76,8 @@ public:
rpl::producer<bool> desiredShadowVisibility() const override; rpl::producer<bool> desiredShadowVisibility() const override;
bool closeByOutsideClick() const override;
void checkBeforeClose(Fn<void()> close) override;
rpl::producer<QString> title() override; rpl::producer<QString> title() override;
void enableBackButton() override; void enableBackButton() override;

View File

@ -38,6 +38,7 @@ public:
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller);
~AwayMessage(); ~AwayMessage();
[[nodiscard]] bool closeByOutsideClick() const override;
[[nodiscard]] rpl::producer<QString> title() override; [[nodiscard]] rpl::producer<QString> title() override;
private: private:
@ -199,6 +200,10 @@ AwayMessage::~AwayMessage() {
} }
} }
bool AwayMessage::closeByOutsideClick() const {
return false;
}
rpl::producer<QString> AwayMessage::title() { rpl::producer<QString> AwayMessage::title() {
return tr::lng_away_title(); return tr::lng_away_title();
} }

View File

@ -53,6 +53,7 @@ public:
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller);
~Chatbots(); ~Chatbots();
[[nodiscard]] bool closeByOutsideClick() const override;
[[nodiscard]] rpl::producer<QString> title() override; [[nodiscard]] rpl::producer<QString> title() override;
const Ui::RoundRect *bottomSkipRounding() const override { const Ui::RoundRect *bottomSkipRounding() const override {
@ -380,6 +381,10 @@ Chatbots::~Chatbots() {
} }
} }
bool Chatbots::closeByOutsideClick() const {
return false;
}
rpl::producer<QString> Chatbots::title() { rpl::producer<QString> Chatbots::title() {
return tr::lng_chatbots_title(); return tr::lng_chatbots_title();
} }
@ -402,7 +407,7 @@ void Chatbots::setupContent(
.about = tr::lng_chatbots_about( .about = tr::lng_chatbots_about(
lt_link, lt_link,
tr::lng_chatbots_about_link( tr::lng_chatbots_about_link(
) | Ui::Text::ToLink(u"internal:about_business_chatbots"_q), ) | Ui::Text::ToLink(tr::lng_chatbots_info_url(tr::now)),
Ui::Text::WithEntities), Ui::Text::WithEntities),
.aboutMargins = st::peerAppearanceCoverLabelMargin, .aboutMargins = st::peerAppearanceCoverLabelMargin,
}); });
@ -485,7 +490,7 @@ void Chatbots::save() {
.recipients = _recipients.current(), .recipients = _recipients.current(),
.repliesAllowed = _repliesAllowed.current(), .repliesAllowed = _repliesAllowed.current(),
}, [=] { }, [=] {
}, [=](QString error) { show->showToast(error); }); }, fail);
} }
} // namespace } // namespace

View File

@ -42,6 +42,7 @@ public:
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller);
~Greeting(); ~Greeting();
[[nodiscard]] bool closeByOutsideClick() const override;
[[nodiscard]] rpl::producer<QString> title() override; [[nodiscard]] rpl::producer<QString> title() override;
const Ui::RoundRect *bottomSkipRounding() const override { const Ui::RoundRect *bottomSkipRounding() const override {
@ -105,6 +106,10 @@ Greeting::~Greeting() {
} }
} }
bool Greeting::closeByOutsideClick() const {
return false;
}
rpl::producer<QString> Greeting::title() { rpl::producer<QString> Greeting::title() {
return tr::lng_greeting_title(); return tr::lng_greeting_title();
} }

View File

@ -168,8 +168,10 @@ void AddBusinessRecipientsSelector(
modify(now); modify(now);
*data = std::move(now); *data = std::move(now);
}; };
const auto &current = data->current();
const auto all = current.allButExcluded || current.included.empty();
const auto group = std::make_shared<Ui::RadiobuttonGroup>( const auto group = std::make_shared<Ui::RadiobuttonGroup>(
data->current().allButExcluded ? kAllExcept : kSelectedOnly); all ? kAllExcept : kSelectedOnly);
const auto everyone = container->add( const auto everyone = container->add(
object_ptr<Ui::Radiobutton>( object_ptr<Ui::Radiobutton>(
container, container,
@ -281,6 +283,12 @@ void AddBusinessRecipientsSelector(
}, lifetime); }, lifetime);
SetupBusinessChatsPreview(includeInner, included); SetupBusinessChatsPreview(includeInner, included);
included->value(
) | rpl::start_with_next([=](const Data::BusinessChats &value) {
if (value.empty() && group->current() == kSelectedOnly) {
group->setValue(kAllExcept);
}
}, lifetime);
includeWrap->toggleOn(data->value( includeWrap->toggleOn(data->value(
) | rpl::map([](const Data::BusinessRecipients &value) { ) | rpl::map([](const Data::BusinessRecipients &value) {
@ -289,6 +297,20 @@ void AddBusinessRecipientsSelector(
includeWrap->finishAnimating(); includeWrap->finishAnimating();
group->setChangedCallback([=](int value) { group->setChangedCallback([=](int value) {
if (value == kSelectedOnly && data->current().included.empty()) {
group->setValue(kAllExcept);
const auto save = [=](Data::BusinessChats value) {
change([&](Data::BusinessRecipients &data) {
data.included = std::move(value);
});
group->setValue(kSelectedOnly);
};
EditBusinessChats(controller, {
.save = crl::guard(includeAdd, save),
.include = true,
});
return;
}
change([&](Data::BusinessRecipients &data) { change([&](Data::BusinessRecipients &data) {
data.allButExcluded = (value == kAllExcept); data.allButExcluded = (value == kAllExcept);
}); });

View File

@ -44,6 +44,7 @@ public:
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller);
~WorkingHours(); ~WorkingHours();
[[nodiscard]] bool closeByOutsideClick() const override;
[[nodiscard]] rpl::producer<QString> title() override; [[nodiscard]] rpl::producer<QString> title() override;
private: private:
@ -529,6 +530,10 @@ WorkingHours::~WorkingHours() {
} }
} }
bool WorkingHours::closeByOutsideClick() const {
return false;
}
rpl::producer<QString> WorkingHours::title() { rpl::producer<QString> WorkingHours::title() {
return tr::lng_hours_title(); return tr::lng_hours_title();
} }

View File

@ -70,6 +70,12 @@ public:
[[nodiscard]] virtual rpl::producer<std::vector<Type>> removeFromStack() { [[nodiscard]] virtual rpl::producer<std::vector<Type>> removeFromStack() {
return nullptr; return nullptr;
} }
[[nodiscard]] virtual bool closeByOutsideClick() const {
return true;
}
virtual void checkBeforeClose(Fn<void()> close) {
close();
}
[[nodiscard]] virtual rpl::producer<QString> title() = 0; [[nodiscard]] virtual rpl::producer<QString> title() = 0;
virtual void sectionSaveChanges(FnMut<void()> done) { virtual void sectionSaveChanges(FnMut<void()> done) {
done(); done();