diff --git a/Telegram/SourceFiles/api/api_chat_filters.cpp b/Telegram/SourceFiles/api/api_chat_filters.cpp index 1e1476b11..dfba82162 100644 --- a/Telegram/SourceFiles/api/api_chat_filters.cpp +++ b/Telegram/SourceFiles/api/api_chat_filters.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "boxes/peer_list_box.h" +#include "boxes/premium_limits_box.h" #include "boxes/filters/edit_filter_links.h" // FilterChatStatusText #include "core/application.h" #include "data/data_chat_filters.h" @@ -362,6 +363,30 @@ void ToggleChatsController::setAddedTopHeight(int addedTopHeight) { _addedTopWidget->resize(_addedTopWidget->width(), addedTopHeight); } +void ShowImportError( + not_null window, + FilterId id, + int added, + const QString &error) { + const auto session = &window->session(); + const auto &list = session->data().chatsFilters().list(); + const auto i = ranges::find(list, id, &Data::ChatFilter::id); + const auto count = added + + ((i != end(list)) ? int(i->always().size()) : 0); + if (error == u"USER_CHANNELS_TOO_MUCH"_q) { + window->show(Box(ChannelsLimitBox, session)); + } else if (error == u"FILTER_INCLUDE_TOO_MUCH"_q) { + window->show(Box(FilterChatsLimitBox, session, count)); + } else if (error == u"CHATLISTS_TOO_MUCH"_q) { + window->show(Box(ShareableFiltersLimitBox, session)); + } else { + Ui::ShowMultilineToast({ + .parentOverride = Window::Show(window).toastParent(), + .text = { error }, + }); + } +} + void ShowImportToast( base::weak_ptr weak, const QString &title, @@ -462,20 +487,15 @@ void ProcessFilterInvite( button->setClickedCallback([=] { if (peers.empty()) { box->closeBox(); - //} else if (count + alreadyInFilter() >= ...) { - // #TODO filters } else if (!state->importing) { state->importing = true; + const auto added = int(peers.size()); ImportInvite(slug, filterId, peers, crl::guard(box, [=] { ShowImportToast(weak, title, type, peers.size()); box->closeBox(); }), crl::guard(box, [=](QString text) { if (const auto strong = weak.get()) { - Ui::ShowMultilineToast({ - .parentOverride = Window::Show( - strong).toastParent(), - .text = { text }, - }); + ShowImportError(strong, filterId, added, text); } state->importing = false; })); diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp index ba170509b..87221ff0e 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/filters/edit_filter_chats_list.h" #include "boxes/filters/edit_filter_links.h" +#include "boxes/premium_limits_box.h" #include "chat_helpers/emoji_suggestions_widget.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" @@ -769,8 +770,12 @@ void EditFilterBox( window->show(ShowLinkBox(window, updated, link)); }, [=](QString error) { - if (error == "CHATLISTS_TOO_MUCH") { - // #TODO filters + if (error == u"CHATLISTS_TOO_MUCH"_q) { + const auto session = &window->session(); + window->show(Box(ShareableFiltersLimitBox, session)); + } else if (error == u"INVITES_TOO_MUCH"_q) { + const auto session = &window->session(); + window->show(Box(FilterLinksLimitBox, session)); } else { window->show(ShowLinkBox(window, updated, { .id = id })); } diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp index 15ee8c07f..b7ff7a31d 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp @@ -1047,7 +1047,8 @@ bool GoodForExportFilterLink( not_null window, const Data::ChatFilter &filter) { using Flag = Data::ChatFilter::Flag; - if (!filter.never().empty() || (filter.flags() & ~Flag::Chatlist)) { + const auto listflags = Flag::Chatlist | Flag::HasMyLinks; + if (!filter.never().empty() || (filter.flags() & ~listflags)) { Ui::ShowMultilineToast({ .parentOverride = Window::Show(window).toastParent(), .text = { tr::lng_filters_link_cant(tr::now) }, diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.cpp b/Telegram/SourceFiles/boxes/premium_limits_box.cpp index 9afb6b039..b7a3d2411 100644 --- a/Telegram/SourceFiles/boxes/premium_limits_box.cpp +++ b/Telegram/SourceFiles/boxes/premium_limits_box.cpp @@ -723,6 +723,44 @@ void FilterChatsLimitBox( { defaultLimit, current, premiumLimit, &st::premiumIconChats }); } +void FilterLinksLimitBox( + not_null box, + not_null session) { + const auto premium = session->premium(); + const auto premiumPossible = session->premiumPossible(); + + const auto limits = Data::PremiumLimits(session); + const auto defaultLimit = float64(limits.dialogFiltersLinksDefault()); + const auto premiumLimit = float64(limits.dialogFiltersLinksPremium()); + const auto current = (premium ? premiumLimit : defaultLimit); + + auto text = rpl::combine( + tr::lng_filter_links_limit1( + lt_count, + rpl::single(premium ? premiumLimit : defaultLimit), + Ui::Text::RichLangValue), + ((premium || !premiumPossible) + ? rpl::single(TextWithEntities()) + : tr::lng_filter_links_limit2( + lt_count, + rpl::single(premiumLimit), + Ui::Text::RichLangValue)) + ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) { + return b.text.isEmpty() + ? a + : a.append(QChar(' ')).append(std::move(b)); + }); + + SimpleLimitBox( + box, + session, + tr::lng_filter_links_limit_title(), + std::move(text), + "chatlist_invites", + { defaultLimit, current, premiumLimit, &st::premiumIconChats }); +} + + void FiltersLimitBox( not_null box, not_null session) { @@ -761,6 +799,44 @@ void FiltersLimitBox( { defaultLimit, current, premiumLimit, &st::premiumIconFolders }); } +void ShareableFiltersLimitBox( + not_null box, + not_null session) { + const auto premium = session->premium(); + const auto premiumPossible = session->premiumPossible(); + + const auto limits = Data::PremiumLimits(session); + const auto defaultLimit = float64(limits.dialogShareableFiltersDefault()); + const auto premiumLimit = float64(limits.dialogShareableFiltersPremium()); + const auto current = float64(ranges::count_if( + session->data().chatsFilters().list(), + [](const Data::ChatFilter &f) { return f.chatlist(); })); + + auto text = rpl::combine( + tr::lng_filter_shared_limit1( + lt_count, + rpl::single(premium ? premiumLimit : defaultLimit), + Ui::Text::RichLangValue), + ((premium || !premiumPossible) + ? rpl::single(TextWithEntities()) + : tr::lng_filter_shared_limit2( + lt_count, + rpl::single(premiumLimit), + Ui::Text::RichLangValue)) + ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) { + return b.text.isEmpty() + ? a + : a.append(QChar(' ')).append(std::move(b)); + }); + SimpleLimitBox( + box, + session, + tr::lng_filter_shared_limit_title(), + std::move(text), + "chatlists_joined", + { defaultLimit, current, premiumLimit, &st::premiumIconFolders }); +} + void FilterPinsLimitBox( not_null box, not_null session, diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.h b/Telegram/SourceFiles/boxes/premium_limits_box.h index 04a607de2..55be7e40f 100644 --- a/Telegram/SourceFiles/boxes/premium_limits_box.h +++ b/Telegram/SourceFiles/boxes/premium_limits_box.h @@ -32,9 +32,15 @@ void FilterChatsLimitBox( not_null box, not_null session, int currentCount); +void FilterLinksLimitBox( + not_null box, + not_null session); void FiltersLimitBox( not_null box, not_null session); +void ShareableFiltersLimitBox( + not_null box, + not_null session); void FilterPinsLimitBox( not_null box, not_null session, diff --git a/Telegram/SourceFiles/data/data_chat_filters.cpp b/Telegram/SourceFiles/data/data_chat_filters.cpp index 9d815ca18..c822cc6af 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.cpp +++ b/Telegram/SourceFiles/data/data_chat_filters.cpp @@ -155,7 +155,8 @@ ChatFilter ChatFilter::FromTL( data.vid().v, qs(data.vtitle()), qs(data.vemoticon().value_or_empty()), - Flag::Chatlist, + (Flag::Chatlist + | (data.is_has_my_invites() ? Flag::HasMyLinks : Flag())), std::move(list), std::move(pinned), {}); @@ -239,6 +240,10 @@ bool ChatFilter::chatlist() const { return _flags & Flag::Chatlist; } +bool ChatFilter::hasMyLinks() const { + return _flags & Flag::HasMyLinks; +} + const base::flat_set> &ChatFilter::always() const { return _always; } diff --git a/Telegram/SourceFiles/data/data_chat_filters.h b/Telegram/SourceFiles/data/data_chat_filters.h index 024240061..6dc5e6384 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.h +++ b/Telegram/SourceFiles/data/data_chat_filters.h @@ -37,7 +37,8 @@ public: NoRead = (1 << 6), NoArchived = (1 << 7), - Chatlist = (1 << 8), + Chatlist = (1 << 8), + HasMyLinks = (1 << 9), }; friend constexpr inline bool is_flag_type(Flag) { return true; }; using Flags = base::flags; @@ -64,6 +65,7 @@ public: [[nodiscard]] QString iconEmoji() const; [[nodiscard]] Flags flags() const; [[nodiscard]] bool chatlist() const; + [[nodiscard]] bool hasMyLinks() const; [[nodiscard]] const base::flat_set> &always() const; [[nodiscard]] const std::vector> &pinned() const; [[nodiscard]] const base::flat_set> &never() const; diff --git a/Telegram/SourceFiles/data/data_premium_limits.cpp b/Telegram/SourceFiles/data/data_premium_limits.cpp index 0348feed8..41397c383 100644 --- a/Telegram/SourceFiles/data/data_premium_limits.cpp +++ b/Telegram/SourceFiles/data/data_premium_limits.cpp @@ -65,6 +65,18 @@ int PremiumLimits::dialogFiltersCurrent() const { : dialogFiltersDefault(); } +int PremiumLimits::dialogShareableFiltersDefault() const { + return appConfigLimit("chatlists_joined_limit_default", 2); +} +int PremiumLimits::dialogShareableFiltersPremium() const { + return appConfigLimit("chatlists_joined_limit_premium", 20); +} +int PremiumLimits::dialogShareableFiltersCurrent() const { + return isPremium() + ? dialogShareableFiltersPremium() + : dialogShareableFiltersDefault(); +} + int PremiumLimits::dialogFiltersChatsDefault() const { return appConfigLimit("dialog_filters_chats_limit_default", 100); } @@ -77,6 +89,18 @@ int PremiumLimits::dialogFiltersChatsCurrent() const { : dialogFiltersChatsDefault(); } +int PremiumLimits::dialogFiltersLinksDefault() const { + return appConfigLimit("chatlist_invites_limit_default", 3); +} +int PremiumLimits::dialogFiltersLinksPremium() const { + return appConfigLimit("chatlist_invites_limit_premium", 20); +} +int PremiumLimits::dialogFiltersLinksCurrent() const { + return isPremium() + ? dialogFiltersLinksPremium() + : dialogFiltersLinksDefault(); +} + int PremiumLimits::dialogsPinnedDefault() const { return appConfigLimit("dialogs_pinned_limit_default", 5); } diff --git a/Telegram/SourceFiles/data/data_premium_limits.h b/Telegram/SourceFiles/data/data_premium_limits.h index e25ab880f..17ffa1247 100644 --- a/Telegram/SourceFiles/data/data_premium_limits.h +++ b/Telegram/SourceFiles/data/data_premium_limits.h @@ -33,10 +33,18 @@ public: [[nodiscard]] int dialogFiltersPremium() const; [[nodiscard]] int dialogFiltersCurrent() const; + [[nodiscard]] int dialogShareableFiltersDefault() const; + [[nodiscard]] int dialogShareableFiltersPremium() const; + [[nodiscard]] int dialogShareableFiltersCurrent() const; + [[nodiscard]] int dialogFiltersChatsDefault() const; [[nodiscard]] int dialogFiltersChatsPremium() const; [[nodiscard]] int dialogFiltersChatsCurrent() const; + [[nodiscard]] int dialogFiltersLinksDefault() const; + [[nodiscard]] int dialogFiltersLinksPremium() const; + [[nodiscard]] int dialogFiltersLinksCurrent() const; + [[nodiscard]] int dialogsPinnedDefault() const; [[nodiscard]] int dialogsPinnedPremium() const; [[nodiscard]] int dialogsPinnedCurrent() const; diff --git a/Telegram/SourceFiles/settings/settings_folders.cpp b/Telegram/SourceFiles/settings/settings_folders.cpp index 6b2c3aea0..dd3d35784 100644 --- a/Telegram/SourceFiles/settings/settings_folders.cpp +++ b/Telegram/SourceFiles/settings/settings_folders.cpp @@ -104,7 +104,6 @@ struct FilterRow { not_null button; Data::ChatFilter filter; bool removed = false; - bool removeHasLinks = false; mtpRequestId removePeersRequestId = 0; std::vector> suggestRemovePeers; std::vector> removePeers; @@ -399,7 +398,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { const auto row = find(button); if (row->removed || row->removePeersRequestId > 0) { return; - } else if (row->filter.chatlist() && row->removeHasLinks) { + } else if (row->filter.hasMyLinks()) { controller->show(Ui::MakeConfirmBox({ .text = { tr::lng_filters_delete_sure(tr::now) }, .confirmed = crl::guard(button, [=](Fn close) { @@ -430,12 +429,10 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { ) | ranges::views::transform([=](const MTPPeer &peer) { return session->data().peer(peerFromMTP(peer)); }) | ranges::to_vector; - row->removeHasLinks = true; // #TODO filters markForRemoval(button); })).fail(crl::guard(button, [=] { const auto row = find(button); row->removePeersRequestId = -1; - row->removeHasLinks = false; markForRemoval(button); })).send(); } else {