mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-19 14:36:58 +00:00
Implement simple premium limits boxes.
This commit is contained in:
parent
ea3084aea5
commit
739123dedc
@ -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
|
||||
|
@ -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.";
|
||||
|
@ -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 {
|
||||
|
@ -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<PeerData*> 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<ChannelData*> channel) {
|
||||
Ui::show(Box(ChannelsLimitBox, _session));
|
||||
AssertIsDebug();
|
||||
return;
|
||||
if (channel->amIn()) {
|
||||
session().changes().peerUpdated(
|
||||
channel,
|
||||
@ -1660,6 +1664,8 @@ void ApiWrap::joinChannel(not_null<ChannelData*> 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<ChannelData*> 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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
524
Telegram/SourceFiles/boxes/premium_limits_box.cpp
Normal file
524
Telegram/SourceFiles/boxes/premium_limits_box.cpp
Normal file
@ -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<Main::Session*> session);
|
||||
~InactiveController();
|
||||
|
||||
Main::Session &session() const override;
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
|
||||
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;
|
||||
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;
|
||||
void peerListShowBox(
|
||||
object_ptr<Ui::BoxContent> content,
|
||||
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override;
|
||||
void peerListHideLayer() override;
|
||||
not_null<QWidget*> peerListToastParent() 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;
|
||||
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void InactiveDelegate::peerListShowBox(
|
||||
object_ptr<Ui::BoxContent> content,
|
||||
Ui::LayerOptions options) {
|
||||
}
|
||||
|
||||
void InactiveDelegate::peerListHideLayer() {
|
||||
}
|
||||
|
||||
not_null<QWidget*> InactiveDelegate::peerListToastParent() {
|
||||
Unexpected("...InactiveDelegate::peerListToastParent");
|
||||
}
|
||||
|
||||
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() {
|
||||
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<PeerListRow*> row) {
|
||||
delegate()->peerListSetRowChecked(row, !row->checked());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
[[nodiscard]] float64 Limit(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &key,
|
||||
double fallback) {
|
||||
return session->account().appConfig().get<double>(key, fallback);
|
||||
}
|
||||
|
||||
void SimpleLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<QString> title,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
bool premium) {
|
||||
box->setWidth(st::boxWideWidth);
|
||||
|
||||
const auto top = box->setPinnedToTopContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
top->add(
|
||||
object_ptr<Ui::CenterWrap<>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
std::move(title),
|
||||
st::changePhoneTitle)),
|
||||
st::changePhoneTitlePadding);
|
||||
|
||||
top->add(
|
||||
object_ptr<Ui::CenterWrap<>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
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<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> 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<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 = 50;
|
||||
const auto placeholder = box->addRow(
|
||||
object_ptr<PeerListDummy>(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<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);
|
||||
}
|
||||
}
|
||||
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<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> 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<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> 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<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> 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<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> 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);
|
||||
}
|
30
Telegram/SourceFiles/boxes/premium_limits_box.h
Normal file
30
Telegram/SourceFiles/boxes/premium_limits_box.h
Normal file
@ -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<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
void PublicLinksLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
void FilterChatsLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
void FiltersLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
void FilterPinsLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
@ -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<Ui::Animations::Simple> _animations;
|
||||
|
||||
};
|
||||
|
||||
class ListDelegate final : public PeerListContentDelegate {
|
||||
public:
|
||||
void peerListSetTitle(rpl::producer<QString> 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<QString> title) {
|
||||
}
|
||||
|
||||
|
60
Telegram/SourceFiles/ui/controls/peer_list_dummy.cpp
Normal file
60
Telegram/SourceFiles/ui/controls/peer_list_dummy.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
30
Telegram/SourceFiles/ui/controls/peer_list_dummy.h
Normal file
30
Telegram/SourceFiles/ui/controls/peer_list_dummy.h
Normal file
@ -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<Ui::Animations::Simple> _animations;
|
||||
|
||||
};
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user