mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-24 17:26:58 +00:00
Show "more similar channels" premium promo.
This commit is contained in:
parent
49b59d73be
commit
bfebb1339a
@ -1682,6 +1682,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_similar_channels_title" = "Similar channels";
|
||||
"lng_similar_channels_view_all" = "View all";
|
||||
"lng_similar_channels_more" = "More Channels";
|
||||
"lng_similar_channels_premium_all#one" = "Subscribe to {link} to unlock up to **{count}** similar channel.";
|
||||
"lng_similar_channels_premium_all#other" = "Subscribe to {link} to unlock up to **{count}** similar channels.";
|
||||
"lng_similar_channels_premium_all_link" = "Telegram Premium";
|
||||
|
||||
"lng_premium_gift_duration_months#one" = "for {count} month";
|
||||
"lng_premium_gift_duration_months#other" = "for {count} months";
|
||||
|
@ -211,19 +211,24 @@ void ApplyBotsList(
|
||||
Data::PeerUpdate::Flag::FullInfo);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<not_null<ChannelData*>> ParseSimilar(
|
||||
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
|
||||
not_null<ChannelData*> channel,
|
||||
const MTPmessages_Chats &chats) {
|
||||
auto result = std::vector<not_null<ChannelData*>>();
|
||||
auto result = ChatParticipants::Channels();
|
||||
std::vector<not_null<ChannelData*>>();
|
||||
auto total = 0;
|
||||
chats.match([&](const auto &data) {
|
||||
const auto &list = data.vchats().v;
|
||||
result.reserve(list.size());
|
||||
result.list.reserve(list.size());
|
||||
for (const auto &chat : list) {
|
||||
const auto peer = channel->owner().processChat(chat);
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
result.push_back(channel);
|
||||
result.list.push_back(channel);
|
||||
}
|
||||
}
|
||||
if constexpr (MTPDmessages_chatsSlice::Is<decltype(data)>()) {
|
||||
result.more = data.vcount().v - data.vchats().v.size();
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@ -704,18 +709,25 @@ void ChatParticipants::unblock(
|
||||
}
|
||||
|
||||
void ChatParticipants::loadSimilarChannels(not_null<ChannelData*> channel) {
|
||||
if (!channel->isBroadcast() || _similar.contains(channel)) {
|
||||
if (!channel->isBroadcast()) {
|
||||
return;
|
||||
} else if (const auto i = _similar.find(channel); i != end(_similar)) {
|
||||
if (i->second.requestId
|
||||
|| !i->second.channels.more
|
||||
|| !channel->session().premium()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_similar[channel].requestId = _api.request(
|
||||
MTPchannels_GetChannelRecommendations(channel->inputChannel)
|
||||
).done([=](const MTPmessages_Chats &result) {
|
||||
auto &similar = _similar[channel];
|
||||
auto list = ParseSimilar(channel, result);
|
||||
if (similar.list == list) {
|
||||
similar.requestId = 0;
|
||||
auto parsed = ParseSimilar(channel, result);
|
||||
if (similar.channels == parsed) {
|
||||
return;
|
||||
}
|
||||
similar.list = std::move(list);
|
||||
similar.channels = std::move(parsed);
|
||||
if (const auto history = channel->owner().historyLoaded(channel)) {
|
||||
if (const auto item = history->joinedMessageInstance()) {
|
||||
history->owner().requestItemResize(item);
|
||||
@ -725,15 +737,15 @@ void ChatParticipants::loadSimilarChannels(not_null<ChannelData*> channel) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
const std::vector<not_null<ChannelData*>> &ChatParticipants::similar(
|
||||
not_null<ChannelData*> channel) {
|
||||
auto ChatParticipants::similar(not_null<ChannelData*> channel)
|
||||
-> const Channels & {
|
||||
const auto i = channel->isBroadcast()
|
||||
? _similar.find(channel)
|
||||
: end(_similar);
|
||||
if (i != end(_similar)) {
|
||||
return i->second.list;
|
||||
return i->second.channels;
|
||||
}
|
||||
static const auto empty = std::vector<not_null<ChannelData*>>();
|
||||
static const auto empty = Channels();
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
@ -122,14 +122,21 @@ public:
|
||||
|
||||
void loadSimilarChannels(not_null<ChannelData*> channel);
|
||||
|
||||
[[nodiscard]] const std::vector<not_null<ChannelData*>> &similar(
|
||||
not_null<ChannelData*> channel);
|
||||
struct Channels {
|
||||
std::vector<not_null<ChannelData*>> list;
|
||||
int more = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Channels &,
|
||||
const Channels &) = default;
|
||||
};
|
||||
[[nodiscard]] const Channels &similar(not_null<ChannelData*> channel);
|
||||
[[nodiscard]] auto similarLoaded() const
|
||||
-> rpl::producer<not_null<ChannelData*>>;
|
||||
|
||||
private:
|
||||
struct SimilarChannels {
|
||||
std::vector<not_null<ChannelData*>> list;
|
||||
Channels channels;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
|
||||
|
@ -20,10 +20,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/chat/chat_theme.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/painter.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat.h"
|
||||
@ -31,11 +35,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
using Channels = Api::ChatParticipants::Channels;
|
||||
|
||||
class SimilarChannelsController final : public PeerListController {
|
||||
public:
|
||||
SimilarChannelsController(
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::vector<not_null<ChannelData*>> channels);
|
||||
Channels channels);
|
||||
|
||||
void prepare() override;
|
||||
void loadMoreRows() override;
|
||||
@ -44,19 +50,19 @@ public:
|
||||
|
||||
private:
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const std::vector<not_null<ChannelData*>> _channels;
|
||||
const Channels _channels;
|
||||
|
||||
};
|
||||
|
||||
SimilarChannelsController::SimilarChannelsController(
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::vector<not_null<ChannelData*>> channels)
|
||||
Channels channels)
|
||||
: _controller(controller)
|
||||
, _channels(std::move(channels)) {
|
||||
}
|
||||
|
||||
void SimilarChannelsController::prepare() {
|
||||
for (const auto &channel : _channels) {
|
||||
for (const auto &channel : _channels.list) {
|
||||
auto row = std::make_unique<PeerListRow>(channel);
|
||||
if (const auto count = channel->membersCount(); count > 1) {
|
||||
row->setCustomStatus(tr::lng_chat_status_subscribers(
|
||||
@ -84,12 +90,12 @@ void SimilarChannelsController::rowClicked(not_null<PeerListRow*> row) {
|
||||
}
|
||||
|
||||
Main::Session &SimilarChannelsController::session() const {
|
||||
return _channels.front()->session();
|
||||
return _channels.list.front()->session();
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> SimilarChannelsBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const std::vector<not_null<ChannelData*>> &channels) {
|
||||
const Channels &channels) {
|
||||
const auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->setTitle(tr::lng_similar_channels_title());
|
||||
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
|
||||
@ -99,6 +105,43 @@ Main::Session &SimilarChannelsController::session() const {
|
||||
initBox);
|
||||
}
|
||||
|
||||
[[nodiscard]] ClickHandlerPtr MakeViewAllLink(
|
||||
not_null<ChannelData*> channel,
|
||||
bool promoForNonPremium) {
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto strong = my.sessionWindow.get()) {
|
||||
Assert(channel != nullptr);
|
||||
if (promoForNonPremium && !channel->session().premium()) {
|
||||
const auto account = &channel->session().account();
|
||||
const auto upto = account->appConfig().get<int>(
|
||||
u"recommended_channels_limit_premium"_q,
|
||||
100);
|
||||
Settings::ShowPremiumPromoToast(
|
||||
strong->uiShow(),
|
||||
tr::lng_similar_channels_premium_all(
|
||||
tr::now,
|
||||
lt_count,
|
||||
upto,
|
||||
lt_link,
|
||||
Ui::Text::Link(
|
||||
Ui::Text::Bold(
|
||||
tr::lng_similar_channels_premium_all_link(
|
||||
tr::now))),
|
||||
Ui::Text::RichLangValue),
|
||||
u"similar_channels"_q);
|
||||
return;
|
||||
}
|
||||
const auto api = &channel->session().api();
|
||||
const auto &list = api->chatParticipants().similar(channel);
|
||||
if (list.list.empty()) {
|
||||
return;
|
||||
}
|
||||
strong->show(SimilarChannelsBox(strong, list));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SimilarChannels::SimilarChannels(not_null<Element*> parent)
|
||||
@ -180,14 +223,15 @@ void SimilarChannels::draw(Painter &p, const PaintContext &context) const {
|
||||
if (right <= 0) {
|
||||
return;
|
||||
}
|
||||
if (!channel.subscribed) {
|
||||
channel.subscribed = true;
|
||||
const auto subscribing = !channel.subscribed;
|
||||
if (subscribing) {
|
||||
channel.subscribed = 1;
|
||||
const auto raw = channel.thumbnail.get();
|
||||
const auto view = parent();
|
||||
channel.thumbnail->subscribeToUpdates([=] {
|
||||
for (const auto &channel : _channels) {
|
||||
if (channel.thumbnail.get() == raw) {
|
||||
channel.participantsBgValid = false;
|
||||
channel.counterBgValid = 0;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
@ -203,7 +247,9 @@ void SimilarChannels::draw(Painter &p, const PaintContext &context) const {
|
||||
cachedp->translate(-geometry.topLeft());
|
||||
}
|
||||
const auto q = cachedp ? &*cachedp : &p;
|
||||
if (channel.ripple) {
|
||||
if (channel.more) {
|
||||
channel.ripple.reset();
|
||||
} else if (channel.ripple) {
|
||||
q->setOpacity(st::historyPollRippleOpacity);
|
||||
channel.ripple->paint(
|
||||
*q,
|
||||
@ -216,30 +262,87 @@ void SimilarChannels::draw(Painter &p, const PaintContext &context) const {
|
||||
}
|
||||
q->setOpacity(1.);
|
||||
}
|
||||
|
||||
auto pen = stm->msgBg->p;
|
||||
auto left = geometry.x() + 2 * padding.left();
|
||||
const auto stroke = st::lineWidth * 2.;
|
||||
const auto add = stroke / 2.;
|
||||
const auto top = geometry.y() + padding.top();
|
||||
const auto size = st::chatSimilarChannelPhoto;
|
||||
const auto paintCircle = [&] {
|
||||
auto hq = PainterHighQualityEnabler(*q);
|
||||
q->drawEllipse(QRectF(left, top, size, size).marginsAdded(
|
||||
{ add, add, add, add }));
|
||||
};
|
||||
if (channel.more) {
|
||||
pen.setWidthF(stroke);
|
||||
p.setPen(pen);
|
||||
for (auto i = 2; i != 0;) {
|
||||
--i;
|
||||
if (const auto &thumbnail = _moreThumbnails[i]) {
|
||||
if (subscribing) {
|
||||
thumbnail->subscribeToUpdates([=] {
|
||||
repaint();
|
||||
});
|
||||
}
|
||||
q->drawImage(left, top, thumbnail->image(size));
|
||||
q->setBrush(Qt::NoBrush);
|
||||
} else {
|
||||
q->setBrush(st::windowBgRipple->c);
|
||||
}
|
||||
if (!i || !_moreThumbnails[i]) {
|
||||
paintCircle();
|
||||
}
|
||||
left -= padding.left();
|
||||
}
|
||||
} else {
|
||||
left -= padding.left();
|
||||
}
|
||||
q->drawImage(
|
||||
geometry.x() + padding.left(),
|
||||
geometry.y() + padding.top(),
|
||||
channel.thumbnail->image(st::chatSimilarChannelPhoto));
|
||||
if (!channel.participants.isEmpty()) {
|
||||
validateParticipansBg(channel);
|
||||
const auto participants = channel.participantsRect.translated(
|
||||
left,
|
||||
top,
|
||||
channel.thumbnail->image(size));
|
||||
if (channel.more) {
|
||||
q->setBrush(Qt::NoBrush);
|
||||
paintCircle();
|
||||
}
|
||||
if (!channel.counter.isEmpty()) {
|
||||
validateCounterBg(channel);
|
||||
const auto participants = channel.counterRect.translated(
|
||||
geometry.topLeft());
|
||||
q->drawImage(participants.topLeft(), channel.participantsBg);
|
||||
q->drawImage(participants.topLeft(), channel.counterBg);
|
||||
const auto badge = participants.marginsRemoved(
|
||||
st::chatSimilarBadgePadding);
|
||||
const auto &icon = st::chatSimilarBadgeIcon;
|
||||
auto textLeft = badge.x();
|
||||
const auto &font = st::chatSimilarBadgeFont;
|
||||
const auto position = st::chatSimilarBadgeIconPosition;
|
||||
const auto ascent = font->ascent;
|
||||
icon.paint(*q, badge.topLeft() + position, width());
|
||||
const auto textTop = badge.y() + font->ascent;
|
||||
const auto icon = !channel.more
|
||||
? &st::chatSimilarBadgeIcon
|
||||
: channel.moreLocked
|
||||
? &st::chatSimilarLockedIcon
|
||||
: nullptr;
|
||||
const auto position = !channel.more
|
||||
? st::chatSimilarBadgeIconPosition
|
||||
: st::chatSimilarLockedIconPosition;
|
||||
if (icon) {
|
||||
const auto skip = channel.more
|
||||
? (badge.width() - icon->width())
|
||||
: 0;
|
||||
icon->paint(
|
||||
*q,
|
||||
badge.x() + position.x() + skip,
|
||||
badge.y() + position.y(),
|
||||
width());
|
||||
if (!channel.more) {
|
||||
textLeft += position.x() + icon->width();
|
||||
}
|
||||
}
|
||||
q->setFont(font);
|
||||
q->setPen(st::premiumButtonFg);
|
||||
q->drawText(
|
||||
badge.x() + position.x() + icon.width(),
|
||||
badge.y() + font->ascent,
|
||||
channel.participants);
|
||||
q->drawText(textLeft, textTop, channel.counter);
|
||||
}
|
||||
q->setPen(stm->historyTextFg);
|
||||
q->setPen(channel.more ? st::windowSubTextFg : stm->historyTextFg);
|
||||
channel.name.drawLeftElided(
|
||||
*q,
|
||||
geometry.x() + st::normalFont->spacew,
|
||||
@ -268,6 +371,7 @@ void SimilarChannels::draw(Painter &p, const PaintContext &context) const {
|
||||
}
|
||||
drawOne(channel);
|
||||
}
|
||||
p.setPen(stm->historyTextFg);
|
||||
p.setFont(st::chatSimilarTitle);
|
||||
p.drawTextLeft(
|
||||
st::chatSimilarTitlePosition.x(),
|
||||
@ -290,21 +394,23 @@ void SimilarChannels::draw(Painter &p, const PaintContext &context) const {
|
||||
p.setClipping(false);
|
||||
}
|
||||
|
||||
void SimilarChannels::validateParticipansBg(const Channel &channel) const {
|
||||
if (channel.participantsBgValid) {
|
||||
void SimilarChannels::validateCounterBg(const Channel &channel) const {
|
||||
if (channel.counterBgValid) {
|
||||
return;
|
||||
}
|
||||
channel.participantsBgValid = true;
|
||||
channel.counterBgValid = 1;
|
||||
const auto photo = st::chatSimilarChannelPhoto;
|
||||
const auto width = channel.participantsRect.width();
|
||||
const auto height = channel.participantsRect.height();
|
||||
const auto width = channel.counterRect.width();
|
||||
const auto height = channel.counterRect.height();
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
auto result = QImage(
|
||||
channel.participantsRect.size() * ratio,
|
||||
channel.counterRect.size() * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
auto color = Ui::CountAverageColor(
|
||||
channel.thumbnail->image(photo).copy(
|
||||
QRect(photo / 3, photo / 3, photo / 3, photo / 3)));
|
||||
auto color = channel.more
|
||||
? st::windowBgRipple->c
|
||||
: Ui::CountAverageColor(
|
||||
channel.thumbnail->image(photo).copy(
|
||||
QRect(photo / 3, photo / 3, photo / 3, photo / 3)));
|
||||
|
||||
const auto hsl = color.toHsl();
|
||||
constexpr auto kMinSaturation = 0;
|
||||
@ -334,7 +440,7 @@ void SimilarChannels::validateParticipansBg(const Channel &channel) const {
|
||||
height - radius,
|
||||
corners[Images::kBottomRight]);
|
||||
p.end();
|
||||
channel.participantsBg = std::move(result);
|
||||
channel.counterBg = std::move(result);
|
||||
}
|
||||
|
||||
ClickHandlerPtr SimilarChannels::ensureToggleLink() const {
|
||||
@ -385,19 +491,7 @@ TextState SimilarChannels::textState(
|
||||
if (!_viewAllLink) {
|
||||
const auto channel = parent()->history()->peer->asChannel();
|
||||
Assert(channel != nullptr);
|
||||
_viewAllLink = std::make_shared<LambdaClickHandler>([=](
|
||||
ClickContext context) {
|
||||
Assert(channel != nullptr);
|
||||
const auto api = &channel->session().api();
|
||||
const auto &list = api->chatParticipants().similar(channel);
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto strong = my.sessionWindow.get()) {
|
||||
strong->show(SimilarChannelsBox(strong, list));
|
||||
}
|
||||
});
|
||||
_viewAllLink = MakeViewAllLink(channel, false);
|
||||
}
|
||||
result.link = _viewAllLink;
|
||||
return result;
|
||||
@ -419,53 +513,86 @@ QSize SimilarChannels::countOptimalSize() {
|
||||
Assert(channel != nullptr);
|
||||
|
||||
_channels.clear();
|
||||
_moreThumbnails = {};
|
||||
const auto api = &channel->session().api();
|
||||
api->chatParticipants().loadSimilarChannels(channel);
|
||||
const auto premium = channel->session().premium();
|
||||
const auto similar = api->chatParticipants().similar(channel);
|
||||
_empty = similar.empty() ? 1 : 0;
|
||||
_empty = similar.list.empty() ? 1 : 0;
|
||||
using Flag = ChannelDataFlag;
|
||||
_toggled = (channel->flags() & Flag::SimilarExpanded) ? 1 : 0;
|
||||
if (_empty || !_toggled) {
|
||||
return {};
|
||||
}
|
||||
|
||||
_channels.reserve(similar.size());
|
||||
_channels.reserve(similar.list.size());
|
||||
auto x = st::chatSimilarPadding.left();
|
||||
auto y = st::chatSimilarPadding.top();
|
||||
const auto skip = st::chatSimilarSkip;
|
||||
const auto photo = st::chatSimilarChannelPhoto;
|
||||
const auto inner = QRect(0, 0, photo, photo);
|
||||
const auto outer = inner.marginsAdded(st::chatSimilarChannelPadding);
|
||||
for (const auto &channel : similar) {
|
||||
const auto participants = channel->membersCount();
|
||||
const auto count = (participants > 1)
|
||||
? Lang::FormatCountToShort(participants).string
|
||||
: QString();
|
||||
const auto limit = channel->session().account().appConfig().get<int>(
|
||||
u"recommended_channels_limit_default"_q,
|
||||
10);
|
||||
const auto take = (similar.more > 0 || similar.list.size() > 2 * limit)
|
||||
? limit
|
||||
: int(similar.list.size());
|
||||
const auto more = similar.more + int(similar.list.size() - take);
|
||||
auto &&channels = ranges::views::all(similar.list)
|
||||
| ranges::views::take(limit);
|
||||
for (const auto &channel : channels) {
|
||||
const auto moreCounter = (_channels.size() + 1 == take) ? more : 0;
|
||||
_channels.push_back({
|
||||
.geometry = QRect(QPoint(x, y), outer.size()),
|
||||
.name = Ui::Text::String(
|
||||
st::chatSimilarName,
|
||||
channel->name(),
|
||||
(moreCounter
|
||||
? tr::lng_similar_channels_more(tr::now)
|
||||
: channel->name()),
|
||||
kDefaultTextOptions,
|
||||
st::chatSimilarChannelPhoto),
|
||||
.thumbnail = Dialogs::Stories::MakeUserpicThumbnail(channel),
|
||||
.link = channel->openLink(),
|
||||
.participants = count,
|
||||
.more = uint32(moreCounter),
|
||||
.moreLocked = uint32((moreCounter && !premium) ? 1 : 0),
|
||||
});
|
||||
if (!count.isEmpty()) {
|
||||
const auto length = st::chatSimilarBadgeFont->width(count);
|
||||
const auto width = length + st::chatSimilarBadgeIcon.width();
|
||||
auto &last = _channels.back();
|
||||
last.link = moreCounter
|
||||
? MakeViewAllLink(parent()->history()->peer->asChannel(), true)
|
||||
: channel->openLink();
|
||||
|
||||
const auto counter = moreCounter
|
||||
? moreCounter :
|
||||
channel->membersCount();
|
||||
if (moreCounter || counter > 1) {
|
||||
const auto text = (moreCounter ? u"+"_q : QString())
|
||||
+ Lang::FormatCountToShort(counter).string;
|
||||
const auto length = st::chatSimilarBadgeFont->width(text);
|
||||
const auto width = length
|
||||
+ (!moreCounter
|
||||
? st::chatSimilarBadgeIcon.width()
|
||||
: !premium
|
||||
? st::chatSimilarLockedIcon.width()
|
||||
: 0);
|
||||
const auto delta = (outer.width() - width) / 2;
|
||||
const auto badge = QRect(
|
||||
delta,
|
||||
st::chatSimilarBadgeTop,
|
||||
outer.width() - 2 * delta,
|
||||
st::chatSimilarBadgeFont->height);
|
||||
_channels.back().participantsRect = badge.marginsAdded(
|
||||
last.counter = text;
|
||||
last.counterRect = badge.marginsAdded(
|
||||
st::chatSimilarBadgePadding);
|
||||
}
|
||||
x += outer.width() + skip;
|
||||
}
|
||||
for (auto i = 0, count = int(_moreThumbnails.size()); i != count; ++i) {
|
||||
if (similar.list.size() <= _channels.size() + i) {
|
||||
break;
|
||||
}
|
||||
_moreThumbnails[i] = Dialogs::Stories::MakeUserpicThumbnail(
|
||||
similar.list[_channels.size() + i]);
|
||||
}
|
||||
_title = tr::lng_similar_channels_title(tr::now);
|
||||
_titleWidth = st::chatSimilarTitle->width(_title);
|
||||
_viewAll = tr::lng_similar_channels_view_all(tr::now);
|
||||
@ -507,9 +634,14 @@ bool SimilarChannels::hasHeavyPart() const {
|
||||
void SimilarChannels::unloadHeavyPart() {
|
||||
_hasHeavyPart = 0;
|
||||
for (const auto &channel : _channels) {
|
||||
channel.subscribed = false;
|
||||
channel.subscribed = 0;
|
||||
channel.thumbnail->subscribeToUpdates(nullptr);
|
||||
}
|
||||
for (const auto &thumbnail : _moreThumbnails) {
|
||||
if (thumbnail) {
|
||||
thumbnail->subscribeToUpdates(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SimilarChannels::consumeHorizontalScroll(QPoint position, int delta) {
|
||||
|
@ -64,16 +64,18 @@ private:
|
||||
Ui::Text::String name;
|
||||
std::shared_ptr<Thumbnail> thumbnail;
|
||||
ClickHandlerPtr link;
|
||||
QString participants;
|
||||
QRect participantsRect;
|
||||
mutable QImage participantsBg;
|
||||
QString counter;
|
||||
QRect counterRect;
|
||||
mutable QImage counterBg;
|
||||
mutable std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||
mutable bool subscribed = false;
|
||||
mutable bool participantsBgValid = false;
|
||||
uint32 more : 29 = 0;
|
||||
uint32 moreLocked : 1 = 0;
|
||||
mutable uint32 subscribed : 1 = 0;
|
||||
mutable uint32 counterBgValid : 1 = 0;
|
||||
};
|
||||
|
||||
void ensureCacheReady(QSize size) const;
|
||||
void validateParticipansBg(const Channel &channel) const;
|
||||
void validateCounterBg(const Channel &channel) const;
|
||||
[[nodiscard]] ClickHandlerPtr ensureToggleLink() const;
|
||||
|
||||
QSize countOptimalSize() override;
|
||||
@ -94,6 +96,7 @@ private:
|
||||
mutable uint32 _hasHeavyPart : 1 = 0;
|
||||
|
||||
std::vector<Channel> _channels;
|
||||
std::array<std::shared_ptr<Thumbnail>, 2> _moreThumbnails;
|
||||
mutable ClickHandlerPtr _viewAllLink;
|
||||
mutable ClickHandlerPtr _toggleLink;
|
||||
|
||||
|
@ -991,6 +991,8 @@ chatSimilarBadgePadding: margins(2px, 0px, 3px, 1px);
|
||||
chatSimilarBadgeTop: 43px;
|
||||
chatSimilarBadgeIcon: icon{{ "chat/mini_subscribers", premiumButtonFg }};
|
||||
chatSimilarBadgeIconPosition: point(0px, 1px);
|
||||
chatSimilarLockedIcon: icon{{ "emoji/premium_lock", premiumButtonFg }};
|
||||
chatSimilarLockedIconPosition: point(0px, -1px);
|
||||
chatSimilarBadgeFont: font(10px bold);
|
||||
chatSimilarNameTop: 59px;
|
||||
chatSimilarName: TextStyle(defaultTextStyle) {
|
||||
|
Loading…
Reference in New Issue
Block a user