Added ability to provide description and custom link to FillPeerQrBox.

This commit is contained in:
23rd 2024-09-10 13:04:32 +03:00
parent 5dd9ff1062
commit 0916836ff9
2 changed files with 94 additions and 48 deletions

View file

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#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_giveaway.h" #include "styles/style_giveaway.h"
#include "styles/style_credits.h"
#include "styles/style_intro.h" #include "styles/style_intro.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_settings.h" #include "styles/style_settings.h"
@ -85,6 +86,17 @@ using Colors = std::vector<QColor>;
return qr; return qr;
} }
[[nodiscard]] QMargins RoundedMargins(
const QMargins &backgroundMargins,
int photoSize,
int textMaxHeight) {
return (textMaxHeight
? (backgroundMargins + QMargins(0, photoSize / 2, 0, textMaxHeight))
: photoSize
? backgroundMargins + QMargins(0, photoSize / 2, 0, photoSize / 2)
: Margins(backgroundMargins.left()));
}
void Paint( void Paint(
QPainter &p, QPainter &p,
const style::font &font, const style::font &font,
@ -102,8 +114,7 @@ void Paint(
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(Qt::white); p.setBrush(Qt::white);
const auto roundedRect = qrRect const auto roundedRect = qrRect
+ backgroundMargins + RoundedMargins(backgroundMargins, photoSize, textMaxHeight);
+ QMargins(0, photoSize / 2, 0, textMaxHeight);
p.drawRoundedRect(roundedRect, radius, radius); p.drawRoundedRect(roundedRect, radius, radius);
if (!qrImage.isNull() && !backgroundColors.empty()) { if (!qrImage.isNull() && !backgroundColors.empty()) {
constexpr auto kDuration = crl::time(10000); constexpr auto kDuration = crl::time(10000);
@ -125,7 +136,7 @@ void Paint(
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
colored.setDevicePixelRatio(style::DevicePixelRatio()); colored.setDevicePixelRatio(style::DevicePixelRatio());
colored.fill(Qt::transparent); colored.fill(Qt::transparent);
{ if (textMaxHeight) {
// '@' + QString(32, 'W'); // '@' + QString(32, 'W');
auto p = QPainter(&colored); auto p = QPainter(&colored);
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
@ -138,12 +149,14 @@ void Paint(
p.drawImage(0, -back.height() + textMaxHeight, back); p.drawImage(0, -back.height() + textMaxHeight, back);
} }
p.drawImage(qrRect, qrImage); p.drawImage(qrRect, qrImage);
p.drawImage( if (textMaxHeight) {
qrRect.x(), p.drawImage(
rect::bottom(qrRect) qrRect.x(),
+ ((rect::bottom(roundedRect) - rect::bottom(qrRect)) rect::bottom(qrRect)
- textMaxHeight) / 2, + ((rect::bottom(roundedRect) - rect::bottom(qrRect))
colored); - textMaxHeight) / 2,
colored);
}
} }
} }
@ -152,9 +165,10 @@ void Paint(
not_null<Ui::RpWidget*> topWidget, not_null<Ui::RpWidget*> topWidget,
const style::font &font, const style::font &font,
rpl::producer<bool> userpicToggled, rpl::producer<bool> userpicToggled,
rpl::producer<TextWithEntities> username, rpl::producer<QString> username,
rpl::producer<QString> links, rpl::producer<QString> links,
rpl::producer<Colors> bgs) { rpl::producer<Colors> bgs,
rpl::producer<QString> about) {
const auto divider = container->add( const auto divider = container->add(
object_ptr<Ui::BoxContentDivider>(container)); object_ptr<Ui::BoxContentDivider>(container));
struct State final { struct State final {
@ -179,17 +193,22 @@ void Paint(
const auto qrMaxSize = st::boxWideWidth const auto qrMaxSize = st::boxWideWidth
- rect::m::sum::h(st::boxRowPadding) - rect::m::sum::h(st::boxRowPadding)
- rect::m::sum::h(st::profileQrBackgroundMargins); - rect::m::sum::h(st::profileQrBackgroundMargins);
const auto aboutLabel = Ui::CreateChild<Ui::FlatLabel>(
divider,
st::creditsBoxAboutDivider);
rpl::combine( rpl::combine(
std::move(userpicToggled), std::move(userpicToggled),
std::move(username), std::move(username),
std::move(bgs), std::move(bgs),
std::move(links), std::move(links),
std::move(about),
rpl::single(rpl::empty) | rpl::then(style::PaletteChanged()) rpl::single(rpl::empty) | rpl::then(style::PaletteChanged())
) | rpl::start_with_next([=]( ) | rpl::start_with_next([=](
bool userpicToggled, bool userpicToggled,
const TextWithEntities &username, const QString &username,
const Colors &backgroundColors, const Colors &backgroundColors,
const QString &link, const QString &link,
const QString &about,
const auto &) { const auto &) {
state->backgroundMargins = userpicToggled state->backgroundMargins = userpicToggled
? st::profileQrBackgroundMargins ? st::profileQrBackgroundMargins
@ -198,7 +217,7 @@ void Paint(
? st::defaultUserpicButton.photoSize ? st::defaultUserpicButton.photoSize
: 0; : 0;
state->backgroundColors = backgroundColors; state->backgroundColors = backgroundColors;
state->text = username.text.toUpper(); state->text = username.toUpper();
state->textWidth = font->width(state->text); state->textWidth = font->width(state->text);
{ {
const auto remainder = qrMaxSize % st::introQrPixel; const auto remainder = qrMaxSize % st::introQrPixel;
@ -213,25 +232,40 @@ void Paint(
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
} }
const auto resultWidth = qrMaxSize
+ rect::m::sum::h(state->backgroundMargins);
{
aboutLabel->setText(about);
aboutLabel->resizeToWidth(resultWidth);
}
const auto qrWidth = state->qrImage.width() const auto qrWidth = state->qrImage.width()
/ style::DevicePixelRatio(); / style::DevicePixelRatio();
const auto lines = int(state->textWidth / qrWidth) + 1; const auto lines = int(state->textWidth / qrWidth) + 1;
state->textMaxHeight = font->height * lines; state->textMaxHeight = state->textWidth ? (font->height * lines) : 0;
const auto whiteMargins = RoundedMargins(
state->backgroundMargins,
state->photoSize,
state->textMaxHeight);
result->resize( result->resize(
qrMaxSize + rect::m::sum::h(state->backgroundMargins), qrMaxSize + rect::m::sum::h(whiteMargins),
qrMaxSize qrMaxSize
+ rect::m::sum::v(state->backgroundMargins) // White. + rect::m::sum::v(whiteMargins) // White.
+ rect::m::sum::v(st::profileQrBackgroundPadding) // Gray. + rect::m::sum::v(st::profileQrBackgroundPadding) // Gray.
+ state->textMaxHeight + state->photoSize / 2
+ state->photoSize); + aboutLabel->height());
divider->resize(container->width(), result->height()); divider->resize(container->width(), result->height());
result->moveToLeft((container->width() - result->width()) / 2, 0); result->moveToLeft((container->width() - result->width()) / 2, 0);
topWidget->setVisible(userpicToggled); topWidget->setVisible(userpicToggled);
topWidget->moveToLeft( topWidget->moveToLeft(0, -std::numeric_limits<int>::min());
(result->width() - topWidget->width()) / 2,
-std::numeric_limits<int>::min());
topWidget->raise(); topWidget->raise();
aboutLabel->raise();
aboutLabel->moveToLeft(
result->x(),
divider->height()
- aboutLabel->height()
- st::defaultBoxDividerLabelPadding.top());
}, container->lifetime()); }, container->lifetime());
result->paintRequest( result->paintRequest(
) | rpl::start_with_next([=](QRect clip) { ) | rpl::start_with_next([=](QRect clip) {
@ -341,7 +375,9 @@ void Paint(
void FillPeerQrBox( void FillPeerQrBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<PeerData*> peer) { not_null<PeerData*> peer,
std::optional<QString> customLink,
rpl::producer<QString> about) {
const auto window = Core::App().findWindow(box); const auto window = Core::App().findWindow(box);
const auto controller = window ? window->sessionController() : nullptr; const auto controller = window ? window->sessionController() : nullptr;
if (!controller) { if (!controller) {
@ -372,6 +408,19 @@ void FillPeerQrBox(
}; };
state->font = createFont(style::Scale()); state->font = createFont(style::Scale());
const auto usernameValue = [=] {
return customLink
? rpl::single(QString())
: Info::Profile::UsernameValue(peer, true) | rpl::map(
[](const auto &username) { return username.text; });
};
const auto linkValue = [=] {
return customLink
? rpl::single(*customLink)
: Info::Profile::LinkValue(peer, true) | rpl::map(
[](const auto &link) { return link.text; });
};
const auto userpic = Ui::CreateChild<Ui::UserpicButton>( const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
box, box,
peer, peer,
@ -381,11 +430,10 @@ void FillPeerQrBox(
userpic, userpic,
state->font, state->font,
state->userpicToggled.value(), state->userpicToggled.value(),
Info::Profile::UsernameValue(peer, true), usernameValue(),
Info::Profile::LinkValue(peer, true) | rpl::map([](const auto &link) { linkValue(),
return link.text; state->bgs.value(),
}), about ? std::move(about) : rpl::single(QString()));
state->bgs.value());
Ui::AddSkip(box->verticalLayout()); Ui::AddSkip(box->verticalLayout());
Ui::AddSubsectionTitle( Ui::AddSubsectionTitle(
@ -689,6 +737,9 @@ void FillPeerQrBox(
const auto introQrPixel = style::ConvertScale( const auto introQrPixel = style::ConvertScale(
st::introQrPixel / divider, st::introQrPixel / divider,
scale); scale);
const auto lineWidth = style::ConvertScale(
st::lineWidth / divider,
scale);
const auto boxWideWidth = style::ConvertScale( const auto boxWideWidth = style::ConvertScale(
st::boxWideWidth / divider, st::boxWideWidth / divider,
scale); scale);
@ -713,13 +764,9 @@ void FillPeerQrBox(
: 0; : 0;
const auto font = createFont(scale); const auto font = createFont(scale);
using namespace Info::Profile; const auto username = rpl::variable<QString>(
const auto username = rpl::variable<TextWithEntities>( usernameValue()).current().toUpper();
UsernameValue(peer, true)).current().text.toUpper(); const auto link = rpl::variable<QString>(linkValue());
const auto link = rpl::variable<QString>(
LinkValue(peer, true) | rpl::map([](const auto &l) {
return l.text;
}));
const auto textWidth = font->width(username); const auto textWidth = font->width(username);
const auto top = Ui::GrabWidget( const auto top = Ui::GrabWidget(
userpic, userpic,
@ -736,22 +783,21 @@ void FillPeerQrBox(
qrMaxSize); qrMaxSize);
const auto qrWidth = qrImage.width() / style::DevicePixelRatio(); const auto qrWidth = qrImage.width() / style::DevicePixelRatio();
const auto lines = int(textWidth / qrWidth) + 1; const auto lines = int(textWidth / qrWidth) + 1;
const auto textMaxHeight = font->height * lines; const auto textMaxHeight = textWidth ? font->height * lines : 0;
const auto whiteMargins = RoundedMargins(
backgroundMargins,
photoSize,
textMaxHeight);
const auto resultSize = QSize( const auto resultSize = QSize(
qrMaxSize + rect::m::sum::h(backgroundMargins), qrMaxSize + rect::m::sum::h(whiteMargins),
qrMaxSize qrMaxSize + rect::m::sum::v(whiteMargins) + photoSize / 2);
+ rect::m::sum::v(backgroundMargins)
+ textMaxHeight
+ (photoSize
? (backgroundMargins.bottom() * 3 + photoSize)
: 0));
const auto qrImageSize = qrImage.size() const auto qrImageSize = qrImage.size()
/ style::DevicePixelRatio(); / style::DevicePixelRatio();
const auto qrRect = Rect( const auto qrRect = Rect(
(resultSize.width() - qrImageSize.width()) / 2, (resultSize.width() - qrImageSize.width()) / 2,
backgroundMargins.top() + photoSize / 2, whiteMargins.top() + photoSize / 2,
qrImageSize); qrImageSize);
auto image = QImage( auto image = QImage(
@ -761,9 +807,7 @@ void FillPeerQrBox(
image.setDevicePixelRatio(style::DevicePixelRatio()); image.setDevicePixelRatio(style::DevicePixelRatio());
{ {
auto p = QPainter(&image); auto p = QPainter(&image);
if (userpicToggled) { p.translate(0, lineWidth); // Bad.
p.translate(0, photoSize / 2 + backgroundMargins.top());
}
Paint( Paint(
p, p,
font, font,
@ -781,7 +825,7 @@ void FillPeerQrBox(
if (userpicToggled) { if (userpicToggled) {
p.drawPixmap( p.drawPixmap(
(resultSize.width() - photoSize) / 2, (resultSize.width() - photoSize) / 2,
-photoSize / 2, 0,
top.scaled( top.scaled(
Size(photoSize * style::DevicePixelRatio()), Size(photoSize * style::DevicePixelRatio()),
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,

View file

@ -15,6 +15,8 @@ class GenericBox;
void FillPeerQrBox( void FillPeerQrBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<PeerData*> peer); not_null<PeerData*> peer,
std::optional<QString> customLink = std::nullopt,
rpl::producer<QString> about = nullptr);
} // namespace Ui } // namespace Ui