Layout chatbots editing section.

This commit is contained in:
John Preston 2024-02-20 14:33:46 +04:00
parent 0c991466f5
commit 205479fccc
17 changed files with 367 additions and 78 deletions

View File

@ -1277,6 +1277,8 @@ PRIVATE
profile/profile_block_widget.h
profile/profile_cover_drop_area.cpp
profile/profile_cover_drop_area.h
settings/business/settings_chatbots.cpp
settings/business/settings_chatbots.h
settings/cloud_password/settings_cloud_password_common.cpp
settings/cloud_password/settings_cloud_password_common.h
settings/cloud_password/settings_cloud_password_email.cpp

Binary file not shown.

View File

@ -2172,6 +2172,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_business_subtitle_chatbots" = "Chatbots";
"lng_business_about_chatbots" = "Add any third party chatbots that will process customer interactions.";
"lng_chatbots_title" = "Chatbots";
"lng_chatbots_about" = "Add a bot to your account to help you automatically process and respond to the messages you receive. {link}";
"lng_chatbots_about_link" = "Learn more...";
"lng_chatbots_placeholder" = "Enter bot URL or username";
"lng_chatbots_add_about" = "Enter the link to the Telegram bot that you want to automatically process your chats.";
"lng_chatbots_access_title" = "Chats accessible for the bot";
"lng_chatbots_all_except" = "All 1-to-1 Chats Except...";
"lng_chatbots_selected" = "Only Selected Chats";
"lng_chatbots_excluded_title" = "Excluded chats";
"lng_chatbots_exclude_button" = "Exclude Chats";
"lng_chatbots_included_title" = "Included chats";
"lng_chatbots_include_button" = "Select Chats";
"lng_chatbots_exclude_about" = "Select chats or entire chat categories which the bot will not have access to.";
"lng_chatbots_permissions_title" = "Bot permissions";
"lng_chatbots_reply" = "Reply to Messages";
"lng_chatbots_reply_about" = "The bot will be able to view all new incoming messages, but not the messages that had been sent before you added the bot.";
"lng_chatbots_remove" = "Remove Bot";
"lng_boost_channel_button" = "Boost Channel";
"lng_boost_group_button" = "Boost Group";
"lng_boost_again_button" = "Boost Again";

View File

@ -14,5 +14,6 @@
<file alias="voice_ttl_idle.tgs">../../animations/voice_ttl_idle.tgs</file>
<file alias="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
<file alias="palette.tgs">../../animations/palette.tgs</file>
<file alias="robot.tgs">../../animations/robot.tgs</file>
</qresource>
</RCC>

View File

