chore: rewrite settings to new builder & support settings links from android version

This commit is contained in:
AlexeyZavar
2026-02-21 12:11:25 +03:00
parent 1b12c3379f
commit a0604c5594
22 changed files with 2230 additions and 1405 deletions
+2
View File
@@ -141,6 +141,8 @@ set(ayugram_files
ayu/ui/utils/palette.h
ayu/ui/utils/itunes_search.cpp
ayu/ui/utils/itunes_search.h
ayu/ui/settings/ayu_builder.cpp
ayu/ui/settings/ayu_builder.h
ayu/ui/settings/settings_appearance.cpp
ayu/ui/settings/settings_appearance.h
ayu/ui/settings/settings_ayu_utils.cpp
+1 -1
View File
@@ -466,7 +466,7 @@ void AyuSettings::validate() {
modified = true;
}
validateRange(_wideMultiplier, 0.5, 3.0, defaults._wideMultiplier);
validateRange(_wideMultiplier, 0.5, 4.0, defaults._wideMultiplier);
validateRange(_recentStickersCount, 1, 200, defaults._recentStickersCount);
const auto embeddedType = _messageShotSettings._embeddedThemeType.current();
+45 -7
View File
@@ -6,22 +6,20 @@
// Copyright @Radolyn, 2026
#include "ayu/ayu_url_handlers.h"
#include "base/qthelp_url.h"
#include <QDesktopServices>
#include "lang_auto.h"
#include "mainwindow.h"
#include "ayu/ui/settings/settings_main.h"
#include "ayu/utils/telegram_helpers.h"
#include "base/qthelp_url.h"
#include "boxes/abstract_box.h"
#include "core/application.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "ui/boxes/confirm_box.h"
#include <QDesktopServices>
#include "main/main_session.h"
#include "settings/settings_builder.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/donate_info_box.h"
#include "ui/settings/settings_main.h"
#include "window/window_controller.h"
namespace AyuUrlHandlers {
@@ -146,6 +144,46 @@ bool HandleSupport(
return true;
}
[[nodiscard]] ::Settings::Type SectionForSetting(
const QString &controlId,
not_null<::Main::Session*> session) {
const auto &registry = ::Settings::Builder::SearchRegistry::Instance();
const auto entries = registry.collectAll(session);
for (const auto &entry : entries) {
if (entry.id == controlId && entry.section) {
return entry.section;
}
}
return ::Settings::AyuMain::Id();
}
bool HandleAyuSettings(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
const auto params = url_parse_params(
match->captured(1),
qthelp::UrlParamNameTransform::ToLower);
const auto settingName = params.value(u"s"_q);
if (settingName.isEmpty()) {
controller->showSettings(::Settings::AyuMain::Id());
} else {
const auto controlId = u"ayu/"_q + settingName;
controller->window().setHighlightControlId(controlId);
const auto section = SectionForSetting(
controlId,
&controller->session());
controller->showSettings(section);
}
controller->window().activate();
return true;
}
bool TryHandleSpotify(const QString &url) {
if (!url.contains("spotify.com")) {
return false;
@@ -33,6 +33,11 @@ bool HandleSupport(
const Match &match,
const QVariant &context);
bool HandleAyuSettings(
Window::SessionController *controller,
const Match &match,
const QVariant &context);
bool TryHandleSpotify(const QString &url);
}
@@ -0,0 +1,251 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2026
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "settings/settings_common.h"
#include "styles/style_ayu_styles.h"
#include "styles/style_boxes.h"
#include "styles/style_settings.h"
#include "ui/boxes/single_choice_box.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
namespace Settings::AyBuilder {
namespace {
[[nodiscard]] QString ResolveTitle(rpl::producer<QString> title) {
auto result = QString();
auto lifetime = rpl::lifetime();
std::move(title).start(
[&](QString value) { result = std::move(value); },
[](auto&&) {},
[] {},
lifetime);
return result;
}
} // namespace
AyuSectionBuilder::AyuSectionBuilder(Builder::SectionBuilder &builder)
: _builder(builder) {
}
Builder::SectionBuilder &AyuSectionBuilder::base() {
return _builder;
}
Ui::SettingsButton *AyuSectionBuilder::addSettingToggle(
SettingToggleArgs &&args) {
auto getter = [g = args.getter] {
return (AyuSettings::getInstance().*g)();
};
auto setter = [s = args.setter](bool v) {
(AyuSettings::getInstance().*s)(v);
};
return addToggle({
.id = std::move(args.id),
.title = std::move(args.title),
.getter = std::move(getter),
.setter = std::move(setter),
.icon = std::move(args.icon),
.keywords = std::move(args.keywords),
.shown = std::move(args.shown),
});
}
Ui::SettingsButton *AyuSectionBuilder::addToggle(ToggleArgs &&args) {
auto getter = std::move(args.getter);
auto setter = std::move(args.setter);
const auto initialValue = getter();
const auto button = _builder.addButton({
.id = std::move(args.id),
.title = std::move(args.title),
.st = args.icon.icon ? nullptr : &st::settingsButtonNoIcon,
.icon = std::move(args.icon),
.toggled = rpl::single(initialValue),
.keywords = std::move(args.keywords),
.shown = std::move(args.shown),
});
if (button) {
button->toggledValue(
) | rpl::filter(
[=](bool enabled) {
return (enabled != getter());
}
) | rpl::on_next(
[=](bool enabled) {
setter(enabled);
},
button->lifetime());
}
return button;
}
Fn<void()> AyuSectionBuilder::addCollapsibleToggle(
CollapsibleToggleArgs &&args) {
auto resolvedTitle = ResolveTitle(rpl::duplicate(args.title));
auto checkboxes = std::move(args.checkboxes);
auto toggledWhenAll = args.toggledWhenAll;
auto id = std::move(args.id);
auto keywords = std::move(args.keywords);
Fn<void()> result;
_builder.add([&](const Builder::BuildContext &ctx) {
v::match(ctx, [&](const Builder::WidgetContext &wctx) {
result = AddCollapsibleToggle(
wctx.container,
std::move(args.title),
std::move(checkboxes),
toggledWhenAll);
}, [&](const Builder::SearchContext &sctx) {
if (!id.isEmpty()) {
sctx.entries->push_back({
.id = id,
.title = resolvedTitle,
.keywords = keywords,
.section = sctx.sectionId,
});
}
for (const auto &cb : checkboxes) {
if (!cb.checkboxLabel.isEmpty()) {
sctx.entries->push_back({
.id = id + u"/"_q + cb.checkboxLabel,
.title = cb.checkboxLabel,
.section = sctx.sectionId,
.checkIcon = cb.getter()
? Builder::SearchEntryCheckIcon::Checked
: Builder::SearchEntryCheckIcon::Unchecked,
});
}
}
});
});
return result;
}
void AyuSectionBuilder::addChooseButton(ChooseButtonArgs &&args) {
auto options = std::move(args.options);
auto setter = std::move(args.setter);
auto initialSelection = args.initialSelection;
auto id = std::move(args.id);
auto keywords = std::move(args.keywords);
auto icon = std::move(args.icon);
auto resolvedTitle = ResolveTitle(rpl::duplicate(args.title));
_builder.add([&](const Builder::BuildContext &ctx) {
v::match(ctx, [&](const Builder::WidgetContext &wctx) {
AddChooseButtonWithIconAndRightTextInner(
wctx.container,
wctx.controller,
initialSelection,
options,
std::move(args.title),
std::move(args.boxTitle),
icon.icon ? st::settingsButton : st::settingsButtonNoIcon,
std::move(icon),
setter);
}, [&](const Builder::SearchContext &sctx) {
if (!id.isEmpty()) {
sctx.entries->push_back({
.id = id,
.title = resolvedTitle,
.keywords = keywords,
.section = sctx.sectionId,
});
}
});
});
}
void AyuSectionBuilder::addSlider(SliderArgs &&args) {
auto id = std::move(args.id);
auto keywords = std::move(args.keywords);
auto resolvedTitle = ResolveTitle(rpl::duplicate(args.title));
_builder.add([&](const Builder::BuildContext &ctx) {
v::match(ctx, [&](const Builder::WidgetContext &wctx) {
const auto container = wctx.container;
container->add(
object_ptr<Button>(container,
std::move(args.title),
st::settingsButtonNoIcon)
)->setAttribute(Qt::WA_TransparentForMouseEvents);
auto sliderWithLabel = MakeSliderWithLabel(
container,
st::autoDownloadLimitSlider,
st::settingsScaleLabel,
0,
st::settingsScaleLabel.style.font->width("8%%%"));
container->add(
std::move(sliderWithLabel.widget),
st::recentStickersLimitPadding);
const auto slider = sliderWithLabel.slider;
const auto label = sliderWithLabel.label;
auto formatLabel = std::move(args.formatLabel);
auto indexToValue = std::move(args.indexToValue);
auto onChanged = std::move(args.onChanged);
auto onFinalChanged = std::move(args.onFinalChanged);
if (formatLabel) {
label->setText(formatLabel(args.current));
}
slider->setPseudoDiscrete(
args.steps,
[=](int index) {
return indexToValue ? indexToValue(index) : index;
},
args.current,
[=](int value) {
if (formatLabel) {
label->setText(formatLabel(value));
}
if (onChanged) {
onChanged(value);
}
},
[=](int value) {
if (formatLabel) {
label->setText(formatLabel(value));
}
if (onFinalChanged) {
onFinalChanged(value);
}
});
}, [&](const Builder::SearchContext &sctx) {
if (!id.isEmpty()) {
sctx.entries->push_back({
.id = id,
.title = resolvedTitle,
.keywords = keywords,
.section = sctx.sectionId,
});
}
});
});
}
void AyuSectionBuilder::addBetaBadge(not_null<Ui::SettingsButton*> button) {
AddBetaBadge(button);
}
void AyuSectionBuilder::addSectionDivider() {
_builder.addSkip();
_builder.addDivider();
_builder.addSkip();
}
} // namespace Settings::AyBuilder
@@ -0,0 +1,86 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2026
#pragma once
#include "ayu/ayu_settings.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
namespace Settings::AyBuilder {
class AyuSectionBuilder {
public:
explicit AyuSectionBuilder(Builder::SectionBuilder &builder);
[[nodiscard]] Builder::SectionBuilder &base();
struct SettingToggleArgs {
QString id;
rpl::producer<QString> title;
BoolGetter getter;
BoolSetter setter;
IconDescriptor icon;
QStringList keywords;
rpl::producer<bool> shown;
};
Ui::SettingsButton *addSettingToggle(SettingToggleArgs &&args);
struct ToggleArgs {
QString id;
rpl::producer<QString> title;
Fn<bool()> getter;
Fn<void(bool)> setter;
IconDescriptor icon;
QStringList keywords;
rpl::producer<bool> shown;
};
Ui::SettingsButton *addToggle(ToggleArgs &&args);
struct CollapsibleToggleArgs {
QString id;
rpl::producer<QString> title;
std::vector<NestedEntry> checkboxes;
bool toggledWhenAll = true;
QStringList keywords;
};
Fn<void()> addCollapsibleToggle(CollapsibleToggleArgs &&args);
struct ChooseButtonArgs {
QString id;
rpl::producer<QString> title;
rpl::producer<QString> boxTitle;
int initialSelection;
std::vector<QString> options;
Fn<void(int)> setter;
IconDescriptor icon;
QStringList keywords;
};
void addChooseButton(ChooseButtonArgs &&args);
struct SliderArgs {
QString id;
rpl::producer<QString> title;
int steps;
int current;
Fn<int(int)> indexToValue;
Fn<void(int)> onChanged;
Fn<void(int)> onFinalChanged;
Fn<QString(int)> formatLabel;
QStringList keywords;
};
void addSlider(SliderArgs &&args);
void addBetaBadge(not_null<Ui::SettingsButton*> button);
void addSectionDivider();
private:
Builder::SectionBuilder &_builder;
};
} // namespace Settings::AyBuilder
@@ -10,20 +10,24 @@
#include "ayu/ayu_settings.h"
#include "ayu/ui/boxes/font_selector.h"
#include "ayu/ui/components/icon_picker.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ui/settings/settings_main.h"
#include "inline_bots/bot_attach_web_view.h"
#include "main/main_session.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_ayu_icons.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include "ui/vertical_list.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
namespace Settings {
using namespace Builder;
using namespace AyBuilder;
namespace {
bool HasDrawerBots(not_null<Window::SessionController*> controller) {
@@ -33,15 +37,274 @@ bool HasDrawerBots(not_null<Window::SessionController*> controller) {
if (!bot.inMainMenu || !bot.media) {
continue;
}
return true;
}
return false;
}
void BuildAppIcon(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/appIcon"_q,
.title = tr::ayu_AppIconHeader(),
.keywords = { u"icon"_q, u"app"_q },
});
builder.add([](const WidgetContext &ctx) -> SectionBuilder::WidgetToAdd {
return {
.widget = object_ptr<IconPicker>(ctx.container),
.margin = st::settingsCheckboxPadding,
};
}, [] {
return SearchEntry{
.id = u"ayu/iconPicker"_q,
.title = tr::ayu_AppIconHeader(tr::now),
.keywords = { u"icon"_q, u"app"_q, u"logo"_q },
};
});
#ifdef Q_OS_WIN
builder.addDivider();
builder.addSkip();
ayu.addSettingToggle({
.id = u"ayu/hideNotificationBadge"_q,
.title = tr::ayu_HideNotificationBadge(),
.getter = &AyuSettings::hideNotificationBadge,
.setter = &AyuSettings::setHideNotificationBadge,
.keywords = { u"notification"_q, u"badge"_q },
});
builder.addSkip();
builder.addDividerText(tr::ayu_HideNotificationBadgeDescription());
builder.addSkip();
#endif
}
void BuildAppearance(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
builder.addSubsectionTitle({
.id = u"ayu/appearanceSection"_q,
.title = tr::ayu_CategoryAppearance(),
});
ayu.addSettingToggle({
.id = u"ayu/newSwitchStyle"_q,
.title = tr::ayu_MaterialSwitches(),
.getter = &AyuSettings::materialSwitches,
.setter = &AyuSettings::setMaterialSwitches,
.keywords = { u"material"_q, u"switch"_q, u"toggle"_q },
});
ayu.addSettingToggle({
.id = u"ayu/removeMessageTail"_q,
.title = tr::ayu_RemoveMessageTail(),
.getter = &AyuSettings::removeMessageTail,
.setter = &AyuSettings::setRemoveMessageTail,
.keywords = { u"tail"_q, u"bubble"_q },
});
ayu.addSettingToggle({
.id = u"ayu/disableCustomBackgrounds"_q,
.title = tr::ayu_DisableCustomBackgrounds(),
.getter = &AyuSettings::disableCustomBackgrounds,
.setter = &AyuSettings::setDisableCustomBackgrounds,
.keywords = { u"background"_q, u"wallpaper"_q },
});
const auto controller = builder.controller();
builder.addButton({
.id = u"ayu/monoFont"_q,
.title = tr::ayu_MonospaceFont(),
.st = &st::settingsButtonNoIcon,
.label = rpl::single(
settings->monoFont().isEmpty()
? tr::ayu_FontDefault(tr::now)
: settings->monoFont()),
.onClick = [=] {
AyuUi::FontSelectorBox::Show(
controller,
[=](const QString &font) {
AyuSettings::getInstance().setMonoFont(font);
});
},
.keywords = { u"font"_q, u"monospace"_q },
});
ayu.addSectionDivider();
}
void BuildChatFolders(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/chatFolders"_q,
.title = tr::ayu_ChatFoldersHeader(),
.keywords = { u"folders"_q, u"tabs"_q },
});
ayu.addSettingToggle({
.id = u"ayu/hideNotificationCounters"_q,
.title = tr::ayu_HideNotificationCounters(),
.getter = &AyuSettings::hideNotificationCounters,
.setter = &AyuSettings::setHideNotificationCounters,
.keywords = { u"notification"_q, u"counter"_q },
});
ayu.addSettingToggle({
.id = u"ayu/hideAllChats"_q,
.title = tr::ayu_HideAllChats(),
.getter = &AyuSettings::hideAllChatsFolder,
.setter = &AyuSettings::setHideAllChatsFolder,
.keywords = { u"all chats"_q, u"folder"_q },
});
ayu.addSectionDivider();
}
void BuildTrayElements(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/trayElements"_q,
.title = tr::ayu_TrayElementsHeader(),
.keywords = { u"tray"_q },
});
ayu.addSettingToggle({
.id = u"ayu/ghostToggleInTray"_q,
.title = tr::ayu_EnableGhostModeTray(),
.getter = &AyuSettings::showGhostToggleInTray,
.setter = &AyuSettings::setShowGhostToggleInTray,
.keywords = { u"ghost"_q, u"tray"_q },
});
#ifdef WIN32
ayu.addSettingToggle({
.id = u"ayu/streamerToggleInTray"_q,
.title = tr::ayu_EnableStreamerModeTray(),
.getter = &AyuSettings::showStreamerToggleInTray,
.setter = &AyuSettings::setShowStreamerToggleInTray,
.keywords = { u"streamer"_q, u"tray"_q },
});
#endif
ayu.addSectionDivider();
}
void BuildDrawerElements(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/drawerElements"_q,
.title = tr::ayu_DrawerElementsHeader(),
.keywords = { u"drawer"_q, u"menu"_q },
});
ayu.addSettingToggle({
.id = u"ayu/myProfileInDrawer"_q,
.title = tr::lng_menu_my_profile(),
.getter = &AyuSettings::showMyProfileInDrawer,
.setter = &AyuSettings::setShowMyProfileInDrawer,
.icon = { &st::menuIconProfile },
});
const auto controller = builder.controller();
if (controller && HasDrawerBots(controller)) {
ayu.addSettingToggle({
.id = u"ayu/botsInDrawer"_q,
.title = tr::lng_filters_type_bots(),
.getter = &AyuSettings::showBotsInDrawer,
.setter = &AyuSettings::setShowBotsInDrawer,
.icon = { &st::menuIconBot },
});
}
ayu.addSettingToggle({
.id = u"ayu/newGroupInDrawer"_q,
.title = tr::lng_create_group_title(),
.getter = &AyuSettings::showNewGroupInDrawer,
.setter = &AyuSettings::setShowNewGroupInDrawer,
.icon = { &st::menuIconGroups },
});
ayu.addSettingToggle({
.id = u"ayu/newChannelInDrawer"_q,
.title = tr::lng_create_channel_title(),
.getter = &AyuSettings::showNewChannelInDrawer,
.setter = &AyuSettings::setShowNewChannelInDrawer,
.icon = { &st::menuIconChannel },
});
ayu.addSettingToggle({
.id = u"ayu/contactsInDrawer"_q,
.title = tr::lng_menu_contacts(),
.getter = &AyuSettings::showContactsInDrawer,
.setter = &AyuSettings::setShowContactsInDrawer,
.icon = { &st::menuIconUserShow },
});
ayu.addSettingToggle({
.id = u"ayu/callsInDrawer"_q,
.title = tr::lng_menu_calls(),
.getter = &AyuSettings::showCallsInDrawer,
.setter = &AyuSettings::setShowCallsInDrawer,
.icon = { &st::menuIconPhone },
});
ayu.addSettingToggle({
.id = u"ayu/savedMessagesInDrawer"_q,
.title = tr::lng_saved_messages(),
.getter = &AyuSettings::showSavedMessagesInDrawer,
.setter = &AyuSettings::setShowSavedMessagesInDrawer,
.icon = { &st::menuIconSavedMessages },
});
ayu.addSettingToggle({
.id = u"ayu/lreadToggleInDrawer"_q,
.title = tr::ayu_LReadMessages(),
.getter = &AyuSettings::showLReadToggleInDrawer,
.setter = &AyuSettings::setShowLReadToggleInDrawer,
.icon = { &st::ayuLReadMenuIcon },
});
ayu.addSettingToggle({
.id = u"ayu/sreadToggleInDrawer"_q,
.title = tr::ayu_SReadMessages(),
.getter = &AyuSettings::showSReadToggleInDrawer,
.setter = &AyuSettings::setShowSReadToggleInDrawer,
.icon = { &st::ayuSReadMenuIcon },
});
ayu.addSettingToggle({
.id = u"ayu/nightModeToggleInDrawer"_q,
.title = tr::lng_menu_night_mode(),
.getter = &AyuSettings::showNightModeToggleInDrawer,
.setter = &AyuSettings::setShowNightModeToggleInDrawer,
.icon = { &st::menuIconNightMode },
});
ayu.addSettingToggle({
.id = u"ayu/ghostToggleInDrawer"_q,
.title = tr::ayu_GhostModeToggle(),
.getter = &AyuSettings::showGhostToggleInDrawer,
.setter = &AyuSettings::setShowGhostToggleInDrawer,
.icon = { &st::ayuGhostIcon },
});
#ifdef WIN32
ayu.addSettingToggle({
.id = u"ayu/streamerToggleInDrawer"_q,
.title = tr::ayu_StreamerModeToggle(),
.getter = &AyuSettings::showStreamerToggleInDrawer,
.setter = &AyuSettings::setShowStreamerToggleInDrawer,
.icon = { &st::ayuStreamerModeMenuIcon },
});
#endif
builder.addSkip();
}
const auto kMeta = BuildHelper({
.id = AyuAppearance::Id(),
.parentId = AyuMain::Id(),
.title = &tr::ayu_CategoryAppearance,
.icon = &st::menuIconPalette,
}, [](SectionBuilder &builder) {
auto ayu = AyuSectionBuilder(builder);
builder.addSkip();
BuildAppIcon(builder, ayu);
BuildAppearance(builder, ayu);
BuildChatFolders(builder, ayu);
BuildTrayElements(builder, ayu);
BuildDrawerElements(builder, ayu);
builder.addSkip();
});
} // namespace
rpl::producer<QString> AyuAppearance::title() {
return tr::ayu_CategoryAppearance();
}
@@ -49,118 +312,18 @@ rpl::producer<QString> AyuAppearance::title() {
AyuAppearance::AyuAppearance(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent(controller);
: Section(parent, controller) {
setupContent();
}
void SetupAppIcon(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_AppIconHeader());
container->add(
object_ptr<IconPicker>(container),
st::settingsCheckboxPadding);
#ifdef Q_OS_WIN
AddDivider(container);
AddSkip(container);
AddSettingToggle(container, tr::ayu_HideNotificationBadge(), &AyuSettings::hideNotificationBadge, &AyuSettings::setHideNotificationBadge);
AddSkip(container);
AddDividerText(container, tr::ayu_HideNotificationBadgeDescription());
AddSkip(container);
#endif
}
void SetupAppearance(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
auto *settings = &AyuSettings::getInstance();
AddSubsectionTitle(container, tr::ayu_CategoryAppearance());
AddSettingToggle(container, tr::ayu_MaterialSwitches(), &AyuSettings::materialSwitches, &AyuSettings::setMaterialSwitches);
AddSettingToggle(container, tr::ayu_RemoveMessageTail(), &AyuSettings::removeMessageTail, &AyuSettings::setRemoveMessageTail);
AddSettingToggle(container, tr::ayu_DisableCustomBackgrounds(), &AyuSettings::disableCustomBackgrounds, &AyuSettings::setDisableCustomBackgrounds);
const auto monoButton = AddButtonWithLabel(
container,
tr::ayu_MonospaceFont(),
rpl::single(
settings->monoFont().isEmpty() ? tr::ayu_FontDefault(tr::now) : settings->monoFont()
),
st::settingsButtonNoIcon);
const auto monoGuard = Ui::CreateChild<base::binary_guard>(monoButton.get());
monoButton->addClickHandler(
[=]
{
*monoGuard = AyuUi::FontSelectorBox::Show(
controller,
[=](const QString& font)
{
AyuSettings::getInstance().setMonoFont(font);
});
});
AddSectionDivider(container);
}
void SetupChatFolders(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_ChatFoldersHeader());
AddSettingToggle(container, tr::ayu_HideNotificationCounters(), &AyuSettings::hideNotificationCounters, &AyuSettings::setHideNotificationCounters);
AddSettingToggle(container, tr::ayu_HideAllChats(), &AyuSettings::hideAllChatsFolder, &AyuSettings::setHideAllChatsFolder);
AddSectionDivider(container);
}
void SetupDrawerElements(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
AddSubsectionTitle(container, tr::ayu_DrawerElementsHeader());
AddSettingToggle(container, tr::lng_menu_my_profile(), &AyuSettings::showMyProfileInDrawer, &AyuSettings::setShowMyProfileInDrawer, st::menuIconProfile);
if (HasDrawerBots(controller)) {
AddSettingToggle(container, tr::lng_filters_type_bots(), &AyuSettings::showBotsInDrawer, &AyuSettings::setShowBotsInDrawer, st::menuIconBot);
}
AddSettingToggle(container, tr::lng_create_group_title(), &AyuSettings::showNewGroupInDrawer, &AyuSettings::setShowNewGroupInDrawer, st::menuIconGroups);
AddSettingToggle(container, tr::lng_create_channel_title(), &AyuSettings::showNewChannelInDrawer, &AyuSettings::setShowNewChannelInDrawer, st::menuIconChannel);
AddSettingToggle(container, tr::lng_menu_contacts(), &AyuSettings::showContactsInDrawer, &AyuSettings::setShowContactsInDrawer, st::menuIconUserShow);
AddSettingToggle(container, tr::lng_menu_calls(), &AyuSettings::showCallsInDrawer, &AyuSettings::setShowCallsInDrawer, st::menuIconPhone);
AddSettingToggle(container, tr::lng_saved_messages(), &AyuSettings::showSavedMessagesInDrawer, &AyuSettings::setShowSavedMessagesInDrawer, st::menuIconSavedMessages);
AddSettingToggle(container, tr::ayu_LReadMessages(), &AyuSettings::showLReadToggleInDrawer, &AyuSettings::setShowLReadToggleInDrawer, st::ayuLReadMenuIcon);
AddSettingToggle(container, tr::ayu_SReadMessages(), &AyuSettings::showSReadToggleInDrawer, &AyuSettings::setShowSReadToggleInDrawer, st::ayuSReadMenuIcon);
AddSettingToggle(container, tr::lng_menu_night_mode(), &AyuSettings::showNightModeToggleInDrawer, &AyuSettings::setShowNightModeToggleInDrawer, st::menuIconNightMode);
AddSettingToggle(container, tr::ayu_GhostModeToggle(), &AyuSettings::showGhostToggleInDrawer, &AyuSettings::setShowGhostToggleInDrawer, st::ayuGhostIcon);
#ifdef WIN32
AddSettingToggle(container, tr::ayu_StreamerModeToggle(), &AyuSettings::showStreamerToggleInDrawer, &AyuSettings::setShowStreamerToggleInDrawer, st::ayuStreamerModeMenuIcon);
#endif
AddSkip(container);
}
void SetupTrayElements(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_TrayElementsHeader());
AddSettingToggle(container, tr::ayu_EnableGhostModeTray(), &AyuSettings::showGhostToggleInTray, &AyuSettings::setShowGhostToggleInTray);
#ifdef WIN32
AddSettingToggle(container, tr::ayu_EnableStreamerModeTray(), &AyuSettings::showStreamerToggleInTray, &AyuSettings::setShowStreamerToggleInTray);
#endif
AddSectionDivider(container);
}
void AyuAppearance::setupContent(not_null<Window::SessionController*> controller) {
void AyuAppearance::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
AddSkip(content);
SetupAppIcon(content);
SetupAppearance(content, controller);
SetupChatFolders(content);
SetupTrayElements(content);
SetupDrawerElements(content, controller);
AddSkip(content);
ResizeFitChild(this, content);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
} // namespace Settings
Type AyuAppearanceId() {
return AyuAppearance::Id();
}
} // namespace Settings
@@ -15,15 +15,16 @@ class SessionController;
namespace Settings {
class AyuAppearance : public Section<AyuAppearance>
{
class AyuAppearance : public Section<AyuAppearance> {
public:
AyuAppearance(QWidget *parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
};
} // namespace Settings
[[nodiscard]] Type AyuAppearanceId();
} // namespace Settings
@@ -9,19 +9,21 @@
#include "lang_auto.h"
#include "settings_ayu_utils.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ui/settings/settings_main.h"
#include "boxes/peer_list_box.h"
#include "core/application.h"
#include "data/data_user.h"
#include "filters/settings_filters_list.h"
#include "main/main_account.h"
#include "main/main_domain.h"
#include "main/main_session.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_ayu_styles.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_info.h"
#include "styles/style_layers.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
@@ -35,6 +37,11 @@
namespace Settings {
using namespace Builder;
using namespace AyBuilder;
namespace {
struct GhostPickerState {
rpl::variable<uint64> selectedUserId;
base::unique_qptr<Ui::PopupMenu> menu;
@@ -243,256 +250,349 @@ void selectGhostProfile(GhostPickerState *state, uint64 userId) {
}
}
void SetupGhostEssentials(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
auto activeCount = 0;
for (const auto &account : Core::App().domain().orderedAccounts()) {
if (account->sessionExists()) {
++activeCount;
}
}
void BuildGhostEssentials(SectionBuilder &builder) {
builder.add([](const BuildContext &ctx) {
v::match(ctx, [&](const WidgetContext &wctx) {
const auto container = wctx.container;
const auto controller = wctx.controller;
if (activeCount <= 1 && !AyuSettings::getInstance().useGlobalGhostMode()) {
auto userId = controller->session().userId().bare;
auto &src = AyuSettings::ghost(userId);
auto &dst = AyuSettings::ghost(0);
dst.setSendReadMessages(src.sendReadMessages());
dst.setSendReadStories(src.sendReadStories());
dst.setSendOnlinePackets(src.sendOnlinePackets());
dst.setSendUploadProgress(src.sendUploadProgress());
dst.setSendOfflinePacketAfterOnline(src.sendOfflinePacketAfterOnline());
dst.setMarkReadAfterAction(src.markReadAfterAction());
dst.setUseScheduledMessages(src.useScheduledMessages());
dst.setSendWithoutSound(src.sendWithoutSound());
dst.setSendReadMessagesLocked(src.sendReadMessagesLocked());
dst.setSendReadStoriesLocked(src.sendReadStoriesLocked());
dst.setSendOnlinePacketsLocked(src.sendOnlinePacketsLocked());
dst.setSendUploadProgressLocked(src.sendUploadProgressLocked());
dst.setSendOfflinePacketAfterOnlineLocked(src.sendOfflinePacketAfterOnlineLocked());
AyuSettings::getInstance().setUseGlobalGhostMode(true);
}
const auto isGlobal = AyuSettings::getInstance().useGlobalGhostMode();
auto initialUserId = isGlobal
? uint64(0)
: controller->session().userId().bare;
const auto state = container->lifetime().make_state<GhostPickerState>();
state->selectedUserId = initialUserId;
const auto title = AddSubsectionTitle(container, tr::ayu_GhostEssentialsHeader());
const auto pickerButton = Ui::CreateChild<Ui::LinkButton>(
container.get(),
PickerLabel(initialUserId),
st::ghostPickerButton);
state->pickerButton = pickerButton;
const auto arrow = Ui::CreateChild<Ui::AbstractButton>(container.get());
{
const auto &icon = st::ghostPickerArrow;
arrow->resize(icon.size());
arrow->paintRequest(
) | rpl::on_next([=, &icon] {
auto p = QPainter(arrow);
icon.paint(p, 0, 0, arrow->width());
}, arrow->lifetime());
}
arrow->setCursor(style::cur_pointer);
const auto showPicker = activeCount > 1;
pickerButton->setVisible(showPicker);
arrow->setVisible(showPicker);
rpl::combine(
title->geometryValue(),
container->widthValue(),
pickerButton->naturalWidthValue()
) | rpl::on_next([=](QRect r, int width, int natural) {
pickerButton->resizeToNaturalWidth(width / 2);
pickerButton->moveToRight(
st::defaultSubsectionTitlePadding.right() + arrow->width() + st::normalFont->spacew / 2,
r.y() + (r.height() - pickerButton->height()) / 2,
width);
arrow->moveToLeft(
pickerButton->x() + pickerButton->width() + st::normalFont->spacew / 2,
r.y() + (r.height() - arrow->height()) / 2);
}, pickerButton->lifetime());
std::vector checkboxes{
NestedEntry{
tr::ayu_DontReadMessages(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendReadMessages(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadMessages(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendReadMessagesLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadMessagesLocked(v); }
},
NestedEntry{
tr::ayu_DontReadStories(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendReadStories(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadStories(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendReadStoriesLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadStoriesLocked(v); }
},
NestedEntry{
tr::ayu_DontSendOnlinePackets(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendOnlinePackets(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOnlinePackets(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendOnlinePacketsLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOnlinePacketsLocked(v); }
},
NestedEntry{
tr::ayu_DontSendUploadProgress(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendUploadProgress(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendUploadProgress(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendUploadProgressLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendUploadProgressLocked(v); }
},
NestedEntry{
tr::ayu_SendOfflinePacketAfterOnline(tr::now),
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendOfflinePacketAfterOnline(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOfflinePacketAfterOnline(v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendOfflinePacketAfterOnlineLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOfflinePacketAfterOnlineLocked(v); }
},
};
state->refreshCheckboxes = AddCollapsibleToggle(
container, tr::ayu_GhostModeToggle(), std::move(checkboxes), true);
AddButtonWithIcon(
container,
tr::ayu_MarkReadAfterAction(),
st::settingsButtonNoIcon
)->toggleOn(
state->selectedUserId.value()
| rpl::map([](uint64 id) {
return AyuSettings::ghost(id).markReadAfterActionChanges();
}) | rpl::flatten_latest()
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return enabled != AyuSettings::ghost(state->selectedUserId.current()).markReadAfterAction();
}) | on_next(
[=](bool enabled)
{
auto &ghost = AyuSettings::ghost(state->selectedUserId.current());
ghost.setMarkReadAfterAction(enabled);
if (enabled) {
ghost.setUseScheduledMessages(false);
auto activeCount = 0;
for (const auto &account : Core::App().domain().orderedAccounts()) {
if (account->sessionExists()) {
++activeCount;
}
}
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_MarkReadAfterActionDescription());
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_UseScheduledMessages(),
st::settingsButtonNoIcon
)->toggleOn(
state->selectedUserId.value()
| rpl::map([](uint64 id) {
return AyuSettings::ghost(id).useScheduledMessagesChanges();
}) | rpl::flatten_latest()
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return enabled != AyuSettings::ghost(state->selectedUserId.current()).useScheduledMessages();
}) | on_next(
[=](bool enabled)
{
auto &ghost = AyuSettings::ghost(state->selectedUserId.current());
ghost.setUseScheduledMessages(enabled);
if (enabled) {
ghost.setMarkReadAfterAction(false);
if (activeCount <= 1 && !AyuSettings::getInstance().useGlobalGhostMode()) {
auto userId = controller->session().userId().bare;
auto &src = AyuSettings::ghost(userId);
auto &dst = AyuSettings::ghost(0);
dst.setSendReadMessages(src.sendReadMessages());
dst.setSendReadStories(src.sendReadStories());
dst.setSendOnlinePackets(src.sendOnlinePackets());
dst.setSendUploadProgress(src.sendUploadProgress());
dst.setSendOfflinePacketAfterOnline(src.sendOfflinePacketAfterOnline());
dst.setMarkReadAfterAction(src.markReadAfterAction());
dst.setUseScheduledMessages(src.useScheduledMessages());
dst.setSendWithoutSound(src.sendWithoutSound());
dst.setSendReadMessagesLocked(src.sendReadMessagesLocked());
dst.setSendReadStoriesLocked(src.sendReadStoriesLocked());
dst.setSendOnlinePacketsLocked(src.sendOnlinePacketsLocked());
dst.setSendUploadProgressLocked(src.sendUploadProgressLocked());
dst.setSendOfflinePacketAfterOnlineLocked(src.sendOfflinePacketAfterOnlineLocked());
AyuSettings::getInstance().setUseGlobalGhostMode(true);
}
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_UseScheduledMessagesDescription());
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_SendWithoutSoundByDefault(),
st::settingsButtonNoIcon
)->toggleOn(
state->selectedUserId.value()
| rpl::map([](uint64 id) {
return AyuSettings::ghost(id).sendWithoutSoundChanges();
}) | rpl::flatten_latest()
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return enabled != AyuSettings::ghost(state->selectedUserId.current()).sendWithoutSound();
}) | on_next(
[=](bool enabled)
{
AyuSettings::ghost(state->selectedUserId.current()).setSendWithoutSound(enabled);
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_SendWithoutSoundByDefaultDescription());
const auto isGlobal = AyuSettings::getInstance().useGlobalGhostMode();
auto initialUserId = isGlobal
? uint64(0)
: controller->session().userId().bare;
auto showMenu = [=] {
state->menu = base::make_unique_q<Ui::PopupMenu>(
pickerButton,
st::defaultPopupMenu);
const auto state = container->lifetime().make_state<GhostPickerState>();
state->selectedUserId = initialUserId;
state->menu->addAction(
base::make_unique_q<GlobalAction>(
state->menu->menu(),
st::defaultPopupMenu.menu,
tr::ayu_GhostModeGlobalSettings(tr::now),
[=] { selectGhostProfile(state, 0); }));
const auto title = AddSubsectionTitle(container, tr::ayu_GhostEssentialsHeader());
for (const auto &account : Core::App().domain().orderedAccounts()) {
if (!account->sessionExists()) {
continue;
const auto pickerButton = Ui::CreateChild<Ui::LinkButton>(
container.get(),
PickerLabel(initialUserId),
st::ghostPickerButton);
state->pickerButton = pickerButton;
const auto arrow = Ui::CreateChild<Ui::AbstractButton>(container.get());
{
const auto &icon = st::ghostPickerArrow;
arrow->resize(icon.size());
arrow->paintRequest(
) | rpl::on_next([=, &icon] {
auto p = QPainter(arrow);
icon.paint(p, 0, 0, arrow->width());
}, arrow->lifetime());
}
auto user = account->session().user();
auto id = account->session().userId().bare;
state->menu->addAction(
base::make_unique_q<AccountAction>(
state->menu->menu(),
st::defaultPopupMenu.menu,
user,
[=] { selectGhostProfile(state, id); }));
}
arrow->setCursor(style::cur_pointer);
state->menu->popup(
pickerButton->mapToGlobal(
QPoint(pickerButton->width(), pickerButton->height())));
};
pickerButton->setClickedCallback(showMenu);
arrow->setClickedCallback(showMenu);
const auto showPicker = activeCount > 1;
pickerButton->setVisible(showPicker);
arrow->setVisible(showPicker);
rpl::combine(
title->geometryValue(),
container->widthValue(),
pickerButton->naturalWidthValue()
) | rpl::on_next([=](QRect r, int width, int natural) {
pickerButton->resizeToNaturalWidth(width / 2);
pickerButton->moveToRight(
st::defaultSubsectionTitlePadding.right() + arrow->width() + st::normalFont->spacew / 2,
r.y() + (r.height() - pickerButton->height()) / 2,
width);
arrow->moveToLeft(
pickerButton->x() + pickerButton->width() + st::normalFont->spacew / 2,
r.y() + (r.height() - arrow->height()) / 2);
}, pickerButton->lifetime());
std::vector checkboxes{
NestedEntry{
tr::ayu_DontReadMessages(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendReadMessages(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadMessages(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendReadMessagesLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadMessagesLocked(v); }
},
NestedEntry{
tr::ayu_DontReadStories(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendReadStories(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadStories(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendReadStoriesLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendReadStoriesLocked(v); }
},
NestedEntry{
tr::ayu_DontSendOnlinePackets(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendOnlinePackets(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOnlinePackets(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendOnlinePacketsLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOnlinePacketsLocked(v); }
},
NestedEntry{
tr::ayu_DontSendUploadProgress(tr::now),
[state] { return !AyuSettings::ghost(state->selectedUserId.current()).sendUploadProgress(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendUploadProgress(!v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendUploadProgressLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendUploadProgressLocked(v); }
},
NestedEntry{
tr::ayu_SendOfflinePacketAfterOnline(tr::now),
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendOfflinePacketAfterOnline(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOfflinePacketAfterOnline(v); },
[state] { return AyuSettings::ghost(state->selectedUserId.current()).sendOfflinePacketAfterOnlineLocked(); },
[state](bool v) { AyuSettings::ghost(state->selectedUserId.current()).setSendOfflinePacketAfterOnlineLocked(v); }
},
};
state->refreshCheckboxes = AddCollapsibleToggle(
container, tr::ayu_GhostModeToggle(), std::move(checkboxes), true);
AddButtonWithIcon(
container,
tr::ayu_MarkReadAfterAction(),
st::settingsButtonNoIcon
)->toggleOn(
state->selectedUserId.value()
| rpl::map([](uint64 id) {
return AyuSettings::ghost(id).markReadAfterActionChanges();
}) | rpl::flatten_latest()
)->toggledValue(
) | rpl::filter(
[=](bool enabled) {
return enabled != AyuSettings::ghost(state->selectedUserId.current()).markReadAfterAction();
}
) | on_next(
[=](bool enabled) {
auto &ghost = AyuSettings::ghost(state->selectedUserId.current());
ghost.setMarkReadAfterAction(enabled);
if (enabled) {
ghost.setUseScheduledMessages(false);
}
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_MarkReadAfterActionDescription());
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_UseScheduledMessages(),
st::settingsButtonNoIcon
)->toggleOn(
state->selectedUserId.value()
| rpl::map([](uint64 id) {
return AyuSettings::ghost(id).useScheduledMessagesChanges();
}) | rpl::flatten_latest()
)->toggledValue(
) | rpl::filter(
[=](bool enabled) {
return enabled != AyuSettings::ghost(state->selectedUserId.current()).useScheduledMessages();
}
) | on_next(
[=](bool enabled) {
auto &ghost = AyuSettings::ghost(state->selectedUserId.current());
ghost.setUseScheduledMessages(enabled);
if (enabled) {
ghost.setMarkReadAfterAction(false);
}
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_UseScheduledMessagesDescription());
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_SendWithoutSoundByDefault(),
st::settingsButtonNoIcon
)->toggleOn(
state->selectedUserId.value()
| rpl::map([](uint64 id) {
return AyuSettings::ghost(id).sendWithoutSoundChanges();
}) | rpl::flatten_latest()
)->toggledValue(
) | rpl::filter(
[=](bool enabled) {
return enabled != AyuSettings::ghost(state->selectedUserId.current()).sendWithoutSound();
}
) | on_next(
[=](bool enabled) {
AyuSettings::ghost(state->selectedUserId.current()).setSendWithoutSound(enabled);
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_SendWithoutSoundByDefaultDescription());
auto showMenu = [=] {
state->menu = base::make_unique_q<Ui::PopupMenu>(
pickerButton,
st::defaultPopupMenu);
state->menu->addAction(
base::make_unique_q<GlobalAction>(
state->menu->menu(),
st::defaultPopupMenu.menu,
tr::ayu_GhostModeGlobalSettings(tr::now),
[=] { selectGhostProfile(state, 0); }));
for (const auto &account : Core::App().domain().orderedAccounts()) {
if (!account->sessionExists()) {
continue;
}
auto user = account->session().user();
auto id = account->session().userId().bare;
state->menu->addAction(
base::make_unique_q<AccountAction>(
state->menu->menu(),
st::defaultPopupMenu.menu,
user,
[=] { selectGhostProfile(state, id); }));
}
state->menu->popup(
pickerButton->mapToGlobal(
QPoint(pickerButton->width(), pickerButton->height())));
};
pickerButton->setClickedCallback(showMenu);
arrow->setClickedCallback(showMenu);
}, [&](const SearchContext &sctx) {
sctx.entries->push_back({
.id = u"ayu/ghostModeToggle"_q,
.title = tr::ayu_GhostModeToggle(tr::now),
.keywords = { u"ghost"_q, u"read"_q, u"online"_q, u"stealth"_q },
.section = sctx.sectionId,
});
sctx.entries->push_back({
.id = u"ayu/markReadAfterAction"_q,
.title = tr::ayu_MarkReadAfterAction(tr::now),
.section = sctx.sectionId,
});
sctx.entries->push_back({
.id = u"ayu/useScheduledMessages"_q,
.title = tr::ayu_UseScheduledMessages(tr::now),
.keywords = { u"schedule"_q },
.section = sctx.sectionId,
});
sctx.entries->push_back({
.id = u"ayu/sendWithoutSound"_q,
.title = tr::ayu_SendWithoutSoundByDefault(tr::now),
.keywords = { u"silent"_q, u"sound"_q },
.section = sctx.sectionId,
});
});
});
}
void SetupSpyEssentials(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_SpyEssentialsHeader());
void BuildSpyEssentials(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/spyEssentials"_q,
.title = tr::ayu_SpyEssentialsHeader(),
.keywords = { u"spy"_q, u"save"_q },
});
AddSettingToggle(container, tr::ayu_SaveDeletedMessages(), &AyuSettings::saveDeletedMessages, &AyuSettings::setSaveDeletedMessages);
AddSettingToggle(container, tr::ayu_SaveMessagesHistory(), &AyuSettings::saveMessagesHistory, &AyuSettings::setSaveMessagesHistory);
ayu.addSettingToggle({
.id = u"ayu/saveDeletedMessages"_q,
.title = tr::ayu_SaveDeletedMessages(),
.getter = &AyuSettings::saveDeletedMessages,
.setter = &AyuSettings::setSaveDeletedMessages,
.keywords = { u"deleted"_q, u"save"_q },
});
ayu.addSettingToggle({
.id = u"ayu/saveMessagesHistory"_q,
.title = tr::ayu_SaveMessagesHistory(),
.getter = &AyuSettings::saveMessagesHistory,
.setter = &AyuSettings::setSaveMessagesHistory,
.keywords = { u"history"_q, u"edit"_q },
});
AddSectionDivider(container);
ayu.addSectionDivider();
AddSettingToggle(container, tr::ayu_MessageSavingSaveForBots(), &AyuSettings::saveForBots, &AyuSettings::setSaveForBots);
ayu.addSettingToggle({
.id = u"ayu/saveForBots"_q,
.title = tr::ayu_MessageSavingSaveForBots(),
.getter = &AyuSettings::saveForBots,
.setter = &AyuSettings::setSaveForBots,
.keywords = { u"bots"_q },
});
}
void SetupOther(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_MessageSavingOtherHeader());
void BuildOther(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/ghostOther"_q,
.title = tr::ayu_MessageSavingOtherHeader(),
});
AddSettingToggle(container, tr::ayu_LocalPremium(), &AyuSettings::localPremium, &AyuSettings::setLocalPremium);
AddSettingToggle(container, tr::ayu_DisableAds(), &AyuSettings::disableAds, &AyuSettings::setDisableAds);
AddBetaBadge(AddSettingToggle(container, tr::ayu_SemiTransparentDeletedMessages(), &AyuSettings::semiTransparentDeletedMessages, &AyuSettings::setSemiTransparentDeletedMessages));
ayu.addSettingToggle({
.id = u"ayu/localPremium"_q,
.title = tr::ayu_LocalPremium(),
.getter = &AyuSettings::localPremium,
.setter = &AyuSettings::setLocalPremium,
.keywords = { u"premium"_q },
});
ayu.addSettingToggle({
.id = u"ayu/disableAds"_q,
.title = tr::ayu_DisableAds(),
.getter = &AyuSettings::disableAds,
.setter = &AyuSettings::setDisableAds,
.keywords = { u"ads"_q, u"sponsored"_q },
});
const auto semiTransparent = ayu.addSettingToggle({
.id = u"ayu/translucentDeletedMessages"_q,
.title = tr::ayu_SemiTransparentDeletedMessages(),
.getter = &AyuSettings::semiTransparentDeletedMessages,
.setter = &AyuSettings::setSemiTransparentDeletedMessages,
.keywords = { u"semi-transparent"_q, u"transcluent"_q },
});
if (semiTransparent) {
ayu.addBetaBadge(semiTransparent);
}
}
const auto kMeta = BuildHelper({
.id = AyuGhost::Id(),
.parentId = AyuMain::Id(),
.title = &tr::ayu_AyuPreferences,
.icon = &st::menuIconGroupReactions,
}, [](SectionBuilder &builder) {
auto ayu = AyuSectionBuilder(builder);
builder.addSkip();
BuildGhostEssentials(builder);
builder.addSkip();
BuildSpyEssentials(builder, ayu);
ayu.addSectionDivider();
BuildOther(builder, ayu);
builder.addSkip();
});
} // namespace
rpl::producer<QString> AyuGhost::title() {
return rpl::single(QString("AyuGram"));
}
@@ -500,27 +600,19 @@ rpl::producer<QString> AyuGhost::title() {
AyuGhost::AyuGhost(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller)
, _controller(controller) {
setupContent(controller);
: Section(parent, controller)
, _controller(controller) {
setupContent();
}
void AyuGhost::setupContent(not_null<Window::SessionController*> controller) {
void AyuGhost::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
AddSkip(content);
SetupGhostEssentials(content, controller);
AddSkip(content);
SetupSpyEssentials(content);
AddSectionDivider(content);
SetupOther(content);
AddSkip(content);
ResizeFitChild(this, content);
Type AyuGhostId() {
return AyuGhost::Id();
}
} // namespace Settings
@@ -15,17 +15,18 @@ class SessionController;
namespace Settings {
class AyuGhost : public Section<AyuGhost>
{
class AyuGhost : public Section<AyuGhost> {
public:
AyuGhost(QWidget *parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
not_null<Window::SessionController*> _controller;
};
} // namespace Settings
[[nodiscard]] Type AyuGhostId();
} // namespace Settings
@@ -6,28 +6,439 @@
// Copyright @Radolyn, 2026
#include "settings_chats.h"
#include <styles/style_ayu_icons.h>
#include "lang_auto.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/boxes/edit_mark_box.h"
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "ayu/ui/settings/settings_main.h"
#include "core/application.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_ayu_styles.h"
#include "styles/style_boxes.h"
#include "styles/style_ayu_icons.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include "ui/vertical_list.h"
#include "ui/boxes/confirm_box.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
namespace Settings {
using namespace Builder;
using namespace AyBuilder;
namespace {
void BuildStickersAndEmoji(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/stickersEmoji"_q,
.title = tr::lng_settings_stickers_emoji(),
.keywords = { u"stickers"_q, u"emoji"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showOnlyAddedEmojis"_q,
.title = tr::ayu_ShowOnlyAddedEmojisAndStickers(),
.getter = &AyuSettings::showOnlyAddedEmojisAndStickers,
.setter = &AyuSettings::setShowOnlyAddedEmojisAndStickers,
.keywords = { u"emoji"_q, u"stickers"_q, u"added"_q },
});
ayu.addCollapsibleToggle({
.id = u"ayu/hideReactions"_q,
.title = tr::ayu_HideReactions(),
.checkboxes = {
NestedEntry{
tr::ayu_HideReactionsInChannels(tr::now),
[] { return !AyuSettings::getInstance().showChannelReactions(); },
[](bool v) { AyuSettings::getInstance().setShowChannelReactions(!v); }
},
NestedEntry{
tr::ayu_HideReactionsInGroups(tr::now),
[] { return !AyuSettings::getInstance().showGroupReactions(); },
[](bool v) { AyuSettings::getInstance().setShowGroupReactions(!v); }
}
},
.toggledWhenAll = false,
.keywords = { u"reactions"_q, u"hide"_q },
});
ayu.addSectionDivider();
}
void BuildRecentStickersLimit(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
ayu.addSlider({
.id = u"ayu/recentStickersCount"_q,
.title = tr::ayu_SettingsRecentStickersCount(),
.steps = 200 + 1,
.current = settings->recentStickersCount(),
.indexToValue = [](int index) { return index; },
.onChanged = nullptr,
.onFinalChanged = [](int amount) {
AyuSettings::getInstance().setRecentStickersCount(amount);
},
.formatLabel = [](int amount) { return QString::number(amount); },
.keywords = { u"stickers"_q, u"recent"_q, u"limit"_q },
});
ayu.addSectionDivider();
}
void BuildGroupsAndChannels(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
builder.addSubsectionTitle({
.id = u"ayu/groupsChannels"_q,
.title = tr::lng_premium_double_limits_subtitle_channels(),
.keywords = { u"groups"_q, u"channels"_q },
});
ayu.addChooseButton({
.id = u"ayu/bottomButton"_q,
.title = tr::ayu_ChannelBottomButton(),
.boxTitle = tr::ayu_ChannelBottomButton(),
.initialSelection = static_cast<int>(settings->channelBottomButton()),
.options = {
tr::ayu_ChannelBottomButtonHide(tr::now),
tr::ayu_ChannelBottomButtonMute(tr::now),
tr::ayu_ChannelBottomButtonDiscuss(tr::now),
},
.setter = [](int index) {
AyuSettings::getInstance().setChannelBottomButton(
static_cast<ChannelBottomButton>(index));
},
.keywords = { u"channel"_q, u"bottom"_q, u"button"_q },
});
ayu.addSettingToggle({
.id = u"ayu/adminShortcuts"_q,
.title = tr::ayu_QuickAdminShortcuts(),
.getter = &AyuSettings::quickAdminShortcuts,
.setter = &AyuSettings::setQuickAdminShortcuts,
.keywords = { u"admin"_q, u"shortcuts"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showMessageShot"_q,
.title = tr::ayu_SettingsShowMessageShot(),
.getter = &AyuSettings::showMessageShot,
.setter = &AyuSettings::setShowMessageShot,
.keywords = { u"screenshot"_q, u"shot"_q },
});
builder.addSkip();
builder.addDividerText(tr::ayu_SettingsShowMessageShotDescription());
builder.addSkip();
}
void BuildMarks(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
builder.addSubsectionTitle({
.id = u"ayu/messages"_q,
.title = tr::lng_settings_messages(),
.keywords = { u"messages"_q, u"marks"_q },
});
builder.addButton({
.id = u"ayu/deletedMark"_q,
.title = tr::ayu_DeletedMarkText(),
.st = &st::settingsButtonNoIcon,
.label = AyuSettings::getInstance().deletedMarkChanges(),
.onClick = [=] {
auto box = Box<EditMarkBox>(
tr::ayu_DeletedMarkText(),
settings->deletedMark(),
QString("🧹"),
[=](const QString &value) {
AyuSettings::getInstance().setDeletedMark(value);
});
Ui::show(std::move(box));
},
.keywords = { u"deleted"_q, u"mark"_q },
});
builder.addButton({
.id = u"ayu/editedMark"_q,
.title = tr::ayu_EditedMarkText(),
.st = &st::settingsButtonNoIcon,
.label = AyuSettings::getInstance().editedMarkChanges(),
.onClick = [=] {
auto box = Box<EditMarkBox>(
tr::ayu_EditedMarkText(),
settings->editedMark(),
tr::lng_edited(tr::now),
[=](const QString &value) {
AyuSettings::getInstance().setEditedMark(value);
});
Ui::show(std::move(box));
},
.keywords = { u"edited"_q, u"mark"_q },
});
ayu.addSettingToggle({
.id = u"ayu/replaceEditedWithIcon"_q,
.title = tr::ayu_ReplaceMarksWithIcons(),
.getter = &AyuSettings::replaceBottomInfoWithIcons,
.setter = &AyuSettings::setReplaceBottomInfoWithIcons,
.keywords = { u"icons"_q, u"marks"_q },
});
ayu.addSectionDivider();
ayu.addSettingToggle({
.id = u"ayu/hideShareButton"_q,
.title = tr::ayu_HideShareButton(),
.getter = &AyuSettings::hideFastShare,
.setter = &AyuSettings::setHideFastShare,
.keywords = { u"share"_q, u"forward"_q },
});
ayu.addSettingToggle({
.id = u"ayu/disableColorfulReplies"_q,
.title = tr::ayu_SimpleQuotesAndReplies(),
.getter = &AyuSettings::simpleQuotesAndReplies,
.setter = &AyuSettings::setSimpleQuotesAndReplies,
.keywords = { u"quotes"_q, u"replies"_q, u"simple"_q },
});
ayu.addSectionDivider();
}
void BuildWideMessagesMultiplier(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
constexpr auto kSizeAmount = 61; // (4.00 - 1.00) / 0.05 + 1
constexpr auto kMinSize = 1.00;
constexpr auto kStep = 0.05;
const auto valueToIndex = [=](double value) {
return static_cast<int>(std::round((value - kMinSize) / kStep));
};
const auto controller = builder.controller();
ayu.addSlider({
.id = u"ayu/wideMultiplier"_q,
.title = tr::ayu_SettingsWideMultiplier(),
.steps = kSizeAmount,
.current = valueToIndex(settings->wideMultiplier()),
.indexToValue = [](int index) { return index; },
.onChanged = nullptr,
.onFinalChanged = [=](int index) {
AyuSettings::getInstance().setWideMultiplier(
kMinSize + index * kStep);
crl::on_main([=] {
controller->show(Ui::MakeConfirmBox({
.text = tr::lng_settings_need_restart(),
.confirmed = [] { Core::Restart(); },
.confirmText = tr::lng_settings_restart_now(),
.cancelText = tr::lng_settings_restart_later(),
}));
});
},
.formatLabel = [=](int index) {
return QString::number(kMinSize + index * kStep, 'f', 2);
},
.keywords = { u"wide"_q, u"multiplier"_q, u"width"_q },
});
builder.addSkip();
builder.addDividerText(tr::ayu_SettingsWideMultiplierDescription());
builder.addSkip();
}
void BuildContextMenuElements(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
builder.addSubsectionTitle({
.id = u"ayu/contextMenu"_q,
.title = tr::ayu_ContextMenuElementsHeader(),
.keywords = { u"context"_q, u"menu"_q },
});
const auto options = std::vector{
tr::ayu_SettingsContextMenuItemHidden(tr::now),
tr::ayu_SettingsContextMenuItemShown(tr::now),
tr::ayu_SettingsContextMenuItemExtended(tr::now),
};
ayu.addChooseButton({
.id = u"ayu/contextReactionsPanel"_q,
.title = tr::ayu_SettingsContextMenuReactionsPanel(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showReactionsPanelInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowReactionsPanelInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconReactions },
.keywords = { u"reactions"_q, u"panel"_q },
});
ayu.addChooseButton({
.id = u"ayu/contextViewsPanel"_q,
.title = tr::ayu_SettingsContextMenuViewsPanel(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showViewsPanelInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowViewsPanelInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconShowInChat },
.keywords = { u"views"_q, u"panel"_q },
});
ayu.addChooseButton({
.id = u"ayu/contextHideMessage"_q,
.title = tr::ayu_ContextHideMessage(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showHideMessageInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowHideMessageInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconClear },
.keywords = { u"hide"_q, u"message"_q },
});
ayu.addChooseButton({
.id = u"ayu/contextUserMessages"_q,
.title = tr::ayu_UserMessagesMenuText(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showUserMessagesInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowUserMessagesInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconTTL },
.keywords = { u"user"_q, u"messages"_q },
});
ayu.addChooseButton({
.id = u"ayu/contextMessageDetails"_q,
.title = tr::ayu_MessageDetailsPC(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showMessageDetailsInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowMessageDetailsInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconInfo },
.keywords = { u"details"_q, u"info"_q },
});
ayu.addChooseButton({
.id = u"ayu/contextRepeatMessage"_q,
.title = tr::ayu_RepeatMessage(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showRepeatMessageInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowRepeatMessageInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconRestore },
.keywords = { u"repeat"_q, u"resend"_q },
});
if (settings->filtersEnabled()) {
ayu.addChooseButton({
.id = u"ayu/contextAddFilter"_q,
.title = tr::ayu_RegexFilterQuickAdd(),
.boxTitle = tr::ayu_SettingsContextMenuTitle(),
.initialSelection = static_cast<int>(settings->showAddFilterInContextMenu()),
.options = options,
.setter = [](int i) { AyuSettings::getInstance().setShowAddFilterInContextMenu(static_cast<ContextMenuVisibility>(i)); },
.icon = { &st::menuIconAddToFolder },
.keywords = { u"filter"_q, u"add"_q },
});
}
builder.addSkip();
builder.addDividerText(tr::ayu_SettingsContextMenuDescription());
builder.addSkip();
}
void BuildMessageFieldElements(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/messageField"_q,
.title = tr::ayu_MessageFieldElementsHeader(),
.keywords = { u"message"_q, u"field"_q, u"compose"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showAttachButton"_q,
.title = tr::ayu_MessageFieldElementAttach(),
.getter = &AyuSettings::showAttachButtonInMessageField,
.setter = &AyuSettings::setShowAttachButtonInMessageField,
.icon = { &st::messageFieldAttachIcon },
.keywords = { u"attach"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showCommandsButton"_q,
.title = tr::ayu_MessageFieldElementCommands(),
.getter = &AyuSettings::showCommandsButtonInMessageField,
.setter = &AyuSettings::setShowCommandsButtonInMessageField,
.icon = { &st::messageFieldCommandsIcon },
.keywords = { u"commands"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showAutoDeleteButton"_q,
.title = tr::ayu_MessageFieldElementTTL(),
.getter = &AyuSettings::showAutoDeleteButtonInMessageField,
.setter = &AyuSettings::setShowAutoDeleteButtonInMessageField,
.icon = { &st::messageFieldTTLIcon },
.keywords = { u"auto delete"_q, u"ttl"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showEmojiButton"_q,
.title = tr::ayu_MessageFieldElementEmoji(),
.getter = &AyuSettings::showEmojiButtonInMessageField,
.setter = &AyuSettings::setShowEmojiButtonInMessageField,
.icon = { &st::messageFieldEmojiIcon },
.keywords = { u"emoji"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showMicrophoneButton"_q,
.title = tr::ayu_MessageFieldElementVoice(),
.getter = &AyuSettings::showMicrophoneButtonInMessageField,
.setter = &AyuSettings::setShowMicrophoneButtonInMessageField,
.icon = { &st::messageFieldVoiceIcon },
.keywords = { u"voice"_q, u"microphone"_q },
});
ayu.addSectionDivider();
}
void BuildMessageFieldPopups(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle({
.id = u"ayu/messageFieldPopups"_q,
.title = tr::ayu_MessageFieldPopupsHeader(),
.keywords = { u"popup"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showAttachPopup"_q,
.title = tr::ayu_MessageFieldElementAttach(),
.getter = &AyuSettings::showAttachPopup,
.setter = &AyuSettings::setShowAttachPopup,
.icon = { &st::messageFieldAttachIcon },
.keywords = { u"attach"_q, u"popup"_q },
});
ayu.addSettingToggle({
.id = u"ayu/showEmojiPopup"_q,
.title = tr::ayu_MessageFieldElementEmoji(),
.getter = &AyuSettings::showEmojiPopup,
.setter = &AyuSettings::setShowEmojiPopup,
.icon = { &st::messageFieldEmojiIcon },
.keywords = { u"emoji"_q, u"popup"_q },
});
}
const auto kMeta = BuildHelper({
.id = AyuChats::Id(),
.parentId = AyuMain::Id(),
.title = &tr::ayu_CategoryChats,
.icon = &st::menuIconChatBubble,
}, [](SectionBuilder &builder) {
auto ayu = AyuSectionBuilder(builder);
builder.addSkip();
BuildStickersAndEmoji(builder, ayu);
BuildRecentStickersLimit(builder, ayu);
BuildGroupsAndChannels(builder, ayu);
BuildMarks(builder, ayu);
BuildWideMessagesMultiplier(builder, ayu);
BuildContextMenuElements(builder, ayu);
BuildMessageFieldElements(builder, ayu);
BuildMessageFieldPopups(builder, ayu);
builder.addSkip();
});
} // namespace
rpl::producer<QString> AyuChats::title() {
return tr::ayu_CategoryChats();
}
@@ -35,382 +446,18 @@ rpl::producer<QString> AyuChats::title() {
AyuChats::AyuChats(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent(controller);
: Section(parent, controller) {
setupContent();
}
void SetupStickersAndEmojiSettings(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::lng_settings_stickers_emoji()/*rpl::single(QString("Stickers and Emoji"))*/);
AddSettingToggle(container, tr::ayu_ShowOnlyAddedEmojisAndStickers(), &AyuSettings::showOnlyAddedEmojisAndStickers, &AyuSettings::setShowOnlyAddedEmojisAndStickers);
std::vector checkboxes = {
NestedEntry{
tr::ayu_HideReactionsInChannels(tr::now),
[] { return !AyuSettings::getInstance().showChannelReactions(); },
[](bool v) { AyuSettings::getInstance().setShowChannelReactions(!v); }
},
NestedEntry{
tr::ayu_HideReactionsInGroups(tr::now),
[] { return !AyuSettings::getInstance().showGroupReactions(); },
[](bool v) { AyuSettings::getInstance().setShowGroupReactions(!v); }
}
};
AddCollapsibleToggle(container, tr::ayu_HideReactions(), checkboxes, false);
AddSectionDivider(container);
}
void SetupRecentStickersLimit(not_null<Ui::VerticalLayout*> container) {
auto *settings = &AyuSettings::getInstance();
container->add(
object_ptr<Button>(container,
tr::ayu_SettingsRecentStickersCount(),
st::settingsButtonNoIcon)
)->setAttribute(Qt::WA_TransparentForMouseEvents);
auto recentStickersLimitSlider = MakeSliderWithLabel(
container,
st::autoDownloadLimitSlider,
st::settingsScaleLabel,
0,
st::settingsScaleLabel.style.font->width("8%%"));
container->add(std::move(recentStickersLimitSlider.widget), st::recentStickersLimitPadding);
const auto slider = recentStickersLimitSlider.slider;
const auto label = recentStickersLimitSlider.label;
const auto updateLabel = [=](int amount)
{
label->setText(QString::number(amount));
};
updateLabel(settings->recentStickersCount());
slider->setPseudoDiscrete(
200 + 1,
[=](int amount)
{
return amount;
},
settings->recentStickersCount(),
[=](int amount)
{
updateLabel(amount);
},
[=](int amount)
{
updateLabel(amount);
AyuSettings::getInstance().setRecentStickersCount(amount);
});
AddSectionDivider(container);
}
void SetupGroupsAndChannels(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
auto *settings = &AyuSettings::getInstance();
AddSubsectionTitle(container,
tr::lng_premium_double_limits_subtitle_channels()
/*rpl::single(QString("Groups and Channels"))*/);
const auto options = std::vector{
tr::ayu_ChannelBottomButtonHide(tr::now),
tr::ayu_ChannelBottomButtonMute(tr::now),
tr::ayu_ChannelBottomButtonDiscuss(tr::now),
};
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->channelBottomButton()),
options,
tr::ayu_ChannelBottomButton(),
tr::ayu_ChannelBottomButton(),
[=](int index)
{
AyuSettings::getInstance().setChannelBottomButton(static_cast<ChannelBottomButton>(index));
});
AddSettingToggle(container, tr::ayu_QuickAdminShortcuts(), &AyuSettings::quickAdminShortcuts, &AyuSettings::setQuickAdminShortcuts);
AddSettingToggle(container, tr::ayu_SettingsShowMessageShot(), &AyuSettings::showMessageShot, &AyuSettings::setShowMessageShot);
AddSkip(container);
AddDividerText(container, tr::ayu_SettingsShowMessageShotDescription());
AddSkip(container);
}
void SetupMarks(not_null<Ui::VerticalLayout*> container) {
auto *settings = &AyuSettings::getInstance();
AddSubsectionTitle(container, tr::lng_settings_messages()/*rpl::single(QString("Messages"))*/);
AddButtonWithLabel(
container,
tr::ayu_DeletedMarkText(),
AyuSettings::getInstance().deletedMarkChanges(),
st::settingsButtonNoIcon
)->addClickHandler(
[=]()
{
auto box = Box<EditMarkBox>(
tr::ayu_DeletedMarkText(),
settings->deletedMark(),
QString("🧹"),
[=](const QString &value)
{
AyuSettings::getInstance().setDeletedMark(value);
}
);
Ui::show(std::move(box));
});
AddButtonWithLabel(
container,
tr::ayu_EditedMarkText(),
AyuSettings::getInstance().editedMarkChanges(),
st::settingsButtonNoIcon
)->addClickHandler(
[=]()
{
auto box = Box<EditMarkBox>(
tr::ayu_EditedMarkText(),
settings->editedMark(),
tr::lng_edited(tr::now),
[=](const QString &value)
{
AyuSettings::getInstance().setEditedMark(value);
}
);
Ui::show(std::move(box));
});
AddSettingToggle(container, tr::ayu_ReplaceMarksWithIcons(), &AyuSettings::replaceBottomInfoWithIcons, &AyuSettings::setReplaceBottomInfoWithIcons);
AddSectionDivider(container);
AddSettingToggle(container, tr::ayu_HideShareButton(), &AyuSettings::hideFastShare, &AyuSettings::setHideFastShare);
AddSettingToggle(container, tr::ayu_SimpleQuotesAndReplies(), &AyuSettings::simpleQuotesAndReplies, &AyuSettings::setSimpleQuotesAndReplies);
AddSectionDivider(container);
}
void SetupWideMessagesMultiplier(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
auto *settings = &AyuSettings::getInstance();
container->add(
object_ptr<Button>(container,
tr::ayu_SettingsWideMultiplier(),
st::settingsButtonNoIcon)
)->setAttribute(Qt::WA_TransparentForMouseEvents);
auto wideMultiplierSlider = MakeSliderWithLabel(
container,
st::autoDownloadLimitSlider,
st::settingsScaleLabel,
0,
st::settingsScaleLabel.style.font->width("8%%%"));
container->add(std::move(wideMultiplierSlider.widget), st::recentStickersLimitPadding);
const auto slider = wideMultiplierSlider.slider;
const auto label = wideMultiplierSlider.label;
const auto updateLabel = [=](double val)
{
label->setText(QString::number(val, 'f', 2));
};
constexpr auto kSizeAmount = 61; // (4.00 - 1.00) / 0.05 + 1
constexpr auto kMinSize = 1.00;
constexpr auto kStep = 0.05;
const auto valueToIndex = [=](double value)
{
return static_cast<int>(std::round((value - kMinSize) / kStep));
};
const auto indexToValue = [=](int index)
{
return kMinSize + index * kStep;
};
updateLabel(settings->wideMultiplier());
slider->setPseudoDiscrete(
kSizeAmount,
[=](int index) { return index; },
valueToIndex(settings->wideMultiplier()),
[=](int index)
{
updateLabel(indexToValue(index));
},
[=](int index)
{
updateLabel(indexToValue(index));
AyuSettings::getInstance().setWideMultiplier(indexToValue(index));
// fix slider
crl::on_main([=]
{
controller->show(Ui::MakeConfirmBox({
.text = tr::lng_settings_need_restart(),
.confirmed = []
{
Core::Restart();
},
.confirmText = tr::lng_settings_restart_now(),
.cancelText = tr::lng_settings_restart_later(),
}));
});
});
AddSkip(container);
AddDividerText(container, tr::ayu_SettingsWideMultiplierDescription());
AddSkip(container);
}
void SetupContextMenuElements(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
auto *settings = &AyuSettings::getInstance();
AddSubsectionTitle(container, tr::ayu_ContextMenuElementsHeader());
const auto options = std::vector{
tr::ayu_SettingsContextMenuItemHidden(tr::now),
tr::ayu_SettingsContextMenuItemShown(tr::now),
tr::ayu_SettingsContextMenuItemExtended(tr::now),
};
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showReactionsPanelInContextMenu()),
options,
tr::ayu_SettingsContextMenuReactionsPanel(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconReactions,
[=](int index)
{
AyuSettings::getInstance().setShowReactionsPanelInContextMenu(static_cast<ContextMenuVisibility>(index));
});
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showViewsPanelInContextMenu()),
options,
tr::ayu_SettingsContextMenuViewsPanel(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconShowInChat,
[=](int index)
{
AyuSettings::getInstance().setShowViewsPanelInContextMenu(static_cast<ContextMenuVisibility>(index));
});
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showHideMessageInContextMenu()),
options,
tr::ayu_ContextHideMessage(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconClear,
[=](int index)
{
AyuSettings::getInstance().setShowHideMessageInContextMenu(static_cast<ContextMenuVisibility>(index));
});
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showUserMessagesInContextMenu()),
options,
tr::ayu_UserMessagesMenuText(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconTTL,
[=](int index)
{
AyuSettings::getInstance().setShowUserMessagesInContextMenu(static_cast<ContextMenuVisibility>(index));
});
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showMessageDetailsInContextMenu()),
options,
tr::ayu_MessageDetailsPC(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconInfo,
[=](int index)
{
AyuSettings::getInstance().setShowMessageDetailsInContextMenu(static_cast<ContextMenuVisibility>(index));
});
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showRepeatMessageInContextMenu()),
options,
tr::ayu_RepeatMessage(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconRestore,
[=](int index)
{
AyuSettings::getInstance().setShowRepeatMessageInContextMenu(static_cast<ContextMenuVisibility>(index));
});
if (settings->filtersEnabled()) {
AddChooseButtonWithIconAndRightText(
container,
controller,
static_cast<int>(settings->showAddFilterInContextMenu()),
options,
tr::ayu_RegexFilterQuickAdd(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconAddToFolder,
[=](int index)
{
AyuSettings::getInstance().setShowAddFilterInContextMenu(static_cast<ContextMenuVisibility>(index));
});
}
AddSkip(container);
AddDividerText(container, tr::ayu_SettingsContextMenuDescription());
AddSkip(container);
}
void SetupMessageFieldElements(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_MessageFieldElementsHeader());
AddSettingToggle(container, tr::ayu_MessageFieldElementAttach(), &AyuSettings::showAttachButtonInMessageField, &AyuSettings::setShowAttachButtonInMessageField, st::messageFieldAttachIcon);
AddSettingToggle(container, tr::ayu_MessageFieldElementCommands(), &AyuSettings::showCommandsButtonInMessageField, &AyuSettings::setShowCommandsButtonInMessageField, st::messageFieldCommandsIcon);
AddSettingToggle(container, tr::ayu_MessageFieldElementTTL(), &AyuSettings::showAutoDeleteButtonInMessageField, &AyuSettings::setShowAutoDeleteButtonInMessageField, st::messageFieldTTLIcon);
AddSettingToggle(container, tr::ayu_MessageFieldElementEmoji(), &AyuSettings::showEmojiButtonInMessageField, &AyuSettings::setShowEmojiButtonInMessageField, st::messageFieldEmojiIcon);
AddSettingToggle(container, tr::ayu_MessageFieldElementVoice(), &AyuSettings::showMicrophoneButtonInMessageField, &AyuSettings::setShowMicrophoneButtonInMessageField, st::messageFieldVoiceIcon);
AddSectionDivider(container);
}
void SetupMessageFieldPopups(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_MessageFieldPopupsHeader());
AddSettingToggle(container, tr::ayu_MessageFieldElementAttach(), &AyuSettings::showAttachPopup, &AyuSettings::setShowAttachPopup, st::messageFieldAttachIcon);
AddSettingToggle(container, tr::ayu_MessageFieldElementEmoji(), &AyuSettings::showEmojiPopup, &AyuSettings::setShowEmojiPopup, st::messageFieldEmojiIcon);
}
void AyuChats::setupContent(not_null<Window::SessionController*> controller) {
void AyuChats::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
AddSkip(content);
SetupStickersAndEmojiSettings(content);
SetupRecentStickersLimit(content);
SetupGroupsAndChannels(content, controller);
SetupMarks(content);
SetupWideMessagesMultiplier(content, controller);
SetupContextMenuElements(content, controller);
SetupMessageFieldElements(content);
SetupMessageFieldPopups(content);
AddSkip(content);
ResizeFitChild(this, content);
Type AyuChatsId() {
return AyuChats::Id();
}
} // namespace Settings
@@ -15,15 +15,16 @@ class SessionController;
namespace Settings {
class AyuChats : public Section<AyuChats>
{
class AyuChats : public Section<AyuChats> {
public:
AyuChats(QWidget *parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
};
} // namespace Settings
[[nodiscard]] Type AyuChatsId();
} // namespace Settings
@@ -11,7 +11,8 @@
#include "ayu/data/ayu_database.h"
#include "ayu/features/filters/filters_cache_controller.h"
#include "ayu/ui/boxes/import_filters_box.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ui/settings/settings_main.h"
#include "ayu/utils/telegram_helpers.h"
#include "boxes/abstract_box.h"
#include "boxes/peer_list_box.h"
@@ -19,6 +20,7 @@
#include "filters/per_dialog_filter.h"
#include "filters/settings_filters_list.h"
#include "inline_bots/bot_attach_web_view.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_boxes.h"
#include "styles/style_menu_icons.h"
@@ -34,6 +36,161 @@
namespace Settings {
using namespace Builder;
using namespace AyBuilder;
namespace {
void BuildFiltersSettings(SectionBuilder &builder) {
auto *settings = &AyuSettings::getInstance();
builder.addSkip();
builder.addSubsectionTitle({
.id = u"ayu/regexFilters"_q,
.title = tr::ayu_RegexFilters(),
.keywords = { u"regex"_q, u"filters"_q },
});
const auto enabledButton = builder.addButton({
.id = u"ayu/filtersEnabled"_q,
.title = tr::ayu_RegexFiltersEnable(),
.st = &st::settingsButtonNoIcon,
.toggled = rpl::single(settings->filtersEnabled()),
.keywords = { u"regex"_q, u"enable"_q },
});
if (enabledButton) {
enabledButton->toggledValue(
) | rpl::filter([=](bool enabled) {
return (enabled != settings->filtersEnabled());
}) | on_next([=](bool enabled) {
AyuSettings::getInstance().setFiltersEnabled(enabled);
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
}, enabledButton->lifetime());
}
const auto sharedButton = builder.addButton({
.id = u"ayu/filtersInChats"_q,
.title = tr::ayu_RegexFiltersEnableSharedInChats(),
.st = &st::settingsButtonNoIcon,
.toggled = rpl::single(settings->filtersEnabledInChats()),
.keywords = { u"shared"_q, u"chats"_q },
});
if (sharedButton) {
sharedButton->toggledValue(
) | rpl::filter([=](bool enabled) {
return (enabled != settings->filtersEnabledInChats());
}) | on_next([=](bool enabled) {
AyuSettings::getInstance().setFiltersEnabledInChats(enabled);
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
}, sharedButton->lifetime());
}
const auto blockedButton = builder.addButton({
.id = u"ayu/hideFromBlocked"_q,
.title = tr::ayu_FiltersHideFromBlocked(),
.st = &st::settingsButtonNoIcon,
.toggled = rpl::single(settings->hideFromBlocked()),
.keywords = { u"blocked"_q, u"hide"_q },
});
if (blockedButton) {
blockedButton->toggledValue(
) | rpl::filter([=](bool enabled) {
return (enabled != settings->hideFromBlocked());
}) | on_next([=](bool enabled) {
AyuSettings::getInstance().setHideFromBlocked(enabled);
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
}, blockedButton->lifetime());
}
builder.addSkip();
}
void BuildShared(SectionBuilder &builder) {
builder.addDivider();
builder.addSkip();
const auto controller = builder.controller();
builder.addButton({
.id = u"ayu/sharedFilters"_q,
.title = tr::ayu_RegexFiltersShared(),
.st = &st::settingsButtonNoIcon,
.onClick = [=] {
controller->dialogId = std::nullopt;
controller->showExclude = false;
controller->showSettings(AyuFiltersList::Id());
},
.keywords = { u"shared"_q, u"filters"_q },
});
}
void BuildShadowBan(SectionBuilder &builder) {
const auto controller = builder.controller();
builder.addButton({
.id = u"ayu/shadowBanList"_q,
.title = tr::ayu_FiltersShadowBan(),
.st = &st::settingsButtonNoIcon,
.onClick = [=] {
controller->dialogId = std::nullopt;
controller->showExclude = false;
controller->shadowBan = true;
controller->showSettings(AyuFiltersList::Id());
},
.keywords = { u"shadow"_q, u"ban"_q },
});
}
void BuildPerDialog(SectionBuilder &builder) {
builder.add([](const BuildContext &ctx) {
v::match(ctx, [&](const WidgetContext &wctx) {
if (!AyuDatabase::hasPerDialogFilters()) {
return;
}
const auto container = wctx.container;
const auto controller = wctx.controller;
AddSkip(container);
AddDivider(container);
auto ctrl = container->lifetime().make_state<PerDialogFiltersListController>(
&controller->session(),
controller);
auto list = object_ptr<Ui::PaddingWrap<PeerListContent>>(
container,
object_ptr<PeerListContent>(
container,
ctrl),
QMargins(0, -st::peerListBox.padding.top(), 0, -st::peerListBox.padding.bottom()));
AddSkip(container);
const auto content = container->add(std::move(list));
AddSkip(container);
auto delegate = container->lifetime().make_state<PeerListContentDelegateSimple>();
delegate->setContent(content->entity());
ctrl->setDelegate(delegate);
}, [&](const SearchContext &) {
});
});
}
const auto kMeta = BuildHelper({
.id = AyuFilters::Id(),
.parentId = AyuMain::Id(),
.title = &tr::ayu_CategoryFilters,
.icon = &st::menuIconTagFilter,
}, [](SectionBuilder &builder) {
BuildFiltersSettings(builder);
BuildShared(builder);
BuildShadowBan(builder);
BuildPerDialog(builder);
});
} // namespace
rpl::producer<QString> AyuFilters::title() {
return tr::ayu_CategoryFilters();
}
@@ -41,8 +198,7 @@ rpl::producer<QString> AyuFilters::title() {
void AyuFilters::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
addAction(
tr::ayu_FiltersMenuSelectChat(tr::now),
[=]
{
[=] {
if (const auto window = Core::App().activeWindow()) {
if (const auto controller = window->sessionController()) {
auto types = InlineBots::PeerTypes();
@@ -52,8 +208,7 @@ void AyuFilters::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
Window::ShowChooseRecipientBox(
controller,
[=](not_null<Data::Thread*> thread)
{
[=](not_null<Data::Thread*> thread) {
const auto peer = thread->peer();
controller->dialogId = getDialogIdFromPeer(peer);
controller->showExclude = true;
@@ -62,19 +217,15 @@ void AyuFilters::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
},
tr::ayu_FiltersMenuSelectChat(),
nullptr,
types
);
types);
}
}
},
&st::menuIconSearch);
addAction({
.isSeparator = true
});
addAction({ .isSeparator = true });
addAction(
tr::ayu_FiltersMenuImport(tr::now),
[=]
{
[=] {
auto box = Box(Ui::FillImportFiltersBox, true);
Ui::show(std::move(box));
},
@@ -82,29 +233,23 @@ void AyuFilters::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
if (AyuDatabase::hasFilters()) {
addAction(
tr::ayu_FiltersMenuExport(tr::now),
[=]
{
[=] {
auto box = Box(Ui::FillImportFiltersBox, false);
Ui::show(std::move(box));
},
&st::menuIconUnarchive);
}
addAction({
.isSeparator = true
});
addAction({ .isSeparator = true });
addAction(
tr::ayu_FiltersMenuClear(tr::now),
[=]
{
auto callback = [=](Fn<void()> &&close)
{
[=] {
auto callback = [=](Fn<void()> &&close) {
AyuDatabase::deleteAllFilters();
AyuDatabase::deleteAllExclusions();
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
close();
};
auto box = Ui::MakeConfirmBox({
.text = tr::ayu_FiltersClearPopupText(),
.confirmed = callback,
@@ -118,159 +263,18 @@ void AyuFilters::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
AyuFilters::AyuFilters(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent(controller);
: Section(parent, controller) {
setupContent();
}
void SetupFiltersSettings(not_null<Ui::VerticalLayout*> container) {
auto *settings = &AyuSettings::getInstance();
AddSkip(container);
AddSubsectionTitle(container, tr::ayu_RegexFilters());
AddButtonWithIcon(
container,
tr::ayu_RegexFiltersEnable(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->filtersEnabled())
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->filtersEnabled());
}) | on_next(
[=](bool enabled)
{
AyuSettings::getInstance().setFiltersEnabled(enabled);
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_RegexFiltersEnableSharedInChats(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->filtersEnabledInChats())
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->filtersEnabledInChats());
}) | on_next(
[=](bool enabled)
{
AyuSettings::getInstance().setFiltersEnabledInChats(enabled);
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_FiltersHideFromBlocked(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->hideFromBlocked())
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->hideFromBlocked());
}) | on_next(
[=](bool enabled)
{
AyuSettings::getInstance().setHideFromBlocked(enabled);
FiltersCacheController::rebuildCache();
FiltersCacheController::fireUpdate();
},
container->lifetime());
AddSkip(container);
}
void SetupShared(not_null<Window::SessionController*> controller,
Ui::VerticalLayout *container) {
Ui::AddSkip(container);
auto button = container->add(object_ptr<Ui::SettingsButton>(
container,
tr::ayu_RegexFiltersShared()
));
button->addClickHandler([=]
{
controller->dialogId = std::nullopt; // ensure we're handling shared filters
controller->showExclude = false;
controller->showSettings(AyuFiltersList::Id());
});
}
void SetupShadowBan(not_null<Window::SessionController*> controller,
Ui::VerticalLayout *container) {
auto button = container->add(object_ptr<Ui::SettingsButton>(
container,
tr::ayu_FiltersShadowBan()
));
button->addClickHandler([=]
{
controller->dialogId = std::nullopt;
controller->showExclude = false;
controller->shadowBan = true;
controller->showSettings(AyuFiltersList::Id());
});
}
void SetupPerDialog(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container
) {
auto ctrl = container->lifetime().make_state<PerDialogFiltersListController>(
&controller->session(),
controller
);
auto list = object_ptr<Ui::PaddingWrap<PeerListContent>>(
container,
object_ptr<PeerListContent>(
container,
ctrl),
QMargins(0, -st::peerListBox.padding.top(), 0, -st::peerListBox.padding.bottom()));
AddSkip(container);
const auto content = container->add(std::move(list));
AddSkip(container);
auto delegate = container->lifetime().make_state<PeerListContentDelegateSimple>();
delegate->setContent(content->entity());
ctrl->setDelegate(delegate);
}
void SetupMessageFilters(not_null<Ui::VerticalLayout*> container) {
AddSubsectionTitle(container, tr::ayu_RegexFilters());
AddSettingToggle(container, tr::ayu_FiltersHideFromBlocked(), &AyuSettings::hideFromBlocked, &AyuSettings::setHideFromBlocked);
}
void AyuFilters::setupContent(not_null<Window::SessionController*> controller) {
void AyuFilters::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
SetupFiltersSettings(content);
AddDivider(content);
SetupShared(controller, content);
SetupShadowBan(controller, content);
if (AyuDatabase::hasPerDialogFilters()) {
AddSkip(content);
AddDivider(content);
SetupPerDialog(controller, content);
}
ResizeFitChild(this, content);
Type AyuFiltersId() {
return AyuFilters::Id();
}
} // namespace Settings
@@ -15,8 +15,7 @@ class SessionController;
namespace Settings {
class AyuFilters : public Section<AyuFilters>
{
class AyuFilters : public Section<AyuFilters> {
public:
AyuFilters(QWidget *parent, not_null<Window::SessionController*> controller);
@@ -24,7 +23,9 @@ public:
void fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
};
} // namespace Settings
[[nodiscard]] Type AyuFiltersId();
} // namespace Settings
@@ -7,94 +7,83 @@
#include "settings_general.h"
#include "lang_auto.h"
#include "settings_ayu_utils.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "ayu/ui/settings/settings_main.h"
#include "core/application.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include "ui/vertical_list.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/single_choice_box.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_controller.h"
#include "window/window_session_controller.h"
namespace Settings {
rpl::producer<QString> AyuGeneral::title() {
return tr::ayu_CategoryGeneral();
}
using namespace Builder;
using namespace AyBuilder;
AyuGeneral::AyuGeneral(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent(controller);
}
namespace {
void BuildTranslator(SectionBuilder &builder, AyuSectionBuilder &ayu) {
builder.addSubsectionTitle(tr::lng_translate_settings_subtitle());
void SetupTranslator(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
auto *settings = &AyuSettings::getInstance();
AddSubsectionTitle(container, tr::lng_translate_settings_subtitle()/*rpl::single(QString("Translate Messages"))*/);
const auto options = std::vector{
QString("Telegram"),
QString("Google"),
QString("Yandex")
};
const auto getIndex = [=](const QString &val)
{
if (val == "telegram") {
return 0;
}
if (val == "google") {
return 1;
}
if (val == "yandex") {
return 2;
}
const auto getIndex = [=](const QString &val) {
if (val == "telegram") return 0;
if (val == "google") return 1;
if (val == "yandex") return 2;
return 0;
};
auto currentVal = AyuSettings::getInstance().translationProviderChanges() | rpl::map(getIndex) | rpl::map(
[=](int val)
{
return options[val];
});
auto currentVal = AyuSettings::getInstance().translationProviderChanges()
| rpl::map(getIndex)
| rpl::map([=](int val) { return options[val]; });
const auto button = AddButtonWithLabel(
container,
tr::ayu_TranslationProvider(),
currentVal,
st::settingsButtonNoIcon);
AddBetaBadge(button);
button->addClickHandler(
[=]
{
controller->show(Box(
[=](not_null<Ui::GenericBox*> box)
{
const auto save = [=](int index)
{
const auto provider = (index == 0) ? "telegram" : (index == 1) ? "google" : "yandex";
AyuSettings::getInstance().setTranslationProvider(provider);
};
SingleChoiceBox(box,
{
.title = tr::ayu_TranslationProvider(),
.options = options,
.initialSelection = getIndex(settings->translationProvider()),
.callback = save,
});
}));
});
const auto button = builder.addButton({
.id = u"ayu/translationProvider"_q,
.title = tr::ayu_TranslationProvider(),
.st = &st::settingsButtonNoIcon,
.label = std::move(currentVal),
.onClick = [=] {
if (const auto controller = Core::App().activeWindow()->sessionController()) {
controller->show(Box(
[=](not_null<Ui::GenericBox*> box) {
const auto save = [=](int index) {
const auto provider = (index == 0)
? "telegram"
: (index == 1) ? "google" : "yandex";
AyuSettings::getInstance().setTranslationProvider(provider);
};
SingleChoiceBox(box, {
.title = tr::ayu_TranslationProvider(),
.options = options,
.initialSelection = getIndex(settings->translationProvider()),
.callback = save,
});
}));
}
},
.keywords = { u"translate"_q, u"translation"_q, u"provider"_q },
});
if (button) {
ayu.addBetaBadge(button);
}
}
void SetupShowPeerId(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
void BuildShowPeerId(SectionBuilder &builder) {
auto *settings = &AyuSettings::getInstance();
const auto options = std::vector{
@@ -103,144 +92,229 @@ void SetupShowPeerId(not_null<Ui::VerticalLayout*> container,
QString("Bot API")
};
auto currentVal = AyuSettings::getInstance().showPeerIdChanges() | rpl::map(
[=](PeerIdDisplay val)
{
auto currentVal = AyuSettings::getInstance().showPeerIdChanges()
| rpl::map([=](PeerIdDisplay val) {
return options[static_cast<int>(val)];
});
const auto button = AddButtonWithLabel(
container,
tr::ayu_SettingsShowID(),
currentVal,
st::settingsButtonNoIcon);
button->addClickHandler(
[=]
{
const auto controller = builder.controller();
builder.addButton({
.id = u"ayu/showIdAndDc"_q,
.title = tr::ayu_SettingsShowID(),
.st = &st::settingsButtonNoIcon,
.label = std::move(currentVal),
.onClick = [=] {
controller->show(Box(
[=](not_null<Ui::GenericBox*> box)
{
const auto save = [=](int index)
{
AyuSettings::getInstance().setShowPeerId(static_cast<PeerIdDisplay>(index));
[=](not_null<Ui::GenericBox*> box) {
const auto save = [=](int index) {
AyuSettings::getInstance().setShowPeerId(
static_cast<PeerIdDisplay>(index));
};
SingleChoiceBox(box,
{
.title = tr::ayu_SettingsShowID(),
.options = options,
.initialSelection = static_cast<int>(settings->showPeerId()),
.callback = save,
});
SingleChoiceBox(box, {
.title = tr::ayu_SettingsShowID(),
.options = options,
.initialSelection = static_cast<int>(settings->showPeerId()),
.callback = save,
});
}));
});
},
.keywords = { u"peer"_q, u"id"_q },
});
}
void SetupQoLToggles(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
void BuildQoLToggles(SectionBuilder &builder, AyuSectionBuilder &ayu) {
auto *settings = &AyuSettings::getInstance();
SetupTranslator(container, controller);
AddSectionDivider(container);
BuildTranslator(builder, ayu);
ayu.addSectionDivider();
AddSubsectionTitle(container, tr::ayu_CategoryGeneral());
builder.addSubsectionTitle({
.id = u"ayu/generalSection"_q,
.title = tr::ayu_CategoryGeneral(),
});
AddSettingToggle(container, tr::ayu_DisableStories(), &AyuSettings::disableStories, &AyuSettings::setDisableStories);
ayu.addSettingToggle({
.id = u"ayu/hideStories"_q,
.title = tr::ayu_DisableStories(),
.getter = &AyuSettings::disableStories,
.setter = &AyuSettings::setDisableStories,
.keywords = { u"stories"_q },
});
std::vector checkboxes = {
NestedEntry{
tr::ayu_CollapseSimilarChannels(tr::now),
[] { return AyuSettings::getInstance().collapseSimilarChannels(); },
[](bool v) { AyuSettings::getInstance().setCollapseSimilarChannels(v); }
ayu.addCollapsibleToggle({
.id = u"ayu/similarChannels"_q,
.title = tr::ayu_DisableSimilarChannels(),
.checkboxes = {
NestedEntry{
tr::ayu_CollapseSimilarChannels(tr::now),
[] { return AyuSettings::getInstance().collapseSimilarChannels(); },
[](bool v) { AyuSettings::getInstance().setCollapseSimilarChannels(v); }
},
NestedEntry{
tr::ayu_HideSimilarChannelsTab(tr::now),
[] { return AyuSettings::getInstance().hideSimilarChannels(); },
[](bool v) { AyuSettings::getInstance().setHideSimilarChannels(v); }
}
},
NestedEntry{
tr::ayu_HideSimilarChannelsTab(tr::now),
[] { return AyuSettings::getInstance().hideSimilarChannels(); },
[](bool v) { AyuSettings::getInstance().setHideSimilarChannels(v); }
}
};
.toggledWhenAll = true,
.keywords = { u"similar"_q, u"channels"_q },
});
AddCollapsibleToggle(container, tr::ayu_DisableSimilarChannels(), checkboxes, true);
ayu.addSettingToggle({
.id = u"ayu/disableNotificationsDelay"_q,
.title = tr::ayu_DisableNotificationsDelay(),
.getter = &AyuSettings::disableNotificationsDelay,
.setter = &AyuSettings::setDisableNotificationsDelay,
.keywords = { u"notifications"_q, u"delay"_q },
});
ayu.addSectionDivider();
AddSettingToggle(container, tr::ayu_DisableNotificationsDelay(), &AyuSettings::disableNotificationsDelay, &AyuSettings::setDisableNotificationsDelay);
const auto controller = builder.controller();
const auto zalgoButton = builder.addButton({
.id = u"ayu/filterZalgo"_q,
.title = tr::ayu_FilterZalgo(),
.st = &st::settingsButtonNoIcon,
.toggled = rpl::single(settings->filterZalgo()),
.keywords = { u"zalgo"_q, u"filter"_q },
});
if (zalgoButton) {
zalgoButton->toggledValue(
) | rpl::filter(
[=](bool enabled) {
return (enabled != settings->filterZalgo());
}
) | on_next(
[=](bool enabled) {
AyuSettings::getInstance().setFilterZalgo(enabled);
controller->show(Ui::MakeConfirmBox({
.text = tr::lng_settings_need_restart(),
.confirmed = [] { Core::Restart(); },
.confirmText = tr::lng_settings_restart_now(),
.cancelText = tr::lng_settings_restart_later(),
}));
},
zalgoButton->lifetime());
ayu.addBetaBadge(zalgoButton);
}
AddSectionDivider(container);
ayu.addSettingToggle({
.id = u"ayu/improveLinkPreviews"_q,
.title = tr::ayu_ImproveLinkPreviews(),
.getter = &AyuSettings::improveLinkPreviews,
.setter = &AyuSettings::setImproveLinkPreviews,
.keywords = { u"link"_q, u"preview"_q },
});
ayu.addSettingToggle({
.id = u"ayu/formatTimeWithSeconds"_q,
.title = tr::ayu_SettingsShowMessageSeconds(),
.getter = &AyuSettings::showMessageSeconds,
.setter = &AyuSettings::setShowMessageSeconds,
.keywords = { u"seconds"_q, u"time"_q },
});
const auto button = AddButtonWithIcon(
container,
tr::ayu_FilterZalgo(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->filterZalgo())
);
button->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->filterZalgo());
}) | on_next(
[=](bool enabled)
{
AyuSettings::getInstance().setFilterZalgo(enabled);
BuildShowPeerId(builder);
// restart because hooks for filter are in Peer::setName which can be updated only on restart
// same for HistoryItem::setText
controller->show(Ui::MakeConfirmBox({
.text = tr::lng_settings_need_restart(),
.confirmed = []
{
Core::Restart();
},
.confirmText = tr::lng_settings_restart_now(),
.cancelText = tr::lng_settings_restart_later(),
}));
ayu.addSectionDivider();
builder.addSubsectionTitle({
.id = u"ayu/webviewSection"_q,
.title = rpl::single(QString("Webview")),
.keywords = { u"webview"_q },
});
ayu.addSettingToggle({
.id = u"ayu/spoofWebviewAsAndroid"_q,
.title = tr::ayu_SettingsSpoofWebviewAsAndroid(),
.getter = &AyuSettings::spoofWebviewAsAndroid,
.setter = &AyuSettings::setSpoofWebviewAsAndroid,
.keywords = { u"webview"_q, u"android"_q, u"spoof"_q },
});
ayu.addCollapsibleToggle({
.id = u"ayu/biggerWindow"_q,
.title = tr::ayu_SettingsBiggerWindow(),
.checkboxes = {
NestedEntry{
tr::ayu_SettingsIncreaseWebviewHeight(tr::now),
[] { return AyuSettings::getInstance().increaseWebviewHeight(); },
[](bool v) { AyuSettings::getInstance().setIncreaseWebviewHeight(v); }
},
NestedEntry{
tr::ayu_SettingsIncreaseWebviewWidth(tr::now),
[] { return AyuSettings::getInstance().increaseWebviewWidth(); },
[](bool v) { AyuSettings::getInstance().setIncreaseWebviewWidth(v); }
}
},
container->lifetime());
AddBetaBadge(button);
.toggledWhenAll = false,
.keywords = { u"webview"_q, u"window"_q, u"size"_q },
});
AddSettingToggle(container, tr::ayu_ImproveLinkPreviews(), &AyuSettings::improveLinkPreviews, &AyuSettings::setImproveLinkPreviews);
AddSettingToggle(container, tr::ayu_SettingsShowMessageSeconds(), &AyuSettings::showMessageSeconds, &AyuSettings::setShowMessageSeconds);
ayu.addSectionDivider();
SetupShowPeerId(container, controller);
builder.addSubsectionTitle({
.id = u"ayu/confirmationsSection"_q,
.title = tr::ayu_ConfirmationsTitle(),
.keywords = { u"confirmation"_q },
});
AddSectionDivider(container);
AddSubsectionTitle(container, rpl::single(QString("Webview")));
AddSettingToggle(container, tr::ayu_SettingsSpoofWebviewAsAndroid(), &AyuSettings::spoofWebviewAsAndroid, &AyuSettings::setSpoofWebviewAsAndroid);
std::vector webviewCheckboxes = {
NestedEntry{
tr::ayu_SettingsIncreaseWebviewHeight(tr::now),
[] { return AyuSettings::getInstance().increaseWebviewHeight(); },
[](bool v) { AyuSettings::getInstance().setIncreaseWebviewHeight(v); }
},
NestedEntry{
tr::ayu_SettingsIncreaseWebviewWidth(tr::now),
[] { return AyuSettings::getInstance().increaseWebviewWidth(); },
[](bool v) { AyuSettings::getInstance().setIncreaseWebviewWidth(v); }
}
};
AddCollapsibleToggle(container, tr::ayu_SettingsBiggerWindow(), webviewCheckboxes, false);
AddSectionDivider(container);
// todo: move into a single checkbox with dropdown
AddSubsectionTitle(container, tr::ayu_ConfirmationsTitle());
AddSettingToggle(container, tr::ayu_StickerConfirmation(), &AyuSettings::stickerConfirmation, &AyuSettings::setStickerConfirmation);
AddSettingToggle(container, tr::ayu_GIFConfirmation(), &AyuSettings::gifConfirmation, &AyuSettings::setGifConfirmation);
AddSettingToggle(container, tr::ayu_VoiceConfirmation(), &AyuSettings::voiceConfirmation, &AyuSettings::setVoiceConfirmation);
ayu.addSettingToggle({
.id = u"ayu/stickerConfirmation"_q,
.title = tr::ayu_StickerConfirmation(),
.getter = &AyuSettings::stickerConfirmation,
.setter = &AyuSettings::setStickerConfirmation,
.keywords = { u"sticker"_q, u"confirmation"_q },
});
ayu.addSettingToggle({
.id = u"ayu/gifConfirmation"_q,
.title = tr::ayu_GIFConfirmation(),
.getter = &AyuSettings::gifConfirmation,
.setter = &AyuSettings::setGifConfirmation,
.keywords = { u"gif"_q, u"confirmation"_q },
});
ayu.addSettingToggle({
.id = u"ayu/voiceConfirmation"_q,
.title = tr::ayu_VoiceConfirmation(),
.getter = &AyuSettings::voiceConfirmation,
.setter = &AyuSettings::setVoiceConfirmation,
.keywords = { u"voice"_q, u"confirmation"_q },
});
}
void AyuGeneral::setupContent(not_null<Window::SessionController*> controller) {
const auto kMeta = BuildHelper({
.id = AyuGeneral::Id(),
.parentId = AyuMain::Id(),
.title = &tr::ayu_CategoryGeneral,
.icon = &st::menuIconShowAll,
}, [](SectionBuilder &builder) {
auto ayu = AyuSectionBuilder(builder);
builder.addSkip();
BuildQoLToggles(builder, ayu);
builder.addSkip();
});
} // namespace
rpl::producer<QString> AyuGeneral::title() {
return tr::ayu_CategoryGeneral();
}
AyuGeneral::AyuGeneral(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent();
}
void AyuGeneral::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
AddSkip(content);
SetupQoLToggles(content, controller);
AddSkip(content);
ResizeFitChild(this, content);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
} // namespace Settings
Type AyuGeneralId() {
return AyuGeneral::Id();
}
} // namespace Settings
@@ -15,15 +15,16 @@ class SessionController;
namespace Settings {
class AyuGeneral : public Section<AyuGeneral>
{
class AyuGeneral : public Section<AyuGeneral> {
public:
AyuGeneral(QWidget *parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
};
[[nodiscard]] Type AyuGeneralId();
} // namespace Settings
@@ -7,27 +7,25 @@
#include "settings_main.h"
#include <QDesktopServices>
#include <styles/style_ayu_icons.h>
#include "settings/sections/settings_main.h"
#include "lang_auto.h"
#include "settings_appearance.h"
#include "settings_ayu.h"
#include "settings_ayu_utils.h"
#include "settings_chats.h"
#include "settings_filters.h"
#include "settings_general.h"
#include "settings_other.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/ayu_logo.h"
#include "core/version.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_ayu_settings.h"
#include "styles/style_layers.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h"
@@ -36,6 +34,176 @@
namespace Settings {
using namespace Builder;
namespace {
void BuildLogo(SectionBuilder &builder) {
builder.add([](const WidgetContext &ctx) -> SectionBuilder::WidgetToAdd {
auto logo = object_ptr<Ui::RpWidget>(ctx.container);
const auto logoRaw = logo.data();
logoRaw->resize(
QSize(st::settingsCloudPasswordIconSize,
st::settingsCloudPasswordIconSize));
logoRaw->setNaturalWidth(st::settingsCloudPasswordIconSize);
logoRaw->paintRequest(
) | rpl::on_next([=] {
auto p = QPainter(logoRaw);
const auto image = AyuAssets::currentAppLogoPad();
if (!image.isNull()) {
const auto size = st::settingsCloudPasswordIconSize;
const auto scaled = image.scaled(
size * style::DevicePixelRatio(),
size * style::DevicePixelRatio(),
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
p.drawImage(QRect(0, 0, size, size), scaled);
}
}, logoRaw->lifetime());
return { .widget = std::move(logo), .align = style::al_top };
});
}
void BuildVersionInfo(SectionBuilder &builder) {
builder.add([](const WidgetContext &ctx) -> SectionBuilder::WidgetToAdd {
return {
.widget = object_ptr<Ui::FlatLabel>(
ctx.container,
rpl::single(
QString("AyuGram Desktop v")
+ QString::fromLatin1(AppVersionStr)),
st::boxTitle),
.align = style::al_top,
};
});
builder.addSkip();
builder.add([](const WidgetContext &ctx) -> SectionBuilder::WidgetToAdd {
return {
.widget = object_ptr<Ui::FlatLabel>(
ctx.container,
tr::ayu_SettingsDescription(),
st::centeredBoxLabel),
.align = style::al_top,
};
});
}
void BuildCategories(SectionBuilder &builder) {
builder.addSkip();
builder.addSkip();
builder.addSkip();
builder.addSkip();
builder.addDivider();
builder.addSkip();
builder.addSubsectionTitle(tr::ayu_CategoriesHeader());
builder.addSectionButton({
.title = rpl::single(QString("AyuGram")),
.targetSection = AyuGhost::Id(),
.icon = { &st::menuIconGroupReactions },
.keywords = { u"ghost"_q, u"ayugram"_q },
});
builder.addSectionButton({
.title = tr::ayu_CategoryFilters(),
.targetSection = AyuFilters::Id(),
.icon = { &st::menuIconTagFilter },
.keywords = { u"filters"_q, u"regex"_q },
});
builder.addSectionButton({
.title = tr::ayu_CategoryGeneral(),
.targetSection = AyuGeneral::Id(),
.icon = { &st::menuIconShowAll },
.keywords = { u"general"_q },
});
builder.addSectionButton({
.title = tr::ayu_CategoryAppearance(),
.targetSection = AyuAppearance::Id(),
.icon = { &st::menuIconPalette },
.keywords = { u"appearance"_q, u"theme"_q },
});
builder.addSectionButton({
.title = tr::ayu_CategoryChats(),
.targetSection = AyuChats::Id(),
.icon = { &st::menuIconChatBubble },
.keywords = { u"chats"_q, u"messages"_q },
});
builder.addSectionButton({
.title = tr::ayu_CategoryOther(),
.targetSection = AyuOther::Id(),
.icon = { &st::menuIconFave },
.keywords = { u"other"_q, u"donate"_q },
});
}
void BuildLinks(SectionBuilder &builder) {
builder.addSkip();
builder.addDivider();
builder.addSkip();
builder.addSubsectionTitle(tr::ayu_LinksHeader());
const auto controller = builder.controller();
builder.addButton({
.title = tr::ayu_LinksChannel(),
.icon = { &st::menuIconChannel },
.label = rpl::single(QString("@ayugram")),
.onClick = [=] {
controller->showPeerByLink(Window::PeerByLinkInfo{
.usernameOrId = QString("ayugram"),
});
},
});
builder.addButton({
.title = tr::ayu_LinksChats(),
.icon = { &st::menuIconChats },
.label = rpl::single(QString("@ayugramchat")),
.onClick = [=] {
controller->showPeerByLink(Window::PeerByLinkInfo{
.usernameOrId = QString("ayugramchat"),
});
},
});
builder.addButton({
.title = tr::ayu_LinksTranslate(),
.icon = { &st::menuIconTranslate },
.label = rpl::single(QString("Crowdin")),
.onClick = [=] {
QDesktopServices::openUrl(
QString("https://translate.ayugram.one"));
},
});
builder.addButton({
.title = tr::ayu_LinksDocumentation(),
.icon = { &st::menuIconIpAddress },
.label = rpl::single(QString("docs.ayugram.one")),
.onClick = [=] {
QDesktopServices::openUrl(
QString("https://docs.ayugram.one"));
},
});
builder.addSkip();
}
const auto kMeta = BuildHelper({
.id = AyuMain::Id(),
.parentId = MainId(),
.title = &tr::ayu_AyuPreferences,
.icon = &st::menuIconPremium,
}, [](SectionBuilder &builder) {
BuildLogo(builder);
builder.addSkip();
BuildVersionInfo(builder);
BuildCategories(builder);
BuildLinks(builder);
});
} // namespace
rpl::producer<QString> AyuMain::title() {
return rpl::single(QString(""));
}
@@ -43,179 +211,18 @@ rpl::producer<QString> AyuMain::title() {
AyuMain::AyuMain(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent(controller);
: Section(parent, controller) {
setupContent();
}
void SetupAppLogo(not_null<Ui::VerticalLayout*> container) {
const auto logo = container->add(
object_ptr<Ui::RpWidget>(container),
style::al_top);
logo->resize(QSize(st::settingsCloudPasswordIconSize, st::settingsCloudPasswordIconSize));
logo->setNaturalWidth(st::settingsCloudPasswordIconSize);
logo->paintRequest(
) | rpl::on_next([=](QRect clip)
{
auto p = QPainter(logo);
const auto image = AyuAssets::currentAppLogoPad();
if (!image.isNull()) {
const auto size = st::settingsCloudPasswordIconSize;
const auto scaled = image.scaled(
size * style::DevicePixelRatio(),
size * style::DevicePixelRatio(),
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
p.drawImage(
QRect(0, 0, size, size),
scaled);
}
},
logo->lifetime());
}
void SetupCategories(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
Fn<void(Type)> showOther) {
struct CategoryInfo
{
QString name;
const style::icon *icon;
std::function<void()> handler;
};
const auto categories = std::vector<CategoryInfo>{
{QString("AyuGram"), &st::menuIconGroupReactions, [=] { showOther(AyuGhost::Id()); }},
{tr::ayu_CategoryFilters(tr::now), &st::menuIconTagFilter, [=] { showOther(AyuFilters::Id()); }},
{tr::ayu_CategoryGeneral(tr::now), &st::menuIconShowAll, [=] { showOther(AyuGeneral::Id()); }},
{tr::ayu_CategoryAppearance(tr::now), &st::menuIconPalette, [=] { showOther(AyuAppearance::Id()); }},
{tr::ayu_CategoryChats(tr::now), &st::menuIconChatBubble, [=] { showOther(AyuChats::Id()); }},
{tr::ayu_CategoryOther(tr::now), &st::menuIconFave, [=] { showOther(AyuOther::Id()); }},
};
for (const auto &category : categories) {
AddButtonWithIcon(
container,
rpl::single(category.name),
st::settingsButton,
{category.icon}
)->setClickedCallback([=]
{
if (category.handler) {
category.handler();
}
});
}
}
void SetupLinks(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
struct LinkInfo
{
QString name;
QString value;
const style::icon *icon;
std::function<void()> handler;
};
const auto links = std::vector<LinkInfo>{
{
tr::ayu_LinksChannel(tr::now),
QString("@ayugram"),
&st::menuIconChannel,
[=]
{
controller->showPeerByLink(Window::PeerByLinkInfo{
.usernameOrId = QString("ayugram"),
});
}
},
{
tr::ayu_LinksChats(tr::now),
QString("@ayugramchat"),
&st::menuIconChats,
[=]
{
controller->showPeerByLink(Window::PeerByLinkInfo{
.usernameOrId = QString("ayugramchat"),
});
}
},
{
tr::ayu_LinksTranslate(tr::now),
QString("Crowdin"),
&st::menuIconTranslate,
[=]
{
QDesktopServices::openUrl(QString("https://translate.ayugram.one"));
}
},
{
tr::ayu_LinksDocumentation(tr::now),
QString("docs.ayugram.one"),
&st::menuIconIpAddress,
[=]
{
QDesktopServices::openUrl(QString("https://docs.ayugram.one"));
}
},
};
for (const auto &link : links) {
AddButtonWithLabel(
container,
rpl::single(link.name),
rpl::single(link.value),
st::settingsButton,
{link.icon}
)->setClickedCallback(link.handler);
}
}
void AyuMain::setupContent(not_null<Window::SessionController*> controller) {
void AyuMain::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
SetupAppLogo(content);
AddSkip(content);
content->add(
object_ptr<Ui::FlatLabel>(
content,
rpl::single(QString("AyuGram Desktop v") + QString::fromLatin1(AppVersionStr)),
st::boxTitle),
style::al_top);
AddSkip(content);
content->add(
object_ptr<Ui::FlatLabel>(
content,
tr::ayu_SettingsDescription(),
st::centeredBoxLabel),
style::al_top);
AddSkip(content);
AddSkip(content);
AddSkip(content);
AddSkip(content);
AddDivider(content);
AddSkip(content);
AddSubsectionTitle(content, tr::ayu_CategoriesHeader());
SetupCategories(content, controller, showOtherMethod());
AddSectionDivider(content);
AddSubsectionTitle(content, tr::ayu_LinksHeader());
SetupLinks(content, controller);
AddSkip(content);
ResizeFitChild(this, content);
Type AyuMainId() {
return AyuMain::Id();
}
} // namespace Settings
@@ -9,24 +9,23 @@
#include "settings/settings_common.h"
#include "settings/settings_common_session.h"
class BoxContent;
namespace Window {
class Controller;
class SessionController;
}
} // namespace Window
namespace Settings {
class AyuMain : public Section<AyuMain>
{
class AyuMain : public Section<AyuMain> {
public:
AyuMain(QWidget *parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
};
}
[[nodiscard]] Type AyuMainId();
} // namespace Settings
@@ -13,11 +13,14 @@
#include "lang_auto.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/boxes/donate_qr_box.h"
#include "ayu/ui/settings/ayu_builder.h"
#include "ayu/ui/settings/settings_ayu_utils.h"
#include "ayu/ui/settings/settings_main.h"
#include "boxes/abstract_box.h"
#include "core/application.h"
#include "lang/lang_text_entity.h"
#include "main/main_session.h"
#include "settings/settings_builder.h"
#include "settings/settings_common.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
@@ -33,10 +36,13 @@
#include "window/themes/window_theme.h"
namespace Settings {
using namespace Builder;
using namespace AyBuilder;
namespace {
struct Asset
{
struct Asset {
QString icon;
QColor background;
};
@@ -78,7 +84,9 @@ QImage getImage(const QString &name) {
return image;
}
[[nodiscard]] not_null<Ui::SettingsButton*> AddDonate(not_null<Ui::SettingsButton*> button, const QString &name) {
[[nodiscard]] not_null<Ui::SettingsButton*> AddDonate(
not_null<Ui::SettingsButton*> button,
const QString &name) {
const auto btnContainer = Ui::CreateChild<Ui::RpWidget>(button);
const auto &buttonSt = button->st();
const auto fullHeight = buttonSt.height
@@ -89,40 +97,38 @@ QImage getImage(const QString &name) {
auto icon = getImage(name);
iconWidget->resize(icon.size() / style::DevicePixelRatio());
iconWidget->paintRequest(
) | rpl::on_next([=]
{
auto p = QPainter(iconWidget);
p.drawImage(0, 0, icon);
},
iconWidget->lifetime());
) | rpl::on_next([=] {
auto p = QPainter(iconWidget);
p.drawImage(0, 0, icon);
}, iconWidget->lifetime());
button->sizeValue(
) | rpl::on_next([=](const QSize &s)
{
iconWidget->moveToLeft(
button->st().iconLeft
+ (st::menuIconShop.width() - iconWidget->width()) / 2,
(s.height() - iconWidget->height()) / 2);
btnContainer->moveToLeft(
iconWidget->x() - (fullHeight - iconWidget->height()) / 2,
0);
},
iconWidget->lifetime());
) | rpl::on_next([=](const QSize &s) {
iconWidget->moveToLeft(
button->st().iconLeft
+ (st::menuIconShop.width() - iconWidget->width()) / 2,
(s.height() - iconWidget->height()) / 2);
btnContainer->moveToLeft(
iconWidget->x() - (fullHeight - iconWidget->height()) / 2,
0);
}, iconWidget->lifetime());
btnContainer->resize(fullHeight, fullHeight);
return button;
}
void AddCryptoDonate(const QString &name, const QString &address, not_null<Ui::VerticalLayout*> container) {
void AddCryptoDonate(
const QString &name,
const QString &address,
not_null<Ui::VerticalLayout*> container) {
const auto button = AddDonate(
AddButtonWithIcon(
container,
rpl::single(name),
st::settingsButton),
name);
button->setClickedCallback([=]
{
button->setClickedCallback([=] {
auto box = Box(
Ui::FillDonateQrBox,
address,
@@ -131,8 +137,117 @@ void AddCryptoDonate(const QString &name, const QString &address, not_null<Ui::V
});
}
void BuildDonations(SectionBuilder &builder) {
builder.add([](const BuildContext &ctx) {
v::match(ctx, [&](const WidgetContext &wctx) {
const auto container = wctx.container;
AddSubsectionTitle(container, tr::ayu_SupportHeader());
AddDonate(
AddButtonWithIcon(
container,
rpl::single(QString("Boosty")),
st::settingsButton),
"boosty"
)->setClickedCallback([=] {
QDesktopServices::openUrl(QString("https://boosty.to/alexeyzavar"));
});
AddCryptoDonate("TON", QString("UQA4i8U8vP3mYUZSV3KqDQEHPwmhninEqCkkKc7BITQ652de"), container);
AddCryptoDonate("Bitcoin", QString("bc1qdk6qq4mzq5yap3fpy0qau3246w3m3uwac9f0xd"), container);
AddCryptoDonate("Ethereum", QString("0x405589857C8DFAb45B2027c68ad1e58877FDa347"), container);
AddCryptoDonate("Solana", QString("8ZHQpPxpsdRjsWoBcF1dmvRM5dB6zEhJ3jMBFZjYfyHs"), container);
AddCryptoDonate("Tron", QString("TRpbajq38qU8joThgAfKJLyEPbNjzsdPJ1"), container);
AddSkip(container);
AddDividerText(container,
tr::ayu_SupportDescription2(
lt_item,
rpl::single(
Ui::Text::Link(tr::ayu_SupportDescription1(tr::now), QString("tg://support"))
),
tr::marked));
}, [&](const SearchContext &sctx) {
sctx.entries->push_back({
.id = u"ayu/donate"_q,
.title = tr::ayu_SupportHeader(tr::now),
.keywords = { u"donate"_q, u"support"_q, u"boosty"_q, u"crypto"_q },
.section = sctx.sectionId,
});
});
});
}
void BuildCrashReporting(SectionBuilder &builder, AyuSectionBuilder &ayu) {
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
builder.addSkip();
builder.addSubsectionTitle({
.id = u"ayu/otherSection"_q,
.title = tr::ayu_CategoryOther(),
});
ayu.addSettingToggle({
.id = u"ayu/crashlytics"_q,
.title = tr::ayu_CrashReporting(),
.getter = &AyuSettings::crashReporting,
.setter = &AyuSettings::setCrashReporting,
.icon = { &st::menuIconReport },
.keywords = { u"crash"_q, u"report"_q },
});
builder.addSkip();
builder.addDividerText(tr::ayu_CrashReportingDescription());
#endif
}
void BuildOtherThings(SectionBuilder &builder) {
const auto controller = builder.controller();
builder.addSkip();
builder.addButton({
.id = u"ayu/registerUrlScheme"_q,
.title = tr::ayu_RegisterURLScheme(),
.icon = { &st::menuIconLink },
.onClick = [=] {
Core::Application::RegisterUrlScheme();
controller->showToast(tr::lng_box_done(tr::now));
},
.keywords = { u"url"_q, u"scheme"_q, u"register"_q },
});
builder.addButton({
.id = u"ayu/resetSettings"_q,
.title = tr::ayu_ResetSettings(),
.icon = { &st::menuIconRestore },
.onClick = [=] {
controller->show(Ui::MakeConfirmBox({
.text = tr::ayu_ResetSettingsConfirmation(tr::rich),
.confirmed = [=](Fn<void()> &&close) {
AyuSettings::reset();
controller->showToast(tr::lng_box_done(tr::now));
close();
},
.confirmText = tr::lng_box_yes(),
}));
},
.keywords = { u"reset"_q, u"settings"_q },
});
builder.addSkip();
}
const auto kMeta = BuildHelper({
.id = AyuOther::Id(),
.parentId = AyuMain::Id(),
.title = &tr::ayu_CategoryOther,
.icon = &st::menuIconFave,
}, [](SectionBuilder &builder) {
auto ayu = AyuSectionBuilder(builder);
builder.addSkip();
BuildDonations(builder);
BuildCrashReporting(builder, ayu);
BuildOtherThings(builder);
});
} // namespace
rpl::producer<QString> AyuOther::title() {
return tr::ayu_CategoryOther();
}
@@ -140,93 +255,18 @@ rpl::producer<QString> AyuOther::title() {
AyuOther::AyuOther(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent, controller) {
setupContent(controller);
: Section(parent, controller) {
setupContent();
}
void SetupDonations(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
AddSubsectionTitle(container, tr::ayu_SupportHeader());
AddDonate(
AddButtonWithIcon(
container,
rpl::single(QString("Boosty")),
st::settingsButton),
"boosty"
)->setClickedCallback([=]
{
QDesktopServices::openUrl(QString("https://boosty.to/alexeyzavar"));
});
AddCryptoDonate("TON", QString("UQA4i8U8vP3mYUZSV3KqDQEHPwmhninEqCkkKc7BITQ652de"), container);
AddCryptoDonate("Bitcoin", QString("bc1qdk6qq4mzq5yap3fpy0qau3246w3m3uwac9f0xd"), container);
AddCryptoDonate("Ethereum", QString("0x405589857C8DFAb45B2027c68ad1e58877FDa347"), container);
AddCryptoDonate("Solana", QString("8ZHQpPxpsdRjsWoBcF1dmvRM5dB6zEhJ3jMBFZjYfyHs"), container);
AddCryptoDonate("Tron", QString("TRpbajq38qU8joThgAfKJLyEPbNjzsdPJ1"), container);
AddSkip(container);
AddDividerText(container,
tr::ayu_SupportDescription2(
lt_item,
rpl::single(
Ui::Text::Link(tr::ayu_SupportDescription1(tr::now), QString("tg://support"))
),
tr::marked
)
);
}
void SetupCrashReporting(not_null<Ui::VerticalLayout*> container) {
AddSkip(container);
AddSubsectionTitle(container, tr::ayu_CategoryOther());
AddSettingToggle(container, tr::ayu_CrashReporting(), &AyuSettings::crashReporting, &AyuSettings::setCrashReporting, st::menuIconReport);
AddSkip(container);
AddDividerText(container, tr::ayu_CrashReportingDescription());
}
void SetupOtherThings(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_RegisterURLScheme(),
st::settingsButton,
{&st::menuIconLink}
)->setClickedCallback([=]
{
Core::Application::RegisterUrlScheme();
controller->showToast(tr::lng_box_done(tr::now));
});
AddButtonWithIcon(
container,
tr::ayu_ResetSettings(),
st::settingsButton,
{&st::menuIconRestore}
)->setClickedCallback([=]
{
controller->show(Ui::MakeConfirmBox({
.text = tr::ayu_ResetSettingsConfirmation(tr::rich),
.confirmed = [=](Fn<void()> &&close)
{
AyuSettings::reset();
controller->showToast(tr::lng_box_done(tr::now));
close();
},
.confirmText = tr::lng_box_yes(),
}));
});
AddSkip(container);
}
void AyuOther::setupContent(not_null<Window::SessionController*> controller) {
void AyuOther::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
AddSkip(content);
SetupDonations(content, controller);
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
SetupCrashReporting(content);
#endif
SetupOtherThings(content, controller);
ResizeFitChild(this, content);
build(content, kMeta.build);
Ui::ResizeFitChild(this, content);
}
} // namespace Settings
Type AyuOtherId() {
return AyuOther::Id();
}
} // namespace Settings
@@ -15,15 +15,16 @@ class SessionController;
namespace Settings {
class AyuOther : public Section<AyuOther>
{
class AyuOther : public Section<AyuOther> {
public:
AyuOther(QWidget *parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContent();
};
} // namespace Settings
[[nodiscard]] Type AyuOtherId();
} // namespace Settings
@@ -1733,6 +1733,14 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
u"^chat\\?(.+)(#|$)"_q,
AyuUrlHandlers::ResolveChat
},
{
u"^ayusettings/?\\?(.+)(#|$)"_q,
AyuUrlHandlers::HandleAyuSettings
},
{
u"^ayusettings/?$"_q,
AyuUrlHandlers::HandleAyuSettings
},
{
u"^ayu(/?.+)?(#|$)"_q,
AyuUrlHandlers::HandleAyu
@@ -1929,6 +1937,9 @@ QString TryConvertUrlToLocal(QString url) {
added = u"&post="_q + postMatch->captured(1);
}
return base + added + (params.isEmpty() ? QString() : '&' + params);
} else if (const auto ayuSettingsMatch = regex_match(
u"^(?:ayuSettings|exteraSettings)/?\\?(.+)$"_q, query, matchOptions)) {
return u"tg://ayusettings?"_q + ayuSettingsMatch->captured(1);
} else if (const auto usernameMatch = regex_match(u"^"
"([a-zA-Z0-9\\.\\_]+)"
"("
@@ -21,7 +21,7 @@ bool HasMenu(Type type) {
return (type == ::Settings::CloudPasswordEmailConfirmId())
|| (type == MainId())
|| (type == ChatId())
|| (type == AyuFilters::Id());
|| (type == AyuFiltersId());
}
} // namespace Settings