From 739123dedc6b05ff311882cea568b9c28a43da93 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 6 May 2022 16:46:43 +0400 Subject: [PATCH] Implement simple premium limits boxes. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 54 +- Telegram/SourceFiles/api/api_chat_invite.cpp | 9 +- Telegram/SourceFiles/apiwrap.cpp | 10 +- .../SourceFiles/boxes/add_contact_box.cpp | 3 +- .../SourceFiles/boxes/premium_limits_box.cpp | 524 ++++++++++++++++++ .../SourceFiles/boxes/premium_limits_box.h | 30 + .../polls/info_polls_results_inner_widget.cpp | 63 +-- .../ui/controls/peer_list_dummy.cpp | 60 ++ .../SourceFiles/ui/controls/peer_list_dummy.h | 30 + Telegram/cmake/td_ui.cmake | 2 + 11 files changed, 716 insertions(+), 71 deletions(-) create mode 100644 Telegram/SourceFiles/boxes/premium_limits_box.cpp create mode 100644 Telegram/SourceFiles/boxes/premium_limits_box.h create mode 100644 Telegram/SourceFiles/ui/controls/peer_list_dummy.cpp create mode 100644 Telegram/SourceFiles/ui/controls/peer_list_dummy.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 3be5f9145..d66ff8495 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -256,6 +256,8 @@ PRIVATE boxes/phone_banned_box.h boxes/pin_messages_box.cpp boxes/pin_messages_box.h + boxes/premium_limits_box.cpp + boxes/premium_limits_box.h boxes/reactions_settings_box.cpp boxes/reactions_settings_box.h boxes/report_messages_box.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index bd5eef6f4..3ca197ddd 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -164,11 +164,61 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_scam_badge" = "SCAM"; "lng_fake_badge" = "FAKE"; +"lng_channels_limit_title" = "Too Many Communities"; +"lng_channels_limit1#one" = "You are a member of **{count}** groups and channels."; +"lng_channels_limit1#other" = "You are a member of **{count}** groups and channels."; +"lng_channels_limit2#one" = "Please leave some before joining a new one - or upgrade to **Telegram Premium** to doulbe the limit to **{count}** groups and channels."; +"lng_channels_limit2#other" = "Please leave some before joining a new one - or upgrade to **Telegram Premium** to doulbe the limit to **{count}** groups and channels."; +"lng_channels_limit2_final" = "Please leave some before joining a new one."; +"lng_channels_leave_title" = "Least active communities"; +"lng_channels_leave_status" = "{type}, inactive {time}"; +"lng_channels_leave#one" = "Leave {count} community"; +"lng_channels_leave#other" = "Leave {count} communities"; +"lng_channels_leave_done" = "You've left the selected communities."; + +"lng_links_limit_title" = "Too Many Public Links"; +"lng_links_limit1#one" = "You have reserved **{count}** public link."; +"lng_links_limit1#other" = "You have reserved **{count}** public links."; +"lng_links_limit2#one" = "Try revoking the link from an older group or channel, or upgrade to **Telegram Premium** to double the limit to **{count}** public link."; +"lng_links_limit2#other" = "Try revoking the link from an older group or channel, or upgrade to **Telegram Premium** to double the limit to **{count}** public links."; +"lng_links_limit2_final" = "Try revoking the link from an older group or channel"; +"lng_links_revoke_title" = "Your public communities"; + +"lng_filter_chats_limit_title" = "Limit Reached"; +"lng_filter_chats_limit1#one" = "Sorry, you can't add more than **{count}** chat to a folder."; +"lng_filter_chats_limit1#other" = "Sorry, you can't add more than **{count}** chats to a folder."; +"lng_filter_chats_limit2#one" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**."; +"lng_filter_chats_limit2#other" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**."; + +"lng_filters_limit_title" = "Limit Reached"; +"lng_filters_limit1#one" = "You have reached the limit of **{count}** folder."; +"lng_filters_limit1#other" = "You have reached the limit of **{count}** folders."; +"lng_filters_limit2#one" = "You can double the limit to **{count}** folder by subscribing to **Telegram Premium**."; +"lng_filters_limit2#other" = "You can double the limit to **{count}** folders by subscribing to **Telegram Premium**."; + +"lng_filter_pin_limit_title" = "Limit Reached"; +"lng_filter_pin_limit1#one" = "Sorry, you can't pin more than **{count}** chat to the top."; +"lng_filter_pin_limit1#other" = "Sorry, you can't pin more than **{count}** chats to the top."; +"lng_filter_pin_limit2#one" = "Unpin some of the currently pinned ones or subscribe to **Telegram Premium** to double the limit to **{count}** chat."; +"lng_filter_pin_limit2#other" = "Unpin some of the currently pinned ones or subscribe to **Telegram Premium** to double the limit to **{count}** chats."; + +"lng_fave_sticker_limit_title#one" = "The Limit of {count} Stickers Reached"; +"lng_fave_sticker_limit_title#other" = "The Limit of {count} Stickers Reached"; +"lng_fave_sticker_limit_more#one" = "An older sticker was replaced with this one. You can {link} to {count} sticker."; +"lng_fave_sticker_limit_more#other" = "An older sticker was replaced with this one. You can {link} to {count} stickers."; +"lng_fave_sticker_limit_link" = "increase the limit"; + +"lng_saved_gif_limit_title#one" = "The Limit of {count} GIF Reached"; +"lng_saved_gif_limit_title#other" = "The Limit of {count} GIFs Reached"; +"lng_saved_gif_limit_more#one" = "An older GIF was replaced with this one. You can {link} to {count} GIF."; +"lng_saved_gif_limit_more#other" = "An older GIF was replaced with this one. You can {link} to {count} GIFs."; +"lng_saved_gif_limit_link" = "increase the limit"; + +"lng_limits_increase" = "Increase Limit"; + "lng_flood_error" = "Too many tries. Please try again later."; "lng_gif_error" = "An error has occurred while reading GIF animation :("; "lng_edit_error" = "You cannot edit this message"; -"lng_join_channel_error" = "Sorry, you have joined too many channels and supergroups. Please leave some before joining this one."; -"lng_migrate_error" = "This action will convert the group to a supergroup. Unfortunately, you are a member of too many supergroups and channels. Please leave some of the channels or groups you don't need before proceeding."; "lng_error_phone_flood" = "Sorry, you have deleted and re-created your account too many times recently. Please wait for a few days before signing up again."; "lng_error_start_minimized_passcoded" = "You have set a local passcode, so Telegram Desktop can't be launched minimised; it will ask you to enter your passcode before it can start working."; "lng_error_pinned_max#one" = "Sorry, you can pin no more than {count} chat to the top."; diff --git a/Telegram/SourceFiles/api/api_chat_invite.cpp b/Telegram/SourceFiles/api/api_chat_invite.cpp index f2ec67629..e8dae68e8 100644 --- a/Telegram/SourceFiles/api/api_chat_invite.cpp +++ b/Telegram/SourceFiles/api/api_chat_invite.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/boxes/confirm_box.h" #include "ui/toasts/common_toasts.h" #include "boxes/abstract_box.h" +#include "boxes/premium_limits_box.h" #include "styles/style_boxes.h" #include "styles/style_layers.h" @@ -70,12 +71,16 @@ void SubmitChatInvite( "(ApiWrap::importChatInvite)").arg(result.type())); }); }).fail([=](const MTP::Error &error) { + const auto &type = error.type(); + const auto strongController = weak.get(); if (!strongController) { return; + } else if (type == u"CHANNELS_TOO_MUCH"_q) { + strongController->show( + Box(ChannelsLimitBox, &strongController->session())); } - const auto &type = error.type(); strongController->hideLayer(); Ui::ShowMultilineToast({ .parentOverride = Window::Show(strongController).toastParent(), @@ -84,8 +89,6 @@ void SubmitChatInvite( return isGroup ? tr::lng_group_request_sent(tr::now) : tr::lng_group_request_sent_channel(tr::now); - } else if (type == u"CHANNELS_TOO_MUCH"_q) { - return tr::lng_join_channel_error(tr::now); } else if (type == u"USERS_TOO_MUCH"_q) { return tr::lng_group_invite_no_room(tr::now); } else { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 6e464eed1..5cc2978df 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -70,6 +70,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/boxes/confirm_box.h" #include "boxes/stickers_box.h" #include "boxes/sticker_set_box.h" +#include "boxes/premium_limits_box.h" #include "window/notifications_manager.h" #include "window/window_lock_widgets.h" #include "window/window_session_controller.h" @@ -1229,7 +1230,7 @@ void ApiWrap::migrateDone( void ApiWrap::migrateFail(not_null peer, const QString &error) { if (error == u"CHANNELS_TOO_MUCH"_q) { - Ui::show(Ui::MakeInformBox(tr::lng_migrate_error())); + Ui::show(Box(ChannelsLimitBox, _session)); } if (auto handlers = _migrateCallbacks.take(peer)) { for (auto &handler : *handlers) { @@ -1645,6 +1646,9 @@ void ApiWrap::saveStickerSets( } void ApiWrap::joinChannel(not_null channel) { + Ui::show(Box(ChannelsLimitBox, _session)); + AssertIsDebug(); + return; if (channel->amIn()) { session().changes().peerUpdated( channel, @@ -1660,6 +1664,8 @@ void ApiWrap::joinChannel(not_null channel) { if (type == qstr("CHANNEL_PRIVATE") && channel->invitePeekExpires()) { channel->privateErrorReceived(); + } else if (type == qstr("CHANNELS_TOO_MUCH")) { + Ui::show(Box(ChannelsLimitBox, _session)); } else { const auto text = [&] { if (type == qstr("INVITE_REQUEST_SENT")) { @@ -1672,8 +1678,6 @@ void ApiWrap::joinChannel(not_null channel) { return channel->isMegagroup() ? tr::lng_group_not_accessible(tr::now) : tr::lng_channel_not_accessible(tr::now); - } else if (type == qstr("CHANNELS_TOO_MUCH")) { - return tr::lng_join_channel_error(tr::now); } else if (type == qstr("USERS_TOO_MUCH")) { return tr::lng_group_full(tr::now); } diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index f9727afd7..98099b526 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/random.h" #include "ui/boxes/confirm_box.h" #include "boxes/peer_list_controllers.h" +#include "boxes/premium_limits_box.h" #include "boxes/peers/add_participants_box.h" #include "boxes/peers/edit_peer_common.h" #include "boxes/peers/edit_participant_box.h" @@ -782,7 +783,7 @@ void GroupInfoBox::createChannel( Ui::LayerOption::CloseOther); } else if (type == u"CHANNELS_TOO_MUCH"_q) { controller->show( - Ui::MakeInformBox(tr::lng_cant_do_this()), + Box(ChannelsLimitBox, &controller->session()), Ui::LayerOption::CloseOther); // TODO } }).send(); diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.cpp b/Telegram/SourceFiles/boxes/premium_limits_box.cpp new file mode 100644 index 000000000..9fe4ad0ab --- /dev/null +++ b/Telegram/SourceFiles/boxes/premium_limits_box.cpp @@ -0,0 +1,524 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "boxes/premium_limits_box.h" + +#include "ui/controls/peer_list_dummy.h" +#include "ui/widgets/buttons.h" +#include "ui/wrap/padding_wrap.h" +#include "ui/text/text_utilities.h" +#include "ui/toasts/common_toasts.h" +#include "main/main_session.h" +#include "main/main_account.h" +#include "main/main_app_config.h" +#include "boxes/peer_list_controllers.h" +#include "data/data_user.h" +#include "data/data_session.h" +#include "lang/lang_keys.h" +#include "base/unixtime.h" +#include "apiwrap.h" +#include "styles/style_boxes.h" +#include "styles/style_layers.h" + +namespace { + +class InactiveController final : public PeerListController { +public: + explicit InactiveController(not_null session); + ~InactiveController(); + + Main::Session &session() const override; + void prepare() override; + void rowClicked(not_null row) override; + +private: + void appendRow(not_null peer, TimeId date); + [[nodiscard]] std::unique_ptr createRow( + not_null peer, + TimeId date) const; + + const not_null _session; + mtpRequestId _requestId = 0; + +}; + +class InactiveDelegate final : public PeerListContentDelegate { +public: + void peerListSetTitle(rpl::producer title) override; + void peerListSetAdditionalTitle(rpl::producer title) override; + bool peerListIsRowChecked(not_null row) override; + int peerListSelectedRowsCount() override; + void peerListScrollToTop() override; + void peerListAddSelectedPeerInBunch( + not_null peer) override; + void peerListAddSelectedRowInBunch( + not_null row) override; + void peerListFinishSelectedRowsBunch() override; + void peerListSetDescription( + object_ptr description) override; + void peerListShowBox( + object_ptr content, + Ui::LayerOptions options = Ui::LayerOption::KeepOther) override; + void peerListHideLayer() override; + not_null peerListToastParent() override; + void peerListSetRowChecked( + not_null row, + bool checked) override; + + [[nodiscard]] rpl::producer selectedCountChanges() const; + [[nodiscard]] const base::flat_set &selected() const; + +private: + base::flat_set _selectedIds; + rpl::event_stream _selectedCountChanges; + +}; + +void InactiveDelegate::peerListSetTitle(rpl::producer title) { +} + +void InactiveDelegate::peerListSetAdditionalTitle( + rpl::producer title) { +} + +bool InactiveDelegate::peerListIsRowChecked(not_null row) { + return _selectedIds.contains(row->id()); +} + +int InactiveDelegate::peerListSelectedRowsCount() { + return int(_selectedIds.size()); +} + +void InactiveDelegate::peerListScrollToTop() { +} + +void InactiveDelegate::peerListAddSelectedPeerInBunch( + not_null peer) { + _selectedIds.emplace(PeerListRowId(peer->id.value)); + _selectedCountChanges.fire(int(_selectedIds.size())); +} + +void InactiveDelegate::peerListAddSelectedRowInBunch( + not_null row) { + _selectedIds.emplace(row->id()); + _selectedCountChanges.fire(int(_selectedIds.size())); +} + +void InactiveDelegate::peerListSetRowChecked( + not_null row, + bool checked) { + if (checked) { + _selectedIds.emplace(row->id()); + } else { + _selectedIds.remove(row->id()); + } + _selectedCountChanges.fire(int(_selectedIds.size())); + PeerListContentDelegate::peerListSetRowChecked(row, checked); +} + +void InactiveDelegate::peerListFinishSelectedRowsBunch() { +} + +void InactiveDelegate::peerListSetDescription( + object_ptr description) { + description.destroy(); +} + +void InactiveDelegate::peerListShowBox( + object_ptr content, + Ui::LayerOptions options) { +} + +void InactiveDelegate::peerListHideLayer() { +} + +not_null InactiveDelegate::peerListToastParent() { + Unexpected("...InactiveDelegate::peerListToastParent"); +} + +rpl::producer InactiveDelegate::selectedCountChanges() const { + return _selectedCountChanges.events(); +} + +const base::flat_set &InactiveDelegate::selected() const { + return _selectedIds; +} + + +InactiveController::InactiveController(not_null session) +: _session(session) { +} + +InactiveController::~InactiveController() { + if (_requestId) { + _session->api().request(_requestId).cancel(); + } +} + +Main::Session &InactiveController::session() const { + return *_session; +} + +void InactiveController::prepare() { + delegate()->peerListSetTitle(tr::lng_blocked_list_title()); + setDescriptionText(tr::lng_contacts_loading(tr::now)); + delegate()->peerListRefreshRows(); + + _requestId = _session->api().request(MTPchannels_GetInactiveChannels( + )).done([=](const MTPmessages_InactiveChats &result) { + _requestId = 0; + result.match([&](const MTPDmessages_inactiveChats &data) { + _session->data().processUsers(data.vusers()); + const auto &list = data.vchats().v; + const auto &dates = data.vdates().v; + for (auto i = 0, count = int(list.size()); i != count; ++i) { + const auto peer = _session->data().processChat(list[i]); + const auto date = (i < dates.size()) ? dates[i].v : TimeId(); + appendRow(peer, date); + } + delegate()->peerListRefreshRows(); + }); + }).send(); +} + +void InactiveController::rowClicked(not_null row) { + delegate()->peerListSetRowChecked(row, !row->checked()); +} + +void InactiveController::appendRow( + not_null participant, + TimeId date) { + if (!delegate()->peerListFindRow(participant->id.value)) { + delegate()->peerListAppendRow(createRow(participant, date)); + } +} + +std::unique_ptr InactiveController::createRow( + not_null peer, + TimeId date) const { + auto result = std::make_unique(peer); + const auto active = base::unixtime::parse(date).date(); + const auto now = QDate::currentDate(); + const auto time = [&] { + const auto days = active.daysTo(now); + if (now < active) { + return QString(); + } else if (active == now) { + const auto unixtime = base::unixtime::now(); + const auto delta = int64(unixtime) - int64(date); + if (delta <= 0) { + return QString(); + } else if (delta >= 3600) { + return tr::lng_hours(tr::now, lt_count, delta / 3600); + } else if (delta >= 60) { + return tr::lng_minutes(tr::now, lt_count, delta / 60); + } else { + return tr::lng_seconds(tr::now, lt_count, delta); + } + } else if (days >= 365) { + return tr::lng_years(tr::now, lt_count, days / 365); + } else if (days >= 31) { + return tr::lng_months(tr::now, lt_count, days / 31); + } else if (days >= 7) { + return tr::lng_weeks(tr::now, lt_count, days / 7); + } else { + return tr::lng_days(tr::now, lt_count, days); + } + }(); + result->setCustomStatus(tr::lng_channels_leave_status( + tr::now, + lt_type, + (peer->isBroadcast() + ? tr::lng_channel_status(tr::now) + : tr::lng_group_status(tr::now)), + lt_time, + time)); + return result; +} + +[[nodiscard]] float64 Limit( + not_null session, + const QString &key, + double fallback) { + return session->account().appConfig().get(key, fallback); +} + +void SimpleLimitBox( + not_null box, + not_null session, + rpl::producer title, + rpl::producer text, + bool premium) { + box->setWidth(st::boxWideWidth); + + const auto top = box->setPinnedToTopContent( + object_ptr(box)); + top->add( + object_ptr>( + box, + object_ptr( + box, + std::move(title), + st::changePhoneTitle)), + st::changePhoneTitlePadding); + + top->add( + object_ptr>( + box, + object_ptr( + box, + std::move(text), + st::changePhoneDescription)), + st::changePhoneDescriptionPadding); + + if (premium) { + box->addButton(tr::lng_box_ok(), [=] { + box->closeBox(); + }); + } else { + box->addButton(tr::lng_limits_increase(), [=] { + Ui::ShowMultilineToast({ + .text = { u"Premium!"_q }, + }); + }); + } +} + +} // namespace + +void ChannelsLimitBox( + not_null box, + not_null session) { + const auto premium = session->user()->isPremium(); + + auto text = rpl::combine( + tr::lng_channels_limit1( + lt_count, + rpl::single(Limit( + session, + (premium + ? "channels_limit_premium" + : "channels_limit_default"), + premium ? 1000 : 500)), + Ui::Text::RichLangValue), + (premium + ? tr::lng_channels_limit2_final(Ui::Text::RichLangValue) + : tr::lng_channels_limit2( + lt_count, + rpl::single(Limit(session, "channels_limit_premium", 1000)), + Ui::Text::RichLangValue)) + ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) { + return a.append(QChar(' ')).append(std::move(b)); + }); + + SimpleLimitBox( + box, + session, + tr::lng_channels_limit_title(), + std::move(text), + premium); + + const auto delegate = box->lifetime().make_state(); + const auto controller = box->lifetime().make_state( + session); + + const auto content = box->addRow( + object_ptr(box, controller), + {}); + delegate->setContent(content); + controller->setDelegate(delegate); + + const auto count = 50; + const auto placeholder = box->addRow( + object_ptr(box, count, st::defaultPeerList), + {}); + + using namespace rpl::mappers; + content->heightValue( + ) | rpl::filter(_1 > 0) | rpl::start_with_next([=] { + delete placeholder; + }, placeholder->lifetime()); + + delegate->selectedCountChanges( + ) | rpl::start_with_next([=](int count) { + const auto leave = [=](const base::flat_set &ids) { + for (const auto rowId : ids) { + const auto id = peerToChannel(PeerId(rowId)); + if (const auto channel = session->data().channelLoaded(id)) { + session->api().leaveChannel(channel); + } + } + Ui::ShowMultilineToast({ + .text = { tr::lng_channels_leave_done(tr::now) }, + }); + box->closeBox(); + }; + box->clearButtons(); + if (count) { + box->addButton( + tr::lng_channels_leave(lt_count, rpl::single(count * 1.)), + [=] { leave(delegate->selected()); }); + } else if (premium) { + box->addButton(tr::lng_box_ok(), [=] { + box->closeBox(); + }); + } else { + box->addButton(tr::lng_limits_increase(), [=] { + Ui::ShowMultilineToast({ + .text = { u"Premium!"_q }, + }); + }); + } + }, box->lifetime()); +} + +void PublicLinksLimitBox( + not_null box, + not_null session) { + const auto premium = session->user()->isPremium(); + + auto text = rpl::combine( + tr::lng_links_limit1( + lt_count, + rpl::single(Limit( + session, + (premium + ? "channels_public_limit_premium" + : "channels_public_limit_default"), + premium ? 20 : 10)), + Ui::Text::RichLangValue), + (premium + ? tr::lng_links_limit2_final(Ui::Text::RichLangValue) + : tr::lng_links_limit2( + lt_count, + rpl::single(Limit( + session, + "channels_public_limit_premium", + 20)), + Ui::Text::RichLangValue)) + ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) { + return a.append(QChar(' ')).append(std::move(b)); + }); + + SimpleLimitBox( + box, + session, + tr::lng_links_limit_title(), + std::move(text), + premium); +} + +void FilterChatsLimitBox( + not_null box, + not_null session) { + const auto premium = session->user()->isPremium(); + + auto text = rpl::combine( + tr::lng_filter_chats_limit1( + lt_count, + rpl::single( + Limit( + session, + (premium + ? "dialog_filters_chats_limit_premium" + : "dialog_filters_chats_limit_default"), + premium ? 200 : 100)), + Ui::Text::RichLangValue), + (premium + ? rpl::single(TextWithEntities()) + : tr::lng_filter_chats_limit2( + lt_count, + rpl::single(Limit( + session, + "dialog_filters_chats_limit_premium", + 200)), + 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_chats_limit_title(), + std::move(text), + premium); +} + +void FiltersLimitBox( + not_null box, + not_null session) { + const auto premium = session->user()->isPremium(); + + auto text = rpl::combine( + tr::lng_filters_limit1( + lt_count, + rpl::single(Limit( + session, + (premium + ? "dialog_filters_limit_premium" + : "dialog_filters_limit_default"), + premium ? 20 : 10)), + Ui::Text::RichLangValue), + (premium + ? rpl::single(TextWithEntities()) + : tr::lng_filters_limit2( + lt_count, + rpl::single( + Limit(session, "dialog_filters_limit_premium", 20)), + 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_filters_limit_title(), + std::move(text), + premium); +} + +void FilterPinsLimitBox( + not_null box, + not_null session) { + const auto premium = session->user()->isPremium(); + + auto text = rpl::combine( + tr::lng_filter_pin_limit1( + lt_count, + rpl::single(Limit( + session, + (premium + ? "dialog_filters_pinned_limit_premium" + : "dialog_filters_pinned_limit_default"), + premium ? 200 : 100)), + Ui::Text::RichLangValue), + (premium + ? rpl::single(TextWithEntities()) + : tr::lng_filter_pin_limit2( + lt_count, + rpl::single(Limit( + session, + "dialog_filters_pinned_limit_premium", + 200)), + 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_pin_limit_title(), + std::move(text), + premium); +} diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.h b/Telegram/SourceFiles/boxes/premium_limits_box.h new file mode 100644 index 000000000..423481a09 --- /dev/null +++ b/Telegram/SourceFiles/boxes/premium_limits_box.h @@ -0,0 +1,30 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "ui/layers/generic_box.h" + +namespace Main { +class Session; +} // namespace Main + +void ChannelsLimitBox( + not_null box, + not_null session); +void PublicLinksLimitBox( + not_null box, + not_null session); +void FilterChatsLimitBox( + not_null box, + not_null session); +void FiltersLimitBox( + not_null box, + not_null session); +void FilterPinsLimitBox( + not_null box, + not_null session); diff --git a/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp b/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp index 6a9df2132..2b8248e13 100644 --- a/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp +++ b/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer.h" #include "data/data_user.h" #include "data/data_session.h" +#include "ui/controls/peer_list_dummy.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/wrap/vertical_layout.h" @@ -36,21 +37,6 @@ constexpr auto kFirstPage = 15; constexpr auto kPerPage = 50; constexpr auto kLeavePreloaded = 5; -class PeerListDummy final : public Ui::RpWidget { -public: - PeerListDummy(QWidget *parent, int count, const style::PeerList &st); - -protected: - void paintEvent(QPaintEvent *e) override; - -private: - const style::PeerList &_st; - int _count = 0; - - std::vector _animations; - -}; - class ListDelegate final : public PeerListContentDelegate { public: void peerListSetTitle(rpl::producer title) override; @@ -73,53 +59,6 @@ public: }; -PeerListDummy::PeerListDummy( - QWidget *parent, - int count, - const style::PeerList &st) -: _st(st) -, _count(count) { - resize(width(), _count * _st.item.height); -} - -void PeerListDummy::paintEvent(QPaintEvent *e) { - QPainter p(this); - - PainterHighQualityEnabler hq(p); - - const auto fill = e->rect(); - const auto bottom = fill.top() + fill.height(); - const auto from = floorclamp(fill.top(), _st.item.height, 0, _count); - const auto till = ceilclamp(bottom, _st.item.height, 0, _count); - p.translate(0, _st.item.height * from); - p.setPen(Qt::NoPen); - for (auto i = from; i != till; ++i) { - p.setBrush(st::windowBgOver); - p.drawEllipse( - _st.item.photoPosition.x(), - _st.item.photoPosition.y(), - _st.item.photoSize, - _st.item.photoSize); - - const auto small = int(1.5 * _st.item.photoSize); - const auto large = 2 * small; - const auto second = (i % 2) ? large : small; - const auto height = _st.item.nameStyle.font->height / 2; - const auto radius = height / 2; - const auto left = _st.item.namePosition.x(); - const auto top = _st.item.namePosition.y() - + (_st.item.nameStyle.font->height - height) / 2; - const auto skip = _st.item.namePosition.x() - - _st.item.photoPosition.x() - - _st.item.photoSize; - const auto next = left + small + skip; - p.drawRoundedRect(left, top, small, height, radius, radius); - p.drawRoundedRect(next, top, second, height, radius, radius); - - p.translate(0, _st.item.height); - } -} - void ListDelegate::peerListSetTitle(rpl::producer title) { } diff --git a/Telegram/SourceFiles/ui/controls/peer_list_dummy.cpp b/Telegram/SourceFiles/ui/controls/peer_list_dummy.cpp new file mode 100644 index 000000000..e4a3e2575 --- /dev/null +++ b/Telegram/SourceFiles/ui/controls/peer_list_dummy.cpp @@ -0,0 +1,60 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "ui/controls/peer_list_dummy.h" + +#include "styles/style_widgets.h" + +PeerListDummy::PeerListDummy( + QWidget *parent, + int count, + const style::PeerList &st) +: _st(st) +, _count(count) { + resize(width(), _count * _st.item.height); +} + +void PeerListDummy::paintEvent(QPaintEvent *e) { + QPainter p(this); + + PainterHighQualityEnabler hq(p); + + const auto fill = e->rect(); + const auto bottom = fill.top() + fill.height(); + const auto from = std::clamp(fill.top() / _st.item.height, 0, _count); + const auto till = std::clamp( + (bottom + _st.item.height - 1) / _st.item.height, + 0, + _count); + p.translate(0, _st.item.height * from); + p.setPen(Qt::NoPen); + for (auto i = from; i != till; ++i) { + p.setBrush(st::windowBgOver); + p.drawEllipse( + _st.item.photoPosition.x(), + _st.item.photoPosition.y(), + _st.item.photoSize, + _st.item.photoSize); + + const auto small = int(1.5 * _st.item.photoSize); + const auto large = 2 * small; + const auto second = (i % 2) ? large : small; + const auto height = _st.item.nameStyle.font->height / 2; + const auto radius = height / 2; + const auto left = _st.item.namePosition.x(); + const auto top = _st.item.namePosition.y() + + (_st.item.nameStyle.font->height - height) / 2; + const auto skip = _st.item.namePosition.x() + - _st.item.photoPosition.x() + - _st.item.photoSize; + const auto next = left + small + skip; + p.drawRoundedRect(left, top, small, height, radius, radius); + p.drawRoundedRect(next, top, second, height, radius, radius); + + p.translate(0, _st.item.height); + } +} diff --git a/Telegram/SourceFiles/ui/controls/peer_list_dummy.h b/Telegram/SourceFiles/ui/controls/peer_list_dummy.h new file mode 100644 index 000000000..fec54223d --- /dev/null +++ b/Telegram/SourceFiles/ui/controls/peer_list_dummy.h @@ -0,0 +1,30 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "ui/rp_widget.h" +#include "ui/effects/animations.h" + +namespace style { +struct PeerList; +} // namespace style + +class PeerListDummy final : public Ui::RpWidget { +public: + PeerListDummy(QWidget *parent, int count, const style::PeerList &st); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + const style::PeerList &_st; + int _count = 0; + + std::vector _animations; + +}; diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 25f10facd..e9c21a4a7 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -218,6 +218,8 @@ PRIVATE ui/controls/invite_link_buttons.h ui/controls/invite_link_label.cpp ui/controls/invite_link_label.h + ui/controls/peer_list_dummy.cpp + ui/controls/peer_list_dummy.h ui/controls/send_as_button.cpp ui/controls/send_as_button.h ui/controls/send_button.cpp