mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Add sending gift preview.
This commit is contained in:
parent
a5be0a685a
commit
37f837dcb7
5 changed files with 616 additions and 39 deletions
|
@ -1855,6 +1855,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_action_gift_received" = "{user} sent you a gift for {cost}";
|
||||
"lng_action_gift_received_me" = "You sent to {user} a gift for {cost}";
|
||||
"lng_action_gift_received_anonymous" = "Unknown user sent you a gift for {cost}";
|
||||
"lng_action_gift_anonymous" = "Anonymous Gift";
|
||||
"lng_action_gift_got_subtitle" = "Gift from {user}";
|
||||
"lng_action_gift_got_stars_text" = "Display this gift on your page or convert it to {cost}.";
|
||||
"lng_action_suggested_photo_me" = "You suggested this photo for {user}'s Telegram profile.";
|
||||
"lng_action_suggested_photo" = "{user} suggests this photo for your Telegram profile.";
|
||||
"lng_action_suggested_photo_button" = "View Photo";
|
||||
|
@ -2991,6 +2994,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_gift_stars_limited" = "limited";
|
||||
"lng_gift_stars_tabs_all" = "All Gifts";
|
||||
"lng_gift_stars_tabs_limited" = "Limited";
|
||||
"lng_gift_send_title" = "Send a Gift";
|
||||
"lng_gift_send_message" = "Enter Message";
|
||||
"lng_gift_send_anonymous" = "Hide My Name";
|
||||
"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message.";
|
||||
"lng_gift_send_button" = "Send a Gift for {cost}";
|
||||
|
||||
"lng_accounts_limit_title" = "Limit Reached";
|
||||
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account.";
|
||||
|
|
|
@ -10,18 +10,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_credits.h"
|
||||
#include "api/api_premium.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/send_credits_box.h"
|
||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||
#include "chat_helpers/stickers_lottie.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/stickers/data_custom_emoji.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/history_view_element.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/session/session_show.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "settings/settings_credits.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/chat/chat_theme.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
#include "ui/effects/premium_graphics.h"
|
||||
#include "ui/effects/premium_stars_colored.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
|
@ -31,8 +43,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/label_with_custom_emoji.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/section_widget.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_channel_earn.h"
|
||||
|
@ -41,9 +56,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_giveaway.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_premium.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 {
|
||||
|
@ -51,6 +68,9 @@ namespace {
|
|||
constexpr auto kPriceTabAll = 0;
|
||||
constexpr auto kPriceTabLimited = -1;
|
||||
constexpr auto kGiftsPerRow = 3;
|
||||
constexpr auto kGiftMessageLimit = 256;
|
||||
|
||||
using namespace HistoryView;
|
||||
|
||||
struct GiftTypePremium {
|
||||
int64 cost = 0;
|
||||
|
@ -81,6 +101,259 @@ struct GiftDescriptor : std::variant<GiftTypePremium, GiftTypeStars> {
|
|||
const GiftDescriptor&) = default;
|
||||
};
|
||||
|
||||
struct GiftDetails {
|
||||
GiftDescriptor descriptor;
|
||||
QString text;
|
||||
bool anonymous = false;
|
||||
};
|
||||
|
||||
class PreviewDelegate final : public DefaultElementDelegate {
|
||||
public:
|
||||
PreviewDelegate(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Ui::ChatStyle*> st,
|
||||
Fn<void()> update);
|
||||
|
||||
bool elementAnimationsPaused() override;
|
||||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||
Context elementContext() override;
|
||||
|
||||
private:
|
||||
const not_null<QWidget*> _parent;
|
||||
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||
|
||||
};
|
||||
|
||||
class PreviewWrap final : public Ui::RpWidget {
|
||||
public:
|
||||
PreviewWrap(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<GiftDetails> details);
|
||||
~PreviewWrap();
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void resizeTo(int width);
|
||||
void prepare(rpl::producer<GiftDetails> details);
|
||||
|
||||
const not_null<History*> _history;
|
||||
const std::unique_ptr<Ui::ChatTheme> _theme;
|
||||
const std::unique_ptr<Ui::ChatStyle> _style;
|
||||
const std::unique_ptr<PreviewDelegate> _delegate;
|
||||
AdminLog::OwnedItem _item;
|
||||
QPoint _position;
|
||||
|
||||
};
|
||||
|
||||
PreviewDelegate::PreviewDelegate(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Ui::ChatStyle*> st,
|
||||
Fn<void()> update)
|
||||
: _parent(parent)
|
||||
, _pathGradient(MakePathShiftGradient(st, update)) {
|
||||
}
|
||||
|
||||
bool PreviewDelegate::elementAnimationsPaused() {
|
||||
return _parent->window()->isActiveWindow();
|
||||
}
|
||||
|
||||
auto PreviewDelegate::elementPathShiftGradient()
|
||||
-> not_null<Ui::PathShiftGradient*> {
|
||||
return _pathGradient.get();
|
||||
}
|
||||
|
||||
Context PreviewDelegate::elementContext() {
|
||||
return Context::History;
|
||||
}
|
||||
|
||||
auto GenerateGiftMedia(
|
||||
not_null<Element*> parent,
|
||||
Element *replacing,
|
||||
const GiftDetails &data)
|
||||
-> Fn<void(Fn<void(std::unique_ptr<MediaGenericPart>)>)> {
|
||||
return [=](Fn<void(std::unique_ptr<MediaGenericPart>)> push) {
|
||||
const auto &descriptor = data.descriptor;
|
||||
auto pushText = [&](
|
||||
TextWithEntities text,
|
||||
QMargins margins = {},
|
||||
const base::flat_map<uint16, ClickHandlerPtr> &links = {}) {
|
||||
if (text.empty()) {
|
||||
return;
|
||||
}
|
||||
push(std::make_unique<MediaGenericTextPart>(
|
||||
std::move(text),
|
||||
margins,
|
||||
links));
|
||||
};
|
||||
const auto sticker = [=] {
|
||||
using Tag = ChatHelpers::StickerLottieSize;
|
||||
const auto &session = parent->history()->session();
|
||||
auto &packs = session.giftBoxStickersPacks();
|
||||
packs.load();
|
||||
auto sticker = v::match(descriptor, [&](GiftTypePremium data) {
|
||||
return packs.lookup(data.months);
|
||||
}, [&](GiftTypeStars data) {
|
||||
return data.document
|
||||
? data.document
|
||||
: packs.lookup(packs.monthsForStars(data.stars));
|
||||
});
|
||||
return StickerInBubblePart::Data{
|
||||
.sticker = sticker,
|
||||
.size = st::chatIntroStickerSize,
|
||||
.cacheTag = Tag::ChatIntroHelloSticker,
|
||||
.singleTimePlayback = v::is<GiftTypePremium>(descriptor),
|
||||
};
|
||||
};
|
||||
push(std::make_unique<StickerInBubblePart>(
|
||||
parent,
|
||||
replacing,
|
||||
sticker,
|
||||
st::giftBoxPreviewStickerPadding));
|
||||
const auto title = data.anonymous
|
||||
? tr::lng_action_gift_anonymous(tr::now)
|
||||
: tr::lng_action_gift_got_subtitle(
|
||||
tr::now,
|
||||
lt_user,
|
||||
parent->data()->history()->session().user()->shortName());
|
||||
auto textFallback = v::match(descriptor, [&](GiftTypePremium data) {
|
||||
return TextWithEntities{
|
||||
u"Use all those premium features with joy!"_q
|
||||
};
|
||||
}, [&](GiftTypeStars data) {
|
||||
return tr::lng_action_gift_got_stars_text(
|
||||
tr::now,
|
||||
lt_cost,
|
||||
tr::lng_gift_stars_title(
|
||||
tr::now,
|
||||
lt_count,
|
||||
data.stars,
|
||||
Ui::Text::Bold),
|
||||
Ui::Text::WithEntities);
|
||||
});
|
||||
auto description = data.text.isEmpty()
|
||||
? std::move(textFallback)
|
||||
: TextWithEntities{ data.text };
|
||||
pushText(Ui::Text::Bold(title), st::giftBoxPreviewTitlePadding);
|
||||
pushText(std::move(description), st::giftBoxPreviewTextPadding);
|
||||
};
|
||||
}
|
||||
|
||||
PreviewWrap::PreviewWrap(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<GiftDetails> details)
|
||||
: RpWidget(parent)
|
||||
, _history(session->data().history(session->userPeerId()))
|
||||
, _theme(Window::Theme::DefaultChatThemeOn(lifetime()))
|
||||
, _style(std::make_unique<Ui::ChatStyle>(
|
||||
_history->session().colorIndicesValue()))
|
||||
, _delegate(std::make_unique<PreviewDelegate>(
|
||||
parent,
|
||||
_style.get(),
|
||||
[=] { update(); }))
|
||||
, _position(0, st::msgMargin.bottom()) {
|
||||
_style->apply(_theme.get());
|
||||
|
||||
using namespace HistoryView;
|
||||
session->data().viewRepaintRequest(
|
||||
) | rpl::start_with_next([=](not_null<const Element*> view) {
|
||||
if (view == _item.get()) {
|
||||
update();
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
session->downloaderTaskFinished() | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
prepare(std::move(details));
|
||||
}
|
||||
|
||||
PreviewWrap::~PreviewWrap() {
|
||||
_item = {};
|
||||
}
|
||||
|
||||
void PreviewWrap::prepare(rpl::producer<GiftDetails> details) {
|
||||
std::move(details) | rpl::start_with_next([=](GiftDetails details) {
|
||||
const auto &descriptor = details.descriptor;
|
||||
const auto cost = v::match(descriptor, [&](GiftTypePremium data) {
|
||||
return FillAmountAndCurrency(data.cost, data.currency, true);
|
||||
}, [&](GiftTypeStars data) {
|
||||
return tr::lng_gift_stars_title(tr::now, lt_count, data.stars);
|
||||
});
|
||||
const auto text = details.anonymous
|
||||
? tr::lng_action_gift_received_anonymous(tr::now, lt_cost, cost)
|
||||
: tr::lng_action_gift_received(
|
||||
tr::now,
|
||||
lt_user,
|
||||
_history->session().user()->shortName(),
|
||||
lt_cost,
|
||||
cost);
|
||||
const auto item = _history->makeMessage({
|
||||
.id = _history->nextNonHistoryEntryId(),
|
||||
.flags = (MessageFlag::FakeAboutView
|
||||
| MessageFlag::FakeHistoryItem
|
||||
| MessageFlag::Local),
|
||||
.from = _history->peer->id,
|
||||
}, PreparedServiceText{ { text } });
|
||||
|
||||
auto owned = AdminLog::OwnedItem(_delegate.get(), item);
|
||||
owned->overrideMedia(std::make_unique<MediaGeneric>(
|
||||
owned.get(),
|
||||
GenerateGiftMedia(owned.get(), _item.get(), details),
|
||||
MediaGenericDescriptor{
|
||||
.maxWidth = st::chatIntroWidth,
|
||||
.service = true,
|
||||
}));
|
||||
_item = std::move(owned);
|
||||
if (width() >= st::msgMinWidth) {
|
||||
resizeTo(width());
|
||||
}
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
widthValue(
|
||||
) | rpl::filter([=](int width) {
|
||||
return width >= st::msgMinWidth;
|
||||
}) | rpl::start_with_next([=](int width) {
|
||||
resizeTo(width);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void PreviewWrap::resizeTo(int width) {
|
||||
const auto height = _position.y()
|
||||
+ _item->resizeGetHeight(width)
|
||||
+ _position.y()
|
||||
+ st::msgServiceMargin.top()
|
||||
+ st::msgServiceGiftBoxTopSkip
|
||||
- st::msgServiceMargin.bottom();
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
void PreviewWrap::paintEvent(QPaintEvent *e) {
|
||||
auto p = Painter(this);
|
||||
|
||||
const auto clip = e->rect();
|
||||
if (!clip.isEmpty()) {
|
||||
p.setClipRect(clip);
|
||||
Window::SectionWidget::PaintBackground(
|
||||
p,
|
||||
_theme.get(),
|
||||
QSize(width(), window()->height()),
|
||||
clip);
|
||||
}
|
||||
|
||||
auto context = _theme->preparePaintContext(
|
||||
_style.get(),
|
||||
rect(),
|
||||
e->rect(),
|
||||
!window()->isActiveWindow());
|
||||
p.translate(_position);
|
||||
_item->draw(p, context);
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<std::vector<GiftTypePremium>> GiftsPremium(
|
||||
not_null<Main::Session*> session,
|
||||
not_null<PeerData*> peer) {
|
||||
|
@ -389,6 +662,8 @@ public:
|
|||
[[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 {
|
||||
|
@ -402,13 +677,17 @@ public:
|
|||
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<HistoryView::StickerPlayer> _player;
|
||||
|
||||
std::unique_ptr<StickerPlayer> _player;
|
||||
rpl::lifetime _mediaLifetime;
|
||||
|
||||
};
|
||||
|
||||
|
@ -423,6 +702,8 @@ 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;
|
||||
|
@ -449,6 +730,10 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
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(
|
||||
|
@ -464,6 +749,44 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
_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));
|
||||
|
@ -474,6 +797,30 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
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();
|
||||
|
@ -481,12 +828,12 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
v::match(_descriptor, [&](const GiftTypePremium &data) {
|
||||
if (data.discountPercent > 0) {
|
||||
p.setPen(st::attentionBoxButton.textFg);
|
||||
p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), '-' + QString::number(data.discountPercent) + '%', style::al_center);
|
||||
p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), '-' + QString::number(data.discountPercent) + '%', style::al_topright);
|
||||
}
|
||||
}, [&](const GiftTypeStars &data) {
|
||||
if (data.limited) {
|
||||
p.setPen(st::windowActiveTextFg);
|
||||
p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), u"limited"_q, style::al_center);
|
||||
p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), u"limited"_q, style::al_topright);
|
||||
}
|
||||
});
|
||||
p.setBrush(premium ? st::lightButtonBgOver : st::creditsBg3);
|
||||
|
@ -520,6 +867,124 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] not_null<Ui::InputField*> AddPartInput(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
rpl::producer<QString> placeholder,
|
||||
QString current,
|
||||
int limit) {
|
||||
const auto field = container->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
container,
|
||||
st::giftBoxTextField,
|
||||
Ui::InputField::Mode::NoNewlines,
|
||||
std::move(placeholder),
|
||||
current),
|
||||
st::giftBoxTextPadding);
|
||||
field->setMaxLength(limit);
|
||||
Ui::AddLengthLimitLabel(field, limit);
|
||||
return field;
|
||||
}
|
||||
|
||||
void SendGiftBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer,
|
||||
const GiftDescriptor &descriptor) {
|
||||
box->setStyle(st::giftBox);
|
||||
box->setWidth(st::boxWideWidth);
|
||||
box->setTitle(tr::lng_gift_send_title());
|
||||
box->addTopButton(st::boxTitleClose, [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
|
||||
const auto session = &window->session();
|
||||
const auto context = Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = [] {},
|
||||
};
|
||||
auto cost = rpl::single([&] {
|
||||
return v::match(descriptor, [&](const GiftTypePremium &data) {
|
||||
if (data.currency == Ui::kCreditsCurrency) {
|
||||
return Ui::CreditsEmojiSmall(session).append(
|
||||
Lang::FormatCountDecimal(std::abs(data.cost)));
|
||||
}
|
||||
return TextWithEntities{
|
||||
FillAmountAndCurrency(data.cost, data.currency),
|
||||
};
|
||||
}, [&](const GiftTypeStars &data) {
|
||||
return Ui::CreditsEmojiSmall(session).append(
|
||||
Lang::FormatCountDecimal(std::abs(data.stars)));
|
||||
});
|
||||
}());
|
||||
const auto button = box->addButton(rpl::single(QString()), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
SetButtonMarkedLabel(
|
||||
button,
|
||||
tr::lng_gift_send_button(
|
||||
lt_cost,
|
||||
std::move(cost),
|
||||
Ui::Text::WithEntities),
|
||||
session,
|
||||
st::creditsBoxButtonLabel,
|
||||
st::giftBox.button.textFg->c);
|
||||
|
||||
struct State {
|
||||
rpl::variable<GiftDetails> details;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->details = GiftDetails{
|
||||
.descriptor = descriptor,
|
||||
};
|
||||
|
||||
const auto container = box->verticalLayout();
|
||||
container->add(object_ptr<PreviewWrap>(
|
||||
container,
|
||||
session,
|
||||
state->details.value()));
|
||||
|
||||
const auto text = AddPartInput(
|
||||
container,
|
||||
tr::lng_gift_send_message(),
|
||||
QString(),
|
||||
kGiftMessageLimit);
|
||||
text->changes() | rpl::start_with_next([=] {
|
||||
auto now = state->details.current();
|
||||
now.text = text->getLastText();
|
||||
state->details = std::move(now);
|
||||
}, text->lifetime());
|
||||
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
container->add(
|
||||
object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
tr::lng_gift_send_anonymous(),
|
||||
st::settingsButtonNoIcon)
|
||||
)->toggleOn(rpl::single(false))->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
auto now = state->details.current();
|
||||
now.anonymous = toggled;
|
||||
state->details = std::move(now);
|
||||
}, container->lifetime());
|
||||
AddSkip(container);
|
||||
AddDividerText(container, tr::lng_gift_send_anonymous_about(
|
||||
lt_user,
|
||||
rpl::single(peer->shortName()),
|
||||
lt_recipient,
|
||||
rpl::single(peer->shortName())));
|
||||
|
||||
const auto buttonWidth = st::boxWideWidth
|
||||
- st::giftBox.buttonPadding.left()
|
||||
- st::giftBox.buttonPadding.right();
|
||||
button->resizeToWidth(buttonWidth);
|
||||
button->widthValue() | rpl::start_with_next([=](int width) {
|
||||
if (width != buttonWidth) {
|
||||
button->resizeToWidth(buttonWidth);
|
||||
}
|
||||
}, button->lifetime());
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<RpWidget> MakeGiftsList(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -563,6 +1028,19 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
QImage background() override {
|
||||
return _bg;
|
||||
}
|
||||
DocumentData *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));
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
const not_null<Window::SessionController*> _window;
|
||||
|
@ -655,6 +1133,10 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
} else {
|
||||
x += single.width() + st::giftBoxGiftSkip.x();
|
||||
}
|
||||
|
||||
button->setClickedCallback([=] {
|
||||
window->show(Box(SendGiftBox, window, peer, descriptor));
|
||||
});
|
||||
}
|
||||
if (gifts.size() % kGiftsPerRow) {
|
||||
y += padding.bottom() + single.height();
|
||||
|
|
|
@ -314,41 +314,22 @@ void SendCreditsBox(
|
|||
AddChildToWidgetCenter(button.data(), loadingAnimation);
|
||||
loadingAnimation->showOn(state->confirmButtonBusy.value());
|
||||
}
|
||||
{
|
||||
auto buttonText = tr::lng_credits_box_out_confirm(
|
||||
lt_count,
|
||||
rpl::single(form->invoice.amount) | tr::to_count(),
|
||||
lt_emoji,
|
||||
rpl::single(CreditsEmojiSmall(session)),
|
||||
Ui::Text::RichLangValue);
|
||||
const auto buttonLabel = Ui::CreateChild<Ui::FlatLabel>(
|
||||
button,
|
||||
rpl::single(QString()),
|
||||
st::creditsBoxButtonLabel);
|
||||
std::move(
|
||||
buttonText
|
||||
) | rpl::start_with_next([=](const TextWithEntities &text) {
|
||||
buttonLabel->setMarkedText(
|
||||
text,
|
||||
Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = [=] { buttonLabel->update(); },
|
||||
});
|
||||
}, buttonLabel->lifetime());
|
||||
buttonLabel->setTextColorOverride(
|
||||
box->getDelegate()->style().button.textFg->c);
|
||||
button->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &size) {
|
||||
buttonLabel->moveToLeft(
|
||||
(size.width() - buttonLabel->width()) / 2,
|
||||
(size.height() - buttonLabel->height()) / 2);
|
||||
}, buttonLabel->lifetime());
|
||||
buttonLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
state->confirmButtonBusy.value(
|
||||
) | rpl::start_with_next([=](bool busy) {
|
||||
buttonLabel->setVisible(!busy);
|
||||
}, buttonLabel->lifetime());
|
||||
}
|
||||
SetButtonMarkedLabel(
|
||||
button,
|
||||
rpl::combine(
|
||||
tr::lng_credits_box_out_confirm(
|
||||
lt_count,
|
||||
rpl::single(form->invoice.amount) | tr::to_count(),
|
||||
lt_emoji,
|
||||
rpl::single(CreditsEmojiSmall(session)),
|
||||
Ui::Text::RichLangValue),
|
||||
state->confirmButtonBusy.value()
|
||||
) | rpl::map([](TextWithEntities &&text, bool busy) {
|
||||
return busy ? TextWithEntities() : std::move(text);
|
||||
}),
|
||||
session,
|
||||
st::creditsBoxButtonLabel,
|
||||
box->getDelegate()->style().button.textFg->c);
|
||||
|
||||
const auto buttonWidth = st::boxWidth
|
||||
- rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding);
|
||||
|
@ -408,4 +389,55 @@ TextWithEntities CreditsEmojiSmall(not_null<Main::Session*> session) {
|
|||
QString(QChar(0x2B50)));
|
||||
}
|
||||
|
||||
not_null<FlatLabel*> SetButtonMarkedLabel(
|
||||
not_null<RpWidget*> button,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
Fn<std::any(Fn<void()> update)> context,
|
||||
const style::FlatLabel &st,
|
||||
std::optional<QColor> textFg) {
|
||||
const auto buttonLabel = Ui::CreateChild<Ui::FlatLabel>(
|
||||
button,
|
||||
rpl::single(QString()),
|
||||
st);
|
||||
rpl::duplicate(
|
||||
text
|
||||
) | rpl::filter([=](const TextWithEntities &text) {
|
||||
return !text.text.isEmpty();
|
||||
}) | rpl::start_with_next([=](const TextWithEntities &text) {
|
||||
buttonLabel->setMarkedText(
|
||||
text,
|
||||
context([=] { buttonLabel->update(); }));
|
||||
}, buttonLabel->lifetime());
|
||||
if (textFg) {
|
||||
buttonLabel->setTextColorOverride(textFg);
|
||||
}
|
||||
button->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &size) {
|
||||
buttonLabel->moveToLeft(
|
||||
(size.width() - buttonLabel->width()) / 2,
|
||||
(size.height() - buttonLabel->height()) / 2);
|
||||
}, buttonLabel->lifetime());
|
||||
buttonLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
buttonLabel->showOn(std::move(
|
||||
text
|
||||
) | rpl::map([=](const TextWithEntities &text) {
|
||||
return !text.text.isEmpty();
|
||||
}));
|
||||
return buttonLabel;
|
||||
}
|
||||
|
||||
not_null<FlatLabel*> SetButtonMarkedLabel(
|
||||
not_null<RpWidget*> button,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
not_null<Main::Session*> session,
|
||||
const style::FlatLabel &st,
|
||||
std::optional<QColor> textFg) {
|
||||
return SetButtonMarkedLabel(button, text, [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = update,
|
||||
};
|
||||
}, st, textFg);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class HistoryItem;
|
||||
|
||||
namespace style {
|
||||
struct FlatLabel;
|
||||
} // namespace style
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
@ -19,7 +23,9 @@ struct CreditsFormData;
|
|||
|
||||
namespace Ui {
|
||||
|
||||
class RpWidget;
|
||||
class GenericBox;
|
||||
class FlatLabel;
|
||||
|
||||
void SendCreditsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
|
@ -32,4 +38,18 @@ void SendCreditsBox(
|
|||
[[nodiscard]] TextWithEntities CreditsEmojiSmall(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
not_null<FlatLabel*> SetButtonMarkedLabel(
|
||||
not_null<RpWidget*> button,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
Fn<std::any(Fn<void()> update)> context,
|
||||
const style::FlatLabel &st,
|
||||
std::optional<QColor> textFg = {});
|
||||
|
||||
not_null<FlatLabel*> SetButtonMarkedLabel(
|
||||
not_null<RpWidget*> button,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
not_null<Main::Session*> session,
|
||||
const style::FlatLabel &st,
|
||||
std::optional<QColor> textFg = {});
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -58,6 +58,15 @@ creditsGiftBox: Box(defaultBox) {
|
|||
shadowIgnoreTopSkip: true;
|
||||
}
|
||||
|
||||
giftBox: Box(defaultBox) {
|
||||
buttonPadding: margins(22px, 11px, 22px, 22px);
|
||||
buttonHeight: 42px;
|
||||
button: RoundButton(defaultActiveButton) {
|
||||
height: 42px;
|
||||
textTop: 12px;
|
||||
style: semiboldTextStyle;
|
||||
}
|
||||
}
|
||||
giftBoxSubtitle: FlatLabel(defaultFlatLabel) {
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: boxTitleFont;
|
||||
|
@ -85,6 +94,32 @@ giftBoxGiftHeight: 164px;
|
|||
giftBoxGiftRadius: 12px;
|
||||
giftBoxPremiumIconSize: 64px;
|
||||
giftBoxPremiumIconTop: 10px;
|
||||
giftBoxPremiumTextTop: 56px;
|
||||
giftBoxPremiumTextTop: 84px;
|
||||
giftBoxButtonBottom: 12px;
|
||||
giftBoxButtonPadding: margins(8px, 4px, 8px, 4px);
|
||||
giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px);
|
||||
giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px);
|
||||
giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 24px);
|
||||
giftBoxStickerTop: 0px;
|
||||
giftBoxStickerStarTop: 24px;
|
||||
giftBoxStickerSize: size(80px, 80px);
|
||||
giftBoxTextField: InputField(defaultInputField) {
|
||||
textBg: transparent;
|
||||
textMargins: margins(2px, 0px, 32px, 0px);
|
||||
|
||||
placeholderFg: placeholderFg;
|
||||
placeholderFgActive: placeholderFgActive;
|
||||
placeholderFgError: placeholderFgActive;
|
||||
placeholderMargins: margins(2px, 0px, 2px, 0px);
|
||||
placeholderScale: 0.;
|
||||
placeholderFont: normalFont;
|
||||
|
||||
border: 0px;
|
||||
borderActive: 0px;
|
||||
|
||||
heightMin: 20px;
|
||||
heightMax: 48px;
|
||||
|
||||
style: defaultTextStyle;
|
||||
}
|
||||
giftBoxTextPadding: margins(20px, 15px, 20px, 11px);
|
||||
|
|
Loading…
Add table
Reference in a new issue