| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195 |
- /*
- 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/boxes/confirm_box.h"
- #include "ui/controls/peer_list_dummy.h"
- #include "ui/effects/premium_bubble.h"
- #include "ui/effects/premium_graphics.h"
- #include "ui/widgets/checkbox.h"
- #include "ui/wrap/padding_wrap.h"
- #include "ui/text/text_utilities.h"
- #include "ui/vertical_list.h"
- #include "main/main_session.h"
- #include "main/main_account.h"
- #include "main/main_domain.h"
- #include "boxes/peer_list_controllers.h"
- #include "boxes/peers/prepare_short_info_box.h" // PrepareShortInfoBox
- #include "window/window_session_controller.h"
- #include "data/data_chat_filters.h"
- #include "data/data_user.h"
- #include "data/data_channel.h"
- #include "data/data_forum.h"
- #include "data/data_saved_messages.h"
- #include "data/data_session.h"
- #include "data/data_folder.h"
- #include "data/data_premium_limits.h"
- #include "lang/lang_keys.h"
- #include "settings/settings_premium.h" // ShowPremium.
- #include "base/unixtime.h"
- #include "apiwrap.h"
- #include "styles/style_premium.h"
- #include "styles/style_boxes.h"
- #include "styles/style_layers.h"
- #include "styles/style_info.h"
- #include "styles/style_settings.h"
- namespace {
- struct InfographicDescriptor {
- float64 defaultLimit = 0;
- float64 current = 0;
- float64 premiumLimit = 0;
- const style::icon *icon;
- std::optional<tr::phrase<lngtag_count>> phrase;
- bool complexRatio = false;
- };
- void AddSubtitle(
- not_null<Ui::VerticalLayout*> container,
- rpl::producer<QString> text) {
- const auto &subtitlePadding = st::settingsButton.padding;
- Ui::AddSubsectionTitle(
- container,
- std::move(text),
- { 0, subtitlePadding.top(), 0, -subtitlePadding.bottom() });
- }
- class InactiveController final : public PeerListController {
- public:
- explicit InactiveController(not_null<Main::Session*> session);
- ~InactiveController();
- Main::Session &session() const override;
- void prepare() override;
- void rowClicked(not_null<PeerListRow*> row) override;
- [[nodiscard]] rpl::producer<int> countValue() const;
- private:
- void appendRow(not_null<PeerData*> peer, TimeId date);
- [[nodiscard]] std::unique_ptr<PeerListRow> createRow(
- not_null<PeerData*> peer,
- TimeId date) const;
- const not_null<Main::Session*> _session;
- rpl::variable<int> _count;
- mtpRequestId _requestId = 0;
- };
- class PublicsController final : public PeerListController {
- public:
- PublicsController(
- not_null<Window::SessionNavigation*> navigation,
- Fn<void()> closeBox);
- ~PublicsController();
- Main::Session &session() const override;
- void prepare() override;
- void rowClicked(not_null<PeerListRow*> row) override;
- void rowRightActionClicked(not_null<PeerListRow*> row) override;
- [[nodiscard]] rpl::producer<int> countValue() const;
- private:
- void appendRow(not_null<PeerData*> peer);
- [[nodiscard]] std::unique_ptr<PeerListRow> createRow(
- not_null<PeerData*> peer) const;
- const not_null<Window::SessionNavigation*> _navigation;
- rpl::variable<int> _count;
- Fn<void()> _closeBox;
- mtpRequestId _requestId = 0;
- };
- class InactiveDelegate final : public PeerListContentDelegate {
- public:
- void peerListSetTitle(rpl::producer<QString> title) override;
- void peerListSetAdditionalTitle(rpl::producer<QString> title) override;
- bool peerListIsRowChecked(not_null<PeerListRow*> row) override;
- int peerListSelectedRowsCount() override;
- void peerListScrollToTop() override;
- void peerListAddSelectedPeerInBunch(
- not_null<PeerData*> peer) override;
- void peerListAddSelectedRowInBunch(
- not_null<PeerListRow*> row) override;
- void peerListFinishSelectedRowsBunch() override;
- void peerListSetDescription(
- object_ptr<Ui::FlatLabel> description) override;
- std::shared_ptr<Main::SessionShow> peerListUiShow() override;
- void peerListSetRowChecked(
- not_null<PeerListRow*> row,
- bool checked) override;
- [[nodiscard]] rpl::producer<int> selectedCountChanges() const;
- [[nodiscard]] const base::flat_set<PeerListRowId> &selected() const;
- private:
- base::flat_set<PeerListRowId> _selectedIds;
- rpl::event_stream<int> _selectedCountChanges;
- };
- [[nodiscard]] Ui::Premium::BubbleType ChooseBubbleType(bool premium) {
- return premium
- ? Ui::Premium::BubbleType::Premium
- : Ui::Premium::BubbleType::NoPremium;
- }
- void InactiveDelegate::peerListSetTitle(rpl::producer<QString> title) {
- }
- void InactiveDelegate::peerListSetAdditionalTitle(
- rpl::producer<QString> title) {
- }
- bool InactiveDelegate::peerListIsRowChecked(not_null<PeerListRow*> row) {
- return _selectedIds.contains(row->id());
- }
- int InactiveDelegate::peerListSelectedRowsCount() {
- return int(_selectedIds.size());
- }
- void InactiveDelegate::peerListScrollToTop() {
- }
- void InactiveDelegate::peerListAddSelectedPeerInBunch(
- not_null<PeerData*> peer) {
- _selectedIds.emplace(PeerListRowId(peer->id.value));
- _selectedCountChanges.fire(int(_selectedIds.size()));
- }
- void InactiveDelegate::peerListAddSelectedRowInBunch(
- not_null<PeerListRow*> row) {
- _selectedIds.emplace(row->id());
- _selectedCountChanges.fire(int(_selectedIds.size()));
- }
- void InactiveDelegate::peerListSetRowChecked(
- not_null<PeerListRow*> 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<Ui::FlatLabel> description) {
- description.destroy();
- }
- std::shared_ptr<Main::SessionShow> InactiveDelegate::peerListUiShow() {
- Unexpected("...InactiveDelegate::peerListUiShow");
- }
- rpl::producer<int> InactiveDelegate::selectedCountChanges() const {
- return _selectedCountChanges.events();
- }
- const base::flat_set<PeerListRowId> &InactiveDelegate::selected() const {
- return _selectedIds;
- }
- InactiveController::InactiveController(not_null<Main::Session*> session)
- : _session(session) {
- }
- InactiveController::~InactiveController() {
- if (_requestId) {
- _session->api().request(_requestId).cancel();
- }
- }
- Main::Session &InactiveController::session() const {
- return *_session;
- }
- void InactiveController::prepare() {
- _requestId = _session->api().request(MTPchannels_GetInactiveChannels(
- )).done([=](const MTPmessages_InactiveChats &result) {
- _requestId = 0;
- const auto &data = result.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();
- _count = delegate()->peerListFullRowsCount();
- }).send();
- }
- void InactiveController::rowClicked(not_null<PeerListRow*> row) {
- delegate()->peerListSetRowChecked(row, !row->checked());
- }
- rpl::producer<int> InactiveController::countValue() const {
- return _count.value();
- }
- void InactiveController::appendRow(
- not_null<PeerData*> participant,
- TimeId date) {
- if (!delegate()->peerListFindRow(participant->id.value)) {
- delegate()->peerListAppendRow(createRow(participant, date));
- }
- }
- std::unique_ptr<PeerListRow> InactiveController::createRow(
- not_null<PeerData*> peer,
- TimeId date) const {
- auto result = std::make_unique<PeerListRow>(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;
- }
- PublicsController::PublicsController(
- not_null<Window::SessionNavigation*> navigation,
- Fn<void()> closeBox)
- : _navigation(navigation)
- , _closeBox(std::move(closeBox)) {
- }
- PublicsController::~PublicsController() {
- if (_requestId) {
- _navigation->session().api().request(_requestId).cancel();
- }
- }
- Main::Session &PublicsController::session() const {
- return _navigation->session();
- }
- rpl::producer<int> PublicsController::countValue() const {
- return _count.value();
- }
- void PublicsController::prepare() {
- _requestId = _navigation->session().api().request(
- MTPchannels_GetAdminedPublicChannels(MTP_flags(0))
- ).done([=](const MTPmessages_Chats &result) {
- _requestId = 0;
- const auto &chats = result.match([](const auto &data) {
- return data.vchats().v;
- });
- auto &owner = _navigation->session().data();
- for (const auto &chat : chats) {
- if (const auto peer = owner.processChat(chat)) {
- if (!peer->isChannel() || peer->username().isEmpty()) {
- continue;
- }
- appendRow(peer);
- }
- delegate()->peerListRefreshRows();
- }
- _count = delegate()->peerListFullRowsCount();
- }).send();
- }
- void PublicsController::rowClicked(not_null<PeerListRow*> row) {
- _navigation->parentController()->show(
- PrepareShortInfoBox(row->peer(), _navigation));
- }
- void PublicsController::rowRightActionClicked(not_null<PeerListRow*> row) {
- const auto peer = row->peer();
- const auto textMethod = peer->isMegagroup()
- ? tr::lng_channels_too_much_public_revoke_confirm_group
- : tr::lng_channels_too_much_public_revoke_confirm_channel;
- const auto text = textMethod(
- tr::now,
- lt_link,
- peer->session().createInternalLink(peer->username()),
- lt_group,
- peer->name());
- const auto confirmText = tr::lng_channels_too_much_public_revoke(
- tr::now);
- const auto closeBox = _closeBox;
- const auto once = std::make_shared<bool>(false);
- auto callback = crl::guard(_navigation, [=](Fn<void()> close) {
- if (*once) {
- return;
- }
- *once = true;
- peer->session().api().request(MTPchannels_UpdateUsername(
- peer->asChannel()->inputChannel,
- MTP_string()
- )).done([=] {
- peer->session().api().request(MTPchannels_DeactivateAllUsernames(
- peer->asChannel()->inputChannel
- )).done([=] {
- closeBox();
- close();
- }).send();
- }).send();
- });
- _navigation->parentController()->show(
- Ui::MakeConfirmBox({
- .text = text,
- .confirmed = std::move(callback),
- .confirmText = confirmText,
- }));
- }
- void PublicsController::appendRow(not_null<PeerData*> participant) {
- if (!delegate()->peerListFindRow(participant->id.value)) {
- delegate()->peerListAppendRow(createRow(participant));
- }
- }
- std::unique_ptr<PeerListRow> PublicsController::createRow(
- not_null<PeerData*> peer) const {
- auto result = std::make_unique<PeerListRowWithLink>(peer);
- result->setActionLink(tr::lng_channels_too_much_public_revoke(tr::now));
- result->setCustomStatus(
- _navigation->session().createInternalLink(peer->username()));
- return result;
- }
- void SimpleLimitBox(
- not_null<Ui::GenericBox*> box,
- const style::PremiumLimits *stOverride,
- not_null<Main::Session*> session,
- bool premiumPossible,
- rpl::producer<QString> title,
- rpl::producer<TextWithEntities> text,
- const QString &refAddition,
- const InfographicDescriptor &descriptor,
- bool fixed = false) {
- const auto &st = stOverride ? *stOverride : st::defaultPremiumLimits;
- box->setWidth(st::boxWideWidth);
- const auto top = fixed
- ? box->setPinnedToTopContent(object_ptr<Ui::VerticalLayout>(box))
- : box->verticalLayout();
- Ui::AddSkip(top, st::premiumInfographicPadding.top());
- Ui::Premium::AddBubbleRow(
- top,
- st::defaultPremiumBubble,
- BoxShowFinishes(box),
- 0,
- descriptor.current,
- (descriptor.complexRatio
- ? descriptor.premiumLimit
- : 2 * descriptor.current),
- ChooseBubbleType(premiumPossible),
- descriptor.phrase,
- descriptor.icon);
- Ui::AddSkip(top, st::premiumLineTextSkip);
- if (premiumPossible) {
- Ui::Premium::AddLimitRow(
- top,
- st,
- descriptor.premiumLimit,
- descriptor.phrase,
- 0,
- (descriptor.complexRatio
- ? (float64(descriptor.current) / descriptor.premiumLimit)
- : Ui::Premium::kLimitRowRatio));
- Ui::AddSkip(top, st::premiumInfographicPadding.bottom());
- }
- box->setTitle(std::move(title));
- auto padding = st::boxPadding;
- padding.setTop(padding.bottom());
- top->add(
- object_ptr<Ui::FlatLabel>(
- box,
- std::move(text),
- st::aboutRevokePublicLabel),
- padding);
- if (session->premium() || !premiumPossible) {
- box->addButton(tr::lng_box_ok(), [=] {
- box->closeBox();
- });
- } else {
- box->addButton(tr::lng_limits_increase(), [=] {
- Settings::ShowPremium(session, LimitsPremiumRef(refAddition));
- });
- box->addButton(tr::lng_cancel(), [=] {
- box->closeBox();
- });
- }
- if (fixed) {
- Ui::AddSkip(top, st::settingsButton.padding.bottom());
- Ui::AddDivider(top);
- }
- }
- void SimpleLimitBox(
- not_null<Ui::GenericBox*> box,
- const style::PremiumLimits *stOverride,
- not_null<Main::Session*> session,
- rpl::producer<QString> title,
- rpl::producer<TextWithEntities> text,
- const QString &refAddition,
- const InfographicDescriptor &descriptor,
- bool fixed = false) {
- SimpleLimitBox(
- box,
- stOverride,
- session,
- session->premiumPossible(),
- std::move(title),
- std::move(text),
- refAddition,
- descriptor,
- fixed);
- }
- [[nodiscard]] int PinsCount(not_null<Dialogs::MainList*> list) {
- return list->pinned()->order().size();
- }
- void SimplePinsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- const QString &refAddition,
- float64 defaultLimit,
- float64 premiumLimit,
- float64 currentCount) {
- const auto premium = session->premium();
- const auto premiumPossible = session->premiumPossible();
- const auto current = std::clamp(currentCount, defaultLimit, premiumLimit);
- auto text = rpl::combine(
- tr::lng_filter_pin_limit1(
- lt_count,
- rpl::single(premium ? premiumLimit : defaultLimit),
- Ui::Text::RichLangValue),
- ((premium || !premiumPossible)
- ? rpl::single(TextWithEntities())
- : tr::lng_filter_pin_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,
- nullptr,
- session,
- tr::lng_filter_pin_limit_title(),
- std::move(text),
- refAddition,
- { defaultLimit, current, premiumLimit, &st::premiumIconPins });
- }
- } // namespace
- void ChannelsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session) {
- const auto premium = session->premium();
- const auto premiumPossible = session->premiumPossible();
- const auto limits = Data::PremiumLimits(session);
- const auto defaultLimit = float64(limits.channelsDefault());
- const auto premiumLimit = float64(limits.channelsPremium());
- const auto current = (premium ? premiumLimit : defaultLimit);
- auto text = rpl::combine(
- tr::lng_channels_limit1(
- lt_count,
- rpl::single(current),
- Ui::Text::RichLangValue),
- ((premium || !premiumPossible)
- ? tr::lng_channels_limit2_final(Ui::Text::RichLangValue)
- : tr::lng_channels_limit2(
- lt_count,
- rpl::single(premiumLimit),
- Ui::Text::RichLangValue))
- ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) {
- return a.append(QChar(' ')).append(std::move(b));
- });
- SimpleLimitBox(
- box,
- nullptr,
- session,
- tr::lng_channels_limit_title(),
- std::move(text),
- "channels",
- { defaultLimit, current, premiumLimit, &st::premiumIconGroups },
- true);
- AddSubtitle(box->verticalLayout(), tr::lng_channels_leave_title());
- const auto delegate = box->lifetime().make_state<InactiveDelegate>();
- const auto controller = box->lifetime().make_state<InactiveController>(
- session);
- const auto content = box->addRow(
- object_ptr<PeerListContent>(box, controller),
- {});
- delegate->setContent(content);
- controller->setDelegate(delegate);
- const auto count = 100;
- const auto placeholder = box->addRow(
- object_ptr<PeerListDummy>(box, count, st::defaultPeerList),
- {});
- using namespace rpl::mappers;
- controller->countValue(
- ) | 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<PeerListRowId> &ids) {
- for (const auto rowId : ids) {
- const auto id = peerToChannel(PeerId(rowId));
- if (const auto channel = session->data().channelLoaded(id)) {
- session->api().leaveChannel(channel);
- }
- }
- box->showToast(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(), [=] {
- Settings::ShowPremium(session, LimitsPremiumRef("channels"));
- });
- }
- }, box->lifetime());
- }
- void PublicLinksLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Window::SessionNavigation*> navigation,
- Fn<void()> retry) {
- const auto session = &navigation->session();
- const auto premium = session->premium();
- const auto premiumPossible = session->premiumPossible();
- const auto limits = Data::PremiumLimits(session);
- const auto defaultLimit = float64(limits.channelsPublicDefault());
- const auto premiumLimit = float64(limits.channelsPublicPremium());
- const auto current = (premium ? premiumLimit : defaultLimit);
- auto text = rpl::combine(
- tr::lng_links_limit1(
- lt_count,
- rpl::single(current),
- Ui::Text::RichLangValue),
- ((premium || !premiumPossible)
- ? tr::lng_links_limit2_final(Ui::Text::RichLangValue)
- : tr::lng_links_limit2(
- lt_count,
- rpl::single(premiumLimit),
- Ui::Text::RichLangValue))
- ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) {
- return a.append(QChar(' ')).append(std::move(b));
- });
- SimpleLimitBox(
- box,
- nullptr,
- session,
- tr::lng_links_limit_title(),
- std::move(text),
- "channels_public",
- { defaultLimit, current, premiumLimit, &st::premiumIconLinks },
- true);
- AddSubtitle(box->verticalLayout(), tr::lng_links_revoke_title());
- const auto delegate = box->lifetime().make_state<InactiveDelegate>();
- const auto controller = box->lifetime().make_state<PublicsController>(
- navigation,
- crl::guard(box, [=] { box->closeBox(); retry(); }));
- const auto content = box->addRow(
- object_ptr<PeerListContent>(box, controller),
- {});
- delegate->setContent(content);
- controller->setDelegate(delegate);
- const auto count = defaultLimit;
- const auto placeholder = box->addRow(
- object_ptr<PeerListDummy>(box, count, st::defaultPeerList),
- {});
- using namespace rpl::mappers;
- controller->countValue(
- ) | rpl::filter(_1 > 0) | rpl::start_with_next([=] {
- delete placeholder;
- }, placeholder->lifetime());
- }
- void FilterChatsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- int currentCount,
- bool include) {
- const auto premium = session->premium();
- const auto premiumPossible = session->premiumPossible();
- const auto limits = Data::PremiumLimits(session);
- const auto defaultLimit = float64(limits.dialogFiltersChatsDefault());
- const auto premiumLimit = float64(limits.dialogFiltersChatsPremium());
- const auto current = std::clamp(
- float64(currentCount),
- defaultLimit,
- premiumLimit);
- auto text = rpl::combine(
- (include
- ? tr::lng_filter_chats_limit1
- : tr::lng_filter_chats_exlude_limit1)(
- lt_count,
- rpl::single(premium ? premiumLimit : defaultLimit),
- Ui::Text::RichLangValue),
- ((premium || !premiumPossible)
- ? rpl::single(TextWithEntities())
- : tr::lng_filter_chats_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,
- nullptr,
- session,
- tr::lng_filter_chats_limit_title(),
- std::move(text),
- "dialog_filters_chats",
- { defaultLimit, current, premiumLimit, &st::premiumIconChats });
- }
- void FilterLinksLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> 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,
- nullptr,
- session,
- tr::lng_filter_links_limit_title(),
- std::move(text),
- "chatlist_invites",
- {
- defaultLimit,
- current,
- premiumLimit,
- &st::premiumIconChats,
- std::nullopt,
- /*true */}); // Don't use real ratio, "Free" doesn't fit.
- }
- void FiltersLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- std::optional<int> filtersCountOverride) {
- const auto premium = session->premium();
- const auto premiumPossible = session->premiumPossible();
- const auto limits = Data::PremiumLimits(session);
- const auto defaultLimit = float64(limits.dialogFiltersDefault());
- const auto premiumLimit = float64(limits.dialogFiltersPremium());
- const auto cloud = int(ranges::count_if(
- session->data().chatsFilters().list(),
- [](const Data::ChatFilter &f) { return f.id() != FilterId(); }));
- const auto current = float64(filtersCountOverride.value_or(cloud));
- auto text = rpl::combine(
- tr::lng_filters_limit1(
- lt_count,
- rpl::single(premium ? premiumLimit : defaultLimit),
- Ui::Text::RichLangValue),
- ((premium || !premiumPossible)
- ? rpl::single(TextWithEntities())
- : tr::lng_filters_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,
- nullptr,
- session,
- tr::lng_filters_limit_title(),
- std::move(text),
- "dialog_filters",
- { defaultLimit, current, premiumLimit, &st::premiumIconFolders });
- }
- void ShareableFiltersLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> 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,
- nullptr,
- session,
- tr::lng_filter_shared_limit_title(),
- std::move(text),
- "chatlists_joined",
- {
- defaultLimit,
- current,
- premiumLimit,
- &st::premiumIconFolders,
- std::nullopt,
- /*true*/ }); // Don't use real ratio, "Free" doesn't fit.
- }
- void FilterPinsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- FilterId filterId) {
- const auto limits = Data::PremiumLimits(session);
- SimplePinsLimitBox(
- box,
- session,
- "dialog_filters_pinned",
- limits.dialogFiltersChatsDefault(),
- limits.dialogFiltersChatsPremium(),
- PinsCount(session->data().chatsFilters().chatsList(filterId)));
- }
- void FolderPinsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session) {
- const auto limits = Data::PremiumLimits(session);
- SimplePinsLimitBox(
- box,
- session,
- "dialogs_folder_pinned",
- limits.dialogsFolderPinnedDefault(),
- limits.dialogsFolderPinnedPremium(),
- PinsCount(session->data().folder(Data::Folder::kId)->chatsList()));
- }
- void PinsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session) {
- const auto limits = Data::PremiumLimits(session);
- SimplePinsLimitBox(
- box,
- session,
- "dialog_pinned",
- limits.dialogsPinnedDefault(),
- limits.dialogsPinnedPremium(),
- PinsCount(session->data().chatsList()));
- }
- void SublistsPinsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session) {
- const auto limits = Data::PremiumLimits(session);
- SimplePinsLimitBox(
- box,
- session,
- "saved_dialog_pinned",
- limits.savedSublistsPinnedDefault(),
- limits.savedSublistsPinnedPremium(),
- PinsCount(session->data().savedMessages().chatsList()));
- }
- void ForumPinsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Data::Forum*> forum) {
- const auto current = forum->owner().pinnedChatsLimit(forum) * 1.;
- auto text = tr::lng_forum_pin_limit(
- lt_count,
- rpl::single(current),
- Ui::Text::RichLangValue);
- SimpleLimitBox(
- box,
- nullptr,
- &forum->session(),
- false,
- tr::lng_filter_pin_limit_title(),
- std::move(text),
- QString(),
- { current, current, current * 2, &st::premiumIconPins });
- }
- void CaptionLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- int remove,
- const style::PremiumLimits *stOverride) {
- const auto premium = session->premium();
- const auto premiumPossible = session->premiumPossible();
- const auto limits = Data::PremiumLimits(session);
- const auto defaultLimit = float64(limits.captionLengthDefault());
- const auto premiumLimit = float64(limits.captionLengthPremium());
- const auto currentLimit = premium ? premiumLimit : defaultLimit;
- const auto current = std::clamp(
- remove + currentLimit,
- defaultLimit,
- premiumLimit);
- auto text = rpl::combine(
- tr::lng_caption_limit1(
- lt_count,
- rpl::single(currentLimit),
- Ui::Text::RichLangValue),
- (!premiumPossible
- ? rpl::single(TextWithEntities())
- : tr::lng_caption_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,
- stOverride,
- session,
- tr::lng_caption_limit_title(),
- std::move(text),
- "caption_length",
- { defaultLimit, current, premiumLimit, &st::premiumIconChats });
- }
- void CaptionLimitReachedBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- int remove,
- const style::PremiumLimits *stOverride) {
- Ui::ConfirmBox(box, Ui::ConfirmBoxArgs{
- .text = tr::lng_caption_limit_reached(tr::now, lt_count, remove),
- .labelStyle = stOverride ? &stOverride->boxLabel : nullptr,
- .inform = true,
- });
- if (!session->premium()) {
- box->addLeftButton(tr::lng_limits_increase(), [=] {
- box->getDelegate()->showBox(
- Box(CaptionLimitBox, session, remove, stOverride),
- Ui::LayerOption::KeepOther,
- anim::type::normal);
- box->closeBox();
- });
- }
- }
- void FileSizeLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session,
- uint64 fileSizeBytes,
- const style::PremiumLimits *stOverride) {
- const auto limits = Data::PremiumLimits(session);
- const auto defaultLimit = float64(limits.uploadMaxDefault());
- const auto premiumLimit = float64(limits.uploadMaxPremium());
- const auto defaultGb = float64(int(defaultLimit + 999) / 2000);
- const auto premiumGb = float64(int(premiumLimit + 999) / 2000);
- const auto tooLarge = (fileSizeBytes > premiumLimit * 512ULL * 1024);
- const auto showLimit = tooLarge ? premiumGb : defaultGb;
- const auto premiumPossible = !tooLarge && session->premiumPossible();
- const auto current = (fileSizeBytes && premiumPossible)
- ? std::clamp(
- float64(((fileSizeBytes / uint64(1024 * 1024)) + 499) / 1000),
- defaultGb,
- premiumGb)
- : showLimit;
- const auto gb = [](int count) {
- return tr::lng_file_size_limit(tr::now, lt_count, count);
- };
- auto text = rpl::combine(
- tr::lng_file_size_limit1(
- lt_size,
- rpl::single(Ui::Text::Bold(gb(showLimit))),
- Ui::Text::RichLangValue),
- (!premiumPossible
- ? rpl::single(TextWithEntities())
- : tr::lng_file_size_limit2(
- lt_size,
- rpl::single(Ui::Text::Bold(gb(premiumGb))),
- Ui::Text::RichLangValue))
- ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) {
- return a.append(QChar(' ')).append(std::move(b));
- });
- SimpleLimitBox(
- box,
- stOverride,
- session,
- premiumPossible,
- tr::lng_file_size_limit_title(),
- std::move(text),
- "upload_max_fileparts",
- {
- defaultGb,
- current,
- (tooLarge ? showLimit * 2 : premiumGb),
- &st::premiumIconFiles,
- tr::lng_file_size_limit
- });
- }
- void AccountsLimitBox(
- not_null<Ui::GenericBox*> box,
- not_null<Main::Session*> session) {
- const auto defaultLimit = Main::Domain::kMaxAccounts;
- const auto premiumLimit = Main::Domain::kPremiumMaxAccounts;
- using Args = Ui::Premium::AccountsRowArgs;
- const auto accounts = session->domain().orderedAccounts();
- auto promotePossible = ranges::views::all(
- accounts
- ) | ranges::views::filter([&](not_null<Main::Account*> account) {
- return account->sessionExists()
- && !account->session().premium()
- && account->session().premiumPossible();
- }) | ranges::views::transform([&](not_null<Main::Account*> account) {
- const auto user = account->session().user();
- return Args::Entry{ user->name(), PaintUserpicCallback(user, false)};
- }) | ranges::views::take(defaultLimit) | ranges::to_vector;
- const auto premiumPossible = !promotePossible.empty();
- const auto current = int(accounts.size());
- auto text = rpl::combine(
- tr::lng_accounts_limit1(
- lt_count,
- rpl::single<float64>(current),
- Ui::Text::RichLangValue),
- ((!premiumPossible || current > premiumLimit)
- ? rpl::single(TextWithEntities())
- : tr::lng_accounts_limit2(Ui::Text::RichLangValue))
- ) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) {
- return b.text.isEmpty()
- ? a
- : a.append(QChar(' ')).append(std::move(b));
- });
- box->setWidth(st::boxWideWidth);
- const auto top = box->verticalLayout();
- const auto group = std::make_shared<Ui::RadiobuttonGroup>(0);
- Ui::AddSkip(top, st::premiumInfographicPadding.top());
- Ui::Premium::AddBubbleRow(
- top,
- st::defaultPremiumBubble,
- BoxShowFinishes(box),
- 0,
- current,
- (!premiumPossible
- ? (current * 2)
- : (current > defaultLimit)
- ? (current + 1)
- : (defaultLimit * 2)),
- ChooseBubbleType(premiumPossible),
- std::nullopt,
- &st::premiumIconAccounts);
- Ui::AddSkip(top, st::premiumLineTextSkip);
- if (premiumPossible) {
- Ui::Premium::AddLimitRow(
- top,
- st::defaultPremiumLimits,
- (QString::number(std::max(current, defaultLimit) + 1)
- + ((current + 1 == premiumLimit) ? "" : "+")),
- QString::number(defaultLimit));
- Ui::AddSkip(top, st::premiumInfographicPadding.bottom());
- }
- box->setTitle(tr::lng_accounts_limit_title());
- auto padding = st::boxPadding;
- padding.setTop(padding.bottom());
- top->add(
- object_ptr<Ui::FlatLabel>(
- box,
- std::move(text),
- st::aboutRevokePublicLabel),
- padding);
- if (!premiumPossible || current > premiumLimit) {
- box->addButton(tr::lng_box_ok(), [=] {
- box->closeBox();
- });
- return;
- }
- auto switchingLifetime = std::make_shared<rpl::lifetime>();
- box->addButton(tr::lng_continue(), [=]() mutable {
- const auto ref = QString();
- const auto wasAccount = &session->account();
- const auto nowAccount = accounts[group->current()];
- if (wasAccount == nowAccount) {
- Settings::ShowPremium(session, ref);
- return;
- }
- if (*switchingLifetime) {
- return;
- }
- *switchingLifetime = session->domain().activeSessionChanges(
- ) | rpl::start_with_next([=](Main::Session *session) mutable {
- if (session) {
- Settings::ShowPremium(session, ref);
- }
- if (switchingLifetime) {
- base::take(switchingLifetime)->destroy();
- }
- });
- session->domain().activate(nowAccount);
- });
- box->addButton(tr::lng_cancel(), [=] {
- box->closeBox();
- });
- auto args = Args{
- .group = group,
- .st = st::premiumAccountsCheckbox,
- .stName = st::shareBoxListItem.nameStyle,
- .stNameFg = st::shareBoxListItem.nameFg,
- .entries = std::move(promotePossible),
- };
- if (!args.entries.empty()) {
- box->addSkip(st::premiumAccountsPadding.top());
- Ui::Premium::AddAccountsRow(box->verticalLayout(), std::move(args));
- box->addSkip(st::premiumAccountsPadding.bottom());
- }
- }
- QString LimitsPremiumRef(const QString &addition) {
- return "double_limits__" + addition;
- }
|