mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Display gifts list in the profile.
This commit is contained in:
parent
79b1c0edee
commit
52afd3d5a8
9 changed files with 760 additions and 426 deletions
|
@ -949,6 +949,8 @@ PRIVATE
|
||||||
info/media/info_media_widget.h
|
info/media/info_media_widget.h
|
||||||
info/members/info_members_widget.cpp
|
info/members/info_members_widget.cpp
|
||||||
info/members/info_members_widget.h
|
info/members/info_members_widget.h
|
||||||
|
info/peer_gifts/info_peer_gifts_common.cpp
|
||||||
|
info/peer_gifts/info_peer_gifts_common.h
|
||||||
info/peer_gifts/info_peer_gifts_widget.cpp
|
info/peer_gifts/info_peer_gifts_widget.cpp
|
||||||
info/peer_gifts/info_peer_gifts_widget.h
|
info/peer_gifts/info_peer_gifts_widget.h
|
||||||
info/polls/info_polls_results_inner_widget.cpp
|
info/polls/info_polls_results_inner_widget.cpp
|
||||||
|
|
|
@ -600,23 +600,12 @@ auto PremiumGiftCodeOptions::requestStarGifts()
|
||||||
result.match([&](const MTPDpayments_starGifts &data) {
|
result.match([&](const MTPDpayments_starGifts &data) {
|
||||||
_giftsHash = data.vhash().v;
|
_giftsHash = data.vhash().v;
|
||||||
const auto &list = data.vgifts().v;
|
const auto &list = data.vgifts().v;
|
||||||
|
const auto session = &_peer->session();
|
||||||
auto gifts = std::vector<StarGift>();
|
auto gifts = std::vector<StarGift>();
|
||||||
gifts.reserve(list.size());
|
gifts.reserve(list.size());
|
||||||
for (const auto &gift : list) {
|
for (const auto &gift : list) {
|
||||||
const auto &data = gift.data();
|
if (auto parsed = FromTL(session, gift)) {
|
||||||
const auto document = _peer->owner().processDocument(
|
gifts.push_back(std::move(*parsed));
|
||||||
data.vsticker());
|
|
||||||
const auto remaining = data.vavailability_remains();
|
|
||||||
const auto total = data.vavailability_total();
|
|
||||||
if (document->sticker()) {
|
|
||||||
gifts.push_back(StarGift{
|
|
||||||
.id = uint64(data.vid().v),
|
|
||||||
.stars = int64(data.vstars().v),
|
|
||||||
.convertStars = int64(data.vconvert_stars().v),
|
|
||||||
.document = document,
|
|
||||||
.limitedLeft = remaining.value_or_empty(),
|
|
||||||
.limitedCount = total.value_or_empty(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_gifts = std::move(gifts);
|
_gifts = std::move(gifts);
|
||||||
|
@ -769,4 +758,53 @@ rpl::producer<DocumentData*> RandomHelloStickerValue(
|
||||||
}) | rpl::take(1) | rpl::map(random));
|
}) | rpl::take(1) | rpl::map(random));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<StarGift> FromTL(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPstarGift &gift) {
|
||||||
|
const auto &data = gift.data();
|
||||||
|
const auto document = session->data().processDocument(
|
||||||
|
data.vsticker());
|
||||||
|
const auto remaining = data.vavailability_remains();
|
||||||
|
const auto total = data.vavailability_total();
|
||||||
|
if (!document->sticker()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return StarGift{
|
||||||
|
.id = uint64(data.vid().v),
|
||||||
|
.stars = int64(data.vstars().v),
|
||||||
|
.convertStars = int64(data.vconvert_stars().v),
|
||||||
|
.document = document,
|
||||||
|
.limitedLeft = remaining.value_or_empty(),
|
||||||
|
.limitedCount = total.value_or_empty(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<UserStarGift> FromTL(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPuserStarGift &gift) {
|
||||||
|
const auto &data = gift.data();
|
||||||
|
auto parsed = FromTL(session, data.vgift());
|
||||||
|
if (!parsed) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return UserStarGift{
|
||||||
|
.gift = std::move(*parsed),
|
||||||
|
.message = (data.vmessage()
|
||||||
|
? TextWithEntities{
|
||||||
|
.text = qs(data.vmessage()->data().vtext()),
|
||||||
|
.entities = Api::EntitiesFromMTP(
|
||||||
|
session,
|
||||||
|
data.vmessage()->data().ventities().v),
|
||||||
|
}
|
||||||
|
: TextWithEntities()),
|
||||||
|
.convertStars = int64(data.vconvert_stars().value_or_empty()),
|
||||||
|
.fromId = (data.vfrom_id()
|
||||||
|
? peerFromUser(data.vfrom_id()->v)
|
||||||
|
: PeerId()),
|
||||||
|
.messageId = data.vmsg_id().value_or_empty(),
|
||||||
|
.anonymous = data.is_name_hidden(),
|
||||||
|
.hidden = data.is_unsaved(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -82,6 +82,16 @@ struct StarGift {
|
||||||
int limitedCount = 0;
|
int limitedCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UserStarGift {
|
||||||
|
StarGift gift;
|
||||||
|
TextWithEntities message;
|
||||||
|
int64 convertStars = 0;
|
||||||
|
PeerId fromId = 0;
|
||||||
|
MsgId messageId = 0;
|
||||||
|
bool anonymous = false;
|
||||||
|
bool hidden = false;
|
||||||
|
};
|
||||||
|
|
||||||
class Premium final {
|
class Premium final {
|
||||||
public:
|
public:
|
||||||
explicit Premium(not_null<ApiWrap*> api);
|
explicit Premium(not_null<ApiWrap*> api);
|
||||||
|
@ -264,4 +274,11 @@ enum class RequirePremiumState {
|
||||||
[[nodiscard]] rpl::producer<DocumentData*> RandomHelloStickerValue(
|
[[nodiscard]] rpl::producer<DocumentData*> RandomHelloStickerValue(
|
||||||
not_null<Main::Session*> session);
|
not_null<Main::Session*> session);
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<StarGift> FromTL(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPstarGift &gift);
|
||||||
|
[[nodiscard]] std::optional<UserStarGift> FromTL(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPuserStarGift &gift);
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -6,34 +6,33 @@ For license and copyright information please follow this link:
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "boxes/gift_credits_box.h"
|
#include "boxes/gift_credits_box.h"
|
||||||
|
//
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "api/api_credits.h"
|
|
||||||
#include "api/api_premium.h"
|
#include "api/api_premium.h"
|
||||||
#include "boxes/peer_list_controllers.h"
|
#include "boxes/peer_list_controllers.h"
|
||||||
#include "boxes/send_credits_box.h"
|
#include "boxes/send_credits_box.h"
|
||||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||||
#include "chat_helpers/stickers_lottie.h"
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/ui_integration.h"
|
||||||
#include "core/local_url_handlers.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "history/admin_log/history_admin_log_item.h"
|
#include "history/admin_log/history_admin_log_item.h"
|
||||||
#include "history/view/media/history_view_sticker_player.h"
|
|
||||||
#include "history/view/media/history_view_media_generic.h"
|
#include "history/view/media/history_view_media_generic.h"
|
||||||
#include "history/view/history_view_element.h"
|
#include "history/view/history_view_element.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
|
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/session/session_show.h"
|
#include "lottie/lottie_common.h"
|
||||||
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "payments/payments_form.h"
|
#include "payments/payments_form.h"
|
||||||
#include "payments/payments_checkout_process.h"
|
#include "payments/payments_checkout_process.h"
|
||||||
#include "payments/payments_non_panel_process.h"
|
#include "payments/payments_non_panel_process.h"
|
||||||
#include "settings/settings_credits_graphics.h"
|
|
||||||
#include "settings/settings_credits.h"
|
#include "settings/settings_credits.h"
|
||||||
#include "settings/settings_premium.h"
|
#include "settings/settings_premium.h"
|
||||||
#include "ui/chat/chat_style.h"
|
#include "ui/chat/chat_style.h"
|
||||||
|
@ -42,9 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/path_shift_gradient.h"
|
#include "ui/effects/path_shift_gradient.h"
|
||||||
#include "ui/effects/premium_graphics.h"
|
#include "ui/effects/premium_graphics.h"
|
||||||
#include "ui/effects/premium_stars_colored.h"
|
#include "ui/effects/premium_stars_colored.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/basic_click_handlers.h"
|
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "ui/text/format_values.h"
|
#include "ui/text/format_values.h"
|
||||||
|
@ -52,71 +49,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "ui/widgets/fields/input_field.h"
|
#include "ui/widgets/fields/input_field.h"
|
||||||
#include "ui/widgets/label_with_custom_emoji.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_channel_earn.h"
|
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_credits.h"
|
#include "styles/style_credits.h"
|
||||||
#include "styles/style_giveaway.h"
|
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_premium.h"
|
#include "styles/style_premium.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
|
|
||||||
#include "data/stickers/data_stickers.h"
|
|
||||||
#include "data/data_document.h"
|
|
||||||
#include "data/data_document_media.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kPriceTabAll = 0;
|
constexpr auto kPriceTabAll = 0;
|
||||||
constexpr auto kPriceTabLimited = -1;
|
constexpr auto kPriceTabLimited = -1;
|
||||||
constexpr auto kGiftsPerRow = 3;
|
|
||||||
constexpr auto kGiftMessageLimit = 256;
|
constexpr auto kGiftMessageLimit = 256;
|
||||||
constexpr auto kSentToastDuration = 3 * crl::time(1000);
|
constexpr auto kSentToastDuration = 3 * crl::time(1000);
|
||||||
|
|
||||||
using namespace HistoryView;
|
using namespace HistoryView;
|
||||||
|
using namespace Info::PeerGifts;
|
||||||
struct GiftTypePremium {
|
|
||||||
int64 cost = 0;
|
|
||||||
QString currency;
|
|
||||||
int months = 0;
|
|
||||||
int discountPercent = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] friend inline bool operator==(
|
|
||||||
const GiftTypePremium &,
|
|
||||||
const GiftTypePremium &) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PremiumGiftsDescriptor {
|
struct PremiumGiftsDescriptor {
|
||||||
std::vector<GiftTypePremium> list;
|
std::vector<GiftTypePremium> list;
|
||||||
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GiftTypeStars {
|
|
||||||
uint64 id = 0;
|
|
||||||
int64 stars = 0;
|
|
||||||
int64 convertStars = 0;
|
|
||||||
DocumentData *document = nullptr;
|
|
||||||
bool limited = false;
|
|
||||||
|
|
||||||
[[nodiscard]] friend inline bool operator==(
|
|
||||||
const GiftTypeStars&,
|
|
||||||
const GiftTypeStars&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GiftDescriptor : std::variant<GiftTypePremium, GiftTypeStars> {
|
|
||||||
using variant::variant;
|
|
||||||
|
|
||||||
[[nodiscard]] friend inline bool operator==(
|
|
||||||
const GiftDescriptor&,
|
|
||||||
const GiftDescriptor&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GiftsDescriptor {
|
struct GiftsDescriptor {
|
||||||
std::vector<GiftDescriptor> list;
|
std::vector<GiftDescriptor> list;
|
||||||
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
||||||
|
@ -739,234 +698,6 @@ struct GiftPriceTabs {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class GiftButtonDelegate {
|
|
||||||
public:
|
|
||||||
[[nodiscard]] virtual TextWithEntities star() = 0;
|
|
||||||
[[nodiscard]] virtual std::any textContext() = 0;
|
|
||||||
[[nodiscard]] virtual QSize buttonSize() = 0;
|
|
||||||
[[nodiscard]] virtual QImage background() = 0;
|
|
||||||
[[nodiscard]] virtual DocumentData *lookupSticker(
|
|
||||||
const GiftDescriptor &descriptor) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GiftButton final : public AbstractButton {
|
|
||||||
public:
|
|
||||||
GiftButton(QWidget *parent, not_null<GiftButtonDelegate*> delegate);
|
|
||||||
using AbstractButton::AbstractButton;
|
|
||||||
|
|
||||||
void setDescriptor(const GiftDescriptor &descriptor);
|
|
||||||
void setGeometry(QRect inner, QMargins extend);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
|
|
||||||
void setDocument(not_null<DocumentData*> document);
|
|
||||||
|
|
||||||
const not_null<GiftButtonDelegate*> _delegate;
|
|
||||||
GiftDescriptor _descriptor;
|
|
||||||
Text::String _text;
|
|
||||||
Text::String _price;
|
|
||||||
QRect _button;
|
|
||||||
QMargins _extend;
|
|
||||||
|
|
||||||
std::unique_ptr<StickerPlayer> _player;
|
|
||||||
rpl::lifetime _mediaLifetime;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
GiftButton::GiftButton(
|
|
||||||
QWidget *parent,
|
|
||||||
not_null<GiftButtonDelegate*> delegate)
|
|
||||||
: AbstractButton(parent)
|
|
||||||
, _delegate(delegate) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|
||||||
if (_descriptor == descriptor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto player = base::take(_player);
|
|
||||||
_mediaLifetime.destroy();
|
|
||||||
_descriptor = descriptor;
|
|
||||||
v::match(descriptor, [&](const GiftTypePremium &data) {
|
|
||||||
const auto months = data.months;
|
|
||||||
const auto years = (months % 12) ? 0 : months / 12;
|
|
||||||
_text = Text::String(st::giftBoxGiftHeight / 4);
|
|
||||||
_text.setMarkedText(
|
|
||||||
st::defaultTextStyle,
|
|
||||||
Text::Bold(years
|
|
||||||
? tr::lng_years(tr::now, lt_count, years)
|
|
||||||
: tr::lng_months(tr::now, lt_count, months)
|
|
||||||
).append('\n').append(
|
|
||||||
tr::lng_gift_premium_label(tr::now)
|
|
||||||
));
|
|
||||||
_price.setText(
|
|
||||||
st::semiboldTextStyle,
|
|
||||||
FillAmountAndCurrency(
|
|
||||||
data.cost,
|
|
||||||
data.currency,
|
|
||||||
true));
|
|
||||||
}, [&](const GiftTypeStars &data) {
|
|
||||||
_price.setMarkedText(
|
|
||||||
st::semiboldTextStyle,
|
|
||||||
_delegate->star().append(QString::number(data.stars)),
|
|
||||||
kMarkupTextOptions,
|
|
||||||
_delegate->textContext());
|
|
||||||
});
|
|
||||||
if (const auto document = _delegate->lookupSticker(descriptor)) {
|
|
||||||
setDocument(document);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto buttonw = _price.maxWidth();
|
|
||||||
const auto buttonh = st::semiboldFont->height;
|
|
||||||
const auto inner = QRect(
|
|
||||||
QPoint(),
|
|
||||||
QSize(buttonw, buttonh)
|
|
||||||
).marginsAdded(st::giftBoxButtonPadding);
|
|
||||||
const auto single = _delegate->buttonSize();
|
|
||||||
const auto skipx = (single.width() - inner.width()) / 2;
|
|
||||||
const auto skipy = single.height()
|
|
||||||
- st::giftBoxButtonBottom
|
|
||||||
- inner.height();
|
|
||||||
const auto outer = (single.width() - 2 * skipx);
|
|
||||||
_button = QRect(skipx, skipy, outer, inner.height());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GiftButton::setDocument(not_null<DocumentData*> document) {
|
|
||||||
const auto media = document->createMediaView();
|
|
||||||
media->checkStickerLarge();
|
|
||||||
media->goodThumbnailWanted();
|
|
||||||
|
|
||||||
rpl::single() | rpl::then(
|
|
||||||
document->owner().session().downloaderTaskFinished()
|
|
||||||
) | rpl::filter([=] {
|
|
||||||
return media->loaded();
|
|
||||||
}) | rpl::start_with_next([=] {
|
|
||||||
_mediaLifetime.destroy();
|
|
||||||
|
|
||||||
auto result = std::unique_ptr<StickerPlayer>();
|
|
||||||
const auto sticker = document->sticker();
|
|
||||||
if (sticker->isLottie()) {
|
|
||||||
result = std::make_unique<HistoryView::LottiePlayer>(
|
|
||||||
ChatHelpers::LottiePlayerFromDocument(
|
|
||||||
media.get(),
|
|
||||||
ChatHelpers::StickerLottieSize::InlineResults,
|
|
||||||
st::giftBoxStickerSize,
|
|
||||||
Lottie::Quality::High));
|
|
||||||
} else if (sticker->isWebm()) {
|
|
||||||
result = std::make_unique<HistoryView::WebmPlayer>(
|
|
||||||
media->owner()->location(),
|
|
||||||
media->bytes(),
|
|
||||||
st::giftBoxStickerSize);
|
|
||||||
} else {
|
|
||||||
result = std::make_unique<HistoryView::StaticStickerPlayer>(
|
|
||||||
media->owner()->location(),
|
|
||||||
media->bytes(),
|
|
||||||
st::giftBoxStickerSize);
|
|
||||||
}
|
|
||||||
result->setRepaintCallback([=] { update(); });
|
|
||||||
_player = std::move(result);
|
|
||||||
update();
|
|
||||||
}, _mediaLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GiftButton::setGeometry(QRect inner, QMargins extend) {
|
|
||||||
_extend = extend;
|
|
||||||
AbstractButton::setGeometry(inner.marginsAdded(extend));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GiftButton::paintEvent(QPaintEvent *e) {
|
|
||||||
auto p = QPainter(this);
|
|
||||||
const auto position = QPoint(_extend.left(), _extend.top());
|
|
||||||
p.drawImage(0, 0, _delegate->background());
|
|
||||||
|
|
||||||
if (_player && _player->ready()) {
|
|
||||||
const auto paused = !isOver();
|
|
||||||
auto info = _player->frame(
|
|
||||||
st::giftBoxStickerSize,
|
|
||||||
QColor(0, 0, 0, 0),
|
|
||||||
false,
|
|
||||||
crl::now(),
|
|
||||||
paused);
|
|
||||||
const auto finished = (info.index + 1 == _player->framesCount());
|
|
||||||
if (!finished || !paused) {
|
|
||||||
_player->markFrameShown();
|
|
||||||
}
|
|
||||||
const auto size = info.image.size() / style::DevicePixelRatio();
|
|
||||||
p.drawImage(
|
|
||||||
QRect(
|
|
||||||
(width() - size.width()) / 2,
|
|
||||||
(_text.isEmpty()
|
|
||||||
? st::giftBoxStickerStarTop
|
|
||||||
: st::giftBoxStickerTop),
|
|
||||||
size.width(),
|
|
||||||
size.height()),
|
|
||||||
info.image);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
|
||||||
const auto premium = v::is<GiftTypePremium>(_descriptor);
|
|
||||||
const auto singlew = _delegate->buttonSize().width();
|
|
||||||
const auto font = st::semiboldFont;
|
|
||||||
p.setFont(font);
|
|
||||||
const auto text = v::match(_descriptor, [&](GiftTypePremium data) {
|
|
||||||
if (data.discountPercent > 0) {
|
|
||||||
p.setBrush(st::attentionBoxButton.textFg);
|
|
||||||
const auto kMinus = QChar(0x2212);
|
|
||||||
return kMinus + QString::number(data.discountPercent) + '%';
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}, [&](const GiftTypeStars &data) {
|
|
||||||
if (data.limited) {
|
|
||||||
p.setBrush(st::windowActiveTextFg);
|
|
||||||
return tr::lng_gift_stars_limited(tr::now);
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
});
|
|
||||||
if (!text.isEmpty()) {
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
const auto twidth = font->width(text);
|
|
||||||
const auto pos = position + QPoint(singlew - twidth, font->height);
|
|
||||||
p.save();
|
|
||||||
p.translate(pos);
|
|
||||||
p.rotate(45.);
|
|
||||||
p.translate(-pos);
|
|
||||||
p.drawRect(-5 * twidth, position.y(), twidth * 12, font->height);
|
|
||||||
p.setPen(st::windowBg);
|
|
||||||
p.drawText(pos - QPoint(0, font->descent), text);
|
|
||||||
p.restore();
|
|
||||||
}
|
|
||||||
p.setBrush(premium ? st::lightButtonBgOver : st::creditsBg3);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
if (!premium) {
|
|
||||||
p.setOpacity(0.12);
|
|
||||||
}
|
|
||||||
const auto geometry = _button.translated(position);
|
|
||||||
const auto radius = geometry.height() / 2.;
|
|
||||||
p.drawRoundedRect(geometry, radius, radius);
|
|
||||||
if (!premium) {
|
|
||||||
p.setOpacity(1.);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_text.isEmpty()) {
|
|
||||||
p.setPen(st::windowFg);
|
|
||||||
_text.draw(p, {
|
|
||||||
.position = (position
|
|
||||||
+ QPoint(0, st::giftBoxPremiumTextTop)),
|
|
||||||
.availableWidth = singlew,
|
|
||||||
.align = style::al_top,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto padding = st::giftBoxButtonPadding;
|
|
||||||
p.setPen(premium ? st::windowActiveTextFg : st::creditsFg);
|
|
||||||
_price.draw(p, {
|
|
||||||
.position = (geometry.topLeft()
|
|
||||||
+ QPoint(padding.left(), padding.top())),
|
|
||||||
.availableWidth = _price.maxWidth(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] not_null<Ui::InputField*> AddPartInput(
|
[[nodiscard]] not_null<Ui::InputField*> AddPartInput(
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
rpl::producer<QString> placeholder,
|
rpl::producer<QString> placeholder,
|
||||||
|
@ -1136,122 +867,25 @@ void SendPremiumGift(
|
||||||
auto result = object_ptr<RpWidget>((QWidget*)nullptr);
|
auto result = object_ptr<RpWidget>((QWidget*)nullptr);
|
||||||
const auto raw = result.data();
|
const auto raw = result.data();
|
||||||
|
|
||||||
class Delegate final : public GiftButtonDelegate {
|
|
||||||
public:
|
|
||||||
Delegate(
|
|
||||||
not_null<Window::SessionController*> window,
|
|
||||||
not_null<PeerData*> peer)
|
|
||||||
: _window(window)
|
|
||||||
, _peer(peer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWithEntities star() override {
|
|
||||||
return _peer->owner().customEmojiManager().creditsEmoji();
|
|
||||||
}
|
|
||||||
std::any textContext() override {
|
|
||||||
return Core::MarkedTextContext{
|
|
||||||
.session = &_peer->session(),
|
|
||||||
.customEmojiRepaint = [] {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
QSize buttonSize() override {
|
|
||||||
if (!_single.isEmpty()) {
|
|
||||||
return _single;
|
|
||||||
}
|
|
||||||
const auto width = st::boxWideWidth;
|
|
||||||
const auto padding = st::giftBoxPadding;
|
|
||||||
const auto available = width - padding.left() - padding.right();
|
|
||||||
const auto singlew = (available - 2 * st::giftBoxGiftSkip.x())
|
|
||||||
/ kGiftsPerRow;
|
|
||||||
_single = QSize(singlew, st::giftBoxGiftHeight);
|
|
||||||
return _single;
|
|
||||||
}
|
|
||||||
void setBackground(QImage bg) {
|
|
||||||
_bg = std::move(bg);
|
|
||||||
}
|
|
||||||
QImage background() override {
|
|
||||||
return _bg;
|
|
||||||
}
|
|
||||||
DocumentData *lookupSticker(
|
|
||||||
const GiftDescriptor &descriptor) override {
|
|
||||||
const auto &session = _window->session();
|
|
||||||
auto &packs = session.giftBoxStickersPacks();
|
|
||||||
packs.load();
|
|
||||||
return v::match(descriptor, [&](GiftTypePremium data) {
|
|
||||||
return packs.lookup(data.months);
|
|
||||||
}, [&](GiftTypeStars data) {
|
|
||||||
return data.document
|
|
||||||
? data.document
|
|
||||||
: packs.lookup(packs.monthsForStars(data.stars));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const not_null<Window::SessionController*> _window;
|
|
||||||
const not_null<PeerData*> _peer;
|
|
||||||
QSize _single;
|
|
||||||
QImage _bg;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
Delegate delegate;
|
Delegate delegate;
|
||||||
std::vector<std::unique_ptr<GiftButton>> buttons;
|
std::vector<std::unique_ptr<GiftButton>> buttons;
|
||||||
bool sending = false;
|
bool sending = false;
|
||||||
};
|
};
|
||||||
const auto state = raw->lifetime().make_state<State>(State{
|
const auto state = raw->lifetime().make_state<State>(State{
|
||||||
.delegate = Delegate(window, peer),
|
.delegate = Delegate(window),
|
||||||
});
|
});
|
||||||
const auto single = state->delegate.buttonSize();
|
const auto single = state->delegate.buttonSize();
|
||||||
const auto shadow = st::defaultDropdownMenu.wrap.shadow;
|
const auto shadow = st::defaultDropdownMenu.wrap.shadow;
|
||||||
const auto extend = shadow.extend;
|
const auto extend = shadow.extend;
|
||||||
|
|
||||||
const auto bgSize = QRect(QPoint(), single ).marginsAdded(extend).size();
|
|
||||||
const auto ratio = style::DevicePixelRatio();
|
|
||||||
auto bg = QImage(
|
|
||||||
bgSize * ratio,
|
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
|
||||||
bg.setDevicePixelRatio(ratio);
|
|
||||||
bg.fill(Qt::transparent);
|
|
||||||
|
|
||||||
const auto radius = st::giftBoxGiftRadius;
|
|
||||||
const auto rect = QRect(QPoint(), bgSize).marginsRemoved(extend);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto p = QPainter(&bg);
|
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
|
||||||
p.setOpacity(0.3);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(st::windowShadowFg);
|
|
||||||
p.drawRoundedRect(
|
|
||||||
QRectF(rect).translated(0, radius / 12.),
|
|
||||||
radius,
|
|
||||||
radius);
|
|
||||||
}
|
|
||||||
bg = bg.scaled(
|
|
||||||
(bgSize * ratio) / 2,
|
|
||||||
Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation);
|
|
||||||
bg = Images::Blur(std::move(bg), true);
|
|
||||||
bg = bg.scaled(
|
|
||||||
bgSize * ratio,
|
|
||||||
Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation);
|
|
||||||
{
|
|
||||||
auto p = QPainter(&bg);
|
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(st::windowBg);
|
|
||||||
p.drawRoundedRect(rect, radius, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
state->delegate.setBackground(std::move(bg));
|
|
||||||
std::move(
|
std::move(
|
||||||
gifts
|
gifts
|
||||||
) | rpl::start_with_next([=](const GiftsDescriptor &gifts) {
|
) | rpl::start_with_next([=](const GiftsDescriptor &gifts) {
|
||||||
const auto width = st::boxWideWidth;
|
const auto width = st::boxWideWidth;
|
||||||
const auto padding = st::giftBoxPadding;
|
const auto padding = st::giftBoxPadding;
|
||||||
const auto available = width - padding.left() - padding.right();
|
const auto available = width - padding.left() - padding.right();
|
||||||
|
const auto perRow = available / single.width();
|
||||||
|
|
||||||
auto x = padding.left();
|
auto x = padding.left();
|
||||||
auto y = padding.top();
|
auto y = padding.top();
|
||||||
|
@ -1268,7 +902,7 @@ void SendPremiumGift(
|
||||||
const auto &descriptor = gifts.list[i];
|
const auto &descriptor = gifts.list[i];
|
||||||
button->setDescriptor(descriptor);
|
button->setDescriptor(descriptor);
|
||||||
|
|
||||||
const auto last = !((i + 1) % kGiftsPerRow);
|
const auto last = !((i + 1) % perRow);
|
||||||
if (last) {
|
if (last) {
|
||||||
x = padding.left() + available - single.width();
|
x = padding.left() + available - single.width();
|
||||||
}
|
}
|
||||||
|
@ -1306,7 +940,7 @@ void SendPremiumGift(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (gifts.list.size() % kGiftsPerRow) {
|
if (gifts.list.size() % perRow) {
|
||||||
y += padding.bottom() + single.height();
|
y += padding.bottom() + single.height();
|
||||||
} else {
|
} else {
|
||||||
y += padding.bottom() - st::giftBoxGiftSkip.y();
|
y += padding.bottom() - st::giftBoxGiftSkip.y();
|
||||||
|
@ -1368,7 +1002,6 @@ void AddBlock(
|
||||||
auto state = std::make_unique<State>();
|
auto state = std::make_unique<State>();
|
||||||
|
|
||||||
state->gifts = GiftsPremium(&window->session(), peer);
|
state->gifts = GiftsPremium(&window->session(), peer);
|
||||||
;
|
|
||||||
|
|
||||||
auto result = MakeGiftsList(window, peer, state->gifts.value(
|
auto result = MakeGiftsList(window, peer, state->gifts.value(
|
||||||
) | rpl::map([=](const PremiumGiftsDescriptor &gifts) {
|
) | rpl::map([=](const PremiumGiftsDescriptor &gifts) {
|
||||||
|
|
|
@ -983,19 +983,26 @@ int BusinessBotStatus::Bar::resizeGetHeight(int newWidth) {
|
||||||
const auto &st = st::defaultPeerList.item;
|
const auto &st = st::defaultPeerList.item;
|
||||||
_settings->moveToRight(0, 0, newWidth);
|
_settings->moveToRight(0, 0, newWidth);
|
||||||
if (_userpic) {
|
if (_userpic) {
|
||||||
_userpic->moveToLeft(st.photoPosition.x(), st.photoPosition.y());
|
_userpic->moveToLeft(
|
||||||
|
st.photoPosition.x(),
|
||||||
|
st.photoPosition.y(),
|
||||||
|
newWidth);
|
||||||
}
|
}
|
||||||
auto available = newWidth - _settings->width() - st.namePosition.x();
|
auto available = newWidth - _settings->width() - st.namePosition.x();
|
||||||
if (!_togglePaused->isHidden()) {
|
if (!_togglePaused->isHidden()) {
|
||||||
_togglePaused->moveToRight(
|
_togglePaused->moveToRight(
|
||||||
_settings->width(),
|
_settings->width(),
|
||||||
(st.height - _togglePaused->height()) / 2);
|
(st.height - _togglePaused->height()) / 2,
|
||||||
|
newWidth);
|
||||||
available -= _togglePaused->width();
|
available -= _togglePaused->width();
|
||||||
}
|
}
|
||||||
_name->resizeToWidth(available);
|
_name->resizeToWidth(available);
|
||||||
_name->moveToLeft(st.namePosition.x(), st.namePosition.y());
|
_name->moveToLeft(st.namePosition.x(), st.namePosition.y(), newWidth);
|
||||||
_status->resizeToWidth(available);
|
_status->resizeToWidth(available);
|
||||||
_status->moveToLeft(st.statusPosition.x(), st.statusPosition.y());
|
_status->moveToLeft(
|
||||||
|
st.statusPosition.x(),
|
||||||
|
st.statusPosition.y(),
|
||||||
|
newWidth);
|
||||||
return st.height;
|
return st.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
352
Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp
Normal file
352
Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
/*
|
||||||
|
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 "info/peer_gifts/info_peer_gifts_common.h"
|
||||||
|
|
||||||
|
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||||
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
|
#include "core/ui_integration.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "history/view/media/history_view_sticker_player.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "ui/text/format_values.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/painter.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
|
#include "styles/style_credits.h"
|
||||||
|
#include "styles/style_layers.h"
|
||||||
|
#include "styles/style_premium.h"
|
||||||
|
|
||||||
|
namespace Info::PeerGifts {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kGiftsPerRow = 3;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
GiftButton::GiftButton(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<GiftButtonDelegate*> delegate)
|
||||||
|
: AbstractButton(parent)
|
||||||
|
, _delegate(delegate) {
|
||||||
|
}
|
||||||
|
|
||||||
|
GiftButton::~GiftButton() = default;
|
||||||
|
|
||||||
|
void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
||||||
|
if (_descriptor == descriptor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto player = base::take(_player);
|
||||||
|
_mediaLifetime.destroy();
|
||||||
|
_descriptor = descriptor;
|
||||||
|
v::match(descriptor, [&](const GiftTypePremium &data) {
|
||||||
|
const auto months = data.months;
|
||||||
|
const auto years = (months % 12) ? 0 : months / 12;
|
||||||
|
_text = Ui::Text::String(st::giftBoxGiftHeight / 4);
|
||||||
|
_text.setMarkedText(
|
||||||
|
st::defaultTextStyle,
|
||||||
|
Ui::Text::Bold(years
|
||||||
|
? tr::lng_years(tr::now, lt_count, years)
|
||||||
|
: tr::lng_months(tr::now, lt_count, months)
|
||||||
|
).append('\n').append(
|
||||||
|
tr::lng_gift_premium_label(tr::now)
|
||||||
|
));
|
||||||
|
_price.setText(
|
||||||
|
st::semiboldTextStyle,
|
||||||
|
Ui::FillAmountAndCurrency(
|
||||||
|
data.cost,
|
||||||
|
data.currency,
|
||||||
|
true));
|
||||||
|
}, [&](const GiftTypeStars &data) {
|
||||||
|
_price.setMarkedText(
|
||||||
|
st::semiboldTextStyle,
|
||||||
|
_delegate->star().append(QString::number(data.stars)),
|
||||||
|
kMarkupTextOptions,
|
||||||
|
_delegate->textContext());
|
||||||
|
});
|
||||||
|
if (const auto document = _delegate->lookupSticker(descriptor)) {
|
||||||
|
setDocument(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto buttonw = _price.maxWidth();
|
||||||
|
const auto buttonh = st::semiboldFont->height;
|
||||||
|
const auto inner = QRect(
|
||||||
|
QPoint(),
|
||||||
|
QSize(buttonw, buttonh)
|
||||||
|
).marginsAdded(st::giftBoxButtonPadding);
|
||||||
|
const auto skipy = _delegate->buttonSize().height()
|
||||||
|
- st::giftBoxButtonBottom
|
||||||
|
- inner.height();
|
||||||
|
const auto skipx = (width() - inner.width()) / 2;
|
||||||
|
const auto outer = (width() - 2 * skipx);
|
||||||
|
_button = QRect(skipx, skipy, outer, inner.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GiftButton::setDocument(not_null<DocumentData*> document) {
|
||||||
|
const auto media = document->createMediaView();
|
||||||
|
media->checkStickerLarge();
|
||||||
|
media->goodThumbnailWanted();
|
||||||
|
|
||||||
|
rpl::single() | rpl::then(
|
||||||
|
document->owner().session().downloaderTaskFinished()
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return media->loaded();
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
_mediaLifetime.destroy();
|
||||||
|
|
||||||
|
auto result = std::unique_ptr<HistoryView::StickerPlayer>();
|
||||||
|
const auto sticker = document->sticker();
|
||||||
|
if (sticker->isLottie()) {
|
||||||
|
result = std::make_unique<HistoryView::LottiePlayer>(
|
||||||
|
ChatHelpers::LottiePlayerFromDocument(
|
||||||
|
media.get(),
|
||||||
|
ChatHelpers::StickerLottieSize::InlineResults,
|
||||||
|
st::giftBoxStickerSize,
|
||||||
|
Lottie::Quality::High));
|
||||||
|
} else if (sticker->isWebm()) {
|
||||||
|
result = std::make_unique<HistoryView::WebmPlayer>(
|
||||||
|
media->owner()->location(),
|
||||||
|
media->bytes(),
|
||||||
|
st::giftBoxStickerSize);
|
||||||
|
} else {
|
||||||
|
result = std::make_unique<HistoryView::StaticStickerPlayer>(
|
||||||
|
media->owner()->location(),
|
||||||
|
media->bytes(),
|
||||||
|
st::giftBoxStickerSize);
|
||||||
|
}
|
||||||
|
result->setRepaintCallback([=] { update(); });
|
||||||
|
_player = std::move(result);
|
||||||
|
update();
|
||||||
|
}, _mediaLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GiftButton::setGeometry(QRect inner, QMargins extend) {
|
||||||
|
_extend = extend;
|
||||||
|
AbstractButton::setGeometry(inner.marginsAdded(extend));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GiftButton::resizeEvent(QResizeEvent *e) {
|
||||||
|
if (!_button.isEmpty()) {
|
||||||
|
_button.moveLeft((width() - _button.width()) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GiftButton::paintEvent(QPaintEvent *e) {
|
||||||
|
auto p = QPainter(this);
|
||||||
|
const auto position = QPoint(_extend.left(), _extend.top());
|
||||||
|
const auto background = _delegate->background();
|
||||||
|
const auto dpr = int(background.devicePixelRatio());
|
||||||
|
const auto width = this->width();
|
||||||
|
if (width * dpr <= background.width()) {
|
||||||
|
p.drawImage(0, 0, background);
|
||||||
|
} else {
|
||||||
|
const auto full = background.width();
|
||||||
|
const auto half = ((full / 2) / dpr) * dpr;
|
||||||
|
const auto height = background.height();
|
||||||
|
p.drawImage(
|
||||||
|
QRect(0, 0, half / dpr, height / dpr),
|
||||||
|
background,
|
||||||
|
QRect(0, 0, half, height));
|
||||||
|
p.drawImage(
|
||||||
|
QRect(width - (half / dpr), 0, half / dpr, height / dpr),
|
||||||
|
background,
|
||||||
|
QRect(full - half, 0, half, height));
|
||||||
|
p.drawImage(
|
||||||
|
QRect(half / dpr, 0, width - 2 * (half / dpr), height / dpr),
|
||||||
|
background,
|
||||||
|
QRect(half, 0, 1, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_player && _player->ready()) {
|
||||||
|
const auto paused = !isOver();
|
||||||
|
auto info = _player->frame(
|
||||||
|
st::giftBoxStickerSize,
|
||||||
|
QColor(0, 0, 0, 0),
|
||||||
|
false,
|
||||||
|
crl::now(),
|
||||||
|
paused);
|
||||||
|
const auto finished = (info.index + 1 == _player->framesCount());
|
||||||
|
if (!finished || !paused) {
|
||||||
|
_player->markFrameShown();
|
||||||
|
}
|
||||||
|
const auto size = info.image.size() / style::DevicePixelRatio();
|
||||||
|
p.drawImage(
|
||||||
|
QRect(
|
||||||
|
(width - size.width()) / 2,
|
||||||
|
(_text.isEmpty()
|
||||||
|
? st::giftBoxStickerStarTop
|
||||||
|
: st::giftBoxStickerTop),
|
||||||
|
size.width(),
|
||||||
|
size.height()),
|
||||||
|
info.image);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
const auto premium = v::is<GiftTypePremium>(_descriptor);
|
||||||
|
const auto singlew = width - _extend.left() - _extend.right();
|
||||||
|
const auto font = st::semiboldFont;
|
||||||
|
p.setFont(font);
|
||||||
|
const auto text = v::match(_descriptor, [&](GiftTypePremium data) {
|
||||||
|
if (data.discountPercent > 0) {
|
||||||
|
p.setBrush(st::attentionBoxButton.textFg);
|
||||||
|
const auto kMinus = QChar(0x2212);
|
||||||
|
return kMinus + QString::number(data.discountPercent) + '%';
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}, [&](const GiftTypeStars &data) {
|
||||||
|
if (data.limited) {
|
||||||
|
p.setBrush(st::windowActiveTextFg);
|
||||||
|
return tr::lng_gift_stars_limited(tr::now);
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
});
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
const auto twidth = font->width(text);
|
||||||
|
const auto pos = position + QPoint(singlew - twidth, font->height);
|
||||||
|
p.save();
|
||||||
|
p.translate(pos);
|
||||||
|
p.rotate(45.);
|
||||||
|
p.translate(-pos);
|
||||||
|
p.drawRect(-5 * twidth, position.y(), twidth * 12, font->height);
|
||||||
|
p.setPen(st::windowBg);
|
||||||
|
p.drawText(pos - QPoint(0, font->descent), text);
|
||||||
|
p.restore();
|
||||||
|
}
|
||||||
|
p.setBrush(premium ? st::lightButtonBgOver : st::creditsBg3);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
if (!premium) {
|
||||||
|
p.setOpacity(0.12);
|
||||||
|
}
|
||||||
|
const auto geometry = _button;
|
||||||
|
const auto radius = geometry.height() / 2.;
|
||||||
|
p.drawRoundedRect(geometry, radius, radius);
|
||||||
|
if (!premium) {
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_text.isEmpty()) {
|
||||||
|
p.setPen(st::windowFg);
|
||||||
|
_text.draw(p, {
|
||||||
|
.position = (position
|
||||||
|
+ QPoint(0, st::giftBoxPremiumTextTop)),
|
||||||
|
.availableWidth = singlew,
|
||||||
|
.align = style::al_top,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto padding = st::giftBoxButtonPadding;
|
||||||
|
p.setPen(premium ? st::windowActiveTextFg : st::creditsFg);
|
||||||
|
_price.draw(p, {
|
||||||
|
.position = (geometry.topLeft()
|
||||||
|
+ QPoint(padding.left(), padding.top())),
|
||||||
|
.availableWidth = _price.maxWidth(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate::Delegate(not_null<Window::SessionController*> window)
|
||||||
|
: _window(window) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextWithEntities Delegate::star() {
|
||||||
|
const auto owner = &_window->session().data();
|
||||||
|
return owner->customEmojiManager().creditsEmoji();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::any Delegate::textContext() {
|
||||||
|
return Core::MarkedTextContext{
|
||||||
|
.session = &_window->session(),
|
||||||
|
.customEmojiRepaint = [] {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize Delegate::buttonSize() {
|
||||||
|
if (!_single.isEmpty()) {
|
||||||
|
return _single;
|
||||||
|
}
|
||||||
|
const auto width = st::boxWideWidth;
|
||||||
|
const auto padding = st::giftBoxPadding;
|
||||||
|
const auto available = width - padding.left() - padding.right();
|
||||||
|
const auto singlew = (available - 2 * st::giftBoxGiftSkip.x())
|
||||||
|
/ kGiftsPerRow;
|
||||||
|
_single = QSize(singlew, st::giftBoxGiftHeight);
|
||||||
|
return _single;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMargins Delegate::buttonExtend() {
|
||||||
|
return st::defaultDropdownMenu.wrap.shadow.extend;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage Delegate::background() {
|
||||||
|
if (!_bg.isNull()) {
|
||||||
|
return _bg;
|
||||||
|
}
|
||||||
|
const auto single = buttonSize();
|
||||||
|
const auto extend = buttonExtend();
|
||||||
|
const auto bgSize = single.grownBy(extend);
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
auto bg = QImage(
|
||||||
|
bgSize * ratio,
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
bg.setDevicePixelRatio(ratio);
|
||||||
|
bg.fill(Qt::transparent);
|
||||||
|
|
||||||
|
const auto radius = st::giftBoxGiftRadius;
|
||||||
|
const auto rect = QRect(QPoint(), bgSize).marginsRemoved(extend);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto p = QPainter(&bg);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setOpacity(0.3);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::windowShadowFg);
|
||||||
|
p.drawRoundedRect(
|
||||||
|
QRectF(rect).translated(0, radius / 12.),
|
||||||
|
radius,
|
||||||
|
radius);
|
||||||
|
}
|
||||||
|
bg = bg.scaled(
|
||||||
|
(bgSize * ratio) / 2,
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
bg = Images::Blur(std::move(bg), true);
|
||||||
|
bg = bg.scaled(
|
||||||
|
bgSize * ratio,
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
{
|
||||||
|
auto p = QPainter(&bg);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::windowBg);
|
||||||
|
p.drawRoundedRect(rect, radius, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
_bg = std::move(bg);
|
||||||
|
return _bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *Delegate::lookupSticker(const GiftDescriptor &descriptor) {
|
||||||
|
const auto &session = _window->session();
|
||||||
|
auto &packs = session.giftBoxStickersPacks();
|
||||||
|
packs.load();
|
||||||
|
return v::match(descriptor, [&](GiftTypePremium data) {
|
||||||
|
return packs.lookup(data.months);
|
||||||
|
}, [&](GiftTypeStars data) {
|
||||||
|
return data.document
|
||||||
|
? data.document
|
||||||
|
: packs.lookup(packs.monthsForStars(data.stars));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Info::PeerGifts
|
111
Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h
Normal file
111
Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
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/abstract_button.h"
|
||||||
|
#include "ui/text/text.h"
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
class StickerPlayer;
|
||||||
|
} // namespace HistoryView
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Info::PeerGifts {
|
||||||
|
|
||||||
|
struct GiftTypePremium {
|
||||||
|
int64 cost = 0;
|
||||||
|
QString currency;
|
||||||
|
int months = 0;
|
||||||
|
int discountPercent = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] friend inline bool operator==(
|
||||||
|
const GiftTypePremium &,
|
||||||
|
const GiftTypePremium &) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GiftTypeStars {
|
||||||
|
uint64 id = 0;
|
||||||
|
int64 stars = 0;
|
||||||
|
int64 convertStars = 0;
|
||||||
|
DocumentData *document = nullptr;
|
||||||
|
PeerData *from = nullptr;
|
||||||
|
bool limited = false;
|
||||||
|
bool userpic = false;
|
||||||
|
|
||||||
|
[[nodiscard]] friend inline bool operator==(
|
||||||
|
const GiftTypeStars&,
|
||||||
|
const GiftTypeStars&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GiftDescriptor : std::variant<GiftTypePremium, GiftTypeStars> {
|
||||||
|
using variant::variant;
|
||||||
|
|
||||||
|
[[nodiscard]] friend inline bool operator==(
|
||||||
|
const GiftDescriptor&,
|
||||||
|
const GiftDescriptor&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GiftButtonDelegate {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] virtual TextWithEntities star() = 0;
|
||||||
|
[[nodiscard]] virtual std::any textContext() = 0;
|
||||||
|
[[nodiscard]] virtual QSize buttonSize() = 0;
|
||||||
|
[[nodiscard]] virtual QMargins buttonExtend() = 0;
|
||||||
|
[[nodiscard]] virtual QImage background() = 0;
|
||||||
|
[[nodiscard]] virtual DocumentData *lookupSticker(
|
||||||
|
const GiftDescriptor &descriptor) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GiftButton final : public Ui::AbstractButton {
|
||||||
|
public:
|
||||||
|
GiftButton(QWidget *parent, not_null<GiftButtonDelegate*> delegate);
|
||||||
|
~GiftButton();
|
||||||
|
|
||||||
|
void setDescriptor(const GiftDescriptor &descriptor);
|
||||||
|
void setGeometry(QRect inner, QMargins extend);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
void setDocument(not_null<DocumentData*> document);
|
||||||
|
|
||||||
|
const not_null<GiftButtonDelegate*> _delegate;
|
||||||
|
GiftDescriptor _descriptor;
|
||||||
|
Ui::Text::String _text;
|
||||||
|
Ui::Text::String _price;
|
||||||
|
QRect _button;
|
||||||
|
QMargins _extend;
|
||||||
|
|
||||||
|
std::unique_ptr<HistoryView::StickerPlayer> _player;
|
||||||
|
rpl::lifetime _mediaLifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Delegate final : public GiftButtonDelegate {
|
||||||
|
public:
|
||||||
|
explicit Delegate(not_null<Window::SessionController*> window);
|
||||||
|
|
||||||
|
TextWithEntities star() override;
|
||||||
|
std::any textContext() override;
|
||||||
|
QSize buttonSize() override;
|
||||||
|
QMargins buttonExtend() override;
|
||||||
|
QImage background() override;
|
||||||
|
DocumentData *lookupSticker(const GiftDescriptor &descriptor) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const not_null<Window::SessionController*> _window;
|
||||||
|
QSize _single;
|
||||||
|
QImage _bg;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Info::PeerGifts
|
|
@ -7,16 +7,40 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "info/peer_gifts/info_peer_gifts_widget.h"
|
#include "info/peer_gifts/info_peer_gifts_widget.h"
|
||||||
|
|
||||||
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||||
#include "info/info_controller.h"
|
#include "info/info_controller.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "mtproto/sender.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_info.h"
|
#include "styles/style_info.h"
|
||||||
|
#include "styles/style_credits.h" // giftBoxPadding
|
||||||
|
|
||||||
namespace Info::PeerGifts {
|
namespace Info::PeerGifts {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kPreloadPages = 2;
|
||||||
|
constexpr auto kPerPage = 50;
|
||||||
|
|
||||||
|
[[nodiscard]] GiftDescriptor DescriptorForGift(
|
||||||
|
not_null<Data::Session*> owner,
|
||||||
|
const Api::UserStarGift &gift) {
|
||||||
|
return GiftTypeStars{
|
||||||
|
.id = gift.gift.id,
|
||||||
|
.stars = gift.gift.stars,
|
||||||
|
.convertStars = gift.gift.convertStars,
|
||||||
|
.document = gift.gift.document,
|
||||||
|
.from = ((gift.hidden || !gift.fromId)
|
||||||
|
? nullptr
|
||||||
|
: owner->peer(gift.fromId).get()),
|
||||||
|
.limited = (gift.gift.limitedCount > 0),
|
||||||
|
.userpic = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class InnerWidget final : public Ui::RpWidget {
|
class InnerWidget final : public Ui::RpWidget {
|
||||||
|
@ -30,24 +54,51 @@ public:
|
||||||
return _user;
|
return _user;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<Ui::ScrollToRequest> scrollToRequests() const;
|
|
||||||
|
|
||||||
int desiredHeight() const;
|
|
||||||
|
|
||||||
void saveState(not_null<Memento*> memento);
|
void saveState(not_null<Memento*> memento);
|
||||||
void restoreState(not_null<Memento*> memento);
|
void restoreState(not_null<Memento*> memento);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
struct Entry {
|
||||||
|
Api::UserStarGift gift;
|
||||||
|
GiftDescriptor descriptor;
|
||||||
|
};
|
||||||
|
struct View {
|
||||||
|
std::unique_ptr<GiftButton> button;
|
||||||
|
Api::UserStarGift gift;
|
||||||
|
};
|
||||||
|
|
||||||
void visibleTopBottomUpdated(
|
void visibleTopBottomUpdated(
|
||||||
int visibleTop,
|
int visibleTop,
|
||||||
int visibleBottom) override;
|
int visibleBottom) override;
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
private:
|
void loadMore();
|
||||||
|
void validateButtons();
|
||||||
|
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
Delegate _delegate;
|
||||||
const std::shared_ptr<Main::SessionShow> _show;
|
const std::shared_ptr<Main::SessionShow> _show;
|
||||||
not_null<Controller*> _controller;
|
not_null<Controller*> _controller;
|
||||||
const not_null<UserData*> _user;
|
const not_null<UserData*> _user;
|
||||||
|
std::vector<Entry> _entries;
|
||||||
|
int _totalCount = 0;
|
||||||
|
|
||||||
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
|
MTP::Sender _api;
|
||||||
|
mtpRequestId _loadMoreRequestId = 0;
|
||||||
|
QString _offset;
|
||||||
|
bool _allLoaded = false;
|
||||||
|
|
||||||
|
std::vector<View> _views;
|
||||||
|
int _viewsForWidth = 0;
|
||||||
|
int _viewsFromRow = 0;
|
||||||
|
int _viewsTillRow = 0;
|
||||||
|
|
||||||
|
QSize _singleMin;
|
||||||
|
QSize _single;
|
||||||
|
int _perRow = 0;
|
||||||
|
int _visibleFrom = 0;
|
||||||
|
int _visibleTill = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,14 +107,155 @@ InnerWidget::InnerWidget(
|
||||||
not_null<Controller*> controller,
|
not_null<Controller*> controller,
|
||||||
not_null<UserData*> user)
|
not_null<UserData*> user)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
|
, _delegate(controller->parentController())
|
||||||
, _show(controller->uiShow())
|
, _show(controller->uiShow())
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _user(user) {
|
, _user(user)
|
||||||
|
, _totalCount(_user->peerGiftsCount())
|
||||||
|
, _api(&_user->session().mtp()) {
|
||||||
|
_singleMin = _delegate.buttonSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::visibleTopBottomUpdated(
|
void InnerWidget::visibleTopBottomUpdated(
|
||||||
int visibleTop,
|
int visibleTop,
|
||||||
int visibleBottom) {
|
int visibleBottom) {
|
||||||
|
const auto page = (visibleBottom - visibleTop);
|
||||||
|
if (visibleBottom + page * kPreloadPages >= height()) {
|
||||||
|
loadMore();
|
||||||
|
}
|
||||||
|
_visibleFrom = visibleTop;
|
||||||
|
_visibleTill = visibleBottom;
|
||||||
|
validateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
auto p = QPainter(this);
|
||||||
|
|
||||||
|
p.fillRect(e->rect(), st::boxDividerBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::loadMore() {
|
||||||
|
if (_allLoaded || _loadMoreRequestId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_loadMoreRequestId = _api.request(MTPpayments_GetUserStarGifts(
|
||||||
|
_user->inputUser,
|
||||||
|
MTP_string(_offset),
|
||||||
|
MTP_int(kPerPage)
|
||||||
|
)).done([=](const MTPpayments_UserStarGifts &result) {
|
||||||
|
_loadMoreRequestId = 0;
|
||||||
|
const auto &data = result.data();
|
||||||
|
if (const auto next = data.vnext_offset()) {
|
||||||
|
_offset = qs(*next);
|
||||||
|
} else {
|
||||||
|
_allLoaded = true;
|
||||||
|
}
|
||||||
|
_totalCount = data.vcount().v;
|
||||||
|
|
||||||
|
const auto owner = &_user->owner();
|
||||||
|
owner->processUsers(data.vusers());
|
||||||
|
|
||||||
|
const auto session = &_show->session();
|
||||||
|
_entries.reserve(_entries.size() + data.vgifts().v.size());
|
||||||
|
for (const auto &gift : data.vgifts().v) {
|
||||||
|
if (auto parsed = Api::FromTL(session, gift)) {
|
||||||
|
auto descriptor = DescriptorForGift(owner, *parsed);
|
||||||
|
_entries.push_back({
|
||||||
|
.gift = std::move(*parsed),
|
||||||
|
.descriptor = std::move(descriptor),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_viewsForWidth = 0;
|
||||||
|
_viewsFromRow = 0;
|
||||||
|
_viewsTillRow = 0;
|
||||||
|
resizeToWidth(width());
|
||||||
|
validateButtons();
|
||||||
|
}).fail([=] {
|
||||||
|
_loadMoreRequestId = 0;
|
||||||
|
_allLoaded = true;
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::validateButtons() {
|
||||||
|
if (!_perRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto row = _single.height() + st::giftBoxGiftSkip.y();
|
||||||
|
const auto fromRow = _visibleFrom / row;
|
||||||
|
const auto tillRow = (_visibleTill + row - 1) / row;
|
||||||
|
Assert(tillRow >= fromRow);
|
||||||
|
if (_viewsFromRow == fromRow
|
||||||
|
&& _viewsTillRow == tillRow
|
||||||
|
&& _viewsForWidth == width()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_viewsFromRow = fromRow;
|
||||||
|
_viewsTillRow = tillRow;
|
||||||
|
_viewsForWidth = width();
|
||||||
|
|
||||||
|
const auto padding = st::giftBoxPadding;
|
||||||
|
const auto available = _viewsForWidth - padding.left() - padding.right();
|
||||||
|
const auto skipw = st::giftBoxGiftSkip.x();
|
||||||
|
const auto fullw = _perRow * (_single.width() + skipw) - skipw;
|
||||||
|
const auto left = padding.left() + (available - fullw) / 2;
|
||||||
|
auto x = left;
|
||||||
|
auto y = padding.bottom();
|
||||||
|
auto entry = 0;
|
||||||
|
for (auto j = fromRow; j != tillRow; ++j) {
|
||||||
|
for (auto i = 0; i != _perRow; ++i) {
|
||||||
|
const auto index = j * _perRow + i;
|
||||||
|
if (index >= _entries.size()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const auto &descriptor = _entries[index].descriptor;
|
||||||
|
if (entry < _views.size()) {
|
||||||
|
_views[entry].button->setDescriptor(descriptor);
|
||||||
|
} else {
|
||||||
|
auto button = std::make_unique<GiftButton>(this, &_delegate);
|
||||||
|
button->setDescriptor(descriptor);
|
||||||
|
_views.push_back({
|
||||||
|
.button = std::move(button),
|
||||||
|
.gift = _entries[index].gift,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_views[entry].button->show();
|
||||||
|
_views[entry].button->setGeometry(
|
||||||
|
QRect(QPoint(x, y), _single),
|
||||||
|
_delegate.buttonExtend());
|
||||||
|
++entry;
|
||||||
|
x += _single.width() + skipw;
|
||||||
|
}
|
||||||
|
x = left;
|
||||||
|
y += _single.height() + st::giftBoxGiftSkip.y();
|
||||||
|
}
|
||||||
|
for (auto k = entry; k != int(_views.size()); ++k) {
|
||||||
|
_views[k].button->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int InnerWidget::resizeGetHeight(int width) {
|
||||||
|
const auto count = int(_entries.size());
|
||||||
|
const auto padding = st::giftBoxPadding;
|
||||||
|
const auto available = width - padding.left() - padding.right();
|
||||||
|
const auto skipw = st::giftBoxGiftSkip.x();
|
||||||
|
_perRow = std::min(
|
||||||
|
(available + skipw) / (_singleMin.width() + skipw),
|
||||||
|
count);
|
||||||
|
if (!_perRow) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto singlew = std::min(
|
||||||
|
((available + skipw) / _perRow) - skipw,
|
||||||
|
2 * _singleMin.width());
|
||||||
|
Assert(singlew >= _singleMin.width());
|
||||||
|
const auto singleh = _singleMin.height();
|
||||||
|
|
||||||
|
_single = QSize(singlew, singleh);
|
||||||
|
const auto rows = (count + _perRow - 1) / _perRow;
|
||||||
|
const auto skiph = st::giftBoxGiftSkip.y();
|
||||||
|
|
||||||
|
return padding.bottom() * 2 + rows * (singleh + skiph) - skiph;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::saveState(not_null<Memento*> memento) {
|
void InnerWidget::saveState(not_null<Memento*> memento) {
|
||||||
|
@ -77,16 +269,6 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<Ui::ScrollToRequest> InnerWidget::scrollToRequests() const {
|
|
||||||
return _scrollToRequests.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
int InnerWidget::desiredHeight() const {
|
|
||||||
auto desired = 0;
|
|
||||||
|
|
||||||
return qMax(height(), desired);
|
|
||||||
}
|
|
||||||
|
|
||||||
Memento::Memento(not_null<UserData*> user)
|
Memento::Memento(not_null<UserData*> user)
|
||||||
: ContentMemento(user, nullptr, PeerId()) {
|
: ContentMemento(user, nullptr, PeerId()) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "api/api_premium.h"
|
||||||
#include "info/info_content_widget.h"
|
#include "info/info_content_widget.h"
|
||||||
|
|
||||||
class UserData;
|
class UserData;
|
||||||
|
@ -14,17 +15,8 @@ struct PeerListState;
|
||||||
|
|
||||||
namespace Info::PeerGifts {
|
namespace Info::PeerGifts {
|
||||||
|
|
||||||
struct ListEntry {
|
|
||||||
TextWithEntities message;
|
|
||||||
int64 convertStars = 0;
|
|
||||||
PeerId fromId = 0;
|
|
||||||
MsgId messageId = 0;
|
|
||||||
bool anonymous = false;
|
|
||||||
bool hidden = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ListState {
|
struct ListState {
|
||||||
std::vector<ListEntry> list;
|
std::vector<Api::UserStarGift> list;
|
||||||
QString offset;
|
QString offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue