diff --git a/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp b/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp index 6da61e78c3..f9ee834312 100644 --- a/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp +++ b/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp @@ -478,7 +478,7 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"folders"_q, - .action = SettingsSection{ ::Settings::Folders::Id() }, + .action = SettingsSection{ ::Settings::FoldersId() }, }); router.add(u"settings"_q, { @@ -1801,28 +1801,28 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"folders/create"_q, .action = SettingsControl{ - ::Settings::Folders::Id(), + ::Settings::FoldersId(), u"folders/create"_q, }, }); router.add(u"settings"_q, { .path = u"folders/add-recommended"_q, .action = SettingsControl{ - ::Settings::Folders::Id(), + ::Settings::FoldersId(), u"folders/add-recommended"_q, }, }); router.add(u"settings"_q, { .path = u"folders/show-tags"_q, .action = SettingsControl{ - ::Settings::Folders::Id(), + ::Settings::FoldersId(), u"folders/show-tags"_q, }, }); router.add(u"settings"_q, { .path = u"folders/tab-view"_q, .action = SettingsControl{ - ::Settings::Folders::Id(), + ::Settings::FoldersId(), u"folders/tab-view"_q, }, }); diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 13a0b9caa9..6e89ea6803 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -825,7 +825,7 @@ bool ResolveSettings( } else if (section == u"devices"_q) { return ::Settings::Sessions::Id(); } else if (section == u"folders"_q) { - return ::Settings::Folders::Id(); + return ::Settings::FoldersId(); } else if (section == u"privacy"_q) { return ::Settings::PrivacySecurity::Id(); } else if (section == u"themes"_q) { diff --git a/Telegram/SourceFiles/settings/sections/settings_folders.cpp b/Telegram/SourceFiles/settings/sections/settings_folders.cpp index 1ea932d0c4..c6af86d564 100644 --- a/Telegram/SourceFiles/settings/sections/settings_folders.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_folders.cpp @@ -25,8 +25,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lottie/lottie_icon.h" #include "main/main_session.h" #include "settings/sections/settings_main.h" -#include "settings/settings_builder.h" #include "settings/sections/settings_premium.h" +#include "settings/settings_builder.h" +#include "settings/settings_common_session.h" #include "ui/boxes/confirm_box.h" #include "ui/empty_userpic.h" #include "ui/filter_icons.h" @@ -44,21 +45,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/slide_wrap.h" #include "window/window_controller.h" #include "window/window_session_controller.h" -#include "styles/style_settings.h" -#include "styles/style_layers.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" +#include "styles/style_layers.h" #include "styles/style_menu_icons.h" +#include "styles/style_settings.h" namespace Settings { - -struct FoldersHighlightTargets { - QPointer createButton; - QPointer tagsButton; - QPointer viewSection; - QPointer recommendedTitle; -}; - namespace { using namespace Builder; @@ -358,30 +351,26 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { } } -[[nodiscard]] Fn SetupFoldersContent( +struct FoldersState { + std::vector rows; + rpl::variable count; + rpl::variable suggested; + Fn)> save; + Ui::Animations::Simple tagsEnabledAnimation; + rpl::event_stream tagsButtonEnabled; +}; + +void SetupFoldersList( not_null controller, not_null container, - not_null*> tagsButtonEnabled, - FoldersHighlightTargets *targets) { - auto &lifetime = container->lifetime(); - + not_null state, + HighlightRegistry *highlights) { const auto weak = base::make_weak(container); const auto session = &controller->session(); const auto limit = [=] { return Data::PremiumLimits(session).dialogFiltersCurrent(); }; - Ui::AddSkip(container, st::defaultVerticalListSkip); - Ui::AddSubsectionTitle(container, tr::lng_filters_subtitle()); - struct State { - std::vector rows; - rpl::variable count; - rpl::variable suggested; - Fn)> save; - Ui::Animations::Simple tagsEnabledAnimation; - }; - - const auto state = lifetime.make_state(); const auto find = [=](not_null button) { const auto i = ranges::find(state->rows, button, &FilterRow::button); Assert(i != end(state->rows)); @@ -574,8 +563,8 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { tr::lng_filters_create(), st::settingsButtonActive, { &st::settingsIconAdd, IconType::Round, &st::windowBgActive }); - if (targets) { - targets->createButton = createButton; + if (highlights) { + highlights->push_back({ u"folders/create"_q, { createButton.get() } }); } createButton->setClickedCallback([=] { if (showLimitReached()) { @@ -603,81 +592,6 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { crl::guard(container, doneCallback), crl::guard(container, saveAnd))); }); - Ui::AddSkip(container); - const auto nonEmptyAbout = container->add( - object_ptr>( - container, - object_ptr(container)) - )->setDuration(0); - const auto aboutRows = nonEmptyAbout->entity(); - Ui::AddDivider(aboutRows); - Ui::AddSkip(aboutRows); - const auto recommendedTitle = Ui::AddSubsectionTitle( - aboutRows, - tr::lng_filters_recommended()); - if (targets) { - targets->recommendedTitle = recommendedTitle; - } - - const auto setTagsProgress = [=](float64 value) { - for (const auto &row : state->rows) { - row.button->setColorIndexProgress(value); - } - }; - tagsButtonEnabled->events() | rpl::distinct_until_changed( - ) | rpl::on_next([=](bool value) { - state->tagsEnabledAnimation.stop(); - state->tagsEnabledAnimation.start( - setTagsProgress, - value ? .0 : 1., - value ? 1. : .0, - st::universalDuration); - }, lifetime); - setTagsProgress(session->data().chatsFilters().tagsEnabled()); - - rpl::single(rpl::empty) | rpl::then( - session->data().chatsFilters().suggestedUpdated() - ) | rpl::map([=] { - return session->data().chatsFilters().suggestedFilters(); - }) | rpl::filter([=](const std::vector &list) { - return !list.empty(); - }) | rpl::take( - 1 - ) | rpl::on_next([=]( - const std::vector &suggestions) { - for (const auto &suggestion : suggestions) { - const auto &filter = suggestion.filter; - if (ranges::contains(state->rows, filter, &FilterRow::filter)) { - continue; - } - state->suggested = state->suggested.current() + 1; - const auto button = aboutRows->add(object_ptr( - aboutRows, - session, - filter, - suggestion.description)); - button->addRequests( - ) | rpl::on_next([=] { - if (showLimitReached()) { - return; - } - addFilter(filter); - state->suggested = state->suggested.current() - 1; - delete button; - }, button->lifetime()); - } - aboutRows->resizeToWidth(container->width()); - Ui::AddSkip(aboutRows, st::defaultVerticalListSkip); - }, aboutRows->lifetime()); - - auto showSuggestions = rpl::combine( - state->suggested.value(), - state->count.value(), - Data::AmPremiumValue(session) - ) | rpl::map([limit](int suggested, int count, bool) { - return suggested > 0 && count < limit(); - }); - nonEmptyAbout->toggleOn(std::move(showSuggestions)); const auto prepareGoodIdsForNewFilters = [=] { const auto &list = session->data().chatsFilters().list(); @@ -851,190 +765,483 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { checkFinished(); }); }; - return [copy = state->save] { - copy(nullptr, nullptr); - }; } -void SetupTopContent( - not_null parent, - rpl::producer<> showFinished) { - const auto divider = Ui::CreateChild(parent.get()); - const auto verticalLayout = parent->add( - object_ptr(parent.get())); - - auto icon = CreateLottieIcon( - verticalLayout, - { - .name = u"filters"_q, - .sizeOverride = { - st::settingsFilterIconSize, - st::settingsFilterIconSize, - }, - }, - st::settingsFilterIconPadding); - std::move( - showFinished - ) | rpl::on_next([animate = std::move(icon.animate)] { - animate(anim::repeat::once); - }, verticalLayout->lifetime()); - verticalLayout->add(std::move(icon.widget)); - - verticalLayout->add( - object_ptr( - verticalLayout, - tr::lng_filters_about(), - st::settingsFilterDividerLabel), - st::settingsFilterDividerLabelPadding, - style::al_top)->setTryMakeSimilarLines(true); - - verticalLayout->geometryValue( - ) | rpl::on_next([=](const QRect &r) { - divider->setGeometry(r); - }, divider->lifetime()); - -} - -void SetupTagContent( +void SetupRecommendedSection( not_null controller, - not_null content, - not_null*> tagsButtonEnabled, - FoldersHighlightTargets *targets) { - Ui::AddDivider(content); - Ui::AddSkip(content); - + not_null container, + not_null state, + HighlightRegistry *highlights) { const auto session = &controller->session(); - - struct State final { - rpl::event_stream tagsTurnOff; - base::Timer requestTimer; - Fn sendCallback; + const auto limit = [=] { + return Data::PremiumLimits(session).dialogFiltersCurrent(); }; - auto premium = Data::AmPremiumValue(session); - const auto tagsButton = content->add( - object_ptr( - content, - tr::lng_filters_enable_tags(), - st::settingsButtonNoIconLocked)); - if (targets) { - targets->tagsButton = tagsButton; - } - const auto state = tagsButton->lifetime().make_state(); - tagsButton->toggleOn(rpl::merge( - rpl::combine( - session->data().chatsFilters().tagsEnabledValue(), - rpl::duplicate(premium), - rpl::mappers::_1 && rpl::mappers::_2), - state->tagsTurnOff.events())); - rpl::duplicate(premium) | rpl::on_next([=](bool value) { - tagsButton->setToggleLocked(!value); - }, tagsButton->lifetime()); + const auto showLimitReached = [=] { + const auto removed = ranges::count_if( + state->rows, + &FilterRow::removed); + const auto count = int(state->rows.size() - removed); + if (count < limit()) { + return false; + } + controller->show(Box(FiltersLimitBox, session, count)); + return true; + }; - const auto send = [=, weak = base::make_weak(tagsButton)](bool checked) { - session->data().chatsFilters().requestToggleTags(checked, [=] { - if ([[maybe_unused]] const auto strong = weak.get()) { - state->tagsTurnOff.fire(!checked); + const auto find = [=](not_null button) { + const auto i = ranges::find(state->rows, button, &FilterRow::button); + Assert(i != end(state->rows)); + return &*i; + }; + + const auto addFilter = [=, wrap = container->parentWidget()]( + const Data::ChatFilter &filter) { + const auto outerWrap = static_cast(wrap); + const auto button = outerWrap->insert( + outerWrap->count() - 1, + object_ptr(outerWrap, session, filter)); + button->removeRequests( + ) | rpl::on_next([=] { + const auto row = find(button); + row->removed = true; + button->setRemoved(true); + }, button->lifetime()); + button->restoreRequests( + ) | rpl::on_next([=] { + if (showLimitReached()) { + return; + } + button->setRemoved(false); + find(button)->removed = false; + }, button->lifetime()); + button->setClickedCallback([=] { + const auto found = find(button); + if (found->removed) { + return; + } + const auto doneCallback = [=](const Data::ChatFilter &result) { + find(button)->filter = result; + button->updateData(result); + }; + const auto saveAnd = [=]( + const Data::ChatFilter &data, + Fn next) { + doneCallback(data); + state->save(button, next); + }; + controller->window().show(Box( + EditFilterBox, + controller, + found->filter, + crl::guard(button, doneCallback), + crl::guard(button, saveAnd))); + }); + state->rows.push_back({ button, filter }); + state->count = state->rows.size(); + return button; + }; + + Ui::AddSkip(container); + const auto nonEmptyAbout = container->add( + object_ptr>( + container, + object_ptr(container)) + )->setDuration(0); + const auto aboutRows = nonEmptyAbout->entity(); + Ui::AddDivider(aboutRows); + Ui::AddSkip(aboutRows); + const auto recommendedTitle = Ui::AddSubsectionTitle( + aboutRows, + tr::lng_filters_recommended()); + if (highlights) { + highlights->push_back({ + u"folders/add-recommended"_q, + { recommendedTitle.get(), SubsectionTitleHighlight() }, + }); + } + + const auto setTagsProgress = [=](float64 value) { + for (const auto &row : state->rows) { + row.button->setColorIndexProgress(value); + } + }; + state->tagsButtonEnabled.events() | rpl::distinct_until_changed( + ) | rpl::on_next([=](bool value) { + state->tagsEnabledAnimation.stop(); + state->tagsEnabledAnimation.start( + setTagsProgress, + value ? .0 : 1., + value ? 1. : .0, + st::universalDuration); + }, container->lifetime()); + setTagsProgress(session->data().chatsFilters().tagsEnabled()); + + rpl::single(rpl::empty) | rpl::then( + session->data().chatsFilters().suggestedUpdated() + ) | rpl::map([=] { + return session->data().chatsFilters().suggestedFilters(); + }) | rpl::filter([=](const std::vector &list) { + return !list.empty(); + }) | rpl::take( + 1 + ) | rpl::on_next([=]( + const std::vector &suggestions) { + for (const auto &suggestion : suggestions) { + const auto &filter = suggestion.filter; + if (ranges::contains(state->rows, filter, &FilterRow::filter)) { + continue; + } + state->suggested = state->suggested.current() + 1; + const auto button = aboutRows->add(object_ptr( + aboutRows, + session, + filter, + suggestion.description)); + button->addRequests( + ) | rpl::on_next([=] { + if (showLimitReached()) { + return; + } + addFilter(filter); + state->suggested = state->suggested.current() - 1; + delete button; + }, button->lifetime()); + } + aboutRows->resizeToWidth(container->width()); + Ui::AddSkip(aboutRows, st::defaultVerticalListSkip); + }, aboutRows->lifetime()); + + auto showSuggestions = rpl::combine( + state->suggested.value(), + state->count.value(), + Data::AmPremiumValue(session) + ) | rpl::map([limit](int suggested, int count, bool) { + return suggested > 0 && count < limit(); + }); + nonEmptyAbout->toggleOn(std::move(showSuggestions)); +} + +void BuildTopContent(SectionBuilder &builder, rpl::producer<> showFinished) { + builder.add([showFinished = std::move(showFinished)]( + const WidgetContext &ctx) mutable { + const auto parent = ctx.container; + const auto divider = Ui::CreateChild( + parent.get()); + const auto verticalLayout = parent->add( + object_ptr(parent.get())); + + auto icon = CreateLottieIcon( + verticalLayout, + { + .name = u"filters"_q, + .sizeOverride = { + st::settingsFilterIconSize, + st::settingsFilterIconSize, + }, + }, + st::settingsFilterIconPadding); + std::move( + showFinished + ) | rpl::on_next([animate = std::move(icon.animate)] { + animate(anim::repeat::once); + }, verticalLayout->lifetime()); + verticalLayout->add(std::move(icon.widget)); + + verticalLayout->add( + object_ptr( + verticalLayout, + tr::lng_filters_about(), + st::settingsFilterDividerLabel), + st::settingsFilterDividerLabelPadding, + style::al_top)->setTryMakeSimilarLines(true); + + verticalLayout->geometryValue( + ) | rpl::on_next([=](const QRect &r) { + divider->setGeometry(r); + }, divider->lifetime()); + + return SectionBuilder::WidgetToAdd{}; + }); +} + +void BuildFoldersListSection( + SectionBuilder &builder, + not_null state) { + builder.addSkip(); + builder.addSubsectionTitle(tr::lng_filters_subtitle()); + + builder.add([=](const WidgetContext &ctx) { + SetupFoldersList(ctx.controller, ctx.container, state, ctx.highlights); + SetupRecommendedSection( + ctx.controller, + ctx.container, + state, + ctx.highlights); + return SectionBuilder::WidgetToAdd{}; + }); +} + +void BuildTagsSection(SectionBuilder &builder, not_null state) { + if (!builder.session()->premiumPossible()) { + return; + } + + builder.addDivider(); + builder.addSkip(); + + const auto session = builder.session(); + + builder.add([=](const WidgetContext &ctx) { + const auto controller = ctx.controller; + const auto content = ctx.container; + + struct TagsState final { + rpl::event_stream tagsTurnOff; + base::Timer requestTimer; + Fn sendCallback; + }; + + auto premium = Data::AmPremiumValue(session); + const auto tagsButton = content->add( + object_ptr( + content, + tr::lng_filters_enable_tags(), + st::settingsButtonNoIconLocked)); + if (ctx.highlights) { + ctx.highlights->push_back({ u"folders/show-tags"_q, { tagsButton } }); + } + const auto tagsState = tagsButton->lifetime().make_state(); + tagsButton->toggleOn(rpl::merge( + rpl::combine( + session->data().chatsFilters().tagsEnabledValue(), + rpl::duplicate(premium), + rpl::mappers::_1 && rpl::mappers::_2), + tagsState->tagsTurnOff.events())); + rpl::duplicate(premium) | rpl::on_next([=](bool value) { + tagsButton->setToggleLocked(!value); + }, tagsButton->lifetime()); + + const auto send = [=, + weak = base::make_weak(tagsButton)](bool checked) { + session->data().chatsFilters().requestToggleTags(checked, [=] { + if ([[maybe_unused]] const auto strong = weak.get()) { + tagsState->tagsTurnOff.fire(!checked); + } + }); + }; + + tagsButton->toggledValue( + ) | rpl::filter([=](bool checked) { + const auto premium = session->premium(); + if (checked && !premium) { + ShowPremiumPreviewToBuy(controller, PremiumFeature::FilterTags); + tagsState->tagsTurnOff.fire(false); + } + if (!premium) { + state->tagsButtonEnabled.fire(false); + } else { + state->tagsButtonEnabled.fire_copy(checked); + } + const auto proceed = premium + && (checked != session->data().chatsFilters().tagsEnabled()); + if (!proceed) { + tagsState->requestTimer.cancel(); + } + return proceed; + }) | rpl::on_next([=](bool v) { + tagsState->sendCallback = [=] { send(v); }; + tagsState->requestTimer.cancel(); + tagsState->requestTimer.setCallback([=] { send(v); }); + tagsState->requestTimer.callOnce(500); + }, tagsButton->lifetime()); + + tagsButton->lifetime().add([=] { + if (tagsState->requestTimer.isActive()) { + if (tagsState->sendCallback) { + tagsState->sendCallback(); + } } }); - }; - tagsButton->toggledValue( - ) | rpl::filter([=](bool checked) { - const auto premium = session->premium(); - if (checked && !premium) { - ShowPremiumPreviewToBuy(controller, PremiumFeature::FilterTags); - state->tagsTurnOff.fire(false); - } - if (!premium) { - tagsButtonEnabled->fire(false); - } else { - tagsButtonEnabled->fire_copy(checked); - } - const auto proceed = premium - && (checked != session->data().chatsFilters().tagsEnabled()); - if (!proceed) { - state->requestTimer.cancel(); - } - return proceed; - }) | rpl::on_next([=](bool v) { - state->sendCallback = [=] { send(v); }; - state->requestTimer.cancel(); - state->requestTimer.setCallback([=] { send(v); }); - state->requestTimer.callOnce(500); - }, tagsButton->lifetime()); - - tagsButton->lifetime().add([=] { - if (state->requestTimer.isActive()) { - if (state->sendCallback) { - state->sendCallback(); - } - } + return SectionBuilder::WidgetToAdd{}; + }, [] { + return SearchEntry{ + .id = u"folders/show-tags"_q, + .title = tr::lng_filters_enable_tags(tr::now), + .keywords = { u"tags"_q, u"colors"_q, u"premium"_q }, + }; }); - Ui::AddSkip(content); - const auto about = Ui::AddDividerText( - content, - rpl::conditional( - rpl::duplicate(premium), - tr::lng_filters_enable_tags_about(tr::rich), - tr::lng_filters_enable_tags_about_premium( - lt_link, - tr::lng_effect_premium_link() | rpl::map([](QString t) { - return tr::link(std::move(t), u"internal:"_q); - }), - tr::rich))); - about->setClickHandlerFilter([=](const auto &...) { - Settings::ShowPremium(controller, u"folder_tags"_q); - return true; + builder.addSkip(); + + builder.add([=](const WidgetContext &ctx) { + auto premium = Data::AmPremiumValue(session); + const auto about = Ui::AddDividerText( + ctx.container, + rpl::conditional( + rpl::duplicate(premium), + tr::lng_filters_enable_tags_about(tr::rich), + tr::lng_filters_enable_tags_about_premium( + lt_link, + tr::lng_effect_premium_link() | rpl::map([](QString t) { + return tr::link(std::move(t), u"internal:"_q); + }), + tr::rich))); + about->setClickHandlerFilter([=](const auto &...) { + Settings::ShowPremium(ctx.controller, u"folder_tags"_q); + return true; + }); + return SectionBuilder::WidgetToAdd{}; }); } -void SetupView( - not_null controller, - not_null content, - bool dividerNeeded, - FoldersHighlightTargets *targets) { - const auto wrap = content->add( - object_ptr>( - content, - object_ptr(content))); - wrap->toggleOn(controller->enoughSpaceForFiltersValue()); - if (targets) { - targets->viewSection = wrap->entity(); - } - content = wrap->entity(); +void BuildViewSection(SectionBuilder &builder) { + builder.add([](const WidgetContext &ctx) { + const auto controller = ctx.controller; + const auto parent = ctx.container; + + const auto wrap = parent->add( + object_ptr>( + parent, + object_ptr(parent))); + wrap->toggleOn(controller->enoughSpaceForFiltersValue()); + if (ctx.highlights) { + ctx.highlights->push_back({ u"folders/tab-view"_q, { wrap->entity() } }); + } + const auto content = wrap->entity(); - if (dividerNeeded) { Ui::AddDivider(content); - } - Ui::AddSkip(content); - Ui::AddSubsectionTitle(content, tr::lng_filters_view_subtitle()); + Ui::AddSkip(content); + Ui::AddSubsectionTitle(content, tr::lng_filters_view_subtitle()); - const auto group = std::make_shared>( - Core::App().settings().chatFiltersHorizontal()); - const auto addSend = [&](bool value, const QString &text) { - content->add( - object_ptr>( - content, - group, - value, - text, - st::settingsSendType), - st::settingsSendTypePadding); - }; - addSend(false, tr::lng_filters_vertical(tr::now)); - addSend(true, tr::lng_filters_horizontal(tr::now)); + const auto group = std::make_shared>( + Core::App().settings().chatFiltersHorizontal()); + const auto addSend = [&](bool value, const QString &text) { + content->add( + object_ptr>( + content, + group, + value, + text, + st::settingsSendType), + st::settingsSendTypePadding); + }; + addSend(false, tr::lng_filters_vertical(tr::now)); + addSend(true, tr::lng_filters_horizontal(tr::now)); - group->setChangedCallback([=](bool value) { - Core::App().settings().setChatFiltersHorizontal(value); - Core::App().saveSettingsDelayed(); + group->setChangedCallback([=](bool value) { + Core::App().settings().setChatFiltersHorizontal(value); + Core::App().saveSettingsDelayed(); + }); + Ui::AddSkip(content); + Ui::AddSkip(content); + + return SectionBuilder::WidgetToAdd{}; + }, [] { + return SearchEntry{ + .id = u"folders/tab-view"_q, + .title = tr::lng_filters_view_subtitle(tr::now), + .keywords = { u"view"_q, u"layout"_q, u"tabs"_q }, + }; }); - Ui::AddSkip(content); - Ui::AddSkip(content); } -void BuildFoldersSectionContent(SectionBuilder &builder) { +class Folders : public Section { +public: + Folders( + QWidget *parent, + not_null controller); + ~Folders(); + + void showFinished() override; + + [[nodiscard]] rpl::producer title() override; + +private: + void setupContent(); + + std::shared_ptr _state; + rpl::event_stream<> _showFinished; + +}; + +Folders::Folders( + QWidget *parent, + not_null controller) +: Section(parent, controller) +, _state(std::make_shared()) { + setupContent(); +} + +Folders::~Folders() { + if (!Core::Quitting() && _state->save) { + _state->save(nullptr, nullptr); + } +} + +rpl::producer Folders::title() { + return tr::lng_filters_title(); +} + +void Folders::setupContent() { + controller()->session().data().chatsFilters().requestSuggested(); + + const auto content = Ui::CreateChild(this); + const auto state = _state; + + const SectionBuildMethod buildMethod = [state]( + not_null container, + not_null controller, + Fn showOther, + rpl::producer<> showFinished) { + auto &lifetime = container->lifetime(); + const auto highlights = lifetime.make_state(); + const auto isPaused = Window::PausedIn( + controller, + Window::GifPauseReason::Layer); + auto showFinishedDup = rpl::duplicate(showFinished); + auto builder = SectionBuilder(WidgetContext{ + .container = container, + .controller = controller, + .showOther = std::move(showOther), + .isPaused = isPaused, + .highlights = highlights, + }); + + BuildTopContent(builder, std::move(showFinishedDup)); + BuildFoldersListSection(builder, state.get()); + BuildTagsSection(builder, state.get()); + BuildViewSection(builder); + + std::move(showFinished) | rpl::on_next([=] { + for (const auto &[id, entry] : *highlights) { + if (entry.widget) { + controller->checkHighlightControl( + id, + entry.widget, + base::duplicate(entry.args)); + } + } + }, lifetime); + }; + + build(content, buildMethod); + + Ui::ResizeFitChild(this, content); +} + +void Folders::showFinished() { + _showFinished.fire({}); + Section::showFinished(); +} + +const auto kMeta = BuildHelper({ + .id = Folders::Id(), + .parentId = Main::Id(), + .title = &tr::lng_filters_title, + .icon = &st::menuIconShowInFolder, +}, [](SectionBuilder &builder) { builder.add(nullptr, [] { return SearchEntry{ .id = u"folders/create"_q, @@ -1068,77 +1275,12 @@ void BuildFoldersSectionContent(SectionBuilder &builder) { .keywords = { u"view"_q, u"layout"_q, u"tabs"_q }, }; }); -} - -const auto kMeta = BuildHelper({ - .id = Folders::Id(), - .parentId = Main::Id(), - .title = &tr::lng_filters_title, - .icon = &st::menuIconShowInFolder, -}, [](SectionBuilder &builder) { - BuildFoldersSectionContent(builder); }); } // namespace -Folders::Folders( - QWidget *parent, - not_null controller) -: Section(parent, controller) { - setupContent(); -} - -Folders::~Folders() { - if (!Core::Quitting()) { - _save(); - } -} - -rpl::producer Folders::title() { - return tr::lng_filters_title(); -} - -void Folders::setupContent() { - controller()->session().data().chatsFilters().requestSuggested(); - - const auto content = Ui::CreateChild(this); - const auto tagsButtonEnabled - = content->lifetime().make_state>(); - - SetupTopContent(content, _showFinished.events()); - - auto targets = FoldersHighlightTargets(); - _save = SetupFoldersContent( - controller(), - content, - tagsButtonEnabled, - &targets); - _createButton = targets.createButton; - _recommendedTitle = targets.recommendedTitle; - - auto dividerNeeded = true; - if (controller()->session().premiumPossible()) { - SetupTagContent(controller(), content, tagsButtonEnabled, &targets); - _tagsButton = targets.tagsButton; - dividerNeeded = false; - } - - SetupView(controller(), content, dividerNeeded, &targets); - _viewSection = targets.viewSection; - - Ui::ResizeFitChild(this, content); -} - -void Folders::showFinished() { - _showFinished.fire({}); - - controller()->checkHighlightControl(u"folders/create"_q, _createButton); - controller()->checkHighlightControl(u"folders/show-tags"_q, _tagsButton); - controller()->checkHighlightControl(u"folders/tab-view"_q, _viewSection); - controller()->checkHighlightControl( - u"folders/add-recommended"_q, - _recommendedTitle, - SubsectionTitleHighlight()); +Type FoldersId() { + return Folders::Id(); } namespace Builder { diff --git a/Telegram/SourceFiles/settings/sections/settings_folders.h b/Telegram/SourceFiles/settings/sections/settings_folders.h index 9451f43ed0..8a2984febb 100644 --- a/Telegram/SourceFiles/settings/sections/settings_folders.h +++ b/Telegram/SourceFiles/settings/sections/settings_folders.h @@ -7,38 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "settings/settings_common_session.h" #include "settings/settings_type.h" +namespace Window { +class SessionController; +} // namespace Window + namespace Settings { -class Folders : public Section { -public: - Folders( - QWidget *parent, - not_null controller); - ~Folders(); +[[nodiscard]] Type FoldersId(); - void showFinished() override; - - [[nodiscard]] rpl::producer title() override; - -private: - void setupContent(); - - Fn _save; - - rpl::event_stream<> _showFinished; - QPointer _createButton; - QPointer _tagsButton; - QPointer _viewSection; - QPointer _recommendedTitle; - -}; - -namespace Builder { - -extern SectionBuildMethod FoldersSection; - -} // namespace Builder } // namespace Settings diff --git a/Telegram/SourceFiles/settings/sections/settings_main.cpp b/Telegram/SourceFiles/settings/sections/settings_main.cpp index 5703d4d6ff..ee14f84169 100644 --- a/Telegram/SourceFiles/settings/sections/settings_main.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_main.cpp @@ -391,7 +391,7 @@ void BuildSectionButtons(SectionBuilder &builder) { .id = u"main/folders"_q, .title = tr::lng_settings_section_filters(), .icon = { &st::menuIconShowInFolder }, - .onClick = [=] { showOther(Folders::Id()); }, + .onClick = [=] { showOther(FoldersId()); }, .keywords = { u"filters"_q, u"tabs"_q }, .shown = std::move(shownProducer), }); diff --git a/Telegram/SourceFiles/settings/settings_codes.cpp b/Telegram/SourceFiles/settings/settings_codes.cpp index 75032f8635..68d0c112a7 100644 --- a/Telegram/SourceFiles/settings/settings_codes.cpp +++ b/Telegram/SourceFiles/settings/settings_codes.cpp @@ -161,7 +161,7 @@ auto GenerateCodes() { }); codes.emplace(u"folders"_q, [](SessionController *window) { if (window) { - window->showSettings(Settings::Folders::Id()); + window->showSettings(Settings::FoldersId()); } }); codes.emplace(u"registertg"_q, [](SessionController *window) { diff --git a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_strip.cpp b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_strip.cpp index a08c7d1ae4..bbbb09806e 100644 --- a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_strip.cpp +++ b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_strip.cpp @@ -111,13 +111,13 @@ void ShowMenu( auto openFiltersSettings = [=] { const auto filters = &session->data().chatsFilters(); if (filters->suggestedLoaded()) { - controller->showSettings(Settings::Folders::Id()); + controller->showSettings(Settings::FoldersId()); } else if (!state->waitingSuggested) { state->waitingSuggested = true; filters->requestSuggested(); filters->suggestedUpdated( ) | rpl::take(1) | rpl::on_next([=] { - controller->showSettings(Settings::Folders::Id()); + controller->showSettings(Settings::FoldersId()); }, parent->lifetime()); } }; diff --git a/Telegram/SourceFiles/window/window_filters_menu.cpp b/Telegram/SourceFiles/window/window_filters_menu.cpp index e862d8a810..715c33c7d2 100644 --- a/Telegram/SourceFiles/window/window_filters_menu.cpp +++ b/Telegram/SourceFiles/window/window_filters_menu.cpp @@ -360,13 +360,13 @@ base::unique_qptr FiltersMenu::prepareButton( void FiltersMenu::openFiltersSettings() { const auto filters = &_session->session().data().chatsFilters(); if (filters->suggestedLoaded()) { - _session->showSettings(Settings::Folders::Id()); + _session->showSettings(Settings::FoldersId()); } else if (!_waitingSuggested) { _waitingSuggested = true; filters->requestSuggested(); filters->suggestedUpdated( ) | rpl::take(1) | rpl::on_next([=] { - _session->showSettings(Settings::Folders::Id()); + _session->showSettings(Settings::FoldersId()); }, _outer.lifetime()); } }