Improve transactions history for new stuff.

This commit is contained in:
John Preston 2025-03-04 18:43:06 +04:00
parent 0dd8ae3d77
commit f4c739ab92
12 changed files with 171 additions and 42 deletions

View file

@ -2681,6 +2681,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_summary_history_entry_inner_in" = "In-App Purchase";
"lng_credits_summary_balance" = "Balance";
"lng_credits_commission" = "{amount} commission";
"lng_credits_paid_messages_fee#one" = "Fee for {count} Message";
"lng_credits_paid_messages_fee#other" = "Fee for {count} Messages";
"lng_credits_paid_messages_fee_about" = "You receive {percent} of the price that you charge for each incoming message. {link}";
"lng_credits_paid_messages_fee_about_link" = "Change Fee {emoji}";
"lng_credits_paid_messages_full" = "Full Price";
"lng_credits_premium_gift_duration" = "Duration";
"lng_credits_more_options" = "More Options";
"lng_credits_balance_me" = "your balance";
"lng_credits_buy_button" = "Buy More Stars";

View file

@ -90,7 +90,13 @@ constexpr auto kTransactionsLimit = 100;
? peerFromMTP(*tl.data().vstarref_peer()).value
: 0;
const auto incoming = (amount >= StarsAmount());
const auto saveActorId = (reaction || !extended.empty()) && incoming;
const auto paidMessagesCount
= tl.data().vpaid_messages().value_or_empty();
const auto premiumMonthsForStars
= tl.data().vpremium_gift_months().value_or_empty();
const auto saveActorId = (reaction
|| !extended.empty()
|| paidMessagesCount) && incoming;
const auto parsedGift = stargift
? FromTL(&peer->session(), *stargift)
: std::optional<Data::StarGift>();
@ -110,9 +116,9 @@ constexpr auto kTransactionsLimit = 100;
.bareGiftStickerId = giftStickerId,
.bareActorId = saveActorId ? barePeerId : uint64(0),
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
.starrefAmount = starrefAmount,
.starrefCommission = starrefCommission,
.starrefRecipientId = starrefBarePeerId,
.starrefAmount = paidMessagesCount ? StarsAmount() : starrefAmount,
.starrefCommission = paidMessagesCount ? 0 : starrefCommission,
.starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId,
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
return Data::CreditsHistoryEntry::PeerType::Peer;
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
@ -138,9 +144,15 @@ constexpr auto kTransactionsLimit = 100;
? base::unixtime::parse(tl.data().vtransaction_date()->v)
: QDateTime(),
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
.paidMessagesCount = paidMessagesCount,
.paidMessagesAmount = (paidMessagesCount
? starrefAmount
: StarsAmount()),
.paidMessagesCommission = paidMessagesCount ? starrefCommission : 0,
.starsConverted = int(nonUniqueGift
? nonUniqueGift->vconvert_stars().v
: 0),
.premiumMonthsForStars = premiumMonthsForStars,
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
.converted = stargift && incoming,
.stargift = stargift.has_value(),

