Show correct gift sender.

This commit is contained in:
John Preston 2024-09-24 20:26:12 +04:00
parent c022a1c838
commit 1acdbb69ae
11 changed files with 192 additions and 38 deletions

View file

@ -3015,6 +3015,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_limited_of_count" = "1 of {amount}";
"lng_gift_anonymous_hint" = "Only you can see the sender's name.";
"lng_gift_availability" = "Availability";
"lng_gift_from_hidden" = "Hidden User";
"lng_gift_availability_left#one" = "{count} of {amount} left";
"lng_gift_availability_left#other" = "{count} of {amount} left";
"lng_gift_availability_none" = "None of {amount} left";

View file

@ -780,8 +780,9 @@ std::optional<StarGift> FromTL(
}
std::optional<UserStarGift> FromTL(
not_null<Main::Session*> session,
not_null<UserData*> to,
const MTPuserStarGift &gift) {
const auto session = &to->session();
const auto &data = gift.data();
auto parsed = FromTL(session, data.vgift());
if (!parsed) {
@ -802,8 +803,10 @@ std::optional<UserStarGift> FromTL(
? peerFromUser(data.vfrom_id()->v)
: PeerId()),
.messageId = data.vmsg_id().value_or_empty(),
.date = data.vdate().v,
.anonymous = data.is_name_hidden(),
.hidden = data.is_unsaved(),
.mine = to->isSelf(),
};
}

View file

@ -88,8 +88,10 @@ struct UserStarGift {
int64 convertStars = 0;
PeerId fromId = 0;
MsgId messageId = 0;
TimeId date = 0;
bool anonymous = false;
bool hidden = false;
bool mine = false;
};
class Premium final {
@ -278,7 +280,7 @@ enum class RequirePremiumState {
not_null<Main::Session*> session,
const MTPstarGift &gift);
[[nodiscard]] std::optional<UserStarGift> FromTL(
not_null<Main::Session*> session,
not_null<UserData*> to,
const MTPuserStarGift &gift);
} // namespace Api

View file