@ -260,11 +260,11 @@ void Controller::choose(not_null<ChatData*> chat) {
const auto init = [=](not_null<ListBox*> box) {
auto above = object_ptr<Ui::VerticalLayout>(box);
Settings::AddDividerTextWithLottie(
above,
box->showFinishes(),
About(channel, chat),
u"discussion"_q);
Settings::AddDividerTextWithLottie(above, {
.lottie = u"discussion"_q,
.showFinished = box->showFinishes(),
.about = About(channel, chat),
});
if (!chat) {
Assert(channel->isBroadcast());

View File

@ -1223,35 +1223,15 @@ void EditPeerColorBox(
state->index = peer->colorIndex();
state->emojiId = peer->backgroundEmojiId();
state->statusId = peer->emojiStatusId();
if (group) {
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(
box.get());
const auto verticalLayout = box->verticalLayout()->add(
object_ptr<Ui::VerticalLayout>(box.get()));
auto icon = CreateLottieIcon(
verticalLayout,
{
.name = u"palette"_q,
.sizeOverride = Size(st::settingsCloudPasswordIconSize),
},
st::peerAppearanceIconPadding);
box->setShowFinishedCallback([animate = std::move(icon.animate)] {
animate(anim::repeat::once);
Settings::AddDividerTextWithLottie(box->verticalLayout(), {
.lottie = u"palette"_q,
.lottieSize = st::settingsCloudPasswordIconSize,
.lottieMargins = st::peerAppearanceIconPadding,
.showFinished = box->showFinishes(),
.about = tr::lng_boost_group_about(Ui::Text::WithEntities),
.aboutMargins = st::peerAppearanceCoverLabelMargin,
});
verticalLayout->add(std::move(icon.widget));
verticalLayout->add(
object_ptr<Ui::FlatLabel>(
verticalLayout,
tr::lng_boost_group_about(),
st::peerAppearanceCoverLabel),
st::peerAppearanceCoverLabelMargin);
verticalLayout->geometryValue(
) | rpl::start_with_next([=](const QRect &r) {
divider->setGeometry(r);
}, divider->lifetime());
} else {
box->addRow(object_ptr<PreviewWrap>(
box,

View File

@ -669,6 +669,17 @@ bool ShowSearchTagsPromo(
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(
not_null<Window::SessionController*> controller,
not_null<const Data::CloudTheme*> theme) {
@ -1036,7 +1047,11 @@ const std::vector<LocalUrlHandler> &InternalUrlHandlers() {
{
u"about_tags"_q,
ShowSearchTagsPromo
}
},
{
u"about_business_chatbots"_q,
ShowAboutBusinessChatbots
},
};
return Result;
}

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/history_inner_widget.h"
#include "chat_helpers/stickers_emoji_pack.h"
#include "core/file_utilities.h"
#include "core/click_handler_types.h"
#include "history/history_item_helpers.h"
@ -32,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/message_sending_animation_controller.h"
#include "ui/effects/reaction_fly_animation.h"
#include "ui/text/text_options.h"
#include "ui/text/text_isolated_emoji.h"
#include "ui/boxes/report_box.h"
#include "ui/layers/generic_box.h"
#include "ui/controls/delete_message_context_action.h"
@ -2239,6 +2241,17 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
};
if (const auto item = _dragStateItem) {
const auto emojiStickers = &session->emojiStickersPack();
if (const auto view = item->mainView()) {
if (const auto isolated = view->isolatedEmoji()) {
if (const auto sticker = emojiStickers->stickerForEmoji(isolated)) {
addDocumentActions(sticker.document, item);
}
}
}
}
const auto asGroup = !Element::Moused()
|| (Element::Moused() != Element::Hovered())
|| (Element::Moused()->pointState(

View File

@ -0,0 +1,201 @@
/*
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 "lang/lang_keys.h"
#include "settings/settings_common_session.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/vertical_list.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
namespace Settings {
namespace {
constexpr auto kAllExcept = 0;
constexpr auto kSelectedOnly = 1;
class Chatbots : public Section<Chatbots> {
public:
Chatbots(
QWidget *parent,
not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
rpl::producer<> showFinishes() const {
return _showFinished.events();
}
const Ui::RoundRect *bottomSkipRounding() const {
return &_bottomSkipRounding;
}
private:
void setupContent(not_null<Window::SessionController*> controller);
void showFinished() override {
_showFinished.fire({});
}
rpl::event_stream<> _showFinished;
Ui::RoundRect _bottomSkipRounding;
};
Chatbots::Chatbots(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent)
, _bottomSkipRounding(st::boxRadius, st::boxDividerBg) {
setupContent(controller);
}
rpl::producer<QString> Chatbots::title() {
return tr::lng_chatbots_title();
}
void Chatbots::setupContent(
not_null<Window::SessionController*> controller) {
using namespace rpl::mappers;
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
struct State {
rpl::variable<bool> onlySelected = false;
rpl::variable<bool> replyAllowed = true;
};
const auto state = content->lifetime().make_state<State>();
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<Ui::InputField>(
content,
st::settingsChatbotsUsername,
tr::lng_chatbots_placeholder()),
st::settingsChatbotsUsernameMargins);
Ui::AddDividerText(
content,
tr::lng_chatbots_add_about(),
st::peerAppearanceDividerTextMargin);
Ui::AddSkip(content);
Ui::AddSubsectionTitle(content, tr::lng_chatbots_access_title());
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
state->onlySelected.current() ? kSelectedOnly : kAllExcept);
const auto everyone = content->add(
object_ptr<Ui::Radiobutton>(
content,
group,
kAllExcept,
tr::lng_chatbots_all_except(tr::now),
st::settingsChatbotsAccess),
st::settingsChatbotsAccessMargins);
const auto selected = content->add(
object_ptr<Ui::Radiobutton>(
content,
group,
kSelectedOnly,
tr::lng_chatbots_selected(tr::now),
st::settingsChatbotsAccess),
st::settingsChatbotsAccessMargins);
Ui::AddSkip(content, st::settingsChatbotsAccessSkip);
Ui::AddDivider(content);
const auto excludeWrap = content->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
content,
object_ptr<Ui::VerticalLayout>(content))
)->setDuration(0);
const auto excludeInner = excludeWrap->entity();
Ui::AddSkip(excludeInner);
Ui::AddSubsectionTitle(excludeInner, tr::lng_chatbots_excluded_title());
const auto excludeAdd = AddButtonWithIcon(
excludeInner,
tr::lng_chatbots_exclude_button(),
st::settingsChatbotsAdd,
{ &st::settingsIconRemove, IconType::Round, &st::windowBgActive });
excludeWrap->toggleOn(state->onlySelected.value() | rpl::map(!_1));
excludeWrap->finishAnimating();
const auto includeWrap = content->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
content,
object_ptr<Ui::VerticalLayout>(content))
)->setDuration(0);
const auto includeInner = includeWrap->entity();
Ui::AddSkip(includeInner);
Ui::AddSubsectionTitle(includeInner, tr::lng_chatbots_included_title());
const auto includeAdd = AddButtonWithIcon(
includeInner,
tr::lng_chatbots_include_button(),
st::settingsChatbotsAdd,
{ &st::settingsIconAdd, IconType::Round, &st::windowBgActive });
includeWrap->toggleOn(state->onlySelected.value());
includeWrap->finishAnimating();
group->setChangedCallback([=](int value) {
state->onlySelected = (value == kSelectedOnly);
});
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<Ui::SettingsButton>(
content,
tr::lng_chatbots_reply(),
st::settingsButtonNoIcon
))->toggleOn(state->replyAllowed.value())->toggledChanges(
) | rpl::start_with_next([=](bool value) {
state->replyAllowed = value;
}, content->lifetime());
Ui::AddSkip(content);
Ui::AddDividerText(
content,
tr::lng_chatbots_reply_about(),
st::settingsChatbotsBottomTextMargin,
RectPart::Top);
Ui::ResizeFitChild(this, content);
}
} // namespace
Type ChatbotsId() {
return Chatbots::Id();
}
} // namespace Settings

View File

@ -0,0 +1,16 @@
/*
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
*/
#pragma once
#include "settings/settings_type.h"
namespace Settings {
[[nodiscard]] Type ChatbotsId();
} // namespace Settings

View File

@ -121,12 +121,12 @@ void Manage::setupContent() {
showOther(type);
};
AddDividerTextWithLottie(
content,
showFinishes(),
tr::lng_settings_cloud_password_manage_about1(
AddDividerTextWithLottie(content, {
.lottie = u"cloud_password/intro"_q,
.showFinished = showFinishes(),
.about = tr::lng_settings_cloud_password_manage_about1(
TextWithEntities::Simple),
u"cloud_password/intro"_q);
});
Ui::AddSkip(content);
AddButtonWithIcon(

View File

@ -589,9 +589,19 @@ peerAppearanceButton: SettingsButton(settingsButtonLight) {
padding: margins(60px, 8px, 22px, 8px);
iconLeft: 20px;
}
peerAppearanceCoverLabel: FlatLabel(boxDividerLabel) {
align: align(top);
}
peerAppearanceCoverLabelMargin: margins(22px, 0px, 22px, 17px);
peerAppearanceIconPadding: margins(0px, 15px, 0px, 5px);
peerAppearanceDividerTextMargin: margins(22px, 8px, 22px, 11px);
settingsChatbotsUsername: InputField(defaultMultiSelectSearchField) {
}
settingsChatbotsAccess: Checkbox(defaultCheckbox) {
textPosition: point(18px, 2px);
}
settingsChatbotsUsernameMargins: margins(20px, 8px, 20px, 8px);
settingsChatbotsAccessMargins: margins(22px, 5px, 22px, 9px);
settingsChatbotsAccessSkip: 4px;
settingsChatbotsBottomTextMargin: margins(22px, 8px, 22px, 3px);
settingsChatbotsAdd: SettingsButton(settingsButton) {
iconLeft: 22px;
}

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "settings/business/settings_chatbots.h"
#include "settings/settings_common_session.h"
#include "settings/settings_premium.h"
#include "ui/effects/gradient.h"
@ -287,6 +288,7 @@ public:
void setStepDataReference(std::any &data) override;
[[nodiscard]] rpl::producer<> sectionShowBack() override final;
[[nodiscard]] rpl::producer<Type> sectionShowOther() override;
private:
void setupContent();
@ -299,9 +301,10 @@ private:
rpl::variable<bool> _backToggles;
rpl::variable<Info::Wrap> _wrap;
Fn<void(bool)> _setPaused;
std::shared_ptr<Ui::RadiobuttonGroup> _radioGroup;
rpl::event_stream<Type> _showOther;
rpl::event_stream<> _showBack;
rpl::event_stream<> _showFinished;
rpl::variable<QString> _buttonText;
@ -330,6 +333,10 @@ rpl::producer<> Business::sectionShowBack() {
return _showBack.events();
}
rpl::producer<Type> Business::sectionShowOther() {
return _showOther.events();
}
void Business::setStepDataReference(std::any &data) {
using namespace Info::Settings;
const auto my = std::any_cast<SectionCustomTopBarData>(&data);
@ -347,6 +354,11 @@ void Business::setupContent() {
Ui::AddSkip(content, st::settingsFromFileTop);
AddBusinessSummary(content, _controller, [=](BusinessFeature feature) {
switch (feature) {
case BusinessFeature::Chatbots:
_showOther.fire(Settings::ChatbotsId());
break;
}
});
Ui::ResizeFitChild(this, content);

View File

@ -170,39 +170,43 @@ not_null<Button*> AddButtonWithLabel(
}
void AddDividerTextWithLottie(
not_null<Ui::VerticalLayout*> parent,
rpl::producer<> showFinished,
rpl::producer<TextWithEntities> text,
const QString &lottie) {
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(parent.get());
const auto verticalLayout = parent->add(
object_ptr<Ui::VerticalLayout>(parent.get()));
not_null<Ui::VerticalLayout*> container,
DividerWithLottieDescriptor &&descriptor) {
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(
container.get());
const auto verticalLayout = container->add(
object_ptr<Ui::VerticalLayout>(container.get()));
const auto size = descriptor.lottieSize.value_or(
st::settingsFilterIconSize);
auto icon = CreateLottieIcon(
verticalLayout,
{
.name = lottie,
.sizeOverride = {
st::settingsFilterIconSize,
st::settingsFilterIconSize,
},
.name = descriptor.lottie,
.sizeOverride = { size, size },
},
st::settingsFilterIconPadding);
std::move(
showFinished
) | rpl::start_with_next([animate = std::move(icon.animate)] {
animate(anim::repeat::once);
}, verticalLayout->lifetime());
descriptor.lottieMargins.value_or(st::settingsFilterIconPadding));
if (descriptor.showFinished) {
const auto repeat = descriptor.lottieRepeat.value_or(
anim::repeat::once);
std::move(
descriptor.showFinished
) | rpl::start_with_next([animate = std::move(icon.animate), repeat] {
animate(repeat);
}, verticalLayout->lifetime());
}
verticalLayout->add(std::move(icon.widget));
verticalLayout->add(
object_ptr<Ui::CenterWrap<>>(
verticalLayout,
object_ptr<Ui::FlatLabel>(
if (descriptor.about) {
verticalLayout->add(
object_ptr<Ui::CenterWrap<>>(
verticalLayout,
std::move(text),
st::settingsFilterDividerLabel)),
st::settingsFilterDividerLabelPadding);
object_ptr<Ui::FlatLabel>(
verticalLayout,
std::move(descriptor.about),
st::settingsFilterDividerLabel)),
descriptor.aboutMargins.value_or(
st::settingsFilterDividerLabelPadding));
}
verticalLayout->geometryValue(
) | rpl::start_with_next([=](const QRect &r) {

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/text/text_variant.h"
#include "ui/rp_widget.h"
#include "ui/round_rect.h"
#include "base/object_ptr.h"
@ -151,11 +152,19 @@ void CreateRightLabel(
rpl::producer<QString> label,
const style::SettingsButton &st,
rpl::producer<QString> buttonText);
struct DividerWithLottieDescriptor {
QString lottie;
std::optional<anim::repeat> lottieRepeat;
std::optional<int> lottieSize;
std::optional<QMargins> lottieMargins;
rpl::producer<> showFinished;
rpl::producer<TextWithEntities> about;
std::optional<QMargins> aboutMargins;
};
void AddDividerTextWithLottie(
not_null<Ui::VerticalLayout*> parent,
rpl::producer<> showFinished,
rpl::producer<TextWithEntities> text,
const QString &lottie);
not_null<Ui::VerticalLayout*> container,
DividerWithLottieDescriptor &&descriptor);
struct LottieIcon {
object_ptr<Ui::RpWidget> widget;

View File

@ -31,24 +31,28 @@ void AddDivider(not_null<Ui::VerticalLayout*> container) {
void AddDividerText(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text,
const style::margins &margins) {
const style::margins &margins,
RectParts parts) {
AddDividerText(
container,
std::move(text) | Ui::Text::ToWithEntities(),
margins);
margins,
parts);
}
void AddDividerText(
not_null<Ui::VerticalLayout*> container,
rpl::producer<TextWithEntities> text,
const style::margins &margins) {
const style::margins &margins,
RectParts parts) {
container->add(object_ptr<Ui::DividerLabel>(
container,
object_ptr<Ui::FlatLabel>(
container,
std::move(text),
st::boxDividerLabel),
margins));
margins,
parts));
}
not_null<Ui::FlatLabel*> AddSubsectionTitle(

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/rect_part.h"
namespace style {
struct FlatLabel;
} // namespace style
@ -26,11 +28,13 @@ void AddDivider(not_null<Ui::VerticalLayout*> container);
void AddDividerText(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text,
const style::margins &margins = st::defaultBoxDividerLabelPadding);
const style::margins &margins = st::defaultBoxDividerLabelPadding,
RectParts parts = RectPart::Top | RectPart::Bottom);
void AddDividerText(
not_null<Ui::VerticalLayout*> container,
rpl::producer<TextWithEntities> text,
const style::margins &margins = st::defaultBoxDividerLabelPadding);
const style::margins &margins = st::defaultBoxDividerLabelPadding,
RectParts parts = RectPart::Top | RectPart::Bottom);
not_null<Ui::FlatLabel*> AddSubsectionTitle(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text,