diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index b1b39f59f..8d1d2369d 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -301,6 +301,8 @@ PRIVATE boxes/ringtones_box.h boxes/self_destruction_box.cpp boxes/self_destruction_box.h + boxes/send_credits_box.cpp + boxes/send_credits_box.h boxes/send_files_box.cpp boxes/send_files_box.h boxes/sessions_box.cpp diff --git a/Telegram/SourceFiles/boxes/send_credits_box.cpp b/Telegram/SourceFiles/boxes/send_credits_box.cpp new file mode 100644 index 000000000..ae45850bd --- /dev/null +++ b/Telegram/SourceFiles/boxes/send_credits_box.cpp @@ -0,0 +1,263 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "boxes/send_credits_box.h" + +#include "api/api_credits.h" +#include "core/ui_integration.h" // Core::MarkedTextContext. +#include "data/data_credits.h" +#include "data/data_file_origin.h" +#include "data/data_photo_media.h" +#include "data/data_session.h" +#include "data/data_user.h" +#include "data/stickers/data_custom_emoji.h" +#include "history/history.h" +#include "history/history_item.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "payments/payments_form.h" +#include "settings/settings_credits.h" +#include "ui/controls/userpic_button.h" +#include "ui/effects/premium_graphics.h" +#include "ui/effects/premium_top_bar.h" // Ui::Premium::ColorizedSvg. +#include "ui/image/image_prepare.h" +#include "ui/layers/generic_box.h" +#include "ui/rect.h" +#include "ui/text/text_utilities.h" +#include "ui/vertical_list.h" +#include "ui/widgets/buttons.h" +#include "styles/style_boxes.h" +#include "styles/style_credits.h" +#include "styles/style_giveaway.h" +#include "styles/style_layers.h" +#include "styles/style_premium.h" +#include "styles/style_settings.h" + +namespace Ui { +namespace { +} // namespace + +void SendCreditsBox( + not_null box, + not_null item) { + const auto media = item->media(); + const auto invoice = media ? media->invoice() : nullptr; + if (!invoice) { + return; + } + box->setStyle(st::giveawayGiftCodeBox); + box->setNoContentMargin(true); + + const auto session = &item->history()->owner().session(); + + const auto photoSize = st::defaultUserpicButton.photoSize; + + const auto content = box->verticalLayout(); + Ui::AddSkip(content, photoSize / 2); + + { + const auto ministarsContainer = Ui::CreateChild(box); + const auto fullHeight = photoSize * 2; + using MiniStars = Ui::Premium::ColoredMiniStars; + const auto ministars = box->lifetime().make_state( + ministarsContainer, + false, + Ui::Premium::MiniStars::Type::BiStars); + ministars->setColorOverride(Ui::Premium::CreditsIconGradientStops()); + + ministarsContainer->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(ministarsContainer); + ministars->paint(p); + }, ministarsContainer->lifetime()); + + box->widthValue( + ) | rpl::start_with_next([=](int width) { + ministarsContainer->resize(width, fullHeight); + const auto w = fullHeight / 3 * 2; + ministars->setCenter(QRect( + (width - w) / 2, + (fullHeight - w) / 2, + w, + w)); + }, ministarsContainer->lifetime()); + } + + if (false && invoice->photo) { + struct State { + std::shared_ptr view; + Image *image = nullptr; + rpl::lifetime downloadLifetime; + }; + const auto state = content->lifetime().make_state(); + const auto widget = box->addRow( + object_ptr>( + content, + object_ptr(content)))->entity(); + state->view = invoice->photo->createMediaView(); + state->view->wanted(Data::PhotoSize::Large, item->fullId()); + + widget->resize(Size(photoSize)); + + rpl::single(rpl::empty_value()) | rpl::then( + session->downloaderTaskFinished() + ) | rpl::start_with_next([=] { + using Size = Data::PhotoSize; + if (const auto large = state->view->image(Size::Large)) { + state->image = large; + } else if (const auto small = state->view->image(Size::Small)) { + state->image = small; + } else if (const auto t = state->view->image(Size::Thumbnail)) { + state->image = t; + } + widget->update(); + if (state->view->loaded()) { + state->downloadLifetime.destroy(); + } + }, state->downloadLifetime); + + widget->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(widget); + if (state->image) { + p.drawPixmap(0, 0, state->image->pix(widget->width(), { + .options = Images::Option::RoundCircle, + })); + } + }, widget->lifetime()); + } else { + const auto widget = box->addRow( + object_ptr>( + content, + object_ptr( + content, + item->author(), + st::defaultUserpicButton))); + widget->setAttribute(Qt::WA_TransparentForMouseEvents); + } + + const auto asd = box->lifetime().make_state(); + + Ui::AddSkip(content); + box->addRow(object_ptr>( + box, + object_ptr( + box, + tr::lng_credits_box_out_title(), + st::settingsPremiumUserTitle))); + Ui::AddSkip(content); + box->addRow(object_ptr>( + box, + object_ptr( + box, + tr::lng_credits_box_out_sure( + lt_count, + rpl::single(invoice->amount) | tr::to_count(), + lt_text, + rpl::single(TextWithEntities{ invoice->title }), + lt_bot, + rpl::single(TextWithEntities{ item->author()->name() }), + Ui::Text::RichLangValue), + st::creditsBoxAbout))); + Ui::AddSkip(content); + Ui::AddSkip(content); + + const auto button = box->addButton(rpl::single(QString()), [=] { + }); + { + const auto emojiMargin = QMargins( + 0, + -st::moderateBoxExpandInnerSkip, + 0, + 0); + const auto buttonEmoji = Ui::Text::SingleCustomEmoji( + session->data().customEmojiManager().registerInternalEmoji( + st::settingsPremiumIconStar, + emojiMargin, + true)); + auto buttonText = tr::lng_credits_box_out_confirm( + lt_count, + rpl::single(invoice->amount) | tr::to_count(), + lt_emoji, + rpl::single(buttonEmoji), + Ui::Text::RichLangValue); + const auto buttonLabel = Ui::CreateChild( + button, + rpl::single(QString()), + st::defaultFlatLabel); + 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); + } + + const auto buttonWidth = st::boxWidth + - rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding); + button->widthValue() | rpl::filter([=] { + return (button->widthNoMargins() != buttonWidth); + }) | rpl::start_with_next([=] { + button->resizeToWidth(buttonWidth); + }, button->lifetime()); + + { + const auto close = Ui::CreateChild( + box.get(), + st::boxTitleClose); + close->setClickedCallback([=] { + box->closeBox(); + }); + box->widthValue( + ) | rpl::start_with_next([=](int width) { + close->moveToRight(0, 0); + close->raise(); + }, close->lifetime()); + } + + { + const auto balance = Settings::AddBalanceWidget( + content, + session->creditsValue(), + false); + const auto api = balance->lifetime().make_state( + session->user()); + api->request({}, [=](Data::CreditsStatusSlice slice) { + session->setCredits(slice.balance); + }); + rpl::combine( + balance->sizeValue(), + content->sizeValue() + ) | rpl::start_with_next([=](const QSize &, const QSize &) { + balance->moveToLeft( + st::creditsHistoryRightSkip * 2, + st::creditsHistoryRightSkip); + balance->update(); + }, balance->lifetime()); + } +} + +bool IsCreditsInvoice(not_null item) { + const auto media = item->media(); + const auto invoice = media ? media->invoice() : nullptr; + return invoice && (invoice->currency == "XTR"); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/boxes/send_credits_box.h b/Telegram/SourceFiles/boxes/send_credits_box.h new file mode 100644 index 000000000..fa877e305 --- /dev/null +++ b/Telegram/SourceFiles/boxes/send_credits_box.h @@ -0,0 +1,22 @@ +/* +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 + +class HistoryItem; + +namespace Ui { + +class GenericBox; + +void SendCreditsBox( + not_null box, + not_null item); + +[[nodiscard]] bool IsCreditsInvoice(not_null item); + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index 8a1afec19..19c73c7ba 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -25,3 +25,8 @@ creditsTopupPrice: FlatLabel(defaultFlatLabel) { creditsHistoryRightSkip: 10px; creditsBalanceStarHeight: 20px; + +creditsBoxAbout: FlatLabel(defaultFlatLabel) { + minWidth: 256px; + align: align(top); +}