@ -481,7 +481,7 @@ void PreviewWrap::paintEvent(QPaintEvent *e) {
.stars = gift.stars,
.convertStars = gift.convertStars,
.document = gift.document,
.limited = (gift.limitedCount > 0),
.limitedCount = gift.limitedCount,
});
}
auto &map = Map[session];
@ -554,7 +554,7 @@ struct GiftPriceTabs {
auto sameKey = 0;
for (const auto &gift : gifts) {
if (same) {
const auto key = gift.stars * (gift.limited ? -1 : 1);
const auto key = gift.stars * (gift.limitedCount ? -1 : 1);
if (!sameKey) {
sameKey = key;
} else if (sameKey != key) {
@ -562,7 +562,7 @@ struct GiftPriceTabs {
}
}
if (gift.limited
if (gift.limitedCount
&& (result.size() < 2 || result[1] != kPriceTabLimited)) {
result.insert(begin(result) + 1, kPriceTabLimited);
}
@ -1036,7 +1036,7 @@ void AddBlock(
) | rpl::map([=](std::vector<GiftTypeStars> &&gifts, int price) {
gifts.erase(ranges::remove_if(gifts, [&](const GiftTypeStars &gift) {
return (price == kPriceTabLimited)
? (!gift.limited)
? (!gift.limitedCount)
: (price && gift.stars != price);
}), end(gifts));
return GiftsDescriptor{

View file

@ -793,6 +793,43 @@ void GiftsBox(
return result;
}
[[nodiscard]] object_ptr<Ui::RpWidget> MakeHiddenPeerTableValue(
not_null<QWidget*> parent,
not_null<Window::SessionNavigation*> controller) {
auto result = object_ptr<Ui::RpWidget>(parent);
const auto raw = result.data();
const auto &st = st::giveawayGiftCodeUserpic;
raw->resize(raw->width(), st.photoSize);
const auto userpic = Ui::CreateChild<Ui::RpWidget>(raw);
const auto usize = st.photoSize;
userpic->resize(usize, usize);
userpic->paintRequest() | rpl::start_with_next([=] {
auto p = QPainter(userpic);
Ui::EmptyUserpic::PaintHiddenAuthor(p, 0, 0, usize, usize);
}, userpic->lifetime());
const auto label = Ui::CreateChild<Ui::FlatLabel>(
raw,
tr::lng_gift_from_hidden(),
st::giveawayGiftCodeValue);
raw->widthValue(
) | rpl::start_with_next([=](int width) {
const auto position = st::giveawayGiftCodeNamePosition;
label->resizeToNaturalWidth(width - position.x());
label->moveToLeft(position.x(), position.y(), width);
const auto top = (raw->height() - userpic->height()) / 2;
userpic->moveToLeft(0, top, width);
}, label->lifetime());
userpic->setAttribute(Qt::WA_TransparentForMouseEvents);
label->setAttribute(Qt::WA_TransparentForMouseEvents);
label->setTextColorOverride(st::windowFg->c);
return result;
}
void AddTableRow(
not_null<Ui::TableLayout*> table,
rpl::producer<QString> label,
@ -1721,10 +1758,17 @@ void AddStarGiftTable(
st::giveawayGiftCodeTableMargin);
const auto peerId = PeerId(entry.barePeerId);
if (peerId) {
auto text = entry.in
? tr::lng_credits_box_history_entry_peer_in()
: tr::lng_credits_box_history_entry_peer();
AddTableRow(table, std::move(text), controller, peerId);
AddTableRow(
table,
tr::lng_credits_box_history_entry_peer_in(),
controller,
peerId);
} else {
AddTableRow(
table,
tr::lng_credits_box_history_entry_peer_in(),
MakeHiddenPeerTableValue(table, controller),
st::giveawayGiftCodePeerMargin);
}
if (!entry.date.isNull()) {
AddTableRow(

View file

@ -19,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "ui/text/format_values.h"
#include "ui/text/text_utilities.h"
#include "ui/dynamic_image.h"
#include "ui/dynamic_thumbnails.h"
#include "ui/painter.h"
#include "window/window_session_controller.h"
#include "styles/style_credits.h"
@ -39,7 +41,15 @@ GiftButton::GiftButton(
, _delegate(delegate) {
}
GiftButton::~GiftButton() = default;
GiftButton::~GiftButton() {
unsubscribe();
}
void GiftButton::unsubscribe() {
if (base::take(_subscribed)) {
_userpic->subscribeToUpdates(nullptr);
}
}
void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
if (_descriptor == descriptor) {
@ -48,6 +58,7 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
auto player = base::take(_player);
_mediaLifetime.destroy();
_descriptor = descriptor;
unsubscribe();
v::match(descriptor, [&](const GiftTypePremium &data) {
const auto months = data.months;
const auto years = (months % 12) ? 0 : months / 12;
@ -66,12 +77,18 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
data.cost,
data.currency,
true));
_userpic = nullptr;
}, [&](const GiftTypeStars &data) {
_price.setMarkedText(
st::semiboldTextStyle,
_delegate->star().append(QString::number(data.stars)),
kMarkupTextOptions,
_delegate->textContext());
_userpic = !data.userpic
? nullptr
: data.from
? Ui::MakeUserpicThumbnail(data.from)
: Ui::MakeHiddenAuthorThumbnail();
});
if (const auto document = _delegate->lookupSticker(descriptor)) {
setDocument(document);
@ -166,6 +183,16 @@ void GiftButton::paintEvent(QPaintEvent *e) {
QRect(half, 0, 1, height));
}
if (_userpic) {
if (!_subscribed) {
_subscribed = true;
_userpic->subscribeToUpdates([=] { update(); });
}
const auto image = _userpic->image(st::giftBoxUserpicSize);
const auto skip = st::giftBoxUserpicSkip;
p.drawImage(_extend.left() + skip, _extend.top() + skip, image);
}
if (_player && _player->ready()) {
const auto paused = !isOver();
auto info = _player->frame(
@ -203,9 +230,18 @@ void GiftButton::paintEvent(QPaintEvent *e) {
}
return QString();
}, [&](const GiftTypeStars &data) {
if (data.limited) {
if (const auto count = data.limitedCount) {
p.setBrush(st::windowActiveTextFg);
return tr::lng_gift_stars_limited(tr::now);
return !data.userpic
? tr::lng_gift_stars_limited(tr::now)
: (count == 1)
? tr::lng_gift_limited_of_one(tr::now)
: tr::lng_gift_limited_of_count(
tr::now,
lt_amount,
((count % 1000)
? Lang::FormatCountDecimal(count)
: Lang::FormatCountToShort(count).string));
}
return QString();
});

View file

@ -14,6 +14,10 @@ namespace HistoryView {
class StickerPlayer;
} // namespace HistoryView
namespace Ui {
class DynamicImage;
} // namespace Ui
namespace Window {
class SessionController;
} // namespace Window
@ -37,8 +41,9 @@ struct GiftTypeStars {
int64 convertStars = 0;
DocumentData *document = nullptr;
PeerData *from = nullptr;
bool limited = false;
int limitedCount = 0;
bool userpic = false;
bool mine = false;
[[nodiscard]] friend inline bool operator==(
const GiftTypeStars&,
@ -77,11 +82,15 @@ private:
void resizeEvent(QResizeEvent *e) override;
void setDocument(not_null<DocumentData*> document);
void unsubscribe();
const not_null<GiftButtonDelegate*> _delegate;
GiftDescriptor _descriptor;
Ui::Text::String _text;
Ui::Text::String _price;
std::shared_ptr<Ui::DynamicImage> _userpic;
bool _subscribed = false;
QRect _button;
QMargins _extend;

View file

@ -11,11 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/info_controller.h"
#include "ui/layers/generic_box.h"
#include "ui/ui_utility.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "mtproto/sender.h"
#include "window/window_session_controller.h"
#include "settings/settings_credits_graphics.h"
#include "styles/style_info.h"
#include "styles/style_credits.h" // giftBoxPadding
@ -26,18 +28,19 @@ constexpr auto kPreloadPages = 2;
constexpr auto kPerPage = 50;
[[nodiscard]] GiftDescriptor DescriptorForGift(
not_null<Data::Session*> owner,
not_null<UserData*> to,
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)
.from = ((gift.anonymous || !gift.fromId)
? nullptr
: owner->peer(gift.fromId).get()),
.limited = (gift.gift.limitedCount > 0),
: to->owner().peer(gift.fromId).get()),
.limitedCount = gift.gift.limitedCount,
.userpic = true,
.mine = to->isSelf(),
};
}
@ -74,11 +77,12 @@ private:
void loadMore();
void validateButtons();
void showGift(int index);
int resizeGetHeight(int width) override;
const not_null<Window::SessionController*> _window;
Delegate _delegate;
const std::shared_ptr<Main::SessionShow> _show;
not_null<Controller*> _controller;
const not_null<UserData*> _user;
std::vector<Entry> _entries;
@ -107,8 +111,8 @@ InnerWidget::InnerWidget(
not_null<Controller*> controller,
not_null<UserData*> user)
: RpWidget(parent)
, _delegate(controller->parentController())
, _show(controller->uiShow())
, _window(controller->parentController())
, _delegate(_window)
, _controller(controller)
, _user(user)
, _totalCount(_user->peerGiftsCount())
@ -155,11 +159,10 @@ void InnerWidget::loadMore() {
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);
if (auto parsed = Api::FromTL(_user, gift)) {
auto descriptor = DescriptorForGift(_user, *parsed);
_entries.push_back({
.gift = std::move(*parsed),
.descriptor = std::move(descriptor),
@ -212,6 +215,9 @@ void InnerWidget::validateButtons() {
return;
}
const auto &descriptor = _entries[index].descriptor;
const auto callback = [=] {
showGift(index);
};
const auto unused = ranges::find_if(_views, [&](const View &v) {
return v.button
&& ((v.entry < fromRow * _perRow)
@ -219,18 +225,18 @@ void InnerWidget::validateButtons() {
});
if (unused != end(_views)) {
views.push_back(base::take(*unused));
views.back().button->setDescriptor(descriptor);
views.back().entry = index;
return;
} else {
auto button = std::make_unique<GiftButton>(this, &_delegate);
button->show();
views.push_back({
.button = std::move(button),
.entry = index,
});
}
auto button = std::make_unique<GiftButton>(this, &_delegate);
button->setDescriptor(descriptor);
button->show();
views.push_back({
.button = std::move(button),
.entry = index,
});
};
views.back().button->setDescriptor(descriptor);
views.back().button->setClickedCallback(callback);
};
for (auto j = fromRow; j != tillRow; ++j) {
for (auto i = 0; i != _perRow; ++i) {
const auto index = j * _perRow + i;
@ -249,6 +255,13 @@ void InnerWidget::validateButtons() {
std::swap(_views, views);
}
void InnerWidget::showGift(int index) {
_window->show(Box(
::Settings::UserStarGiftBox,
_window,
_entries[index].gift));
}
int InnerWidget::resizeGetHeight(int width) {
const auto count = int(_entries.size());
const auto padding = st::giftBoxPadding;

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_chat_invite.h"
#include "api/api_credits.h"
#include "api/api_earn.h"
#include "api/api_premium.h"
#include "apiwrap.h"
#include "base/timer_rpl.h"
#include "base/unixtime.h"
@ -730,10 +731,13 @@ void ReceiptCreditsBox(
const auto item = controller->session().data().message(
PeerId(e.barePeerId), MsgId(e.bareMsgId));
const auto isStarGift = (e.convertStars > 0);
const auto myStarGift = isStarGift && e.in;
const auto starGiftSender = (isStarGift && item)
? item->history()->peer->asUser()
: nullptr;
const auto canConvert = isStarGift && !e.converted && starGiftSender;
const auto canConvert = myStarGift
&& !e.converted
&& starGiftSender;
box->setStyle(canConvert ? st::starGiftBox : st::giveawayGiftCodeBox);
box->setNoContentMargin(true);
@ -857,6 +861,8 @@ void ReceiptCreditsBox(
? tr::lng_credits_box_history_entry_subscription(tr::now)
: !e.title.isEmpty()
? e.title
: (isStarGift && !myStarGift)
? tr::lng_gift_link_label_gift(tr::now)
: e.gift
? tr::lng_credits_box_history_entry_gift_name(tr::now)
: (peer && !e.reaction)
@ -935,7 +941,7 @@ void ReceiptCreditsBox(
? st::windowSubTextFg
: e.pending
? st::creditsStroke
: e.in
: (e.in || isStarGift)
? st::boxTextFgGood
: e.gift
? st::windowBoldFg
@ -990,7 +996,7 @@ void ReceiptCreditsBox(
rpl::single(e.description),
st::creditsBoxAbout)));
}
if (isStarGift) {
if (myStarGift) {
Ui::AddSkip(content);
const auto about = box->addRow(
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
@ -1015,6 +1021,7 @@ void ReceiptCreditsBox(
tr::lng_paid_about_link_url(tr::now));
return false;
});
} else if (isStarGift) {
} else if (e.gift || isPrize) {
Ui::AddSkip(content);
const auto arrow = Ui::Text::SingleCustomEmoji(
@ -1074,7 +1081,7 @@ void ReceiptCreditsBox(
tr::lng_credits_box_out_about_link(tr::now)),
Ui::Text::WithEntities),
st::creditsBoxAboutDivider)));
} else if (e.anonymous) {
} else if (myStarGift && e.anonymous) {
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
object_ptr<Ui::FlatLabel>(
@ -1336,6 +1343,35 @@ void CreditsPrizeBox(
Data::SubscriptionEntry());
}
void UserStarGiftBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
const Api::UserStarGift &data) {
Settings::ReceiptCreditsBox(
box,
controller,
Data::CreditsHistoryEntry{
.description = data.message,
.date = base::unixtime::parse(data.date),
.credits = uint64(data.gift.stars),
.bareMsgId = uint64(data.messageId.bare),
.barePeerId = data.fromId.value,
.bareGiftStickerId = (data.gift.document
? data.gift.document->id
: 0),
.peerType = Data::CreditsHistoryEntry::PeerType::Peer,
.limitedCount = data.gift.limitedCount,
.limitedLeft = data.gift.limitedLeft,
.convertStars = int(data.gift.convertStars),
.converted = false,
.anonymous = data.anonymous,
.savedToProfile = !data.hidden,
.in = data.mine,
.gift = true,
},
Data::SubscriptionEntry());
}
void StarGiftViewBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,

View file

@ -12,6 +12,10 @@ class object_ptr;
class PeerData;
namespace Api {
struct UserStarGift;
} // namespace Api
namespace Data {
struct Boost;
struct CreditsHistoryEntry;
@ -92,6 +96,10 @@ void CreditsPrizeBox(
not_null<Window::SessionController*> controller,
const Data::GiftCode &data,
TimeId date);
void UserStarGiftBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
const Api::UserStarGift &data);
void StarGiftViewBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,

View file

@ -103,6 +103,8 @@ giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 24px);
giftBoxStickerTop: 0px;
giftBoxStickerStarTop: 24px;
giftBoxStickerSize: size(80px, 80px);
giftBoxUserpicSize: 24px;
giftBoxUserpicSkip: 2px;
giftBoxTextField: InputField(defaultInputField) {
textBg: transparent;
textMargins: margins(2px, 0px, 32px, 0px);