mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Start all business sections implementation.
This commit is contained in:
parent
0af131f144
commit
1e5f821c6f
30 changed files with 1196 additions and 310 deletions
|
@ -1282,10 +1282,20 @@ PRIVATE
|
||||||
profile/profile_block_widget.h
|
profile/profile_block_widget.h
|
||||||
profile/profile_cover_drop_area.cpp
|
profile/profile_cover_drop_area.cpp
|
||||||
profile/profile_cover_drop_area.h
|
profile/profile_cover_drop_area.h
|
||||||
settings/business/settings_business_exceptions.cpp
|
settings/business/settings_away_message.cpp
|
||||||
settings/business/settings_business_exceptions.h
|
settings/business/settings_away_message.h
|
||||||
settings/business/settings_chatbots.cpp
|
settings/business/settings_chatbots.cpp
|
||||||
settings/business/settings_chatbots.h
|
settings/business/settings_chatbots.h
|
||||||
|
settings/business/settings_greeting.cpp
|
||||||
|
settings/business/settings_greeting.h
|
||||||
|
settings/business/settings_location.cpp
|
||||||
|
settings/business/settings_location.h
|
||||||
|
settings/business/settings_quick_replies.cpp
|
||||||
|
settings/business/settings_quick_replies.h
|
||||||
|
settings/business/settings_recipients_helper.cpp
|
||||||
|
settings/business/settings_recipients_helper.h
|
||||||
|
settings/business/settings_working_hours.cpp
|
||||||
|
settings/business/settings_working_hours.h
|
||||||
settings/cloud_password/settings_cloud_password_common.cpp
|
settings/cloud_password/settings_cloud_password_common.cpp
|
||||||
settings/cloud_password/settings_cloud_password_common.h
|
settings/cloud_password/settings_cloud_password_common.h
|
||||||
settings/cloud_password/settings_cloud_password_email.cpp
|
settings/cloud_password/settings_cloud_password_email.cpp
|
||||||
|
|
BIN
Telegram/Resources/animations/greeting.tgs
Normal file
BIN
Telegram/Resources/animations/greeting.tgs
Normal file
Binary file not shown.
BIN
Telegram/Resources/animations/hours.tgs
Normal file
BIN
Telegram/Resources/animations/hours.tgs
Normal file
Binary file not shown.
BIN
Telegram/Resources/animations/location.tgs
Normal file
BIN
Telegram/Resources/animations/location.tgs
Normal file
Binary file not shown.
BIN
Telegram/Resources/animations/phone.tgs
Normal file
BIN
Telegram/Resources/animations/phone.tgs
Normal file
Binary file not shown.
BIN
Telegram/Resources/animations/sleep.tgs
Normal file
BIN
Telegram/Resources/animations/sleep.tgs
Normal file
Binary file not shown.
BIN
Telegram/Resources/animations/writing.tgs
Normal file
BIN
Telegram/Resources/animations/writing.tgs
Normal file
Binary file not shown.
|
@ -2172,6 +2172,70 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_business_subtitle_chatbots" = "Chatbots";
|
"lng_business_subtitle_chatbots" = "Chatbots";
|
||||||
"lng_business_about_chatbots" = "Add any third party chatbots that will process customer interactions.";
|
"lng_business_about_chatbots" = "Add any third party chatbots that will process customer interactions.";
|
||||||
|
|
||||||
|
"lng_location_title" = "Location";
|
||||||
|
"lng_location_about" = "Display the location of your business on your account.";
|
||||||
|
"lng_location_address" = "Enter Address";
|
||||||
|
"lng_location_fallback" = "You can set your location on the map from your mobile device.";
|
||||||
|
|
||||||
|
"lng_hours_title" = "Business Hours";
|
||||||
|
"lng_hours_about" = "Turn this on to show your opening hours schedule to your customers.";
|
||||||
|
"lng_hours_show" = "Show Business Hours";
|
||||||
|
"lng_hours_time_zone" = "Time Zone";
|
||||||
|
"lng_hours_monday" = "Monday";
|
||||||
|
"lng_hours_tuesday" = "Tuesday";
|
||||||
|
"lng_hours_wednesday" = "Wednesday";
|
||||||
|
"lng_hours_thursday" = "Thursday";
|
||||||
|
"lng_hours_friday" = "Friday";
|
||||||
|
"lng_hours_saturday" = "Saturday";
|
||||||
|
"lng_hours_sunday" = "Sunday";
|
||||||
|
"lng_hours_closed" = "Closed";
|
||||||
|
|
||||||
|
"lng_replies_title" = "Quick Replies";
|
||||||
|
"lng_replies_about" = "Set up shortcuts with rich text and media to respond to messages faster.";
|
||||||
|
"lng_replies_add" = "Add Quick Reply";
|
||||||
|
"lng_replies_add_title" = "New Quick Reply";
|
||||||
|
"lng_replies_add_shortcut" = "Add a shortcut for your reply.";
|
||||||
|
"lng_replies_add_placeholder" = "Shortcut";
|
||||||
|
"lng_replies_add_exists" = "This shortcut already exists.";
|
||||||
|
"lng_replies_empty_title" = "New Quick Reply";
|
||||||
|
"lng_replies_empty_about" = "Enter a message below that will be sent in chat when you type {shortcut}.\n\nYou can access Quick Replies in any chat by typing / or using Attachment menu.";
|
||||||
|
"lng_replies_remove_title" = "Remove Shortcut";
|
||||||
|
"lng_replies_remove_text" = "You didn't create a quick reply message. Do you want to remove the shortcut?";
|
||||||
|
"lng_replies_edit_title" = "Edit Shortcut";
|
||||||
|
"lng_replies_edit_about" = "Edit the name for this shortcut.";
|
||||||
|
"lng_replies_message_placeholder" = "Add a Quick Reply";
|
||||||
|
|
||||||
|
"lng_greeting_title" = "Greeting Message";
|
||||||
|
"lng_greeting_about" = "Greet customers when they message you the first time or after a period of no activity.";
|
||||||
|
"lng_greeting_enable" = "Send Greeting Message";
|
||||||
|
"lng_greeting_create" = "Create a Greeting Message";
|
||||||
|
"lng_greeting_recipients" = "Recipients";
|
||||||
|
"lng_greeting_select" = "Select chats or entire chat categories for sending a greeting message.";
|
||||||
|
"lng_greeting_period_title" = "Period of no activity";
|
||||||
|
"lng_greeting_period_about" = "Choose how many days should pass after your last interaction with a recipient to send them a greeting in response to their message.";
|
||||||
|
"lng_greeting_empty_title" = "New Greeting Message";
|
||||||
|
"lng_greeting_empty_about" = "Create greetings that will be automatically sent to new customers.";
|
||||||
|
"lng_greeting_message_placeholder" = "Add a Greeting";
|
||||||
|
|
||||||
|
"lng_away_title" = "Away Message";
|
||||||
|
"lng_away_about" = "Automatically reply with a message when you are away.";
|
||||||
|
"lng_away_enable" = "Send Away Message";
|
||||||
|
"lng_away_create" = "Create an Away Message";
|
||||||
|
"lng_away_schedule" = "Schedule";
|
||||||
|
"lng_away_schedule_always" = "Send Always";
|
||||||
|
"lng_away_schedule_outside" = "Outside of Business Hours";
|
||||||
|
"lng_away_schedule_custom" = "Custom Schedule";
|
||||||
|
"lng_away_custom_start" = "Start Time";
|
||||||
|
"lng_away_custom_end" = "End Time";
|
||||||
|
"lng_away_recipients" = "Recipients";
|
||||||
|
"lng_away_select" = "Select chats or entire chat categories for sending an away message.";
|
||||||
|
"lng_away_empty_title" = "New Away Message";
|
||||||
|
"lng_away_empty_about" = "Add messages that will be automatically sent when you are off.";
|
||||||
|
"lng_away_message_placeholder" = "Add an Away Message";
|
||||||
|
|
||||||
|
"lng_business_limit_reached#one" = "Limit of {count} message reached.";
|
||||||
|
"lng_business_limit_reached#other" = "Limit of {count} messages reached.";
|
||||||
|
|
||||||
"lng_chatbots_title" = "Chatbots";
|
"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" = "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_about_link" = "Learn more...";
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
<file alias="voice_ttl_idle.tgs">../../animations/voice_ttl_idle.tgs</file>
|
<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="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
|
||||||
<file alias="palette.tgs">../../animations/palette.tgs</file>
|
<file alias="palette.tgs">../../animations/palette.tgs</file>
|
||||||
<file alias="robot.tgs">../../animations/robot.tgs</file>
|
<file alias="sleep.tgs">../../animations/sleep.tgs</file>
|
||||||
|
<file alias="greeting.tgs">../../animations/greeting.tgs</file>
|
||||||
|
<file alias="location.tgs">../../animations/location.tgs</file>
|
||||||
|
<file alias="robot.tgs">../../animations/robot.tgs</file>
|
||||||
|
<file alias="writing.tgs">../../animations/writing.tgs</file>
|
||||||
|
<file alias="hours.tgs">../../animations/hours.tgs</file>
|
||||||
|
<file alias="phone.tgs">../../animations/phone.tgs</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -17,10 +17,8 @@ class Session;
|
||||||
|
|
||||||
struct ChatbotsSettings {
|
struct ChatbotsSettings {
|
||||||
UserData *bot = nullptr;
|
UserData *bot = nullptr;
|
||||||
BusinessExceptions allowed;
|
BusinessRecipients recipients;
|
||||||
BusinessExceptions disallowed;
|
|
||||||
bool repliesAllowed = false;
|
bool repliesAllowed = false;
|
||||||
bool onlySelected = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Chatbots final {
|
class Chatbots final {
|
||||||
|
|
|
@ -23,9 +23,23 @@ inline constexpr bool is_flag_type(BusinessChatType) { return true; }
|
||||||
|
|
||||||
using BusinessChatTypes = base::flags<BusinessChatType>;
|
using BusinessChatTypes = base::flags<BusinessChatType>;
|
||||||
|
|
||||||
struct BusinessExceptions {
|
struct BusinessChats {
|
||||||
BusinessChatTypes types;
|
BusinessChatTypes types;
|
||||||
std::vector<not_null<UserData*>> list;
|
std::vector<not_null<UserData*>> list;
|
||||||
|
|
||||||
|
friend inline bool operator==(
|
||||||
|
const BusinessChats &a,
|
||||||
|
const BusinessChats &b) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BusinessRecipients {
|
||||||
|
BusinessChats included;
|
||||||
|
BusinessChats excluded;
|
||||||
|
bool onlyIncluded = false;
|
||||||
|
|
||||||
|
friend inline bool operator==(
|
||||||
|
const BusinessRecipients &a,
|
||||||
|
const BusinessRecipients &b) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
117
Telegram/SourceFiles/settings/business/settings_away_message.cpp
Normal file
117
Telegram/SourceFiles/settings/business/settings_away_message.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
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_away_message.h"
|
||||||
|
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "data/data_session.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/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_settings.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class AwayMessage : public BusinessSection<AwayMessage> {
|
||||||
|
public:
|
||||||
|
AwayMessage(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller);
|
||||||
|
~AwayMessage();
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QString> title() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupContent(not_null<Window::SessionController*> controller);
|
||||||
|
void save();
|
||||||
|
|
||||||
|
rpl::variable<Data::BusinessRecipients> _recipients;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
AwayMessage::AwayMessage(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller)
|
||||||
|
: BusinessSection(parent, controller) {
|
||||||
|
setupContent(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
AwayMessage::~AwayMessage() {
|
||||||
|
if (!Core::Quitting()) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QString> AwayMessage::title() {
|
||||||
|
return tr::lng_away_title();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AwayMessage::setupContent(
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
|
//const auto current = controller->session().data().chatbots().current();
|
||||||
|
|
||||||
|
//_recipients = current.recipients;
|
||||||
|
|
||||||
|
AddDividerTextWithLottie(content, {
|
||||||
|
.lottie = u"sleep"_q,
|
||||||
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
||||||
|
.lottieMargins = st::peerAppearanceIconPadding,
|
||||||
|
.showFinished = showFinishes(),
|
||||||
|
.about = tr::lng_away_about(Ui::Text::WithEntities),
|
||||||
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ui::AddSkip(content);
|
||||||
|
const auto enabled = content->add(object_ptr<Ui::SettingsButton>(
|
||||||
|
content,
|
||||||
|
tr::lng_away_enable(),
|
||||||
|
st::settingsButtonNoIcon
|
||||||
|
))->toggleOn(rpl::single(false));
|
||||||
|
|
||||||
|
const auto wrap = content->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
content,
|
||||||
|
object_ptr<Ui::VerticalLayout>(content)));
|
||||||
|
const auto inner = wrap->entity();
|
||||||
|
|
||||||
|
Ui::AddSkip(inner);
|
||||||
|
Ui::AddDivider(inner);
|
||||||
|
|
||||||
|
wrap->toggleOn(enabled->toggledValue());
|
||||||
|
wrap->finishAnimating();
|
||||||
|
|
||||||
|
AddBusinessRecipientsSelector(inner, {
|
||||||
|
.controller = controller,
|
||||||
|
.title = tr::lng_away_recipients(),
|
||||||
|
.data = &_recipients,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ui::AddSkip(inner, st::settingsChatbotsAccessSkip);
|
||||||
|
|
||||||
|
Ui::ResizeFitChild(this, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AwayMessage::save() {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Type AwayMessageId() {
|
||||||
|
return AwayMessage::Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -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 AwayMessageId();
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
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_business_exceptions.h"
|
|
||||||
|
|
||||||
#include "boxes/filters/edit_filter_chats_list.h"
|
|
||||||
#include "boxes/filters/edit_filter_chats_preview.h"
|
|
||||||
#include "data/data_session.h"
|
|
||||||
#include "data/data_user.h"
|
|
||||||
#include "history/history.h"
|
|
||||||
#include "lang/lang_keys.h"
|
|
||||||
#include "ui/wrap/vertical_layout.h"
|
|
||||||
#include "window/window_session_controller.h"
|
|
||||||
|
|
||||||
namespace Settings {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using Flag = Data::ChatFilter::Flag;
|
|
||||||
using Flags = Data::ChatFilter::Flags;
|
|
||||||
|
|
||||||
[[nodiscard]] Flags TypesToFlags(Data::BusinessChatTypes types) {
|
|
||||||
using Type = Data::BusinessChatType;
|
|
||||||
return ((types & Type::Contacts) ? Flag::Contacts : Flag())
|
|
||||||
| ((types & Type::NonContacts) ? Flag::NonContacts : Flag())
|
|
||||||
| ((types & Type::NewChats) ? Flag::NewChats : Flag())
|
|
||||||
| ((types & Type::ExistingChats) ? Flag::ExistingChats : Flag());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Data::BusinessChatTypes FlagsToTypes(Flags flags) {
|
|
||||||
using Type = Data::BusinessChatType;
|
|
||||||
return ((flags & Flag::Contacts) ? Type::Contacts : Type())
|
|
||||||
| ((flags & Flag::NonContacts) ? Type::NonContacts : Type())
|
|
||||||
| ((flags & Flag::NewChats) ? Type::NewChats : Type())
|
|
||||||
| ((flags & Flag::ExistingChats) ? Type::ExistingChats : Type());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void EditBusinessExceptions(
|
|
||||||
not_null<Window::SessionController*> window,
|
|
||||||
BusinessExceptionsDescriptor &&descriptor) {
|
|
||||||
const auto session = &window->session();
|
|
||||||
const auto options = Flag::ExistingChats
|
|
||||||
| Flag::NewChats
|
|
||||||
| Flag::Contacts
|
|
||||||
| Flag::NonContacts;
|
|
||||||
auto &&peers = descriptor.current.list | ranges::views::transform([=](
|
|
||||||
not_null<UserData*> user) {
|
|
||||||
return user->owner().history(user);
|
|
||||||
});
|
|
||||||
auto controller = std::make_unique<EditFilterChatsListController>(
|
|
||||||
session,
|
|
||||||
(descriptor.allow
|
|
||||||
? tr::lng_filters_include_title()
|
|
||||||
: tr::lng_filters_exclude_title()),
|
|
||||||
options,
|
|
||||||
TypesToFlags(descriptor.current.types) & options,
|
|
||||||
base::flat_set<not_null<History*>>(begin(peers), end(peers)),
|
|
||||||
[=](int count) {
|
|
||||||
return nullptr; AssertIsDebug();
|
|
||||||
});
|
|
||||||
const auto rawController = controller.get();
|
|
||||||
const auto save = descriptor.save;
|
|
||||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
|
||||||
box->setCloseByOutsideClick(false);
|
|
||||||
box->addButton(tr::lng_settings_save(), crl::guard(box, [=] {
|
|
||||||
const auto peers = box->collectSelectedRows();
|
|
||||||
auto &&users = ranges::views::all(
|
|
||||||
peers
|
|
||||||
) | ranges::views::transform([=](not_null<PeerData*> peer) {
|
|
||||||
return not_null(peer->asUser());
|
|
||||||
}) | ranges::to_vector;
|
|
||||||
save(Data::BusinessExceptions{
|
|
||||||
.types = FlagsToTypes(rawController->chosenOptions()),
|
|
||||||
.list = std::move(users),
|
|
||||||
});
|
|
||||||
box->closeBox();
|
|
||||||
}));
|
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
|
||||||
};
|
|
||||||
window->show(
|
|
||||||
Box<PeerListBox>(std::move(controller), std::move(initBox)));
|
|
||||||
}
|
|
||||||
|
|
||||||
not_null<FilterChatsPreview*> SetupBusinessExceptionsPreview(
|
|
||||||
not_null<Ui::VerticalLayout*> content,
|
|
||||||
not_null<rpl::variable<Data::BusinessExceptions>*> data) {
|
|
||||||
const auto rules = data->current();
|
|
||||||
|
|
||||||
const auto locked = std::make_shared<bool>();
|
|
||||||
auto &&peers = data->current().list | ranges::views::transform([=](
|
|
||||||
not_null<UserData*> user) {
|
|
||||||
return user->owner().history(user);
|
|
||||||
});
|
|
||||||
const auto preview = content->add(object_ptr<FilterChatsPreview>(
|
|
||||||
content,
|
|
||||||
TypesToFlags(data->current().types),
|
|
||||||
base::flat_set<not_null<History*>>(begin(peers), end(peers))));
|
|
||||||
|
|
||||||
preview->flagRemoved(
|
|
||||||
) | rpl::start_with_next([=](Flag flag) {
|
|
||||||
*locked = true;
|
|
||||||
*data = Data::BusinessExceptions{
|
|
||||||
data->current().types & ~FlagsToTypes(flag),
|
|
||||||
data->current().list
|
|
||||||
};
|
|
||||||
*locked = false;
|
|
||||||
}, preview->lifetime());
|
|
||||||
|
|
||||||
preview->peerRemoved(
|
|
||||||
) | rpl::start_with_next([=](not_null<History*> history) {
|
|
||||||
auto list = data->current().list;
|
|
||||||
list.erase(
|
|
||||||
ranges::remove(list, not_null(history->peer->asUser())),
|
|
||||||
end(list));
|
|
||||||
|
|
||||||
*locked = true;
|
|
||||||
*data = Data::BusinessExceptions{
|
|
||||||
data->current().types,
|
|
||||||
std::move(list)
|
|
||||||
};
|
|
||||||
*locked = false;
|
|
||||||
}, preview->lifetime());
|
|
||||||
|
|
||||||
data->changes(
|
|
||||||
) | rpl::filter([=] {
|
|
||||||
return !*locked;
|
|
||||||
}) | rpl::start_with_next([=](const Data::BusinessExceptions &rules) {
|
|
||||||
auto &&peers = rules.list | ranges::views::transform([=](
|
|
||||||
not_null<UserData*> user) {
|
|
||||||
return user->owner().history(user);
|
|
||||||
});
|
|
||||||
preview->updateData(
|
|
||||||
TypesToFlags(rules.types),
|
|
||||||
base::flat_set<not_null<History*>>(begin(peers), end(peers)));
|
|
||||||
}, preview->lifetime());
|
|
||||||
|
|
||||||
return preview;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Settings
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
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 "data/business/data_business_common.h"
|
|
||||||
|
|
||||||
class FilterChatsPreview;
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class VerticalLayout;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
namespace Window {
|
|
||||||
class SessionController;
|
|
||||||
} // namespace Window
|
|
||||||
|
|
||||||
namespace Settings {
|
|
||||||
|
|
||||||
struct BusinessExceptionsDescriptor {
|
|
||||||
Data::BusinessExceptions current;
|
|
||||||
Fn<void(const Data::BusinessExceptions&)> save;
|
|
||||||
bool allow = false;
|
|
||||||
};
|
|
||||||
void EditBusinessExceptions(
|
|
||||||
not_null<Window::SessionController*> window,
|
|
||||||
BusinessExceptionsDescriptor &&descriptor);
|
|
||||||
|
|
||||||
not_null<FilterChatsPreview*> SetupBusinessExceptionsPreview(
|
|
||||||
not_null<Ui::VerticalLayout*> content,
|
|
||||||
not_null<rpl::variable<Data::BusinessExceptions>*> data);
|
|
||||||
|
|
||||||
} // namespace Settings
|
|
|
@ -6,18 +6,17 @@ For license and copyright information please follow this link:
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "settings/business/settings_chatbots.h"
|
#include "settings/business/settings_chatbots.h"
|
||||||
|
//
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "data/business/data_business_chatbots.h"
|
#include "data/business/data_business_chatbots.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "settings/business/settings_business_exceptions.h"
|
#include "settings/business/settings_recipients_helper.h"
|
||||||
#include "settings/settings_common_session.h"
|
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/widgets/fields/input_field.h"
|
#include "ui/widgets/fields/input_field.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
|
@ -28,10 +27,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kAllExcept = 0;
|
enum class LookupState {
|
||||||
constexpr auto kSelectedOnly = 1;
|
Empty,
|
||||||
|
Loading,
|
||||||
|
Ready,
|
||||||
|
};
|
||||||
|
|
||||||
class Chatbots : public Section<Chatbots> {
|
struct BotState {
|
||||||
|
UserData *bot = nullptr;
|
||||||
|
LookupState state = LookupState::Empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Chatbots : public BusinessSection<Chatbots> {
|
||||||
public:
|
public:
|
||||||
Chatbots(
|
Chatbots(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
@ -40,10 +47,6 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<QString> title() override;
|
[[nodiscard]] rpl::producer<QString> title() override;
|
||||||
|
|
||||||
rpl::producer<> showFinishes() const {
|
|
||||||
return _showFinished.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Ui::RoundRect *bottomSkipRounding() const {
|
const Ui::RoundRect *bottomSkipRounding() const {
|
||||||
return &_bottomSkipRounding;
|
return &_bottomSkipRounding;
|
||||||
}
|
}
|
||||||
|
@ -52,29 +55,37 @@ private:
|
||||||
void setupContent(not_null<Window::SessionController*> controller);
|
void setupContent(not_null<Window::SessionController*> controller);
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
void showFinished() override {
|
|
||||||
_showFinished.fire({});
|
|
||||||
}
|
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
|
||||||
const not_null<Main::Session*> _session;
|
|
||||||
|
|
||||||
rpl::event_stream<> _showFinished;
|
|
||||||
Ui::RoundRect _bottomSkipRounding;
|
Ui::RoundRect _bottomSkipRounding;
|
||||||
|
|
||||||
rpl::variable<bool> _onlySelected = false;
|
rpl::variable<Data::BusinessRecipients> _recipients;
|
||||||
|
rpl::variable<QString> _usernameValue;
|
||||||
|
rpl::variable<BotState> _botValue = nullptr;
|
||||||
rpl::variable<bool> _repliesAllowed = true;
|
rpl::variable<bool> _repliesAllowed = true;
|
||||||
rpl::variable<Data::BusinessExceptions> _allowed;
|
|
||||||
rpl::variable<Data::BusinessExceptions> _disallowed;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QString> DebouncedValue(
|
||||||
|
not_null<Ui::InputField*> field) {
|
||||||
|
return rpl::single(field->getLastText());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<BotState> LookupBot(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
rpl::producer<QString> usernameChanges) {
|
||||||
|
return rpl::never<BotState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] object_ptr<Ui::RpWidget> MakeBotPreview(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
rpl::producer<BotState> state,
|
||||||
|
Fn<void()> resetBot) {
|
||||||
|
return object_ptr<Ui::RpWidget>(parent.get());
|
||||||
|
}
|
||||||
|
|
||||||
Chatbots::Chatbots(
|
Chatbots::Chatbots(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller)
|
not_null<Window::SessionController*> controller)
|
||||||
: Section(parent)
|
: BusinessSection(parent, controller)
|
||||||
, _controller(controller)
|
|
||||||
, _session(&controller->session())
|
|
||||||
, _bottomSkipRounding(st::boxRadius, st::boxDividerBg) {
|
, _bottomSkipRounding(st::boxRadius, st::boxDividerBg) {
|
||||||
setupContent(controller);
|
setupContent(controller);
|
||||||
}
|
}
|
||||||
|
@ -96,10 +107,8 @@ void Chatbots::setupContent(
|
||||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
const auto current = controller->session().data().chatbots().current();
|
const auto current = controller->session().data().chatbots().current();
|
||||||
|
|
||||||
_onlySelected = current.onlySelected;
|
_recipients = current.recipients;
|
||||||
_repliesAllowed = current.repliesAllowed;
|
_repliesAllowed = current.repliesAllowed;
|
||||||
_allowed = current.allowed;
|
|
||||||
_disallowed = current.disallowed;
|
|
||||||
|
|
||||||
AddDividerTextWithLottie(content, {
|
AddDividerTextWithLottie(content, {
|
||||||
.lottie = u"robot"_q,
|
.lottie = u"robot"_q,
|
||||||
|
@ -125,93 +134,31 @@ void Chatbots::setupContent(
|
||||||
: QString())),
|
: QString())),
|
||||||
st::settingsChatbotsUsernameMargins);
|
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<Ui::SlideWrap<Ui::RpWidget>>(
|
||||||
|
content,
|
||||||
|
MakeBotPreview(content, _botValue.value(), resetBot)));
|
||||||
|
|
||||||
Ui::AddDividerText(
|
Ui::AddDividerText(
|
||||||
content,
|
content,
|
||||||
tr::lng_chatbots_add_about(),
|
tr::lng_chatbots_add_about(),
|
||||||
st::peerAppearanceDividerTextMargin);
|
st::peerAppearanceDividerTextMargin);
|
||||||
Ui::AddSkip(content);
|
|
||||||
Ui::AddSubsectionTitle(content, tr::lng_chatbots_access_title());
|
|
||||||
|
|
||||||
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
AddBusinessRecipientsSelector(content, {
|
||||||
_onlySelected.current() ? kSelectedOnly : kAllExcept);
|
.controller = controller,
|
||||||
const auto everyone = content->add(
|
.title = tr::lng_chatbots_access_title(),
|
||||||
object_ptr<Ui::Radiobutton>(
|
.data = &_recipients,
|
||||||
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 });
|
|
||||||
excludeAdd->setClickedCallback([=] {
|
|
||||||
EditBusinessExceptions(_controller, {
|
|
||||||
.current = _disallowed.current(),
|
|
||||||
.save = crl::guard(this, [=](Data::BusinessExceptions value) {
|
|
||||||
_disallowed = std::move(value);
|
|
||||||
}),
|
|
||||||
.allow = false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
SetupBusinessExceptionsPreview(excludeInner, &_disallowed);
|
|
||||||
|
|
||||||
excludeWrap->toggleOn(_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 });
|
|
||||||
includeAdd->setClickedCallback([=] {
|
|
||||||
EditBusinessExceptions(_controller, {
|
|
||||||
.current = _allowed.current(),
|
|
||||||
.save = crl::guard(this, [=](Data::BusinessExceptions value) {
|
|
||||||
_allowed = std::move(value);
|
|
||||||
}),
|
|
||||||
.allow = true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
SetupBusinessExceptionsPreview(includeInner, &_allowed);
|
|
||||||
|
|
||||||
includeWrap->toggleOn(_onlySelected.value());
|
|
||||||
includeWrap->finishAnimating();
|
|
||||||
|
|
||||||
group->setChangedCallback([=](int value) {
|
|
||||||
_onlySelected = (value == kSelectedOnly);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ui::AddSkip(content, st::settingsChatbotsAccessSkip);
|
Ui::AddSkip(content, st::settingsChatbotsAccessSkip);
|
||||||
|
@ -243,13 +190,11 @@ void Chatbots::setupContent(
|
||||||
|
|
||||||
void Chatbots::save() {
|
void Chatbots::save() {
|
||||||
const auto settings = Data::ChatbotsSettings{
|
const auto settings = Data::ChatbotsSettings{
|
||||||
.bot = nullptr,
|
.bot = _botValue.current().bot,
|
||||||
.allowed = _allowed.current(),
|
.recipients = _recipients.current(),
|
||||||
.disallowed = _disallowed.current(),
|
|
||||||
.repliesAllowed = _repliesAllowed.current(),
|
.repliesAllowed = _repliesAllowed.current(),
|
||||||
.onlySelected = _onlySelected.current(),
|
|
||||||
};
|
};
|
||||||
_session->data().chatbots().save(settings);
|
controller()->session().data().chatbots().save(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
117
Telegram/SourceFiles/settings/business/settings_greeting.cpp
Normal file
117
Telegram/SourceFiles/settings/business/settings_greeting.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
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_greeting.h"
|
||||||
|
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "data/data_session.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/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_settings.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class Greeting : public BusinessSection<Greeting> {
|
||||||
|
public:
|
||||||
|
Greeting(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller);
|
||||||
|
~Greeting();
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QString> title() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupContent(not_null<Window::SessionController*> controller);
|
||||||
|
void save();
|
||||||
|
|
||||||
|
rpl::variable<Data::BusinessRecipients> _recipients;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Greeting::Greeting(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller)
|
||||||
|
: BusinessSection(parent, controller) {
|
||||||
|
setupContent(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
Greeting::~Greeting() {
|
||||||
|
if (!Core::Quitting()) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QString> Greeting::title() {
|
||||||
|
return tr::lng_greeting_title();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Greeting::setupContent(
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
|
//const auto current = controller->session().data().chatbots().current();
|
||||||
|
|
||||||
|
//_recipients = current.recipients;
|
||||||
|
|
||||||
|
AddDividerTextWithLottie(content, {
|
||||||
|
.lottie = u"greeting"_q,
|
||||||
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
||||||
|
.lottieMargins = st::peerAppearanceIconPadding,
|
||||||
|
.showFinished = showFinishes(),
|
||||||
|
.about = tr::lng_greeting_about(Ui::Text::WithEntities),
|
||||||
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ui::AddSkip(content);
|
||||||
|
const auto enabled = content->add(object_ptr<Ui::SettingsButton>(
|
||||||
|
content,
|
||||||
|
tr::lng_greeting_enable(),
|
||||||
|
st::settingsButtonNoIcon
|
||||||
|
))->toggleOn(rpl::single(false));
|
||||||
|
|
||||||
|
const auto wrap = content->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
content,
|
||||||
|
object_ptr<Ui::VerticalLayout>(content)));
|
||||||
|
const auto inner = wrap->entity();
|
||||||
|
|
||||||
|
Ui::AddSkip(inner);
|
||||||
|
Ui::AddDivider(inner);
|
||||||
|
|
||||||
|
wrap->toggleOn(enabled->toggledValue());
|
||||||
|
wrap->finishAnimating();
|
||||||
|
|
||||||
|
AddBusinessRecipientsSelector(inner, {
|
||||||
|
.controller = controller,
|
||||||
|
.title = tr::lng_greeting_recipients(),
|
||||||
|
.data = &_recipients,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ui::AddSkip(inner, st::settingsChatbotsAccessSkip);
|
||||||
|
|
||||||
|
Ui::ResizeFitChild(this, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Greeting::save() {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Type GreetingId() {
|
||||||
|
return Greeting::Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings
|
16
Telegram/SourceFiles/settings/business/settings_greeting.h
Normal file
16
Telegram/SourceFiles/settings/business/settings_greeting.h
Normal 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 GreetingId();
|
||||||
|
|
||||||
|
} // namespace Settings
|
121
Telegram/SourceFiles/settings/business/settings_location.cpp
Normal file
121
Telegram/SourceFiles/settings/business/settings_location.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
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_location.h"
|
||||||
|
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "data/data_session.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/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 {
|
||||||
|
|
||||||
|
class Location : public BusinessSection<Location> {
|
||||||
|
public:
|
||||||
|
Location(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller);
|
||||||
|
~Location();
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QString> title() override;
|
||||||
|
|
||||||
|
const Ui::RoundRect *bottomSkipRounding() const {
|
||||||
|
return mapSupported() ? nullptr : &_bottomSkipRounding;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupContent(not_null<Window::SessionController*> controller);
|
||||||
|
void save();
|
||||||
|
|
||||||
|
[[nodiscard]] bool mapSupported() const;
|
||||||
|
|
||||||
|
Ui::RoundRect _bottomSkipRounding;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Location::Location(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller)
|
||||||
|
: BusinessSection(parent, controller)
|
||||||
|
, _bottomSkipRounding(st::boxRadius, st::boxDividerBg) {
|
||||||
|
setupContent(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
Location::~Location() {
|
||||||
|
if (!Core::Quitting()) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QString> Location::title() {
|
||||||
|
return tr::lng_location_title();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Location::setupContent(
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
|
|
||||||
|
AddDividerTextWithLottie(content, {
|
||||||
|
.lottie = u"location"_q,
|
||||||
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
||||||
|
.lottieMargins = st::peerAppearanceIconPadding,
|
||||||
|
.showFinished = showFinishes(),
|
||||||
|
.about = tr::lng_location_about(Ui::Text::WithEntities),
|
||||||
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto address = content->add(
|
||||||
|
object_ptr<Ui::InputField>(
|
||||||
|
content,
|
||||||
|
st::settingsLocationAddress,
|
||||||
|
Ui::InputField::Mode::MultiLine,
|
||||||
|
tr::lng_location_address(),
|
||||||
|
QString()),
|
||||||
|
st::settingsChatbotsUsernameMargins);
|
||||||
|
|
||||||
|
if (!mapSupported()) {
|
||||||
|
AddDividerTextWithLottie(content, {
|
||||||
|
.lottie = u"phone"_q,
|
||||||
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
||||||
|
.lottieMargins = st::peerAppearanceIconPadding,
|
||||||
|
.showFinished = showFinishes(),
|
||||||
|
.about = tr::lng_location_fallback(Ui::Text::WithEntities),
|
||||||
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
||||||
|
.parts = RectPart::Top,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::ResizeFitChild(this, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Location::save() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Location::mapSupported() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Type LocationId() {
|
||||||
|
return Location::Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings
|
16
Telegram/SourceFiles/settings/business/settings_location.h
Normal file
16
Telegram/SourceFiles/settings/business/settings_location.h
Normal 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 LocationId();
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
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 "core/application.h"
|
||||||
|
#include "data/data_session.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/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_settings.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
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);
|
||||||
|
void save();
|
||||||
|
|
||||||
|
rpl::variable<Data::BusinessRecipients> _recipients;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
QuickReplies::QuickReplies(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller)
|
||||||
|
: BusinessSection(parent, controller) {
|
||||||
|
setupContent(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickReplies::~QuickReplies() {
|
||||||
|
if (!Core::Quitting()) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 enabled = content->add(object_ptr<Ui::SettingsButton>(
|
||||||
|
content,
|
||||||
|
tr::lng_replies_add(),
|
||||||
|
st::settingsButtonNoIcon
|
||||||
|
));
|
||||||
|
|
||||||
|
enabled->setClickedCallback([=] {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto wrap = content->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
content,
|
||||||
|
object_ptr<Ui::VerticalLayout>(content)));
|
||||||
|
const auto inner = wrap->entity();
|
||||||
|
|
||||||
|
Ui::AddSkip(inner);
|
||||||
|
Ui::AddDivider(inner);
|
||||||
|
|
||||||
|
Ui::ResizeFitChild(this, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickReplies::save() {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Type QuickRepliesId() {
|
||||||
|
return QuickReplies::Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -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 QuickRepliesId();
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -0,0 +1,294 @@
|
||||||
|
/*
|
||||||
|
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_recipients_helper.h"
|
||||||
|
|
||||||
|
#include "boxes/filters/edit_filter_chats_list.h"
|
||||||
|
#include "boxes/filters/edit_filter_chats_preview.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "settings/settings_common.h"
|
||||||
|
#include "ui/widgets/checkbox.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_settings.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kAllExcept = 0;
|
||||||
|
constexpr auto kSelectedOnly = 1;
|
||||||
|
|
||||||
|
using Flag = Data::ChatFilter::Flag;
|
||||||
|
using Flags = Data::ChatFilter::Flags;
|
||||||
|
|
||||||
|
[[nodiscard]] Flags TypesToFlags(Data::BusinessChatTypes types) {
|
||||||
|
using Type = Data::BusinessChatType;
|
||||||
|
return ((types & Type::Contacts) ? Flag::Contacts : Flag())
|
||||||
|
| ((types & Type::NonContacts) ? Flag::NonContacts : Flag())
|
||||||
|
| ((types & Type::NewChats) ? Flag::NewChats : Flag())
|
||||||
|
| ((types & Type::ExistingChats) ? Flag::ExistingChats : Flag());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Data::BusinessChatTypes FlagsToTypes(Flags flags) {
|
||||||
|
using Type = Data::BusinessChatType;
|
||||||
|
return ((flags & Flag::Contacts) ? Type::Contacts : Type())
|
||||||
|
| ((flags & Flag::NonContacts) ? Type::NonContacts : Type())
|
||||||
|
| ((flags & Flag::NewChats) ? Type::NewChats : Type())
|
||||||
|
| ((flags & Flag::ExistingChats) ? Type::ExistingChats : Type());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void EditBusinessChats(
|
||||||
|
not_null<Window::SessionController*> window,
|
||||||
|
BusinessChatsDescriptor &&descriptor) {
|
||||||
|
const auto session = &window->session();
|
||||||
|
const auto options = Flag::ExistingChats
|
||||||
|
| Flag::NewChats
|
||||||
|
| Flag::Contacts
|
||||||
|
| Flag::NonContacts;
|
||||||
|
auto &&peers = descriptor.current.list | ranges::views::transform([=](
|
||||||
|
not_null<UserData*> user) {
|
||||||
|
return user->owner().history(user);
|
||||||
|
});
|
||||||
|
auto controller = std::make_unique<EditFilterChatsListController>(
|
||||||
|
session,
|
||||||
|
(descriptor.include
|
||||||
|
? tr::lng_filters_include_title()
|
||||||
|
: tr::lng_filters_exclude_title()),
|
||||||
|
options,
|
||||||
|
TypesToFlags(descriptor.current.types) & options,
|
||||||
|
base::flat_set<not_null<History*>>(begin(peers), end(peers)),
|
||||||
|
[=](int count) {
|
||||||
|
return nullptr; AssertIsDebug();
|
||||||
|
});
|
||||||
|
const auto rawController = controller.get();
|
||||||
|
const auto save = descriptor.save;
|
||||||
|
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||||
|
box->setCloseByOutsideClick(false);
|
||||||
|
box->addButton(tr::lng_settings_save(), crl::guard(box, [=] {
|
||||||
|
const auto peers = box->collectSelectedRows();
|
||||||
|
auto &&users = ranges::views::all(
|
||||||
|
peers
|
||||||
|
) | ranges::views::transform([=](not_null<PeerData*> peer) {
|
||||||
|
return not_null(peer->asUser());
|
||||||
|
}) | ranges::to_vector;
|
||||||
|
save(Data::BusinessChats{
|
||||||
|
.types = FlagsToTypes(rawController->chosenOptions()),
|
||||||
|
.list = std::move(users),
|
||||||
|
});
|
||||||
|
box->closeBox();
|
||||||
|
}));
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
};
|
||||||
|
window->show(
|
||||||
|
Box<PeerListBox>(std::move(controller), std::move(initBox)));
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<FilterChatsPreview*> SetupBusinessChatsPreview(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<rpl::variable<Data::BusinessChats>*> data) {
|
||||||
|
const auto rules = data->current();
|
||||||
|
|
||||||
|
const auto locked = std::make_shared<bool>();
|
||||||
|
auto &&peers = data->current().list | ranges::views::transform([=](
|
||||||
|
not_null<UserData*> user) {
|
||||||
|
return user->owner().history(user);
|
||||||
|
});
|
||||||
|
const auto preview = container->add(object_ptr<FilterChatsPreview>(
|
||||||
|
container,
|
||||||
|
TypesToFlags(data->current().types),
|
||||||
|
base::flat_set<not_null<History*>>(begin(peers), end(peers))));
|
||||||
|
|
||||||
|
preview->flagRemoved(
|
||||||
|
) | rpl::start_with_next([=](Flag flag) {
|
||||||
|
*locked = true;
|
||||||
|
*data = Data::BusinessChats{
|
||||||
|
data->current().types & ~FlagsToTypes(flag),
|
||||||
|
data->current().list
|
||||||
|
};
|
||||||
|
*locked = false;
|
||||||
|
}, preview->lifetime());
|
||||||
|
|
||||||
|
preview->peerRemoved(
|
||||||
|
) | rpl::start_with_next([=](not_null<History*> history) {
|
||||||
|
auto list = data->current().list;
|
||||||
|
list.erase(
|
||||||
|
ranges::remove(list, not_null(history->peer->asUser())),
|
||||||
|
end(list));
|
||||||
|
|
||||||
|
*locked = true;
|
||||||
|
*data = Data::BusinessChats{
|
||||||
|
data->current().types,
|
||||||
|
std::move(list)
|
||||||
|
};
|
||||||
|
*locked = false;
|
||||||
|
}, preview->lifetime());
|
||||||
|
|
||||||
|
data->changes(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return !*locked;
|
||||||
|
}) | rpl::start_with_next([=](const Data::BusinessChats &rules) {
|
||||||
|
auto &&peers = rules.list | ranges::views::transform([=](
|
||||||
|
not_null<UserData*> user) {
|
||||||
|
return user->owner().history(user);
|
||||||
|
});
|
||||||
|
preview->updateData(
|
||||||
|
TypesToFlags(rules.types),
|
||||||
|
base::flat_set<not_null<History*>>(begin(peers), end(peers)));
|
||||||
|
}, preview->lifetime());
|
||||||
|
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddBusinessRecipientsSelector(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
BusinessRecipientsSelectorDescriptor &&descriptor) {
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddSubsectionTitle(container, std::move(descriptor.title));
|
||||||
|
|
||||||
|
auto &lifetime = container->lifetime();
|
||||||
|
const auto controller = descriptor.controller;
|
||||||
|
const auto data = descriptor.data;
|
||||||
|
const auto change = [=](Fn<void(Data::BusinessRecipients&)> modify) {
|
||||||
|
auto now = data->current();
|
||||||
|
modify(now);
|
||||||
|
*data = std::move(now);
|
||||||
|
};
|
||||||
|
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
||||||
|
data->current().onlyIncluded ? kSelectedOnly : kAllExcept);
|
||||||
|
const auto everyone = container->add(
|
||||||
|
object_ptr<Ui::Radiobutton>(
|
||||||
|
container,
|
||||||
|
group,
|
||||||
|
kAllExcept,
|
||||||
|
tr::lng_chatbots_all_except(tr::now),
|
||||||
|
st::settingsChatbotsAccess),
|
||||||
|
st::settingsChatbotsAccessMargins);
|
||||||
|
const auto selected = container->add(
|
||||||
|
object_ptr<Ui::Radiobutton>(
|
||||||
|
container,
|
||||||
|
group,
|
||||||
|
kSelectedOnly,
|
||||||
|
tr::lng_chatbots_selected(tr::now),
|
||||||
|
st::settingsChatbotsAccess),
|
||||||
|
st::settingsChatbotsAccessMargins);
|
||||||
|
|
||||||
|
Ui::AddSkip(container, st::settingsChatbotsAccessSkip);
|
||||||
|
Ui::AddDivider(container);
|
||||||
|
|
||||||
|
const auto excludeWrap = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::VerticalLayout>(container))
|
||||||
|
)->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 });
|
||||||
|
excludeAdd->setClickedCallback([=] {
|
||||||
|
const auto save = [=](Data::BusinessChats value) {
|
||||||
|
change([&](Data::BusinessRecipients &data) {
|
||||||
|
data.excluded = std::move(value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
EditBusinessChats(controller, {
|
||||||
|
.current = data->current().excluded,
|
||||||
|
.save = crl::guard(excludeAdd, save),
|
||||||
|
.include = false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto excluded = lifetime.make_state<
|
||||||
|
rpl::variable<Data::BusinessChats>
|
||||||
|
>(data->current().excluded);
|
||||||
|
data->changes(
|
||||||
|
) | rpl::start_with_next([=](const Data::BusinessRecipients &value) {
|
||||||
|
*excluded = value.excluded;
|
||||||
|
}, lifetime);
|
||||||
|
excluded->changes(
|
||||||
|
) | rpl::start_with_next([=](Data::BusinessChats &&value) {
|
||||||
|
auto now = data->current();
|
||||||
|
now.excluded = std::move(value);
|
||||||
|
*data = std::move(now);
|
||||||
|
}, lifetime);
|
||||||
|
|
||||||
|
SetupBusinessChatsPreview(excludeInner, excluded);
|
||||||
|
|
||||||
|
excludeWrap->toggleOn(data->value(
|
||||||
|
) | rpl::map([](const Data::BusinessRecipients &value) {
|
||||||
|
return !value.onlyIncluded;
|
||||||
|
}));
|
||||||
|
excludeWrap->finishAnimating();
|
||||||
|
|
||||||
|
const auto includeWrap = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::VerticalLayout>(container))
|
||||||
|
)->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 });
|
||||||
|
includeAdd->setClickedCallback([=] {
|
||||||
|
const auto save = [=](Data::BusinessChats value) {
|
||||||
|
change([&](Data::BusinessRecipients &data) {
|
||||||
|
data.included = std::move(value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
EditBusinessChats(controller, {
|
||||||
|
.current = data->current().included ,
|
||||||
|
.save = crl::guard(includeAdd, save),
|
||||||
|
.include = true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto included = lifetime.make_state<
|
||||||
|
rpl::variable<Data::BusinessChats>
|
||||||
|
>(data->current().included);
|
||||||
|
data->changes(
|
||||||
|
) | rpl::start_with_next([=](const Data::BusinessRecipients &value) {
|
||||||
|
*included = value.included;
|
||||||
|
}, lifetime);
|
||||||
|
included->changes(
|
||||||
|
) | rpl::start_with_next([=](Data::BusinessChats &&value) {
|
||||||
|
change([&](Data::BusinessRecipients &data) {
|
||||||
|
data.included = std::move(value);
|
||||||
|
});
|
||||||
|
}, lifetime);
|
||||||
|
|
||||||
|
SetupBusinessChatsPreview(includeInner, excluded);
|
||||||
|
|
||||||
|
includeWrap->toggleOn(data->value(
|
||||||
|
) | rpl::map([](const Data::BusinessRecipients &value) {
|
||||||
|
return value.onlyIncluded;
|
||||||
|
}));
|
||||||
|
includeWrap->finishAnimating();
|
||||||
|
|
||||||
|
group->setChangedCallback([=](int value) {
|
||||||
|
change([&](Data::BusinessRecipients &data) {
|
||||||
|
data.onlyIncluded = (value == kSelectedOnly);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
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 "data/business/data_business_common.h"
|
||||||
|
#include "settings/settings_common_session.h"
|
||||||
|
|
||||||
|
class FilterChatsPreview;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class VerticalLayout;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
template <typename SectionType>
|
||||||
|
class BusinessSection : public Section<SectionType> {
|
||||||
|
public:
|
||||||
|
BusinessSection(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller)
|
||||||
|
: Section<SectionType>(parent)
|
||||||
|
, _controller(controller) {
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<Window::SessionController*> controller() const {
|
||||||
|
return _controller;
|
||||||
|
}
|
||||||
|
[[nodiscard]] rpl::producer<> showFinishes() const {
|
||||||
|
return _showFinished.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void showFinished() override {
|
||||||
|
_showFinished.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
rpl::event_stream<> _showFinished;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BusinessChatsDescriptor {
|
||||||
|
Data::BusinessChats current;
|
||||||
|
Fn<void(const Data::BusinessChats&)> save;
|
||||||
|
bool include = false;
|
||||||
|
};
|
||||||
|
void EditBusinessChats(
|
||||||
|
not_null<Window::SessionController*> window,
|
||||||
|
BusinessChatsDescriptor &&descriptor);
|
||||||
|
|
||||||
|
not_null<FilterChatsPreview*> SetupBusinessChatsPreview(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<rpl::variable<Data::BusinessChats>*> data);
|
||||||
|
|
||||||
|
struct BusinessRecipientsSelectorDescriptor {
|
||||||
|
not_null<Window::SessionController*> controller;
|
||||||
|
rpl::producer<QString> title;
|
||||||
|
not_null<rpl::variable<Data::BusinessRecipients>*> data;
|
||||||
|
};
|
||||||
|
void AddBusinessRecipientsSelector(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
BusinessRecipientsSelectorDescriptor &&descriptor);
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
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_working_hours.h"
|
||||||
|
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "data/data_session.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/buttons.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/vertical_list.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class WorkingHours : public BusinessSection<WorkingHours> {
|
||||||
|
public:
|
||||||
|
WorkingHours(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller);
|
||||||
|
~WorkingHours();
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QString> title() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupContent(not_null<Window::SessionController*> controller);
|
||||||
|
void save();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
WorkingHours::WorkingHours(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller)
|
||||||
|
: BusinessSection(parent, controller) {
|
||||||
|
setupContent(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkingHours::~WorkingHours() {
|
||||||
|
if (!Core::Quitting()) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QString> WorkingHours::title() {
|
||||||
|
return tr::lng_hours_title();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkingHours::setupContent(
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
|
|
||||||
|
AddDividerTextWithLottie(content, {
|
||||||
|
.lottie = u"hours"_q,
|
||||||
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
||||||
|
.lottieMargins = st::peerAppearanceIconPadding,
|
||||||
|
.showFinished = showFinishes(),
|
||||||
|
.about = tr::lng_hours_about(Ui::Text::WithEntities),
|
||||||
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ui::AddSkip(content);
|
||||||
|
const auto enabled = content->add(object_ptr<Ui::SettingsButton>(
|
||||||
|
content,
|
||||||
|
tr::lng_hours_show(),
|
||||||
|
st::settingsButtonNoIcon
|
||||||
|
))->toggleOn(rpl::single(false));
|
||||||
|
|
||||||
|
const auto wrap = content->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
content,
|
||||||
|
object_ptr<Ui::VerticalLayout>(content)));
|
||||||
|
const auto inner = wrap->entity();
|
||||||
|
|
||||||
|
Ui::AddSkip(inner);
|
||||||
|
Ui::AddDivider(inner);
|
||||||
|
|
||||||
|
wrap->toggleOn(enabled->toggledValue());
|
||||||
|
wrap->finishAnimating();
|
||||||
|
|
||||||
|
Ui::ResizeFitChild(this, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkingHours::save() {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Type WorkingHoursId() {
|
||||||
|
return WorkingHours::Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -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 WorkingHoursId();
|
||||||
|
|
||||||
|
} // namespace Settings
|
|
@ -598,6 +598,8 @@ settingsChatbotsUsername: InputField(defaultMultiSelectSearchField) {
|
||||||
settingsChatbotsAccess: Checkbox(defaultCheckbox) {
|
settingsChatbotsAccess: Checkbox(defaultCheckbox) {
|
||||||
textPosition: point(18px, 2px);
|
textPosition: point(18px, 2px);
|
||||||
}
|
}
|
||||||
|
settingsLocationAddress: InputField(defaultMultiSelectSearchField) {
|
||||||
|
}
|
||||||
settingsChatbotsUsernameMargins: margins(20px, 8px, 20px, 8px);
|
settingsChatbotsUsernameMargins: margins(20px, 8px, 20px, 8px);
|
||||||
settingsChatbotsAccessMargins: margins(22px, 5px, 22px, 9px);
|
settingsChatbotsAccessMargins: margins(22px, 5px, 22px, 9px);
|
||||||
settingsChatbotsAccessSkip: 4px;
|
settingsChatbotsAccessSkip: 4px;
|
||||||
|
|
|
@ -14,7 +14,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
|
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "settings/business/settings_away_message.h"
|
||||||
#include "settings/business/settings_chatbots.h"
|
#include "settings/business/settings_chatbots.h"
|
||||||
|
#include "settings/business/settings_greeting.h"
|
||||||
|
#include "settings/business/settings_location.h"
|
||||||
|
#include "settings/business/settings_quick_replies.h"
|
||||||
|
#include "settings/business/settings_working_hours.h"
|
||||||
#include "settings/settings_common_session.h"
|
#include "settings/settings_common_session.h"
|
||||||
#include "settings/settings_premium.h"
|
#include "settings/settings_premium.h"
|
||||||
#include "ui/effects/gradient.h"
|
#include "ui/effects/gradient.h"
|
||||||
|
@ -354,11 +359,17 @@ void Business::setupContent() {
|
||||||
Ui::AddSkip(content, st::settingsFromFileTop);
|
Ui::AddSkip(content, st::settingsFromFileTop);
|
||||||
|
|
||||||
AddBusinessSummary(content, _controller, [=](BusinessFeature feature) {
|
AddBusinessSummary(content, _controller, [=](BusinessFeature feature) {
|
||||||
switch (feature) {
|
_showOther.fire([&] {
|
||||||
case BusinessFeature::Chatbots:
|
switch (feature) {
|
||||||
_showOther.fire(Settings::ChatbotsId());
|
case BusinessFeature::AwayMessages: return AwayMessageId();
|
||||||
break;
|
case BusinessFeature::OpeningHours: return WorkingHoursId();
|
||||||
}
|
case BusinessFeature::Location: return LocationId();
|
||||||
|
case BusinessFeature::GreetingMessages: return GreetingId();
|
||||||
|
case BusinessFeature::QuickReplies: return QuickRepliesId();
|
||||||
|
case BusinessFeature::Chatbots: return ChatbotsId();
|
||||||
|
}
|
||||||
|
Unexpected("Feature in Business::setupContent.");
|
||||||
|
}());
|
||||||
});
|
});
|
||||||
|
|
||||||
Ui::ResizeFitChild(this, content);
|
Ui::ResizeFitChild(this, content);
|
||||||
|
|
|
@ -173,7 +173,10 @@ void AddDividerTextWithLottie(
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
DividerWithLottieDescriptor &&descriptor) {
|
DividerWithLottieDescriptor &&descriptor) {
|
||||||
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(
|
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(
|
||||||
container.get());
|
container.get(),
|
||||||
|
0,
|
||||||
|
st::boxDividerBg,
|
||||||
|
descriptor.parts);
|
||||||
const auto verticalLayout = container->add(
|
const auto verticalLayout = container->add(
|
||||||
object_ptr<Ui::VerticalLayout>(container.get()));
|
object_ptr<Ui::VerticalLayout>(container.get()));
|
||||||
const auto size = descriptor.lottieSize.value_or(
|
const auto size = descriptor.lottieSize.value_or(
|
||||||
|
|
|
@ -161,6 +161,7 @@ struct DividerWithLottieDescriptor {
|
||||||
rpl::producer<> showFinished;
|
rpl::producer<> showFinished;
|
||||||
rpl::producer<TextWithEntities> about;
|
rpl::producer<TextWithEntities> about;
|
||||||
std::optional<QMargins> aboutMargins;
|
std::optional<QMargins> aboutMargins;
|
||||||
|
RectParts parts = RectPart::Top | RectPart::Bottom;
|
||||||
};
|
};
|
||||||
void AddDividerTextWithLottie(
|
void AddDividerTextWithLottie(
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
|
Loading…
Add table
Reference in a new issue