mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Search results look nicer now.
This commit is contained in:
@@ -168,7 +168,7 @@ void BuildDataStorageSection(
|
||||
.keywords = { u"downloads"_q, u"files"_q },
|
||||
});
|
||||
|
||||
const auto askDownloadPath = builder.addToggle({
|
||||
const auto askDownloadPath = builder.addButton({
|
||||
.id = u"advanced/ask_download"_q,
|
||||
.title = tr::lng_download_path_ask(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -375,19 +375,19 @@ void BuildSystemIntegrationSection(
|
||||
: nullptr;
|
||||
|
||||
const auto monochrome = Platform::HasMonochromeSetting()
|
||||
? builder.addSlideCheckbox({
|
||||
? builder.addCheckbox({
|
||||
.id = u"advanced/monochrome_icon"_q,
|
||||
.title = tr::lng_settings_monochrome_icon(),
|
||||
.checked = settings->trayIconMonochrome(),
|
||||
.keywords = { u"monochrome"_q, u"icon"_q, u"tray"_q },
|
||||
.shown = tray
|
||||
? tray->checkedValue()
|
||||
: rpl::single(trayEnabled()),
|
||||
.keywords = { u"monochrome"_q, u"icon"_q, u"tray"_q },
|
||||
})
|
||||
: nullptr;
|
||||
|
||||
if (monochrome && monochrome->entity()) {
|
||||
monochrome->entity()->checkedChanges(
|
||||
if (monochrome) {
|
||||
monochrome->checkedChanges(
|
||||
) | rpl::filter([=](bool value) {
|
||||
return (value != settings->trayIconMonochrome());
|
||||
}) | rpl::on_next([=](bool value) {
|
||||
@@ -501,17 +501,17 @@ void BuildSystemIntegrationSection(
|
||||
}, container->lifetime());
|
||||
}
|
||||
|
||||
const auto closeToTaskbar = builder.addSlideCheckbox({
|
||||
const auto closeToTaskbar = builder.addCheckbox({
|
||||
.id = u"advanced/close_to_taskbar"_q,
|
||||
.title = tr::lng_settings_close_to_taskbar(),
|
||||
.checked = settings->closeBehavior() == Behavior::CloseToTaskbar,
|
||||
.keywords = { u"close"_q, u"taskbar"_q, u"minimize"_q },
|
||||
.shown = closeToTaskbarShown
|
||||
? closeToTaskbarShown->value()
|
||||
: rpl::single(false),
|
||||
.keywords = { u"close"_q, u"taskbar"_q, u"minimize"_q },
|
||||
});
|
||||
if (closeToTaskbar && closeToTaskbar->entity()) {
|
||||
closeToTaskbar->entity()->checkedChanges(
|
||||
if (closeToTaskbar) {
|
||||
closeToTaskbar->checkedChanges(
|
||||
) | rpl::map([=](bool checked) {
|
||||
return checked ? Behavior::CloseToTaskbar : Behavior::Quit;
|
||||
}) | rpl::filter([=](Behavior value) {
|
||||
@@ -537,14 +537,14 @@ void BuildSystemIntegrationSection(
|
||||
.keywords = { u"autostart"_q, u"startup"_q, u"boot"_q },
|
||||
});
|
||||
|
||||
const auto minimized = builder.addSlideCheckbox({
|
||||
const auto minimized = builder.addCheckbox({
|
||||
.id = u"advanced/start_minimized"_q,
|
||||
.title = tr::lng_settings_start_min(),
|
||||
.checked = minimizedToggled(),
|
||||
.keywords = { u"minimized"_q, u"startup"_q, u"hidden"_q },
|
||||
.shown = autostart
|
||||
? autostart->checkedValue()
|
||||
: rpl::single(cAutoStart()),
|
||||
.keywords = { u"minimized"_q, u"startup"_q, u"hidden"_q },
|
||||
});
|
||||
|
||||
if (autostart) {
|
||||
@@ -563,10 +563,10 @@ void BuildSystemIntegrationSection(
|
||||
Ui::PostponeCall(autostart, [=] {
|
||||
autostart->setChecked(enabled);
|
||||
});
|
||||
if (enabled || !minimized || !minimized->entity()->checked()) {
|
||||
if (enabled || !minimized || !minimized->checked()) {
|
||||
Local::writeSettings();
|
||||
} else if (minimized) {
|
||||
minimized->entity()->setChecked(false);
|
||||
minimized->setChecked(false);
|
||||
}
|
||||
}));
|
||||
}, autostart->lifetime());
|
||||
@@ -578,13 +578,13 @@ void BuildSystemIntegrationSection(
|
||||
}
|
||||
}
|
||||
|
||||
if (minimized && minimized->entity() && controller) {
|
||||
minimized->entity()->checkedChanges(
|
||||
if (minimized && controller) {
|
||||
minimized->checkedChanges(
|
||||
) | rpl::filter([=](bool checked) {
|
||||
return (checked != minimizedToggled());
|
||||
}) | rpl::on_next([=](bool checked) {
|
||||
if (controller->session().domain().local().hasLocalPasscode()) {
|
||||
minimized->entity()->setChecked(false);
|
||||
minimized->setChecked(false);
|
||||
controller->show(Ui::MakeInformBox(
|
||||
tr::lng_error_start_minimized_passcoded()));
|
||||
} else {
|
||||
@@ -595,7 +595,7 @@ void BuildSystemIntegrationSection(
|
||||
|
||||
controller->session().domain().local().localPasscodeChanged(
|
||||
) | rpl::on_next([=] {
|
||||
minimized->entity()->setChecked(minimizedToggled());
|
||||
minimized->setChecked(minimizedToggled());
|
||||
}, minimized->lifetime());
|
||||
}
|
||||
}
|
||||
@@ -703,7 +703,7 @@ void BuildANGLEOption(
|
||||
void BuildOpenGLOption(
|
||||
SectionBuilder &builder,
|
||||
Window::SessionController *controller) {
|
||||
const auto opengl = builder.addToggle({
|
||||
const auto opengl = builder.addButton({
|
||||
.id = u"advanced/opengl"_q,
|
||||
.title = tr::lng_settings_enable_opengl(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -750,7 +750,7 @@ void BuildPerformanceSection(
|
||||
.keywords = { u"power"_q, u"saving"_q, u"battery"_q, u"animation"_q },
|
||||
});
|
||||
|
||||
const auto hwAccel = builder.addToggle({
|
||||
const auto hwAccel = builder.addButton({
|
||||
.id = u"advanced/hw_accel"_q,
|
||||
.title = tr::lng_settings_enable_hwaccel(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -794,7 +794,7 @@ void BuildSpellcheckerSection(
|
||||
builder.addSkip();
|
||||
builder.addSubsectionTitle(tr::lng_settings_spellchecker());
|
||||
|
||||
const auto spellchecker = builder.addToggle({
|
||||
const auto spellchecker = builder.addButton({
|
||||
.id = u"advanced/spellchecker"_q,
|
||||
.title = isSystem
|
||||
? tr::lng_settings_system_spellchecker()
|
||||
@@ -823,7 +823,7 @@ void BuildSpellcheckerSection(
|
||||
const auto inner = sliding ? sliding->entity() : nullptr;
|
||||
|
||||
if (!isSystem) {
|
||||
const auto autoDownload = builder.addToggle({
|
||||
const auto autoDownload = builder.addButton({
|
||||
.id = u"advanced/auto_download_dictionaries"_q,
|
||||
.title = tr::lng_settings_auto_download_dictionaries(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -898,7 +898,7 @@ void BuildUpdateSection(
|
||||
? Ui::CreateChild<rpl::event_stream<bool>>(container)
|
||||
: nullptr;
|
||||
|
||||
const auto toggle = builder.addToggle({
|
||||
const auto toggle = builder.addButton({
|
||||
.id = u"advanced/auto_update"_q,
|
||||
.title = tr::lng_settings_update_automatically(),
|
||||
.st = &st::settingsUpdateToggle,
|
||||
@@ -933,7 +933,7 @@ void BuildUpdateSection(
|
||||
|
||||
const auto install = cAlphaVersion()
|
||||
? nullptr
|
||||
: builder.addToggle({
|
||||
: builder.addButton({
|
||||
.id = u"advanced/install_beta"_q,
|
||||
.title = tr::lng_settings_install_beta(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -1112,25 +1112,29 @@ void BuildExportSection(
|
||||
});
|
||||
}
|
||||
|
||||
const auto kMeta = BuildHelper(Advanced::Id(), [](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
const auto showOther = builder.showOther();
|
||||
const auto autoUpdate = cAutoUpdate();
|
||||
const auto kMeta = BuildHelper(
|
||||
Advanced::Id(),
|
||||
tr::lng_settings_advanced,
|
||||
[](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
const auto showOther = builder.showOther();
|
||||
const auto autoUpdate = cAutoUpdate();
|
||||
|
||||
if (!autoUpdate) {
|
||||
BuildUpdateSection(builder, controller, true);
|
||||
}
|
||||
BuildDataStorageSection(builder, controller);
|
||||
BuildAutoDownloadSection(builder, controller);
|
||||
BuildWindowTitleSection(builder, controller);
|
||||
BuildSystemIntegrationSection(builder, controller);
|
||||
BuildPerformanceSection(builder, controller);
|
||||
BuildSpellcheckerSection(builder, controller);
|
||||
if (autoUpdate) {
|
||||
BuildUpdateSection(builder, controller, false);
|
||||
}
|
||||
BuildExportSection(builder, controller, showOther);
|
||||
}, Main::Id());
|
||||
if (!autoUpdate) {
|
||||
BuildUpdateSection(builder, controller, true);
|
||||
}
|
||||
BuildDataStorageSection(builder, controller);
|
||||
BuildAutoDownloadSection(builder, controller);
|
||||
BuildWindowTitleSection(builder, controller);
|
||||
BuildSystemIntegrationSection(builder, controller);
|
||||
BuildPerformanceSection(builder, controller);
|
||||
BuildSpellcheckerSection(builder, controller);
|
||||
if (autoUpdate) {
|
||||
BuildUpdateSection(builder, controller, false);
|
||||
}
|
||||
BuildExportSection(builder, controller, showOther);
|
||||
},
|
||||
Main::Id());
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "settings/builder/settings_builder.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "boxes/edit_privacy_box.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
@@ -37,6 +40,7 @@ namespace {
|
||||
|
||||
BuildHelper::BuildHelper(
|
||||
Type sectionId,
|
||||
tr::phrase<> sectionTitle,
|
||||
FnMut<void(SectionBuilder&)> method,
|
||||
Type parentSectionId)
|
||||
: build([=](
|
||||
@@ -50,7 +54,10 @@ BuildHelper::BuildHelper(
|
||||
controller,
|
||||
Window::GifPauseReason::Layer);
|
||||
auto builder = SectionBuilder(WidgetContext{
|
||||
.container = container,
|
||||
.container = static_cast<Ui::VerticalLayout*>(
|
||||
container->add(object_ptr<Ui::OverrideMargins>(
|
||||
container,
|
||||
object_ptr<Ui::VerticalLayout>(container)))->entity()),
|
||||
.controller = controller,
|
||||
.showOther = std::move(showOther),
|
||||
.isPaused = isPaused,
|
||||
@@ -74,8 +81,10 @@ BuildHelper::BuildHelper(
|
||||
, _method(std::move(method)) {
|
||||
Expects(_method != nullptr);
|
||||
|
||||
SearchRegistry::Instance().add(
|
||||
auto ®istry = SearchRegistry::Instance();
|
||||
registry.add(
|
||||
sectionId,
|
||||
sectionTitle,
|
||||
parentSectionId,
|
||||
[=](not_null<::Main::Session*> session) { return index(session); });
|
||||
}
|
||||
@@ -87,10 +96,12 @@ SearchRegistry &SearchRegistry::Instance() {
|
||||
|
||||
void SearchRegistry::add(
|
||||
Type sectionId,
|
||||
tr::phrase<> title,
|
||||
Type parentSectionId,
|
||||
SearchEntriesIndexer indexer) {
|
||||
_indexers.push_back({ sectionId, std::move(indexer) });
|
||||
_sectionTitles[sectionId] = title;
|
||||
_parentSections[sectionId] = parentSectionId;
|
||||
_indexers.push_back({ sectionId, std::move(indexer) });
|
||||
}
|
||||
|
||||
std::vector<SearchEntry> SearchRegistry::collectAll(
|
||||
@@ -103,6 +114,24 @@ std::vector<SearchEntry> SearchRegistry::collectAll(
|
||||
return result;
|
||||
}
|
||||
|
||||
QString SearchRegistry::sectionTitle(Type sectionId) const {
|
||||
const auto it = _sectionTitles.find(sectionId);
|
||||
return (it != _sectionTitles.end()) ? it->second(tr::now) : QString();
|
||||
}
|
||||
|
||||
QString SearchRegistry::sectionPath(Type sectionId) const {
|
||||
auto parts = QStringList();
|
||||
auto current = sectionId;
|
||||
while (current) {
|
||||
if (const auto title = sectionTitle(current); !title.isEmpty()) {
|
||||
parts.prepend(title);
|
||||
}
|
||||
const auto it = _parentSections.find(current);
|
||||
current = (it != _parentSections.end()) ? it->second : nullptr;
|
||||
}
|
||||
return parts.join(u" > "_q);
|
||||
}
|
||||
|
||||
std::vector<SearchEntry> BuildHelper::index(
|
||||
not_null<Main::Session*> session) const {
|
||||
auto entries = std::vector<SearchEntry>();
|
||||
@@ -208,17 +237,20 @@ Ui::RpWidget *SectionBuilder::addControl(ControlArgs &&args) {
|
||||
.align = args.align,
|
||||
.highlight = std::move(args.highlight),
|
||||
};
|
||||
}, [&] {
|
||||
}, [&]() mutable {
|
||||
return SearchEntry{
|
||||
.id = std::move(args.id),
|
||||
.title = ResolveTitle(std::move(args.title)),
|
||||
.keywords = std::move(args.keywords),
|
||||
.icon = std::move(args.searchIcon),
|
||||
.checkIcon = args.searchCheckIcon,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Ui::SettingsButton *SectionBuilder::addButton(ButtonArgs &&args) {
|
||||
const auto &st = args.st ? *args.st : st::settingsButton;
|
||||
auto iconForSearch = IconDescriptor{ args.icon.icon };
|
||||
const auto factory = [&](not_null<Ui::VerticalLayout*> container) {
|
||||
auto button = CreateButtonWithIcon(
|
||||
args.container ? args.container : container.get(),
|
||||
@@ -235,15 +267,20 @@ Ui::SettingsButton *SectionBuilder::addButton(ButtonArgs &&args) {
|
||||
st,
|
||||
rpl::duplicate(args.title));
|
||||
}
|
||||
if (args.toggled) {
|
||||
button->toggleOn(std::move(args.toggled));
|
||||
}
|
||||
return std::move(button);
|
||||
};
|
||||
return static_cast<Ui::SettingsButton*>(addControl({
|
||||
.factory = factory,
|
||||
.id = std::move(args.id),
|
||||
.title = rpl::duplicate(args.title),
|
||||
.keywords = std::move(args.keywords),
|
||||
.highlight = std::move(args.highlight),
|
||||
.shown = std::move(args.shown),
|
||||
|
||||
.keywords = std::move(args.keywords),
|
||||
.searchIcon = std::move(iconForSearch),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -297,7 +334,7 @@ Ui::SettingsButton *SectionBuilder::addPremiumButton(PremiumButtonArgs &&args) {
|
||||
.keywords = std::move(args.keywords),
|
||||
});
|
||||
if (result) {
|
||||
[[maybe_unused]] const auto decorated = AddPremiumStar(
|
||||
AddPremiumStar(
|
||||
result,
|
||||
args.credits,
|
||||
v::get<WidgetContext>(_context).isPaused);
|
||||
@@ -306,120 +343,65 @@ Ui::SettingsButton *SectionBuilder::addPremiumButton(PremiumButtonArgs &&args) {
|
||||
}
|
||||
|
||||
Ui::SettingsButton *SectionBuilder::addPrivacyButton(PrivacyButtonArgs &&args) {
|
||||
const auto id = args.id;
|
||||
const auto premium = args.premium;
|
||||
auto title = std::move(args.title);
|
||||
return v::match(_context, [&](const WidgetContext &ctx)
|
||||
-> Ui::SettingsButton* {
|
||||
const auto button = AddPrivacyButton(
|
||||
ctx.controller,
|
||||
ctx.container,
|
||||
rpl::duplicate(title),
|
||||
{},
|
||||
args.key,
|
||||
std::move(args.controllerFactory));
|
||||
const auto controller = this->controller();
|
||||
const auto session = this->session();
|
||||
|
||||
const auto button = addButton({
|
||||
.id = args.id,
|
||||
.title = rpl::duplicate(args.title),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
.label = PrivacyButtonLabel(session, args.key),
|
||||
.keywords = args.keywords,
|
||||
});
|
||||
if (button) {
|
||||
const auto id = args.id;
|
||||
const auto premium = args.premium;
|
||||
const auto shower = Ui::CreateChild<rpl::lifetime>(button);
|
||||
const auto factory = args.controllerFactory;
|
||||
button->addClickHandler([=, key = args.key] {
|
||||
*shower = session->api().userPrivacy().value(
|
||||
key
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::on_next(crl::guard(controller, [=](
|
||||
const Api::UserPrivacy::Rule &value) {
|
||||
controller->show(Box<EditPrivacyBox>(
|
||||
controller,
|
||||
factory(),
|
||||
value));
|
||||
}));
|
||||
});
|
||||
if (premium) {
|
||||
AddPrivacyPremiumStar(
|
||||
button,
|
||||
&ctx.controller->session(),
|
||||
rpl::duplicate(title),
|
||||
session,
|
||||
std::move(args.title),
|
||||
st::settingsButtonNoIcon.padding);
|
||||
}
|
||||
if (!id.isEmpty()) {
|
||||
registerHighlight(id, button, {});
|
||||
}
|
||||
return button;
|
||||
}, [&](const SearchContext &ctx) -> Ui::SettingsButton* {
|
||||
if (!args.id.isEmpty()) {
|
||||
ctx.entries->push_back({
|
||||
.id = std::move(args.id),
|
||||
.title = ResolveTitle(std::move(title)),
|
||||
.keywords = std::move(args.keywords),
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
Ui::SettingsButton *SectionBuilder::addToggle(ToggleArgs &&args) {
|
||||
auto highlight = std::move(args.highlight);
|
||||
const auto id = args.id;
|
||||
const auto button = v::match(_context, [&](const WidgetContext &ctx)
|
||||
-> Ui::SettingsButton* {
|
||||
const auto &st = args.st ? *args.st : st::settingsButton;
|
||||
const auto target = args.container ? args.container : ctx.container.get();
|
||||
const auto button = target->add(CreateButtonWithIcon(
|
||||
target,
|
||||
rpl::duplicate(args.title),
|
||||
st,
|
||||
std::move(args.icon)));
|
||||
button->toggleOn(std::move(args.toggled));
|
||||
return button;
|
||||
}, [&](const SearchContext &ctx) -> Ui::SettingsButton* {
|
||||
if (!args.id.isEmpty()) {
|
||||
ctx.entries->push_back({
|
||||
.id = std::move(args.id),
|
||||
.title = ResolveTitle(std::move(args.title)),
|
||||
.keywords = std::move(args.keywords),
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
if (button && !id.isEmpty()) {
|
||||
registerHighlight(id, button, std::move(highlight));
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
Ui::Checkbox *SectionBuilder::addCheckbox(CheckboxArgs &&args) {
|
||||
return v::match(_context, [&](const WidgetContext &ctx) -> Ui::Checkbox* {
|
||||
const auto checkbox = ctx.container->add(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
ctx.container,
|
||||
ResolveTitle(rpl::duplicate(args.title)),
|
||||
args.checked,
|
||||
st::settingsCheckbox),
|
||||
st::settingsCheckboxPadding);
|
||||
return checkbox;
|
||||
}, [&](const SearchContext &ctx) -> Ui::Checkbox* {
|
||||
if (!args.id.isEmpty()) {
|
||||
ctx.entries->push_back({
|
||||
.id = std::move(args.id),
|
||||
.title = ResolveTitle(std::move(args.title)),
|
||||
.keywords = std::move(args.keywords),
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
Ui::SlideWrap<Ui::Checkbox> *SectionBuilder::addSlideCheckbox(
|
||||
SlideCheckboxArgs &&args) {
|
||||
return v::match(_context, [&](const WidgetContext &ctx)
|
||||
-> Ui::SlideWrap<Ui::Checkbox>* {
|
||||
const auto wrap = ctx.container->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::Checkbox>>(
|
||||
ctx.container,
|
||||
object_ptr<Ui::Checkbox>(
|
||||
ctx.container,
|
||||
ResolveTitle(rpl::duplicate(args.title)),
|
||||
args.checked,
|
||||
st::settingsCheckbox),
|
||||
st::settingsCheckboxPadding));
|
||||
if (args.shown) {
|
||||
wrap->toggleOn(std::move(args.shown));
|
||||
}
|
||||
return wrap;
|
||||
}, [&](const SearchContext &ctx) -> Ui::SlideWrap<Ui::Checkbox>* {
|
||||
if (!args.id.isEmpty()) {
|
||||
ctx.entries->push_back({
|
||||
.id = std::move(args.id),
|
||||
.title = ResolveTitle(std::move(args.title)),
|
||||
.keywords = std::move(args.keywords),
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
const auto factory = [&](not_null<Ui::VerticalLayout*> container) {
|
||||
return object_ptr<Ui::Checkbox>(
|
||||
container,
|
||||
ResolveTitle(rpl::duplicate(args.title)),
|
||||
args.checked,
|
||||
st::settingsCheckbox);
|
||||
};
|
||||
return static_cast<Ui::Checkbox*>(addControl({
|
||||
.factory = factory,
|
||||
.id = std::move(args.id),
|
||||
.title = rpl::duplicate(args.title),
|
||||
.margin = st::settingsCheckboxPadding,
|
||||
.highlight = std::move(args.highlight),
|
||||
.shown = std::move(args.shown),
|
||||
.keywords = std::move(args.keywords),
|
||||
.searchCheckIcon = (args.checked
|
||||
? SearchEntryCheckIcon::Checked
|
||||
: SearchEntryCheckIcon::Unchecked),
|
||||
}));
|
||||
}
|
||||
|
||||
void SectionBuilder::addSubsectionTitle(rpl::producer<QString> text) {
|
||||
|
||||
@@ -36,20 +36,36 @@ namespace style {
|
||||
struct SettingsButton;
|
||||
} // namespace style
|
||||
|
||||
namespace st {
|
||||
extern const int &boxRadius;
|
||||
} // namespace st
|
||||
|
||||
namespace Ui {
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
} // namespace Ui
|
||||
|
||||
namespace tr {
|
||||
template <typename ...Tags>
|
||||
struct phrase;
|
||||
} // namespace tr
|
||||
|
||||
namespace Settings::Builder {
|
||||
|
||||
class SectionBuilder;
|
||||
|
||||
enum class SearchEntryCheckIcon {
|
||||
None,
|
||||
Checked,
|
||||
Unchecked,
|
||||
};
|
||||
struct SearchEntry {
|
||||
QString id;
|
||||
QString title;
|
||||
QStringList keywords;
|
||||
Type section;
|
||||
IconDescriptor icon;
|
||||
SearchEntryCheckIcon checkIcon = SearchEntryCheckIcon::None;
|
||||
|
||||
explicit operator bool() const {
|
||||
return !id.isEmpty();
|
||||
@@ -70,15 +86,20 @@ public:
|
||||
|
||||
void add(
|
||||
Type sectionId,
|
||||
tr::phrase<> title,
|
||||
Type parentSectionId,
|
||||
SearchEntriesIndexer indexer);
|
||||
|
||||
[[nodiscard]] std::vector<SearchEntry> collectAll(
|
||||
not_null<::Main::Session*> session) const;
|
||||
|
||||
[[nodiscard]] QString sectionTitle(Type sectionId) const;
|
||||
[[nodiscard]] QString sectionPath(Type sectionId) const;
|
||||
|
||||
private:
|
||||
std::vector<SearchIndexerEntry> _indexers;
|
||||
base::flat_map<Type, Type> _parentSections;
|
||||
base::flat_map<Type, tr::phrase<>> _sectionTitles;
|
||||
|
||||
};
|
||||
|
||||
@@ -86,6 +107,7 @@ class BuildHelper {
|
||||
public:
|
||||
BuildHelper(
|
||||
Type sectionId,
|
||||
tr::phrase<> sectionTitle,
|
||||
FnMut<void(SectionBuilder&)> method,
|
||||
Type parentSectionId = nullptr);
|
||||
|
||||
@@ -147,11 +169,14 @@ public:
|
||||
Fn<object_ptr<Ui::RpWidget>(not_null<Ui::VerticalLayout*>)> factory;
|
||||
QString id;
|
||||
rpl::producer<QString> title;
|
||||
QStringList keywords;
|
||||
style::margins margin;
|
||||
style::align align = style::al_left;
|
||||
HighlightArgs highlight;
|
||||
rpl::producer<bool> shown;
|
||||
|
||||
QStringList keywords;
|
||||
IconDescriptor searchIcon;
|
||||
SearchEntryCheckIcon searchCheckIcon = SearchEntryCheckIcon::None;
|
||||
};
|
||||
Ui::RpWidget *addControl(ControlArgs &&args);
|
||||
|
||||
@@ -162,6 +187,7 @@ public:
|
||||
IconDescriptor icon;
|
||||
Ui::VerticalLayout *container = nullptr;
|
||||
rpl::producer<QString> label;
|
||||
rpl::producer<bool> toggled;
|
||||
Fn<void()> onClick;
|
||||
QStringList keywords;
|
||||
HighlightArgs highlight;
|
||||
@@ -198,35 +224,16 @@ public:
|
||||
};
|
||||
Ui::SettingsButton *addPrivacyButton(PrivacyButtonArgs &&args);
|
||||
|
||||
struct ToggleArgs {
|
||||
QString id;
|
||||
rpl::producer<QString> title;
|
||||
const style::SettingsButton *st = nullptr;
|
||||
IconDescriptor icon;
|
||||
Ui::VerticalLayout *container = nullptr;
|
||||
rpl::producer<bool> toggled;
|
||||
QStringList keywords;
|
||||
HighlightArgs highlight;
|
||||
};
|
||||
Ui::SettingsButton *addToggle(ToggleArgs &&args);
|
||||
|
||||
struct CheckboxArgs {
|
||||
QString id;
|
||||
rpl::producer<QString> title;
|
||||
bool checked = false;
|
||||
QStringList keywords;
|
||||
HighlightArgs highlight = { .radius = st::boxRadius };
|
||||
rpl::producer<bool> shown;
|
||||
};
|
||||
Ui::Checkbox *addCheckbox(CheckboxArgs &&args);
|
||||
|
||||
struct SlideCheckboxArgs {
|
||||
QString id;
|
||||
rpl::producer<QString> title;
|
||||
bool checked = false;
|
||||
rpl::producer<bool> shown;
|
||||
QStringList keywords;
|
||||
};
|
||||
Ui::SlideWrap<Ui::Checkbox> *addSlideCheckbox(SlideCheckboxArgs &&args);
|
||||
|
||||
void addSubsectionTitle(rpl::producer<QString> text);
|
||||
void addDivider();
|
||||
void addDividerText(rpl::producer<QString> text);
|
||||
|
||||
@@ -54,12 +54,16 @@ void BuildChatSectionContent(
|
||||
SetupArchive(controller, container, showOther);
|
||||
}
|
||||
|
||||
const auto kMeta = BuildHelper(Chat::Id(), [](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
const auto showOther = builder.showOther();
|
||||
const auto highlights = builder.highlights();
|
||||
BuildChatSectionContent(builder, controller, showOther, highlights);
|
||||
}, Main::Id());
|
||||
const auto kMeta = BuildHelper(
|
||||
Chat::Id(),
|
||||
tr::lng_settings_section_chat_settings,
|
||||
[](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
const auto showOther = builder.showOther();
|
||||
const auto highlights = builder.highlights();
|
||||
BuildChatSectionContent(builder, controller, showOther, highlights);
|
||||
},
|
||||
Main::Id());
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -138,14 +138,13 @@ void BuildSectionButtons(SectionBuilder &builder) {
|
||||
.keywords = { u"sessions"_q, u"calls"_q },
|
||||
});
|
||||
|
||||
const auto window = controller ? &controller->window() : nullptr;
|
||||
builder.addButton({
|
||||
.id = u"main/power"_q,
|
||||
.title = tr::lng_settings_power_menu(),
|
||||
.icon = { &st::menuIconPowerUsage },
|
||||
.onClick = window
|
||||
? Fn<void()>([=] { window->show(Box(PowerSavingBox, PowerSaving::Flags())); })
|
||||
: Fn<void()>(nullptr),
|
||||
.onClick = [=] {
|
||||
controller->show(Box(PowerSavingBox, PowerSaving::Flags()));
|
||||
},
|
||||
.keywords = { u"battery"_q, u"animations"_q, u"power"_q, u"saving"_q },
|
||||
});
|
||||
|
||||
@@ -158,10 +157,10 @@ void BuildSectionButtons(SectionBuilder &builder) {
|
||||
) | rpl::then(
|
||||
Lang::GetInstance().idChanges()
|
||||
) | rpl::map([] { return Lang::GetInstance().nativeName(); }),
|
||||
.onClick = controller ? Fn<void()>([=] {
|
||||
.onClick = [=] {
|
||||
static auto Guard = base::binary_guard();
|
||||
Guard = LanguageBox::Show(controller);
|
||||
}) : Fn<void()>(nullptr),
|
||||
},
|
||||
.keywords = { u"translate"_q, u"localization"_q, u"language"_q },
|
||||
});
|
||||
}
|
||||
@@ -205,10 +204,10 @@ void BuildPremiumSection(SectionBuilder &builder) {
|
||||
builder.addPremiumButton({
|
||||
.id = u"main/premium"_q,
|
||||
.title = tr::lng_premium_summary_title(),
|
||||
.onClick = controller ? Fn<void()>([=] {
|
||||
.onClick = [=] {
|
||||
controller->setPremiumRef("settings");
|
||||
showOther(PremiumId());
|
||||
}) : Fn<void()>(nullptr),
|
||||
},
|
||||
.keywords = { u"subscription"_q },
|
||||
});
|
||||
|
||||
@@ -217,16 +216,16 @@ void BuildPremiumSection(SectionBuilder &builder) {
|
||||
.id = u"main/credits"_q,
|
||||
.title = tr::lng_settings_credits(),
|
||||
.label = session->credits().balanceValue(
|
||||
) | rpl::map([](CreditsAmount c) {
|
||||
return c
|
||||
? Lang::FormatCreditsAmountToShort(c).string
|
||||
: QString();
|
||||
}),
|
||||
) | rpl::map([](CreditsAmount c) {
|
||||
return c
|
||||
? Lang::FormatCreditsAmountToShort(c).string
|
||||
: QString();
|
||||
}),
|
||||
.credits = true,
|
||||
.onClick = controller ? Fn<void()>([=] {
|
||||
.onClick = [=] {
|
||||
controller->setPremiumRef("settings");
|
||||
showOther(CreditsId());
|
||||
}) : Fn<void()>(nullptr),
|
||||
},
|
||||
.keywords = { u"stars"_q, u"balance"_q },
|
||||
});
|
||||
|
||||
@@ -237,14 +236,12 @@ void BuildPremiumSection(SectionBuilder &builder) {
|
||||
.icon = { &st::menuIconTon },
|
||||
.label = session->credits().tonBalanceValue(
|
||||
) | rpl::map([](CreditsAmount c) {
|
||||
return c
|
||||
? Lang::FormatCreditsAmountToShort(c).string
|
||||
: QString();
|
||||
return c ? Lang::FormatCreditsAmountToShort(c).string : u""_q;
|
||||
}),
|
||||
.onClick = controller ? Fn<void()>([=] {
|
||||
.onClick = [=] {
|
||||
controller->setPremiumRef("settings");
|
||||
showOther(CurrencyId());
|
||||
}) : Fn<void()>(nullptr),
|
||||
},
|
||||
.keywords = { u"ton"_q, u"crypto"_q, u"wallet"_q },
|
||||
.shown = session->credits().tonBalanceValue(
|
||||
) | rpl::map([](CreditsAmount c) { return !c.empty(); }),
|
||||
@@ -254,9 +251,7 @@ void BuildPremiumSection(SectionBuilder &builder) {
|
||||
.id = u"main/business"_q,
|
||||
.title = tr::lng_business_title(),
|
||||
.icon = { .icon = &st::menuIconShop },
|
||||
.onClick = showOther
|
||||
? Fn<void()>([=] { showOther(BusinessId()); })
|
||||
: Fn<void()>(nullptr),
|
||||
.onClick = [=] { showOther(BusinessId()); },
|
||||
.keywords = { u"work"_q, u"company"_q },
|
||||
});
|
||||
|
||||
@@ -265,9 +260,7 @@ void BuildPremiumSection(SectionBuilder &builder) {
|
||||
.id = u"main/send-gift"_q,
|
||||
.title = tr::lng_settings_gift_premium(),
|
||||
.icon = { .icon = &st::menuIconGiftPremium, .newBadge = true },
|
||||
.onClick = controller
|
||||
? Fn<void()>([=] { Ui::ChooseStarGiftRecipient(controller); })
|
||||
: Fn<void()>(nullptr),
|
||||
.onClick = [=] { Ui::ChooseStarGiftRecipient(controller); },
|
||||
.keywords = { u"present"_q, u"send"_q },
|
||||
});
|
||||
}
|
||||
@@ -327,19 +320,22 @@ void BuildValidationSuggestions(SectionBuilder &builder) {
|
||||
});
|
||||
}
|
||||
|
||||
const auto kMeta = BuildHelper(Main::Id(), [](SectionBuilder &builder) {
|
||||
builder.addDivider();
|
||||
builder.addSkip();
|
||||
const auto kMeta = BuildHelper(
|
||||
Main::Id(),
|
||||
tr::lng_menu_settings,
|
||||
[](SectionBuilder &builder) {
|
||||
builder.addDivider();
|
||||
builder.addSkip();
|
||||
|
||||
BuildValidationSuggestions(builder);
|
||||
BuildSectionButtons(builder);
|
||||
BuildValidationSuggestions(builder);
|
||||
BuildSectionButtons(builder);
|
||||
|
||||
builder.addSkip();
|
||||
builder.addSkip();
|
||||
|
||||
BuildInterfaceScale(builder);
|
||||
BuildPremiumSection(builder);
|
||||
BuildHelpSection(builder);
|
||||
});
|
||||
BuildInterfaceScale(builder);
|
||||
BuildPremiumSection(builder);
|
||||
BuildHelpSection(builder);
|
||||
});
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ void BuildMultiAccountSection(
|
||||
|
||||
const auto container = builder.container();
|
||||
if (!container) {
|
||||
builder.addToggle({
|
||||
builder.addButton({
|
||||
.id = u"notifications/multi_account"_q,
|
||||
.title = tr::lng_settings_notify_all(),
|
||||
.toggled = rpl::single(Core::App().settings().notifyFromAll()),
|
||||
@@ -75,7 +75,7 @@ void BuildMultiAccountSection(
|
||||
return;
|
||||
}
|
||||
|
||||
const auto fromAll = builder.addToggle({
|
||||
const auto fromAll = builder.addButton({
|
||||
.id = u"notifications/accounts"_q,
|
||||
.title = tr::lng_settings_notify_all(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -120,7 +120,7 @@ void BuildGlobalNotificationsSection(
|
||||
const auto desktopToggles = container
|
||||
? container->lifetime().make_state<rpl::event_stream<bool>>()
|
||||
: nullptr;
|
||||
const auto desktop = builder.addToggle({
|
||||
const auto desktop = builder.addButton({
|
||||
.id = u"notifications/desktop"_q,
|
||||
.title = tr::lng_settings_desktop_notify(),
|
||||
.icon = { &st::menuIconNotifications },
|
||||
@@ -133,7 +133,7 @@ void BuildGlobalNotificationsSection(
|
||||
const auto flashbounceToggles = container
|
||||
? container->lifetime().make_state<rpl::event_stream<bool>>()
|
||||
: nullptr;
|
||||
const auto flashbounce = builder.addToggle({
|
||||
const auto flashbounce = builder.addButton({
|
||||
.id = u"notifications/flash"_q,
|
||||
.title = (Platform::IsWindows()
|
||||
? tr::lng_settings_alert_windows
|
||||
@@ -153,7 +153,7 @@ void BuildGlobalNotificationsSection(
|
||||
const auto allowed = [=] {
|
||||
return Core::App().settings().soundNotify();
|
||||
};
|
||||
const auto sound = builder.addToggle({
|
||||
const auto sound = builder.addButton({
|
||||
.id = u"notifications/sound"_q,
|
||||
.title = tr::lng_settings_sound_allowed(),
|
||||
.icon = { &st::menuIconUnmute },
|
||||
@@ -366,7 +366,7 @@ void BuildEventNotificationsSection(
|
||||
session->api().contactSignupSilentCurrent().value_or(false)
|
||||
) | rpl::then(session->api().contactSignupSilent());
|
||||
|
||||
const auto joined = builder.addToggle({
|
||||
const auto joined = builder.addButton({
|
||||
.id = u"notifications/events/joined"_q,
|
||||
.title = tr::lng_settings_events_joined(),
|
||||
.icon = { &st::menuIconInvite },
|
||||
@@ -383,7 +383,7 @@ void BuildEventNotificationsSection(
|
||||
}, joined->lifetime());
|
||||
}
|
||||
|
||||
const auto pinned = builder.addToggle({
|
||||
const auto pinned = builder.addButton({
|
||||
.id = u"notifications/events/pinned"_q,
|
||||
.title = tr::lng_settings_events_pinned(),
|
||||
.icon = { &st::menuIconPin },
|
||||
@@ -419,7 +419,7 @@ void BuildCallNotificationsSection(
|
||||
const auto authorizations = &session->api().authorizations();
|
||||
authorizations->reload();
|
||||
|
||||
const auto acceptCalls = builder.addToggle({
|
||||
const auto acceptCalls = builder.addButton({
|
||||
.id = u"notifications/calls/accept"_q,
|
||||
.title = tr::lng_settings_call_accept_calls(),
|
||||
.icon = { &st::menuIconCallsReceive },
|
||||
@@ -448,7 +448,7 @@ void BuildBadgeCounterSection(
|
||||
|
||||
const auto &settings = Core::App().settings();
|
||||
|
||||
const auto muted = builder.addToggle({
|
||||
const auto muted = builder.addButton({
|
||||
.id = u"notifications/include-muted-chats"_q,
|
||||
.title = tr::lng_settings_include_muted(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -458,7 +458,7 @@ void BuildBadgeCounterSection(
|
||||
|
||||
const auto hasFolders = controller
|
||||
&& controller->session().data().chatsFilters().has();
|
||||
const auto mutedFolders = hasFolders ? builder.addToggle({
|
||||
const auto mutedFolders = hasFolders ? builder.addButton({
|
||||
.id = u"notifications/badge/muted_folders"_q,
|
||||
.title = tr::lng_settings_include_muted_folders(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -466,7 +466,7 @@ void BuildBadgeCounterSection(
|
||||
.keywords = { u"muted"_q, u"folders"_q },
|
||||
}) : nullptr;
|
||||
|
||||
const auto count = builder.addToggle({
|
||||
const auto count = builder.addButton({
|
||||
.id = u"notifications/count-unread-messages"_q,
|
||||
.title = tr::lng_settings_count_unread(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -534,7 +534,7 @@ void BuildSystemIntegrationAndAdvancedSection(
|
||||
}
|
||||
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto native = nativeText ? builder.addToggle({
|
||||
const auto native = nativeText ? builder.addButton({
|
||||
.id = u"notifications/native"_q,
|
||||
.title = std::move(nativeText),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -721,10 +721,14 @@ void BuildNotificationsSectionContent(
|
||||
BuildSystemIntegrationAndAdvancedSection(builder, controller);
|
||||
}
|
||||
|
||||
const auto kMeta = BuildHelper(Notifications::Id(), [](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
BuildNotificationsSectionContent(builder, controller);
|
||||
}, Main::Id());
|
||||
const auto kMeta = BuildHelper(
|
||||
Notifications::Id(),
|
||||
tr::lng_settings_section_notify,
|
||||
[](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
BuildNotificationsSectionContent(builder, controller);
|
||||
},
|
||||
Main::Id());
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -484,7 +484,7 @@ void BuildTopPeersSection(
|
||||
builder.addSkip();
|
||||
builder.addSubsectionTitle(tr::lng_settings_top_peers_title());
|
||||
|
||||
const auto toggle = builder.addToggle({
|
||||
const auto toggle = builder.addButton({
|
||||
.id = u"privacy/top_peers"_q,
|
||||
.title = tr::lng_settings_top_peers_suggest(),
|
||||
.st = &st::settingsButtonNoIcon,
|
||||
@@ -569,11 +569,15 @@ void BuildPrivacySecuritySectionContent(
|
||||
BuildSelfDestructionSection(builder, controller, trigger());
|
||||
}
|
||||
|
||||
const auto kMeta = BuildHelper(PrivacySecurity::Id(), [](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
const auto showOther = builder.showOther();
|
||||
BuildPrivacySecuritySectionContent(builder, controller, showOther);
|
||||
}, Main::Id());
|
||||
const auto kMeta = BuildHelper(
|
||||
PrivacySecurity::Id(),
|
||||
tr::lng_settings_section_privacy,
|
||||
[](SectionBuilder &builder) {
|
||||
const auto controller = builder.controller();
|
||||
const auto showOther = builder.showOther();
|
||||
BuildPrivacySecuritySectionContent(builder, controller, showOther);
|
||||
},
|
||||
Main::Id());
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -535,6 +535,16 @@ settingsNotificationTypeDetails: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
|
||||
settingsSearchResult: SettingsButton(settingsButton) {
|
||||
height: 40px;
|
||||
padding: margins(60px, 4px, 22px, 4px);
|
||||
}
|
||||
settingsSearchResultNoIcon: SettingsButton(settingsSearchResult) {
|
||||
padding: margins(22px, 4px, 22px, 4px);
|
||||
}
|
||||
settingsSearchResultDetails: FlatLabel(settingsNotificationTypeDetails) {
|
||||
}
|
||||
|
||||
powerSavingButton: SettingsButton(settingsButton) {
|
||||
style: boxTextStyle;
|
||||
padding: margins(57px, 8px, 22px, 8px);
|
||||
|
||||
@@ -641,7 +641,7 @@ void AddLottieIconWithCircle(
|
||||
}, circle->lifetime());
|
||||
}
|
||||
|
||||
not_null<Button*> AddPremiumStar(
|
||||
void AddPremiumStar(
|
||||
not_null<Button*> button,
|
||||
bool credits,
|
||||
Fn<bool()> isPaused) {
|
||||
@@ -716,8 +716,6 @@ not_null<Button*> AddPremiumStar(
|
||||
|
||||
ministarsContainer->resize(fullHeight, fullHeight);
|
||||
ministars->setCenter(ministarsContainer->rect());
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
@@ -291,7 +291,7 @@ void AddLottieIconWithCircle(
|
||||
QMargins iconPadding,
|
||||
QSize circleSize);
|
||||
|
||||
[[nodiscard]] not_null<Button*> AddPremiumStar(
|
||||
void AddPremiumStar(
|
||||
not_null<Button*> button,
|
||||
bool credits,
|
||||
Fn<bool()> isPaused);
|
||||
|
||||
@@ -277,6 +277,12 @@ rpl::producer<int> BlockedPeersCount(not_null<::Main::Session*> session) {
|
||||
|
||||
} // namespace
|
||||
|
||||
rpl::producer<QString> PrivacyButtonLabel(
|
||||
not_null<::Main::Session*> session,
|
||||
Privacy::Key key) {
|
||||
return PrivacyString(session, key);
|
||||
}
|
||||
|
||||
void AddPrivacyPremiumStar(
|
||||
not_null<Ui::SettingsButton*> button,
|
||||
not_null<Main::Session*> session,
|
||||
|
||||
@@ -40,6 +40,10 @@ not_null<Ui::SettingsButton*> AddPrivacyButton(
|
||||
Fn<std::unique_ptr<EditPrivacyController>()> controllerFactory,
|
||||
const style::SettingsButton *stOverride = nullptr);
|
||||
|
||||
[[nodiscard]] rpl::producer<QString> PrivacyButtonLabel(
|
||||
not_null<::Main::Session*> session,
|
||||
Api::UserPrivacy::Key key);
|
||||
|
||||
void AddPrivacyPremiumStar(
|
||||
not_null<Ui::SettingsButton*> button,
|
||||
not_null<::Main::Session*> session,
|
||||
|
||||
@@ -10,9 +10,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "settings/builder/settings_builder.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/search_field_controller.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
@@ -22,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Settings {
|
||||
namespace {
|
||||
@@ -75,6 +78,70 @@ struct SearchResult {
|
||||
return results;
|
||||
}
|
||||
|
||||
void SetupCheckIcon(
|
||||
not_null<Ui::SettingsButton*> button,
|
||||
Builder::SearchEntryCheckIcon checkIcon,
|
||||
const style::SettingsButton &st) {
|
||||
struct CheckWidget {
|
||||
CheckWidget(QWidget *parent, bool checked)
|
||||
: widget(parent)
|
||||
, view(st::defaultCheck, checked) {
|
||||
view.finishAnimating();
|
||||
}
|
||||
Ui::RpWidget widget;
|
||||
Ui::CheckView view;
|
||||
};
|
||||
const auto checked = (checkIcon == Builder::SearchEntryCheckIcon::Checked);
|
||||
const auto check = button->lifetime().make_state<CheckWidget>(
|
||||
button,
|
||||
checked);
|
||||
check->widget.setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
check->widget.resize(check->view.getSize());
|
||||
check->widget.show();
|
||||
|
||||
button->sizeValue(
|
||||
) | rpl::on_next([=, left = st.iconLeft](QSize size) {
|
||||
check->widget.moveToLeft(
|
||||
left,
|
||||
(size.height() - check->widget.height()) / 2,
|
||||
size.width());
|
||||
}, check->widget.lifetime());
|
||||
|
||||
check->widget.paintRequest(
|
||||
) | rpl::on_next([=] {
|
||||
auto p = QPainter(&check->widget);
|
||||
p.setOpacity(0.5);
|
||||
check->view.paint(p, 0, 0, check->widget.width());
|
||||
}, check->widget.lifetime());
|
||||
}
|
||||
|
||||
[[nodiscard]] not_null<Ui::SettingsButton*> CreateSearchResultButton(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const QString &title,
|
||||
const QString &subtitle,
|
||||
const style::SettingsButton &st,
|
||||
IconDescriptor &&icon,
|
||||
Builder::SearchEntryCheckIcon checkIcon) {
|
||||
const auto button = AddButtonWithIcon(
|
||||
container,
|
||||
rpl::single(title),
|
||||
st,
|
||||
std::move(icon));
|
||||
if (checkIcon != Builder::SearchEntryCheckIcon::None) {
|
||||
SetupCheckIcon(button, checkIcon, st);
|
||||
}
|
||||
const auto details = Ui::CreateChild<Ui::FlatLabel>(
|
||||
button.get(),
|
||||
subtitle,
|
||||
st::settingsSearchResultDetails);
|
||||
details->show();
|
||||
details->moveToLeft(
|
||||
st.padding.left(),
|
||||
st.padding.top() + st.height - details->height());
|
||||
details->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
return button;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Search::Search(
|
||||
@@ -89,57 +156,87 @@ rpl::producer<QString> Search::title() {
|
||||
}
|
||||
|
||||
void Search::setInnerFocus() {
|
||||
_searchField->setFocus();
|
||||
if (_searchField) {
|
||||
_searchField->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
base::weak_qptr<Ui::RpWidget> Search::createPinnedToTop(
|
||||
not_null<QWidget*> parent) {
|
||||
_searchController = std::make_unique<Ui::SearchFieldController>("");
|
||||
auto rowView = _searchController->createRowView(
|
||||
parent,
|
||||
st::infoLayerMediaSearch);
|
||||
_searchField = rowView.field;
|
||||
|
||||
const auto searchContainer = Ui::CreateChild<Ui::FixedHeightWidget>(
|
||||
parent.get(),
|
||||
st::infoLayerMediaSearch.height);
|
||||
const auto wrap = rowView.wrap.release();
|
||||
wrap->setParent(searchContainer);
|
||||
wrap->show();
|
||||
|
||||
searchContainer->widthValue(
|
||||
) | rpl::on_next([=](int width) {
|
||||
wrap->resizeToWidth(width);
|
||||
wrap->moveToLeft(0, 0);
|
||||
}, searchContainer->lifetime());
|
||||
|
||||
_searchController->queryChanges() | rpl::on_next([=](QString &&query) {
|
||||
rebuildResults(std::move(query));
|
||||
}, searchContainer->lifetime());
|
||||
|
||||
return base::make_weak(not_null<Ui::RpWidget*>{ searchContainer });
|
||||
}
|
||||
|
||||
void Search::setupContent() {
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
|
||||
auto searchController = std::make_unique<Ui::SearchFieldController>("");
|
||||
auto rowView = searchController->createRowView(
|
||||
content,
|
||||
st::infoLayerMediaSearch);
|
||||
_searchField = rowView.field;
|
||||
|
||||
const auto searchContainer = content->add(
|
||||
object_ptr<Ui::FixedHeightWidget>(
|
||||
content,
|
||||
st::infoLayerMediaSearch.height));
|
||||
_searchWrap = std::move(rowView.wrap);
|
||||
_searchWrap->setParent(searchContainer);
|
||||
_searchWrap->show();
|
||||
|
||||
searchContainer->widthValue(
|
||||
) | rpl::on_next([wrap = _searchWrap.get()](int width) {
|
||||
wrap->resizeToWidth(width);
|
||||
wrap->moveToLeft(0, 0);
|
||||
}, searchContainer->lifetime());
|
||||
|
||||
_resultsContainer = content->add(
|
||||
object_ptr<Ui::VerticalLayout>(content));
|
||||
|
||||
searchController->queryChanges() | rpl::on_next([=](QString &&query) {
|
||||
rebuildResults(std::move(query));
|
||||
}, content->lifetime());
|
||||
|
||||
_searchController = std::move(searchController);
|
||||
setupCustomizations();
|
||||
rebuildResults(QString());
|
||||
|
||||
Ui::ResizeFitChild(this, content);
|
||||
}
|
||||
|
||||
void Search::setupCustomizations() {
|
||||
const auto isPaused = Window::PausedIn(
|
||||
controller(),
|
||||
Window::GifPauseReason::Layer);
|
||||
const auto add = [&](const QString &id, ResultCustomization value) {
|
||||
_customizations[id] = std::move(value);
|
||||
};
|
||||
|
||||
add(u"main/credits"_q, {
|
||||
.hook = [=](not_null<Ui::SettingsButton*> b) {
|
||||
AddPremiumStar(b, true, isPaused);
|
||||
},
|
||||
.st = &st::settingsSearchResult,
|
||||
});
|
||||
add(u"main/premium"_q, {
|
||||
.hook = [=](not_null<Ui::SettingsButton*> b) {
|
||||
AddPremiumStar(b, false, isPaused);
|
||||
},
|
||||
.st = &st::settingsSearchResult,
|
||||
});
|
||||
}
|
||||
|
||||
void Search::rebuildResults(const QString &query) {
|
||||
while (_resultsContainer->count() > 0) {
|
||||
delete _resultsContainer->widgetAt(0);
|
||||
}
|
||||
|
||||
if (query.trimmed().isEmpty()) {
|
||||
_resultsContainer->resizeToWidth(_resultsContainer->width());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto entries = Builder::SearchRegistry::Instance().collectAll(
|
||||
&controller()->session());
|
||||
const auto results = FilterAndSort(entries, query);
|
||||
const auto results = query.trimmed().isEmpty()
|
||||
? ranges::views::all(entries)
|
||||
| ranges::views::transform([](const auto &e) {
|
||||
return SearchResult{ e, 0 };
|
||||
})
|
||||
| ranges::to<std::vector<SearchResult>>()
|
||||
: FilterAndSort(entries, query);
|
||||
|
||||
if (results.empty()) {
|
||||
_resultsContainer->add(
|
||||
@@ -150,13 +247,38 @@ void Search::rebuildResults(const QString &query) {
|
||||
st::defaultSubsectionTitlePadding);
|
||||
} else {
|
||||
const auto showOther = showOtherMethod();
|
||||
const auto ®istry = Builder::SearchRegistry::Instance();
|
||||
|
||||
for (const auto &result : results) {
|
||||
const auto entry = result.entry;
|
||||
const auto button = AddButtonWithIcon(
|
||||
const auto &entry = result.entry;
|
||||
const auto subtitle = registry.sectionPath(entry.section);
|
||||
const auto hasIcon = entry.icon.icon != nullptr;
|
||||
const auto hasCheckIcon = !hasIcon
|
||||
&& (entry.checkIcon != Builder::SearchEntryCheckIcon::None);
|
||||
|
||||
const auto it = _customizations.find(entry.id);
|
||||
const auto custom = (it != _customizations.end())
|
||||
? &it->second
|
||||
: nullptr;
|
||||
|
||||
const auto &st = custom && custom->st
|
||||
? *custom->st
|
||||
: (hasIcon || hasCheckIcon)
|
||||
? st::settingsSearchResult
|
||||
: st::settingsSearchResultNoIcon;
|
||||
|
||||
const auto button = CreateSearchResultButton(
|
||||
_resultsContainer,
|
||||
rpl::single(entry.title),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconInfo });
|
||||
entry.title,
|
||||
subtitle,
|
||||
st,
|
||||
IconDescriptor{ entry.icon.icon },
|
||||
hasCheckIcon ? entry.checkIcon : Builder::SearchEntryCheckIcon::None);
|
||||
|
||||
if (custom && custom->hook) {
|
||||
custom->hook(button);
|
||||
}
|
||||
|
||||
const auto targetSection = entry.section;
|
||||
const auto controlId = entry.id;
|
||||
button->addClickHandler([=] {
|
||||
|
||||
@@ -29,15 +29,23 @@ public:
|
||||
[[nodiscard]] rpl::producer<QString> title() override;
|
||||
|
||||
void setInnerFocus() override;
|
||||
[[nodiscard]] base::weak_qptr<Ui::RpWidget> createPinnedToTop(
|
||||
not_null<QWidget*> parent) override;
|
||||
|
||||
private:
|
||||
struct ResultCustomization {
|
||||
Fn<void(not_null<Ui::SettingsButton*>)> hook;
|
||||
const style::SettingsButton *st = nullptr;
|
||||
};
|
||||
|
||||
void setupContent();
|
||||
void setupCustomizations();
|
||||
void rebuildResults(const QString &query);
|
||||
|
||||
std::unique_ptr<Ui::SearchFieldController> _searchController;
|
||||
base::unique_qptr<Ui::RpWidget> _searchWrap;
|
||||
Ui::InputField *_searchField = nullptr;
|
||||
Ui::VerticalLayout *_resultsContainer = nullptr;
|
||||
base::flat_map<QString, ResultCustomization> _customizations;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user