View file

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/premium_preview_box.h" // ShowPremiumPreviewBox.
#include "boxes/star_gift_box.h" // ShowStarGiftBox.
#include "boxes/transfer_gift_box.h" // ShowTransferGiftBox.
#include "core/ui_integration.h"
#include "data/data_boosts.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
@ -58,7 +59,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/gradient_round_button.h"
#include "ui/widgets/label_with_custom_emoji.h"
#include "ui/widgets/tooltip.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
@ -66,6 +66,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h" // ShowChooseRecipientBox.
#include "window/window_session_controller.h"
#include "styles/style_boxes.h"
#include "styles/style_credits.h"
#include "styles/style_giveaway.h"
#include "styles/style_info.h"
#include "styles/style_layers.h"
@ -1272,8 +1273,8 @@ void AddStarGiftTable(
const auto selfBareId = session->userPeerId().value;
const auto giftToSelf = (peerId == session->userPeerId())
&& (entry.in || entry.bareGiftOwnerId == selfBareId);
const auto giftToChannel = entry.giftSavedId
&& peerIsChannel(PeerId(entry.bareGiftListPeerId));
const auto giftToChannel = entry.giftChannelSavedId
&& peerIsChannel(PeerId(entry.bareEntryOwnerId));
const auto raw = std::make_shared<Ui::ImportantTooltip*>(nullptr);
const auto showTooltip = [=](
@ -1394,14 +1395,14 @@ void AddStarGiftTable(
? MakePeerTableValue(table, show, PeerId(entry.bareActorId))
: MakeHiddenPeerTableValue(table)),
st::giveawayGiftCodePeerMargin);
if (entry.bareGiftListPeerId) {
if (entry.bareEntryOwnerId) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_peer(),
MakePeerTableValue(
table,
show,
PeerId(entry.bareGiftListPeerId)),
PeerId(entry.bareEntryOwnerId)),
st::giveawayGiftCodePeerMargin);
}
} else if (peerId && !giftToSelf) {
@ -1775,6 +1776,25 @@ void AddCreditsHistoryEntryTable(
tr::lng_credits_box_history_entry_subscription(
Ui::Text::WithEntities));
}
if (entry.paidMessagesAmount) {
auto value = Ui::Text::IconEmoji(&st::starIconEmojiColored);
const auto full = (entry.in ? 1 : -1)
* (entry.credits + entry.paidMessagesAmount);
const auto starsText = Lang::FormatStarsAmountDecimal(full);
AddTableRow(
table,
tr::lng_credits_paid_messages_full(),
rpl::single(value.append(' ' + starsText)));
}
if (const auto months = entry.premiumMonthsForStars) {
AddTableRow(
table,
tr::lng_credits_premium_gift_duration(),
tr::lng_months(
lt_count,
rpl::single(1. * months),
Ui::Text::WithEntities));
}
if (!entry.id.isEmpty()) {
auto label = MakeMaybeMultilineTokenValue(table, entry.id, st);
label->setClickHandlerFilter([=](const auto &...) {

View file

@ -2724,3 +2724,9 @@ bool EditPeerInfoBox::Available(not_null<PeerData*> peer) {
return false;
}
}
void ShowEditChatPermissions(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer) {
ShowEditPermissions(navigation, peer);
}

View file

@ -56,3 +56,7 @@ private:
not_null<PeerData*> _peer;
};
void ShowEditChatPermissions(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer);

View file

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/edit_birthday_box.h"
#include "ui/integration.h"
#include "payments/payments_non_panel_process.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "boxes/share_box.h"
#include "boxes/connection_box.h"
#include "boxes/gift_premium_box.h"
@ -1014,6 +1015,25 @@ bool CopyUsername(
return true;
}
bool EditPaidMessagesFee(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
const auto peerId = PeerId(match->captured(1).toULongLong());
if (const auto id = peerToChannel(peerId)) {
const auto channel = controller->session().data().channelLoaded(id);
if (channel && channel->canEditPermissions()) {
ShowEditChatPermissions(controller, channel);
}
} else {
controller->show(Box(EditMessagesPrivacyBox, controller));
}
return true;
}
bool ShowStarsExamples(
Window::SessionController *controller,
const Match &match,
@ -1517,6 +1537,10 @@ const std::vector<LocalUrlHandler> &InternalUrlHandlers() {
u"^username_regular/([a-zA-Z0-9\\-\\_\\.]+)@([0-9]+)$"_q,
CopyUsername,
},
{
u"^edit_paid_messages_fee/([0-9]+)$"_q,
EditPaidMessagesFee,
},
{
u"^stars_examples$"_q,
ShowStarsExamples,

View file

@ -60,6 +60,11 @@ public:
normalize();
return *this;
}
inline StarsAmount operator-() const {
auto result = *this;
result *= -1;
return result;
}
friend inline auto operator<=>(StarsAmount, StarsAmount) = default;
friend inline bool operator==(StarsAmount, StarsAmount) = default;
@ -97,3 +102,7 @@ private:
[[nodiscard]] inline StarsAmount operator*(StarsAmount a, int64 b) {
return a *= b;
}
[[nodiscard]] inline StarsAmount operator*(int64 a, StarsAmount b) {
return b *= a;
}

View file

@ -66,8 +66,8 @@ struct CreditsHistoryEntry final {
uint64 bareGiftStickerId = 0;
uint64 bareGiftOwnerId = 0;
uint64 bareActorId = 0;
uint64 bareGiftListPeerId = 0;
uint64 giftSavedId = 0;
uint64 bareEntryOwnerId = 0;
uint64 giftChannelSavedId = 0;
uint64 stargiftId = 0;
std::shared_ptr<UniqueGift> uniqueGift;
StarsAmount starrefAmount;
@ -77,11 +77,15 @@ struct CreditsHistoryEntry final {
QDateTime subscriptionUntil;
QDateTime successDate;
QString successLink;
int paidMessagesCount = 0;
StarsAmount paidMessagesAmount;
int paidMessagesCommission = 0;
int limitedCount = 0;
int limitedLeft = 0;
int starsConverted = 0;
int starsToUpgrade = 0;
int starsUpgradedBySender = 0;
int premiumMonthsForStars = 0;
int floodSkip = 0;
bool converted : 1 = false;
bool anonymous : 1 = false;

View file

@ -100,7 +100,7 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
data.currency,
true));
if (const auto stars = data.stars) {
const auto starsText = QString::number(stars);
const auto starsText = Lang::FormatCountDecimal(stars);
_byStars.setMarkedText(
st::giftBoxByStarsStyle,
tr::lng_gift_premium_by_stars(
@ -139,7 +139,7 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
(unique
? tr::lng_gift_price_unique(tr::now, Ui::Text::WithEntities)
: _delegate->star().append(
' ' + QString::number(data.info.stars))),
' ' + Lang::FormatCountDecimal(data.info.stars))),
kMarkupTextOptions,
_delegate->textContext());
if (!_stars) {

View file

@ -797,7 +797,6 @@ private:
PaintRoundImageCallback _paintUserpicCallback;
std::optional<Settings::SubscriptionRightLabel> _rightLabel;
QString _title;
QString _name;
Ui::Text::String _description;
@ -850,9 +849,13 @@ void CreditsRow::init() {
const auto name = !isSpecial
? PeerListRow::generateName()
: Ui::GenerateEntryName(_entry).text;
_name = _entry.title.isEmpty()
? name
: (!_entry.subscriptionUntil.isNull() && !isSpecial)
_name = _entry.paidMessagesCount
? tr::lng_credits_paid_messages_fee(
tr::now,
lt_count,
_entry.paidMessagesCount)
: ((!_entry.subscriptionUntil.isNull() && !isSpecial)
|| _entry.title.isEmpty())
? name
: _entry.title;
setSkipPeerBadge(true);
@ -861,6 +864,8 @@ void CreditsRow::init() {
tr::now,
lt_count_decimal,
_entry.floodSkip)
: _entry.paidMessagesCount
? name
: (!_entry.subscriptionUntil.isNull() && !_entry.title.isEmpty())
? _entry.title
: _entry.refunded
@ -943,11 +948,7 @@ const Data::SubscriptionEntry &CreditsRow::subscription() const {
}
QString CreditsRow::generateName() {
return (!_entry.title.isEmpty() && !_entry.subscriptionUntil.isNull())
? _name
: _entry.title.isEmpty()
? _name
: _entry.title;
return _name;
}
PaintRoundImageCallback CreditsRow::generatePaintUserpicCallback(bool force) {

View file

@ -178,10 +178,10 @@ private:
const Data::CreditsHistoryEntry &entry) {
return !entry.stargift
? Data::SavedStarGiftId()
: (entry.bareGiftListPeerId && entry.giftSavedId)
: (entry.bareEntryOwnerId && entry.giftChannelSavedId)
? Data::SavedStarGiftId::Chat(
session->data().peer(PeerId(entry.bareGiftListPeerId)),
entry.giftSavedId)
session->data().peer(PeerId(entry.bareEntryOwnerId)),
entry.giftChannelSavedId)
: Data::SavedStarGiftId::User(MsgId(entry.bareMsgId));
}
@ -950,9 +950,9 @@ void GenericCreditsEntryBox(
const auto giftToSelf = isStarGift
&& (e.barePeerId == selfPeerId)
&& (e.in || e.bareGiftOwnerId == selfPeerId);
const auto giftChannel = (isStarGift && e.giftSavedId)
const auto giftChannel = (isStarGift && e.giftChannelSavedId)
? session->data().peer(
PeerId(e.bareGiftListPeerId))->asChannel()
PeerId(e.bareEntryOwnerId))->asChannel()
: nullptr;
const auto giftToChannel = (giftChannel != nullptr);
const auto giftToChannelCanManage = giftToChannel
@ -1051,7 +1051,7 @@ void GenericCreditsEntryBox(
content->add(object_ptr<Ui::CenterWrap<>>(
content,
GenericEntryPhoto(content, callback, stUser.photoSize)));
} else if (peer && !e.gift) {
} else if (peer && !e.gift && !e.premiumMonthsForStars) {
if (e.subscriptionUntil.isNull() && s.until.isNull()) {
content->add(object_ptr<Ui::CenterWrap<>>(
content,
@ -1061,7 +1061,7 @@ void GenericCreditsEntryBox(
content,
SubscriptionUserpic(content, peer, stUser.photoSize)));
}
} else if (e.gift || isPrize) {
} else if (e.gift || isPrize || e.premiumMonthsForStars) {
struct State final {
DocumentData *sticker = nullptr;
std::shared_ptr<Data::DocumentMedia> media;
@ -1079,7 +1079,9 @@ void GenericCreditsEntryBox(
auto &packs = session->giftBoxStickersPacks();
const auto document = starGiftSticker
? starGiftSticker
: packs.lookup(packs.monthsForStars(e.credits.whole()));
: packs.lookup(e.premiumMonthsForStars
? e.premiumMonthsForStars
: packs.monthsForStars(e.credits.whole()));
if (document && document->sticker()) {
state->sticker = document;
state->media = document->createMediaView();
@ -1159,6 +1161,13 @@ void GenericCreditsEntryBox(
? tr::lng_credits_box_history_entry_giveaway_name(tr::now)
: (!e.subscriptionUntil.isNull() && e.title.isEmpty())
? tr::lng_credits_box_history_entry_subscription(tr::now)
: e.paidMessagesCount
? tr::lng_credits_paid_messages_fee(
tr::now,
lt_count,
e.paidMessagesCount)
: e.premiumMonthsForStars
? tr::lng_premium_summary_title(tr::now)
: !e.title.isEmpty()
? e.title
: e.starrefCommission
@ -1315,6 +1324,12 @@ void GenericCreditsEntryBox(
rpl::single(e.description),
st::creditsBoxAbout)));
}
const auto arrowEmoji = Ui::Text::SingleCustomEmoji(
owner->customEmojiManager().registerInternalEmoji(
st::topicButtonArrow,
st::channelEarnLearnArrowMargins,
true));
if (!uniqueGift && starGiftCanManage) {
Ui::AddSkip(content);
const auto about = box->addRow(
@ -1380,14 +1395,9 @@ void GenericCreditsEntryBox(
} else if (isStarGift) {
} else if (e.gift || isPrize) {
Ui::AddSkip(content);
const auto arrow = Ui::Text::SingleCustomEmoji(
owner->customEmojiManager().registerInternalEmoji(
st::topicButtonArrow,
st::channelEarnLearnArrowMargins,
true));
auto link = tr::lng_credits_box_history_entry_gift_about_link(
lt_emoji,
rpl::single(arrow),
rpl::single(arrowEmoji),
Ui::Text::RichLangValue
) | rpl::map([](TextWithEntities text) {
return Ui::Text::Link(
@ -1411,6 +1421,31 @@ void GenericCreditsEntryBox(
Ui::Text::RichLangValue),
{ .session = session },
st::creditsBoxAbout)));
} else if (e.paidMessagesCommission && e.barePeerId) {
Ui::AddSkip(content);
auto link = tr::lng_credits_paid_messages_fee_about_link(
lt_emoji,
rpl::single(arrowEmoji),
Ui::Text::RichLangValue
) | rpl::map([id = e.barePeerId](TextWithEntities text) {
return Ui::Text::Link(
std::move(text),
u"internal:edit_paid_messages_fee/"_q + QString::number(id));
});
const auto percent = 100. - (e.paidMessagesCommission / 10.);
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
Ui::CreateLabelWithCustomEmoji(
box,
tr::lng_credits_paid_messages_fee_about(
lt_percent,
rpl::single(
Ui::Text::Bold(QString::number(percent) + '%')),
lt_link,
std::move(link),
Ui::Text::RichLangValue),
{ .session = session },
st::creditsBoxAbout)));
}
Ui::AddSkip(content);
@ -1695,7 +1730,7 @@ void GenericCreditsEntryBox(
: canUpgradeFree
? tr::lng_gift_upgrade_free()
: (canToggle && !e.savedToProfile)
? (e.giftSavedId
? (e.giftChannelSavedId
? tr::lng_gift_show_on_channel
: tr::lng_gift_show_on_page)()
: tr::lng_box_ok()));
@ -1882,8 +1917,8 @@ void SavedStarGiftBox(
.bareGiftStickerId = data.info.document->id,
.bareGiftOwnerId = owner->id.value,
.bareActorId = data.fromId.value,
.bareGiftListPeerId = chatGiftPeer ? chatGiftPeer->id.value : 0,
.giftSavedId = data.manageId.chatSavedId(),
.bareEntryOwnerId = chatGiftPeer ? chatGiftPeer->id.value : 0,
.giftChannelSavedId = data.manageId.chatSavedId(),
.stargiftId = data.info.id,
.uniqueGift = data.info.unique,
.peerType = Data::CreditsHistoryEntry::PeerType::Peer,
@ -1927,8 +1962,8 @@ void StarGiftViewBox(
? data.unique->ownerId.value
: toId.value),
.bareActorId = (toChannel ? data.channelFrom->id.value : 0),
.bareGiftListPeerId = (toChannel ? data.channel->id.value : 0),
.giftSavedId = data.channelSavedId,
.bareEntryOwnerId = (toChannel ? data.channel->id.value : 0),
.giftChannelSavedId = data.channelSavedId,
.stargiftId = data.stargiftId,
.uniqueGift = data.unique,
.peerType = Data::CreditsHistoryEntry::PeerType::Peer,

View file

@ -554,7 +554,15 @@ TextWithEntities GenerateEntryName(const Data::CreditsHistoryEntry &entry) {
Info::BotStarRef::FormatCommission(entry.starrefCommission)
},
TextWithEntities::Simple)
: (entry.floodSkip
: entry.paidMessagesCount
? tr::lng_credits_paid_messages_fee(
tr::now,
lt_count,
entry.paidMessagesCount,
TextWithEntities::Simple)
: (entry.premiumMonthsForStars
? tr::lng_premium_summary_title
: entry.floodSkip
? tr::lng_credits_box_history_entry_api
: entry.reaction
? tr::lng_credits_box_history_entry_reaction_name