mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Implement chatbots section editing.
This commit is contained in:
parent
205479fccc
commit
ad9107ca90
18 changed files with 670 additions and 234 deletions
|
@ -180,6 +180,8 @@ PRIVATE
|
|||
boxes/filters/edit_filter_box.h
|
||||
boxes/filters/edit_filter_chats_list.cpp
|
||||
boxes/filters/edit_filter_chats_list.h
|
||||
boxes/filters/edit_filter_chats_preview.cpp
|
||||
boxes/filters/edit_filter_chats_preview.h
|
||||
boxes/filters/edit_filter_links.cpp
|
||||
boxes/filters/edit_filter_links.h
|
||||
boxes/peers/add_bot_to_chat_box.cpp
|
||||
|
@ -446,6 +448,9 @@ PRIVATE
|
|||
core/version.h
|
||||
countries/countries_manager.cpp
|
||||
countries/countries_manager.h
|
||||
data/business/data_business_chatbots.cpp
|
||||
data/business/data_business_chatbots.h
|
||||
data/business/data_business_common.h
|
||||
data/notify/data_notify_settings.cpp
|
||||
data/notify/data_notify_settings.h
|
||||
data/notify/data_peer_notify_settings.cpp
|
||||
|
@ -1277,6 +1282,8 @@ PRIVATE
|
|||
profile/profile_block_widget.h
|
||||
profile/profile_cover_drop_area.cpp
|
||||
profile/profile_cover_drop_area.h
|
||||
settings/business/settings_business_exceptions.cpp
|
||||
settings/business/settings_business_exceptions.h
|
||||
settings/business/settings_chatbots.cpp
|
||||
settings/business/settings_chatbots.h
|
||||
settings/cloud_password/settings_cloud_password_common.cpp
|
||||
|
|
|
@ -2189,6 +2189,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"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_chatbots_not_found" = "Chatbot not found";
|
||||
"lng_chatbots_add" = "Add";
|
||||
|
||||
"lng_boost_channel_button" = "Boost Channel";
|
||||
"lng_boost_group_button" = "Boost Group";
|
||||
|
@ -4341,6 +4343,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_filters_type_non_contacts" = "Non-Contacts";
|
||||
"lng_filters_type_groups" = "Groups";
|
||||
"lng_filters_type_channels" = "Channels";
|
||||
"lng_filters_type_new" = "New Chats";
|
||||
"lng_filters_type_existing" = "Existing Chats";
|
||||
"lng_filters_type_bots" = "Bots";
|
||||
"lng_filters_type_no_archived" = "Archived";
|
||||
"lng_filters_type_no_muted" = "Muted";
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/filters/edit_filter_box.h"
|
||||
|
||||
#include "boxes/filters/edit_filter_chats_list.h"
|
||||
#include "boxes/filters/edit_filter_chats_preview.h"
|
||||
#include "boxes/filters/edit_filter_links.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
|
@ -56,60 +57,6 @@ using Flags = Data::ChatFilter::Flags;
|
|||
using ExceptionPeersRef = const base::flat_set<not_null<History*>> &;
|
||||
using ExceptionPeersGetter = ExceptionPeersRef(Data::ChatFilter::*)() const;
|
||||
|
||||
constexpr auto kAllTypes = {
|
||||
Flag::Contacts,
|
||||
Flag::NonContacts,
|
||||
Flag::Groups,
|
||||
Flag::Channels,
|
||||
Flag::Bots,
|
||||
Flag::NoMuted,
|
||||
Flag::NoRead,
|
||||
Flag::NoArchived,
|
||||
};
|
||||
|
||||
class FilterChatsPreview final : public Ui::RpWidget {
|
||||
public:
|
||||
FilterChatsPreview(
|
||||
not_null<QWidget*> parent,
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers);
|
||||
|
||||
[[nodiscard]] rpl::producer<Flag> flagRemoved() const;
|
||||
[[nodiscard]] rpl::producer<not_null<History*>> peerRemoved() const;
|
||||
|
||||
void updateData(
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers);
|
||||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
using Button = base::unique_qptr<Ui::IconButton>;
|
||||
struct FlagButton {
|
||||
Flag flag = Flag();
|
||||
Button button;
|
||||
};
|
||||
struct PeerButton {
|
||||
not_null<History*> history;
|
||||
Ui::PeerUserpicView userpic;
|
||||
Ui::Text::String name;
|
||||
Button button;
|
||||
};
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void refresh();
|
||||
void removeFlag(Flag flag);
|
||||
void removePeer(not_null<History*> history);
|
||||
|
||||
std::vector<FlagButton> _removeFlag;
|
||||
std::vector<PeerButton> _removePeer;
|
||||
|
||||
rpl::event_stream<Flag> _flagRemoved;
|
||||
rpl::event_stream<not_null<History*>> _peerRemoved;
|
||||
|
||||
};
|
||||
|
||||
struct NameEditing {
|
||||
not_null<Ui::InputField*> field;
|
||||
bool custom = false;
|
||||
|
@ -167,167 +114,6 @@ not_null<FilterChatsPreview*> SetupChatsPreview(
|
|||
return preview;
|
||||
}
|
||||
|
||||
FilterChatsPreview::FilterChatsPreview(
|
||||
not_null<QWidget*> parent,
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers)
|
||||
: RpWidget(parent) {
|
||||
updateData(flags, peers);
|
||||
}
|
||||
|
||||
void FilterChatsPreview::refresh() {
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void FilterChatsPreview::updateData(
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers) {
|
||||
_removeFlag.clear();
|
||||
_removePeer.clear();
|
||||
const auto makeButton = [&](Fn<void()> handler) {
|
||||
auto result = base::make_unique_q<Ui::IconButton>(
|
||||
this,
|
||||
st::windowFilterSmallRemove);
|
||||
result->setClickedCallback(std::move(handler));
|
||||
return result;
|
||||
};
|
||||
for (const auto flag : kAllTypes) {
|
||||
if (flags & flag) {
|
||||
_removeFlag.push_back({
|
||||
flag,
|
||||
makeButton([=] { removeFlag(flag); }) });
|
||||
}
|
||||
}
|
||||
for (const auto &history : peers) {
|
||||
_removePeer.push_back(PeerButton{
|
||||
.history = history,
|
||||
.button = makeButton([=] { removePeer(history); })
|
||||
});
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
int FilterChatsPreview::resizeGetHeight(int newWidth) {
|
||||
const auto right = st::windowFilterSmallRemoveRight;
|
||||
const auto add = (st::windowFilterSmallItem.height
|
||||
- st::windowFilterSmallRemove.height) / 2;
|
||||
auto top = 0;
|
||||
const auto moveNextButton = [&](not_null<Ui::IconButton*> button) {
|
||||
button->moveToRight(right, top + add, newWidth);
|
||||
top += st::windowFilterSmallItem.height;
|
||||
};
|
||||
for (const auto &[flag, button] : _removeFlag) {
|
||||
moveNextButton(button.get());
|
||||
}
|
||||
for (const auto &[history, userpic, name, button] : _removePeer) {
|
||||
moveNextButton(button.get());
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
void FilterChatsPreview::paintEvent(QPaintEvent *e) {
|
||||
auto p = Painter(this);
|
||||
auto top = 0;
|
||||
const auto &st = st::windowFilterSmallItem;
|
||||
const auto iconLeft = st.photoPosition.x();
|
||||
const auto iconTop = st.photoPosition.y();
|
||||
const auto nameLeft = st.namePosition.x();
|
||||
p.setFont(st::windowFilterSmallItem.nameStyle.font);
|
||||
const auto nameTop = st.namePosition.y();
|
||||
for (const auto &[flag, button] : _removeFlag) {
|
||||
PaintFilterChatsTypeIcon(
|
||||
p,
|
||||
flag,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
|
||||
p.setPen(st::contactsNameFg);
|
||||
p.drawTextLeft(
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
width(),
|
||||
FilterChatsTypeName(flag));
|
||||
top += st.height;
|
||||
}
|
||||
for (auto &[history, userpic, name, button] : _removePeer) {
|
||||
const auto savedMessages = history->peer->isSelf();
|
||||
const auto repliesMessages = history->peer->isRepliesChat();
|
||||
if (savedMessages || repliesMessages) {
|
||||
if (savedMessages) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
} else {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
}
|
||||
p.setPen(st::contactsNameFg);
|
||||
p.drawTextLeft(
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
width(),
|
||||
(savedMessages
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: tr::lng_replies_messages(tr::now)));
|
||||
} else {
|
||||
history->peer->paintUserpicLeft(
|
||||
p,
|
||||
userpic,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
p.setPen(st::contactsNameFg);
|
||||
if (name.isEmpty()) {
|
||||
name.setText(
|
||||
st::msgNameStyle,
|
||||
history->peer->name(),
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
name.drawLeftElided(
|
||||
p,
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
button->x() - nameLeft,
|
||||
width());
|
||||
}
|
||||
top += st.height;
|
||||
}
|
||||
}
|
||||
|
||||
void FilterChatsPreview::removeFlag(Flag flag) {
|
||||
const auto i = ranges::find(_removeFlag, flag, &FlagButton::flag);
|
||||
Assert(i != end(_removeFlag));
|
||||
_removeFlag.erase(i);
|
||||
refresh();
|
||||
_flagRemoved.fire_copy(flag);
|
||||
}
|
||||
|
||||
void FilterChatsPreview::removePeer(not_null<History*> history) {
|
||||
const auto i = ranges::find(_removePeer, history, &PeerButton::history);
|
||||
Assert(i != end(_removePeer));
|
||||
_removePeer.erase(i);
|
||||
refresh();
|
||||
_peerRemoved.fire_copy(history);
|
||||
}
|
||||
|
||||
rpl::producer<Flag> FilterChatsPreview::flagRemoved() const {
|
||||
return _flagRemoved.events();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<History*>> FilterChatsPreview::peerRemoved() const {
|
||||
return _peerRemoved.events();
|
||||
}
|
||||
|
||||
void EditExceptions(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<QObject*> context,
|
||||
|
|
|
@ -28,6 +28,8 @@ using Flag = Data::ChatFilter::Flag;
|
|||
using Flags = Data::ChatFilter::Flags;
|
||||
|
||||
constexpr auto kAllTypes = {
|
||||
Flag::NewChats,
|
||||
Flag::ExistingChats,
|
||||
Flag::Contacts,
|
||||
Flag::NonContacts,
|
||||
Flag::Groups,
|
||||
|
@ -119,7 +121,7 @@ PaintRoundImageCallback TypeRow::generatePaintUserpicCallback(
|
|||
}
|
||||
|
||||
Flag TypeRow::flag() const {
|
||||
return static_cast<Flag>(id() & 0xFF);
|
||||
return static_cast<Flag>(id() & 0xFFFF);
|
||||
}
|
||||
|
||||
ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
|
||||
|
@ -219,6 +221,8 @@ auto TypeController::rowSelectionChanges() const
|
|||
|
||||
[[nodiscard]] QString FilterChatsTypeName(Flag flag) {
|
||||
switch (flag) {
|
||||
case Flag::NewChats: return tr::lng_filters_type_new(tr::now);
|
||||
case Flag::ExistingChats: return tr::lng_filters_type_existing(tr::now);
|
||||
case Flag::Contacts: return tr::lng_filters_type_contacts(tr::now);
|
||||
case Flag::NonContacts:
|
||||
return tr::lng_filters_type_non_contacts(tr::now);
|
||||
|
@ -241,6 +245,8 @@ void PaintFilterChatsTypeIcon(
|
|||
int size) {
|
||||
const auto &color1 = [&]() -> const style::color& {
|
||||
switch (flag) {
|
||||
case Flag::NewChats: return st::historyPeer5UserpicBg;
|
||||
case Flag::ExistingChats: return st::historyPeer8UserpicBg;
|
||||
case Flag::Contacts: return st::historyPeer4UserpicBg;
|
||||
case Flag::NonContacts: return st::historyPeer7UserpicBg;
|
||||
case Flag::Groups: return st::historyPeer2UserpicBg;
|
||||
|
@ -254,6 +260,8 @@ void PaintFilterChatsTypeIcon(
|
|||
}();
|
||||
const auto &color2 = [&]() -> const style::color& {
|
||||
switch (flag) {
|
||||
case Flag::NewChats: return st::historyPeer5UserpicBg2;
|
||||
case Flag::ExistingChats: return st::historyPeer8UserpicBg2;
|
||||
case Flag::Contacts: return st::historyPeer4UserpicBg2;
|
||||
case Flag::NonContacts: return st::historyPeer7UserpicBg2;
|
||||
case Flag::Groups: return st::historyPeer2UserpicBg2;
|
||||
|
@ -267,6 +275,8 @@ void PaintFilterChatsTypeIcon(
|
|||
}();
|
||||
const auto &icon = [&]() -> const style::icon& {
|
||||
switch (flag) {
|
||||
case Flag::NewChats: return st::windowFilterTypeNewChats;
|
||||
case Flag::ExistingChats: return st::windowFilterTypeExistingChats;
|
||||
case Flag::Contacts: return st::windowFilterTypeContacts;
|
||||
case Flag::NonContacts: return st::windowFilterTypeNonContacts;
|
||||
case Flag::Groups: return st::windowFilterTypeGroups;
|
||||
|
@ -469,6 +479,10 @@ object_ptr<Ui::RpWidget> EditFilterChatsListController::prepareTypesList() {
|
|||
|
||||
auto EditFilterChatsListController::createRow(not_null<History*> history)
|
||||
-> std::unique_ptr<Row> {
|
||||
const auto business = _options & (Flag::NewChats | Flag::ExistingChats);
|
||||
if (business && (history->peer->isSelf() || !history->peer->isUser())) {
|
||||
return nullptr;
|
||||
}
|
||||
return history->inChatList()
|
||||
? std::make_unique<ExceptionRow>(history)
|
||||
: nullptr;
|
||||
|
|
199
Telegram/SourceFiles/boxes/filters/edit_filter_chats_preview.cpp
Normal file
199
Telegram/SourceFiles/boxes/filters/edit_filter_chats_preview.cpp
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
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 "boxes/filters/edit_filter_chats_preview.h"
|
||||
|
||||
#include "boxes/filters/edit_filter_chats_list.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/painter.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_window.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using Flag = Data::ChatFilter::Flag;
|
||||
|
||||
constexpr auto kAllTypes = {
|
||||
Flag::NewChats,
|
||||
Flag::ExistingChats,
|
||||
Flag::Contacts,
|
||||
Flag::NonContacts,
|
||||
Flag::Groups,
|
||||
Flag::Channels,
|
||||
Flag::Bots,
|
||||
Flag::NoMuted,
|
||||
Flag::NoRead,
|
||||
Flag::NoArchived,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
FilterChatsPreview::FilterChatsPreview(
|
||||
not_null<QWidget*> parent,
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers)
|
||||
: RpWidget(parent) {
|
||||
updateData(flags, peers);
|
||||
}
|
||||
|
||||
void FilterChatsPreview::refresh() {
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void FilterChatsPreview::updateData(
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers) {
|
||||
_removeFlag.clear();
|
||||
_removePeer.clear();
|
||||
const auto makeButton = [&](Fn<void()> handler) {
|
||||
auto result = base::make_unique_q<Ui::IconButton>(
|
||||
this,
|
||||
st::windowFilterSmallRemove);
|
||||
result->setClickedCallback(std::move(handler));
|
||||
result->show();
|
||||
return result;
|
||||
};
|
||||
for (const auto flag : kAllTypes) {
|
||||
if (flags & flag) {
|
||||
_removeFlag.push_back({
|
||||
flag,
|
||||
makeButton([=] { removeFlag(flag); }) });
|
||||
}
|
||||
}
|
||||
for (const auto &history : peers) {
|
||||
_removePeer.push_back(PeerButton{
|
||||
.history = history,
|
||||
.button = makeButton([=] { removePeer(history); })
|
||||
});
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
int FilterChatsPreview::resizeGetHeight(int newWidth) {
|
||||
const auto right = st::windowFilterSmallRemoveRight;
|
||||
const auto add = (st::windowFilterSmallItem.height
|
||||
- st::windowFilterSmallRemove.height) / 2;
|
||||
auto top = 0;
|
||||
const auto moveNextButton = [&](not_null<Ui::IconButton*> button) {
|
||||
button->moveToRight(right, top + add, newWidth);
|
||||
top += st::windowFilterSmallItem.height;
|
||||
};
|
||||
for (const auto &[flag, button] : _removeFlag) {
|
||||
moveNextButton(button.get());
|
||||
}
|
||||
for (const auto &[history, userpic, name, button] : _removePeer) {
|
||||
moveNextButton(button.get());
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
void FilterChatsPreview::paintEvent(QPaintEvent *e) {
|
||||
auto p = Painter(this);
|
||||
auto top = 0;
|
||||
const auto &st = st::windowFilterSmallItem;
|
||||
const auto iconLeft = st.photoPosition.x();
|
||||
const auto iconTop = st.photoPosition.y();
|
||||
const auto nameLeft = st.namePosition.x();
|
||||
p.setFont(st::windowFilterSmallItem.nameStyle.font);
|
||||
const auto nameTop = st.namePosition.y();
|
||||
for (const auto &[flag, button] : _removeFlag) {
|
||||
PaintFilterChatsTypeIcon(
|
||||
p,
|
||||
flag,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
|
||||
p.setPen(st::contactsNameFg);
|
||||
p.drawTextLeft(
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
width(),
|
||||
FilterChatsTypeName(flag));
|
||||
top += st.height;
|
||||
}
|
||||
for (auto &[history, userpic, name, button] : _removePeer) {
|
||||
const auto savedMessages = history->peer->isSelf();
|
||||
const auto repliesMessages = history->peer->isRepliesChat();
|
||||
if (savedMessages || repliesMessages) {
|
||||
if (savedMessages) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
} else {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
}
|
||||
p.setPen(st::contactsNameFg);
|
||||
p.drawTextLeft(
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
width(),
|
||||
(savedMessages
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: tr::lng_replies_messages(tr::now)));
|
||||
} else {
|
||||
history->peer->paintUserpicLeft(
|
||||
p,
|
||||
userpic,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
p.setPen(st::contactsNameFg);
|
||||
if (name.isEmpty()) {
|
||||
name.setText(
|
||||
st::msgNameStyle,
|
||||
history->peer->name(),
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
name.drawLeftElided(
|
||||
p,
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
button->x() - nameLeft,
|
||||
width());
|
||||
}
|
||||
top += st.height;
|
||||
}
|
||||
}
|
||||
|
||||
void FilterChatsPreview::removeFlag(Flag flag) {
|
||||
const auto i = ranges::find(_removeFlag, flag, &FlagButton::flag);
|
||||
Assert(i != end(_removeFlag));
|
||||
_removeFlag.erase(i);
|
||||
refresh();
|
||||
_flagRemoved.fire_copy(flag);
|
||||
}
|
||||
|
||||
void FilterChatsPreview::removePeer(not_null<History*> history) {
|
||||
const auto i = ranges::find(_removePeer, history, &PeerButton::history);
|
||||
Assert(i != end(_removePeer));
|
||||
_removePeer.erase(i);
|
||||
refresh();
|
||||
_peerRemoved.fire_copy(history);
|
||||
}
|
||||
|
||||
rpl::producer<Flag> FilterChatsPreview::flagRemoved() const {
|
||||
return _flagRemoved.events();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<History*>> FilterChatsPreview::peerRemoved() const {
|
||||
return _peerRemoved.events();
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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/data_chat_filters.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/userpic_view.h"
|
||||
|
||||
class History;
|
||||
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
} // namespace Ui
|
||||
|
||||
class FilterChatsPreview final : public Ui::RpWidget {
|
||||
public:
|
||||
using Flag = Data::ChatFilter::Flag;
|
||||
using Flags = Data::ChatFilter::Flags;
|
||||
|
||||
FilterChatsPreview(
|
||||
not_null<QWidget*> parent,
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers);
|
||||
|
||||
[[nodiscard]] rpl::producer<Flag> flagRemoved() const;
|
||||
[[nodiscard]] rpl::producer<not_null<History*>> peerRemoved() const;
|
||||
|
||||
void updateData(
|
||||
Flags flags,
|
||||
const base::flat_set<not_null<History*>> &peers);
|
||||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
using Button = base::unique_qptr<Ui::IconButton>;
|
||||
struct FlagButton {
|
||||
Flag flag = Flag();
|
||||
Button button;
|
||||
};
|
||||
struct PeerButton {
|
||||
not_null<History*> history;
|
||||
Ui::PeerUserpicView userpic;
|
||||
Ui::Text::String name;
|
||||
Button button;
|
||||
};
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void refresh();
|
||||
void removeFlag(Flag flag);
|
||||
void removePeer(not_null<History*> history);
|
||||
|
||||
std::vector<FlagButton> _removeFlag;
|
||||
std::vector<PeerButton> _removePeer;
|
||||
|
||||
rpl::event_stream<Flag> _flagRemoved;
|
||||
rpl::event_stream<not_null<History*>> _peerRemoved;
|
||||
|
||||
};
|
|
@ -982,8 +982,7 @@ bool GoodForExportFilterLink(
|
|||
not_null<Window::SessionController*> window,
|
||||
const Data::ChatFilter &filter) {
|
||||
using Flag = Data::ChatFilter::Flag;
|
||||
const auto listflags = Flag::Chatlist | Flag::HasMyLinks;
|
||||
if (!filter.never().empty() || (filter.flags() & ~listflags)) {
|
||||
if (!filter.never().empty() || (filter.flags() & Flag::RulesMask)) {
|
||||
window->showToast(tr::lng_filters_link_cant(tr::now));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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 "data/business/data_business_chatbots.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
Chatbots::Chatbots(not_null<Session*> session)
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
Chatbots::~Chatbots() = default;
|
||||
|
||||
const ChatbotsSettings &Chatbots::current() const {
|
||||
return _settings.current();
|
||||
}
|
||||
|
||||
rpl::producer<ChatbotsSettings> Chatbots::changes() const {
|
||||
return _settings.changes();
|
||||
}
|
||||
|
||||
rpl::producer<ChatbotsSettings> Chatbots::value() const {
|
||||
return _settings.value();
|
||||
}
|
||||
|
||||
void Chatbots::save(ChatbotsSettings settings) {
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
} // namespace Data
|
44
Telegram/SourceFiles/data/business/data_business_chatbots.h
Normal file
44
Telegram/SourceFiles/data/business/data_business_chatbots.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
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 UserData;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
|
||||
struct ChatbotsSettings {
|
||||
UserData *bot = nullptr;
|
||||
BusinessExceptions allowed;
|
||||
BusinessExceptions disallowed;
|
||||
bool repliesAllowed = false;
|
||||
bool onlySelected = false;
|
||||
};
|
||||
|
||||
class Chatbots final {
|
||||
public:
|
||||
explicit Chatbots(not_null<Session*> session);
|
||||
~Chatbots();
|
||||
|
||||
[[nodiscard]] const ChatbotsSettings ¤t() const;
|
||||
[[nodiscard]] rpl::producer<ChatbotsSettings> changes() const;
|
||||
[[nodiscard]] rpl::producer<ChatbotsSettings> value() const;
|
||||
|
||||
void save(ChatbotsSettings settings);
|
||||
|
||||
private:
|
||||
const not_null<Session*> _session;
|
||||
|
||||
rpl::variable<ChatbotsSettings> _settings;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
31
Telegram/SourceFiles/data/business/data_business_common.h
Normal file
31
Telegram/SourceFiles/data/business/data_business_common.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
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 "base/flags.h"
|
||||
|
||||
class UserData;
|
||||
|
||||
namespace Data {
|
||||
|
||||
enum class BusinessChatType {
|
||||
NewChats = (1 << 0),
|
||||
ExistingChats = (1 << 1),
|
||||
Contacts = (1 << 2),
|
||||
NonContacts = (1 << 3),
|
||||
};
|
||||
inline constexpr bool is_flag_type(BusinessChatType) { return true; }
|
||||
|
||||
using BusinessChatTypes = base::flags<BusinessChatType>;
|
||||
|
||||
struct BusinessExceptions {
|
||||
BusinessChatTypes types;
|
||||
std::vector<not_null<UserData*>> list;
|
||||
};
|
||||
|
||||
} // namespace Data
|
|
@ -163,6 +163,7 @@ ChatFilter ChatFilter::withTitle(const QString &title) const {
|
|||
|
||||
ChatFilter ChatFilter::withChatlist(bool chatlist, bool hasMyLinks) const {
|
||||
auto result = *this;
|
||||
result._flags &= Flag::RulesMask;
|
||||
if (chatlist) {
|
||||
result._flags |= Flag::Chatlist;
|
||||
if (hasMyLinks) {
|
||||
|
@ -170,8 +171,6 @@ ChatFilter ChatFilter::withChatlist(bool chatlist, bool hasMyLinks) const {
|
|||
} else {
|
||||
result._flags &= ~Flag::HasMyLinks;
|
||||
}
|
||||
} else {
|
||||
result._flags &= ~(Flag::Chatlist | Flag::HasMyLinks);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -593,7 +592,7 @@ bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) {
|
|||
|
||||
const auto id = filter.id();
|
||||
const auto exceptionsChanged = filter.always() != updated.always();
|
||||
const auto rulesMask = ~(Flag::Chatlist | Flag::HasMyLinks);
|
||||
const auto rulesMask = Flag() | Flag::RulesMask;
|
||||
const auto rulesChanged = exceptionsChanged
|
||||
|| ((filter.flags() & rulesMask) != (updated.flags() & rulesMask))
|
||||
|| (filter.never() != updated.never());
|
||||
|
|
|
@ -36,9 +36,13 @@ public:
|
|||
NoMuted = (1 << 5),
|
||||
NoRead = (1 << 6),
|
||||
NoArchived = (1 << 7),
|
||||
RulesMask = ((1 << 8) - 1),
|
||||
|
||||
Chatlist = (1 << 8),
|
||||
HasMyLinks = (1 << 9),
|
||||
|
||||
NewChats = (1 << 10), // Telegram Business exceptions.
|
||||
ExistingChats = (1 << 11),
|
||||
};
|
||||
friend constexpr inline bool is_flag_type(Flag) { return true; };
|
||||
using Flags = base::flags<Flag>;
|
||||
|
|
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/abstract_box.h"
|
||||
#include "passport/passport_form_controller.h"
|
||||
#include "lang/lang_keys.h" // tr::lng_deleted(tr::now) in user name
|
||||
#include "data/business/data_business_chatbots.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_bot_app.h"
|
||||
|
@ -268,7 +269,8 @@ Session::Session(not_null<Main::Session*> session)
|
|||
, _notifySettings(std::make_unique<NotifySettings>(this))
|
||||
, _customEmojiManager(std::make_unique<CustomEmojiManager>(this))
|
||||
, _stories(std::make_unique<Stories>(this))
|
||||
, _savedMessages(std::make_unique<SavedMessages>(this)) {
|
||||
, _savedMessages(std::make_unique<SavedMessages>(this))
|
||||
, _chatbots(std::make_unique<Chatbots>(this)) {
|
||||
_cache->open(_session->local().cacheKey());
|
||||
_bigFileCache->open(_session->local().cacheBigFileKey());
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ class NotifySettings;
|
|||
class CustomEmojiManager;
|
||||
class Stories;
|
||||
class SavedMessages;
|
||||
class Chatbots;
|
||||
struct ReactionId;
|
||||
|
||||
struct RepliesReadTillUpdate {
|
||||
|
@ -142,6 +143,9 @@ public:
|
|||
[[nodiscard]] SavedMessages &savedMessages() const {
|
||||
return *_savedMessages;
|
||||
}
|
||||
[[nodiscard]] Chatbots &chatbots() const {
|
||||
return *_chatbots;
|
||||
}
|
||||
|
||||
[[nodiscard]] MsgId nextNonHistoryEntryId() {
|
||||
return ++_nonHistoryEntryId;
|
||||
|
@ -1065,6 +1069,7 @@ private:
|
|||
const std::unique_ptr<CustomEmojiManager> _customEmojiManager;
|
||||
const std::unique_ptr<Stories> _stories;
|
||||
const std::unique_ptr<SavedMessages> _savedMessages;
|
||||
const std::unique_ptr<Chatbots> _chatbots;
|
||||
|
||||
MsgId _nonHistoryEntryId = ServerMaxMsgId.bare + ScheduledMsgIdsRange;
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
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
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
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
|
|
@ -7,7 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "settings/business/settings_chatbots.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "data/business/data_business_chatbots.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/business/settings_business_exceptions.h"
|
||||
#include "settings/settings_common_session.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
|
@ -15,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
|
@ -29,6 +36,7 @@ public:
|
|||
Chatbots(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller);
|
||||
~Chatbots();
|
||||
|
||||
[[nodiscard]] rpl::producer<QString> title() override;
|
||||
|
||||
|
@ -42,24 +50,41 @@ public:
|
|||
|
||||
private:
|
||||
void setupContent(not_null<Window::SessionController*> controller);
|
||||
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;
|
||||
|
||||
rpl::variable<bool> _onlySelected = false;
|
||||
rpl::variable<bool> _repliesAllowed = true;
|
||||
rpl::variable<Data::BusinessExceptions> _allowed;
|
||||
rpl::variable<Data::BusinessExceptions> _disallowed;
|
||||
|
||||
};
|
||||
|
||||
Chatbots::Chatbots(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: Section(parent)
|
||||
, _controller(controller)
|
||||
, _session(&controller->session())
|
||||
, _bottomSkipRounding(st::boxRadius, st::boxDividerBg) {
|
||||
setupContent(controller);
|
||||
}
|
||||
|
||||
Chatbots::~Chatbots() {
|
||||
if (!Core::Quitting()) {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<QString> Chatbots::title() {
|
||||
return tr::lng_chatbots_title();
|
||||
}
|
||||
|
@ -69,12 +94,12 @@ void Chatbots::setupContent(
|
|||
using namespace rpl::mappers;
|
||||
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
const auto current = controller->session().data().chatbots().current();
|
||||
|
||||
struct State {
|
||||
rpl::variable<bool> onlySelected = false;
|
||||
rpl::variable<bool> replyAllowed = true;
|
||||
};
|
||||
const auto state = content->lifetime().make_state<State>();
|
||||
_onlySelected = current.onlySelected;
|
||||
_repliesAllowed = current.repliesAllowed;
|
||||
_allowed = current.allowed;
|
||||
_disallowed = current.disallowed;
|
||||
|
||||
AddDividerTextWithLottie(content, {
|
||||
.lottie = u"robot"_q,
|
||||
|
@ -93,7 +118,11 @@ void Chatbots::setupContent(
|
|||
object_ptr<Ui::InputField>(
|
||||
content,
|
||||
st::settingsChatbotsUsername,
|
||||
tr::lng_chatbots_placeholder()),
|
||||
tr::lng_chatbots_placeholder(),
|
||||
(current.bot
|
||||
? current.bot->session().createInternalLink(
|
||||
current.bot->username())
|
||||
: QString())),
|
||||
st::settingsChatbotsUsernameMargins);
|
||||
|
||||
Ui::AddDividerText(
|
||||
|
@ -104,7 +133,7 @@ void Chatbots::setupContent(
|
|||
Ui::AddSubsectionTitle(content, tr::lng_chatbots_access_title());
|
||||
|
||||
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
||||
state->onlySelected.current() ? kSelectedOnly : kAllExcept);
|
||||
_onlySelected.current() ? kSelectedOnly : kAllExcept);
|
||||
const auto everyone = content->add(
|
||||
object_ptr<Ui::Radiobutton>(
|
||||
content,
|
||||
|
@ -139,8 +168,18 @@ void Chatbots::setupContent(
|
|||
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(state->onlySelected.value() | rpl::map(!_1));
|
||||
excludeWrap->toggleOn(_onlySelected.value() | rpl::map(!_1));
|
||||
excludeWrap->finishAnimating();
|
||||
|
||||
const auto includeWrap = content->add(
|
||||
|
@ -157,12 +196,22 @@ void Chatbots::setupContent(
|
|||
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(state->onlySelected.value());
|
||||
includeWrap->toggleOn(_onlySelected.value());
|
||||
includeWrap->finishAnimating();
|
||||
|
||||
group->setChangedCallback([=](int value) {
|
||||
state->onlySelected = (value == kSelectedOnly);
|
||||
_onlySelected = (value == kSelectedOnly);
|
||||
});
|
||||
|
||||
Ui::AddSkip(content, st::settingsChatbotsAccessSkip);
|
||||
|
@ -177,9 +226,9 @@ void Chatbots::setupContent(
|
|||
content,
|
||||
tr::lng_chatbots_reply(),
|
||||
st::settingsButtonNoIcon
|
||||
))->toggleOn(state->replyAllowed.value())->toggledChanges(
|
||||
))->toggleOn(_repliesAllowed.value())->toggledChanges(
|
||||
) | rpl::start_with_next([=](bool value) {
|
||||
state->replyAllowed = value;
|
||||
_repliesAllowed = value;
|
||||
}, content->lifetime());
|
||||
Ui::AddSkip(content);
|
||||
|
||||
|
@ -192,6 +241,17 @@ void Chatbots::setupContent(
|
|||
Ui::ResizeFitChild(this, content);
|
||||
}
|
||||
|
||||
void Chatbots::save() {
|
||||
const auto settings = Data::ChatbotsSettings{
|
||||
.bot = nullptr,
|
||||
.allowed = _allowed.current(),
|
||||
.disallowed = _disallowed.current(),
|
||||
.repliesAllowed = _repliesAllowed.current(),
|
||||
.onlySelected = _onlySelected.current(),
|
||||
};
|
||||
_session->data().chatbots().save(settings);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Type ChatbotsId() {
|
||||
|
|
|
@ -303,6 +303,8 @@ windowFilterTypeBots: icon {{ "folders/folders_type_bots", historyPeerUserpicFg
|
|||
windowFilterTypeNoMuted: icon {{ "folders/folders_type_muted", historyPeerUserpicFg }};
|
||||
windowFilterTypeNoArchived: icon {{ "folders/folders_type_archived", historyPeerUserpicFg }};
|
||||
windowFilterTypeNoRead: icon {{ "folders/folders_type_read", historyPeerUserpicFg }};
|
||||
windowFilterTypeNewChats: icon {{ "folders/folders_unread", historyPeerUserpicFg }};
|
||||
windowFilterTypeExistingChats: windowFilterTypeNoRead;
|
||||
windowFilterChatsSectionSubtitleHeight: 28px;
|
||||
windowFilterChatsSectionSubtitle: FlatLabel(defaultFlatLabel) {
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
|
|
Loading…
Add table
Reference in a new issue