mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-24 14:33:02 +02:00
Merge tag 'v5.16.3' into dev
This commit is contained in:
commit
f450001edb
41 changed files with 655 additions and 99 deletions
BIN
Telegram/Resources/icons/menu/cancel_fee.png
Normal file
BIN
Telegram/Resources/icons/menu/cancel_fee.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 865 B |
BIN
Telegram/Resources/icons/menu/cancel_fee@2x.png
Normal file
BIN
Telegram/Resources/icons/menu/cancel_fee@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/menu/cancel_fee@3x.png
Normal file
BIN
Telegram/Resources/icons/menu/cancel_fee@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -2863,6 +2863,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_credits_box_history_entry_gift_converted" = "Converted Gift";
|
||||
"lng_credits_box_history_entry_gift_transfer" = "Gift Transfer";
|
||||
"lng_credits_box_history_entry_gift_unavailable" = "Unavailable";
|
||||
"lng_credits_box_history_entry_gift_released" = "released by {name}";
|
||||
"lng_credits_box_history_entry_gift_sold_out" = "This gift has sold out";
|
||||
"lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}";
|
||||
"lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}";
|
||||
|
@ -3581,12 +3582,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later.";
|
||||
"lng_gift_channel_title" = "Send a Gift";
|
||||
"lng_gift_channel_about" = "Select a gift to show appreciation for {name}.";
|
||||
"lng_gift_released_by" = "Released by {name}";
|
||||
"lng_gift_unique_owner" = "Owner";
|
||||
"lng_gift_unique_address_copied" = "Address copied to clipboard.";
|
||||
"lng_gift_unique_status" = "Status";
|
||||
"lng_gift_unique_status_non" = "Non-Unique";
|
||||
"lng_gift_unique_status_upgrade" = "upgrade";
|
||||
"lng_gift_unique_number" = "Collectible #{index}";
|
||||
"lng_gift_unique_number_by" = "Collectible #{index} by {name}";
|
||||
"lng_gift_unique_model" = "Model";
|
||||
"lng_gift_unique_backdrop" = "Backdrop";
|
||||
"lng_gift_unique_symbol" = "Symbol";
|
||||
|
@ -4312,6 +4315,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_context_edit_shortcut" = "Edit Shortcut";
|
||||
"lng_context_delete_shortcut" = "Delete Quick Reply";
|
||||
"lng_context_gift_send" = "Send Another Gift";
|
||||
"lng_context_charge_fee" = "Charge Fee";
|
||||
"lng_context_remove_fee" = "Remove Fee";
|
||||
"lng_context_fee_now" = "{name} pays {amount} per message.";
|
||||
"lng_context_fee_free" = "{name} can send messages for free.";
|
||||
|
||||
"lng_add_tag_about" = "Tag this message with an emoji for quick search.";
|
||||
"lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}";
|
||||
|
@ -5314,6 +5321,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_payment_bar_button" = "Remove Fee";
|
||||
"lng_payment_refund_title" = "Remove Fee";
|
||||
"lng_payment_refund_text" = "Are you sure you want to allow {name} to message you for free?";
|
||||
"lng_payment_refund_channel" = "Do you want to allow {name} to message the channel for free?";
|
||||
"lng_payment_refund_also#one" = "Refund already paid {count} Star";
|
||||
"lng_payment_refund_also#other" = "Refund already paid {count} Stars";
|
||||
"lng_payment_refund_confirm" = "Confirm";
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="5.16.2.0" />
|
||||
Version="5.16.3.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
|
|
@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,16,2,0
|
||||
PRODUCTVERSION 5,16,2,0
|
||||
FILEVERSION 5,16,3,0
|
||||
PRODUCTVERSION 5,16,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -62,10 +62,10 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop"
|
||||
VALUE "FileVersion", "5.16.2.0"
|
||||
VALUE "FileVersion", "5.16.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "5.16.2.0"
|
||||
VALUE "ProductVersion", "5.16.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,16,2,0
|
||||
PRODUCTVERSION 5,16,2,0
|
||||
FILEVERSION 5,16,3,0
|
||||
PRODUCTVERSION 5,16,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -53,10 +53,10 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop Updater"
|
||||
VALUE "FileVersion", "5.16.2.0"
|
||||
VALUE "FileVersion", "5.16.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "5.16.2.0"
|
||||
VALUE "ProductVersion", "5.16.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -283,7 +283,7 @@ rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
|
|||
auto lifetime = rpl::lifetime();
|
||||
|
||||
const auto finish = [=](const QString &url) {
|
||||
makeRequest(MTPpayments_GetStarsRevenueStats(
|
||||
api().request(MTPpayments_GetStarsRevenueStats(
|
||||
MTP_flags(0),
|
||||
(_isUser ? user()->input : channel()->input)
|
||||
)).done([=](const MTPpayments_StarsRevenueStats &result) {
|
||||
|
@ -313,7 +313,7 @@ rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
|
|||
}).send();
|
||||
};
|
||||
|
||||
makeRequest(
|
||||
api().request(
|
||||
MTPpayments_GetStarsRevenueAdsAccountUrl(
|
||||
(_isUser ? user()->input : channel()->input))
|
||||
).done([=](const MTPpayments_StarsRevenueAdsAccountUrl &result) {
|
||||
|
|
|
@ -619,6 +619,8 @@ auto PremiumGiftCodeOptions::requestStarGifts()
|
|||
MTP_int(0)
|
||||
)).done([=](const MTPpayments_StarGifts &result) {
|
||||
result.match([&](const MTPDpayments_starGifts &data) {
|
||||
_peer->owner().processUsers(data.vusers());
|
||||
_peer->owner().processChats(data.vchats());
|
||||
_giftsHash = data.vhash().v;
|
||||
const auto &list = data.vgifts().v;
|
||||
const auto session = &_peer->session();
|
||||
|
@ -805,6 +807,12 @@ std::optional<Data::StarGift> FromTL(
|
|||
if (!document->sticker()) {
|
||||
return std::optional<Data::StarGift>();
|
||||
}
|
||||
const auto releasedById = data.vreleased_by()
|
||||
? peerFromMTP(*data.vreleased_by())
|
||||
: PeerId();
|
||||
const auto releasedBy = releasedById
|
||||
? session->data().peer(releasedById).get()
|
||||
: nullptr;
|
||||
return std::optional<Data::StarGift>(Data::StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.stars = int64(data.vstars().v),
|
||||
|
@ -812,6 +820,7 @@ std::optional<Data::StarGift> FromTL(
|
|||
.starsToUpgrade = int64(data.vupgrade_stars().value_or_empty()),
|
||||
.starsResellMin = int64(resellPrice),
|
||||
.document = document,
|
||||
.releasedBy = releasedBy,
|
||||
.resellTitle = qs(data.vtitle().value_or_empty()),
|
||||
.resellCount = int(data.vavailability_resale().value_or_empty()),
|
||||
.limitedLeft = remaining.value_or_empty(),
|
||||
|
@ -841,6 +850,12 @@ std::optional<Data::StarGift> FromTL(
|
|||
|| !pattern->document->sticker()) {
|
||||
return std::optional<Data::StarGift>();
|
||||
}
|
||||
const auto releasedById = data.vreleased_by()
|
||||
? peerFromMTP(*data.vreleased_by())
|
||||
: PeerId();
|
||||
const auto releasedBy = releasedById
|
||||
? session->data().peer(releasedById).get()
|
||||
: nullptr;
|
||||
auto result = Data::StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.unique = std::make_shared<Data::UniqueGift>(Data::UniqueGift{
|
||||
|
@ -852,12 +867,14 @@ std::optional<Data::StarGift> FromTL(
|
|||
.ownerId = (data.vowner_id()
|
||||
? peerFromMTP(*data.vowner_id())
|
||||
: PeerId()),
|
||||
.releasedBy = releasedBy,
|
||||
.number = data.vnum().v,
|
||||
.starsForResale = int(data.vresell_stars().value_or_empty()),
|
||||
.model = *model,
|
||||
.pattern = *pattern,
|
||||
}),
|
||||
.document = model->document,
|
||||
.releasedBy = releasedBy,
|
||||
.limitedLeft = (total - data.vavailability_issued().v),
|
||||
.limitedCount = total,
|
||||
};
|
||||
|
|
|
@ -696,7 +696,7 @@ rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
|
|||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
makeRequest(MTPpayments_GetStarsRevenueStats(
|
||||
api().request(MTPpayments_GetStarsRevenueStats(
|
||||
MTP_flags(MTPpayments_getStarsRevenueStats::Flag::f_ton),
|
||||
(_isUser ? user()->input : channel()->input)
|
||||
)).done([=](const MTPpayments_StarsRevenueStats &result) {
|
||||
|
|
|
@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/stickers_lottie.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "core/application.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/components/promo_suggestions.h"
|
||||
#include "data/data_birthday.h"
|
||||
|
@ -94,6 +95,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/section_widget.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
@ -333,6 +335,69 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class TextBubblePart final : public MediaGenericTextPart {
|
||||
public:
|
||||
TextBubblePart(
|
||||
TextWithEntities text,
|
||||
QMargins margins,
|
||||
const style::TextStyle &st = st::defaultTextStyle,
|
||||
const base::flat_map<uint16, ClickHandlerPtr> &links = {},
|
||||
const Ui::Text::MarkedContext &context = {},
|
||||
style::align align = style::al_top);
|
||||
|
||||
void draw(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context,
|
||||
int outerWidth) const override;
|
||||
|
||||
private:
|
||||
void setupPen(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context) const override;
|
||||
int elisionLines() const override;
|
||||
|
||||
};
|
||||
|
||||
TextBubblePart::TextBubblePart(
|
||||
TextWithEntities text,
|
||||
QMargins margins,
|
||||
const style::TextStyle &st,
|
||||
const base::flat_map<uint16, ClickHandlerPtr> &links,
|
||||
const Ui::Text::MarkedContext &context,
|
||||
style::align align)
|
||||
: MediaGenericTextPart(std::move(text), margins, st, links, context, align) {
|
||||
}
|
||||
|
||||
void TextBubblePart::draw(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context,
|
||||
int outerWidth) const {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(context.st->msgServiceBg());
|
||||
const auto radius = height() / 2.;
|
||||
const auto left = (outerWidth - width()) / 2;
|
||||
const auto r = QRect(left, 0, width(), height());
|
||||
p.drawRoundedRect(r, radius, radius);
|
||||
|
||||
MediaGenericTextPart::draw(p, owner, context, outerWidth);
|
||||
}
|
||||
|
||||
void TextBubblePart::setupPen(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context) const {
|
||||
auto pen = context.st->msgServiceFg()->c;
|
||||
pen.setAlphaF(pen.alphaF() * 0.65);
|
||||
p.setPen(pen);
|
||||
}
|
||||
|
||||
int TextBubblePart::elisionLines() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] AttributeId FromTL(const MTPStarGiftAttributeId &id) {
|
||||
return id.match([&](const MTPDstarGiftAttributeIdBackdrop &data) {
|
||||
return AttributeId{
|
||||
|
@ -526,6 +591,21 @@ auto GenerateGiftMedia(
|
|||
st::giftBoxPreviewTitlePadding,
|
||||
{},
|
||||
context);
|
||||
|
||||
if (v::is<GiftTypeStars>(descriptor)) {
|
||||
const auto &stars = v::get<GiftTypeStars>(descriptor);
|
||||
if (const auto by = stars.info.releasedBy) {
|
||||
push(std::make_unique<TextBubblePart>(
|
||||
tr::lng_gift_released_by(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Link('@' + by->username()),
|
||||
Ui::Text::WithEntities),
|
||||
st::giftBoxReleasedByMargin,
|
||||
st::defaultTextStyle));
|
||||
}
|
||||
}
|
||||
|
||||
pushText(
|
||||
std::move(description),
|
||||
st::giftBoxPreviewTextPadding,
|
||||
|
@ -778,7 +858,7 @@ void PreviewWrap::prepare(rpl::producer<GiftDetails> details) {
|
|||
owned.get(),
|
||||
GenerateGiftMedia(owned.get(), _item.get(), _recipient, details),
|
||||
MediaGenericDescriptor{
|
||||
.maxWidth = st::chatIntroWidth,
|
||||
.maxWidth = st::chatGiftPreviewWidth,
|
||||
.service = true,
|
||||
}));
|
||||
_item = std::move(owned);
|
||||
|
@ -3820,6 +3900,19 @@ void AddUniqueGiftCover(
|
|||
Fn<void()> resaleClick) {
|
||||
const auto cover = container->add(object_ptr<RpWidget>(container));
|
||||
|
||||
struct Released {
|
||||
Released() : white(QColor(255, 255, 255)) {
|
||||
}
|
||||
|
||||
style::owned_color white;
|
||||
style::FlatLabel st;
|
||||
PeerData *by = nullptr;
|
||||
QColor bg;
|
||||
};
|
||||
const auto released = cover->lifetime().make_state<Released>();
|
||||
released->st = st::uniqueGiftSubtitle;
|
||||
released->st.palette.linkFg = released->white.color();
|
||||
|
||||
if (resalePrice) {
|
||||
auto background = rpl::duplicate(
|
||||
data
|
||||
|
@ -3841,17 +3934,58 @@ void AddUniqueGiftCover(
|
|||
st::uniqueGiftTitle);
|
||||
title->setTextColorOverride(QColor(255, 255, 255));
|
||||
auto subtitleText = subtitleOverride
|
||||
? std::move(subtitleOverride)
|
||||
: rpl::duplicate(data) | rpl::map([](const Data::UniqueGift &gift) {
|
||||
return tr::lng_gift_unique_number(
|
||||
tr::now,
|
||||
lt_index,
|
||||
QString::number(gift.number));
|
||||
? std::move(
|
||||
subtitleOverride
|
||||
) | Ui::Text::ToWithEntities() | rpl::type_erased()
|
||||
: rpl::duplicate(data) | rpl::map([=](const Data::UniqueGift &gift) {
|
||||
released->by = gift.releasedBy;
|
||||
released->bg = gift.backdrop.patternColor;
|
||||
return gift.releasedBy
|
||||
? tr::lng_gift_unique_number_by(
|
||||
tr::now,
|
||||
lt_index,
|
||||
TextWithEntities{ QString::number(gift.number) },
|
||||
lt_name,
|
||||
Ui::Text::Link('@' + gift.releasedBy->username()),
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_gift_unique_number(
|
||||
tr::now,
|
||||
lt_index,
|
||||
TextWithEntities{ QString::number(gift.number) },
|
||||
Ui::Text::WithEntities);
|
||||
});
|
||||
const auto subtitle = CreateChild<FlatLabel>(
|
||||
cover,
|
||||
std::move(subtitleText),
|
||||
st::uniqueGiftSubtitle);
|
||||
released->st);
|
||||
if (released->by) {
|
||||
const auto button = CreateChild<AbstractButton>(cover);
|
||||
subtitle->raise();
|
||||
subtitle->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
button->setClickedCallback([=] {
|
||||
GiftReleasedByHandler(released->by);
|
||||
});
|
||||
subtitle->geometryValue(
|
||||
) | rpl::start_with_next([=](QRect geometry) {
|
||||
button->setGeometry(
|
||||
geometry.marginsAdded(st::giftBoxReleasedByMargin));
|
||||
}, button->lifetime());
|
||||
button->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(button);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto use = subtitle->textMaxWidth();
|
||||
const auto add = button->width() - subtitle->width();
|
||||
const auto full = use + add;
|
||||
const auto left = (button->width() - full) / 2;
|
||||
const auto height = button->height();
|
||||
const auto radius = height / 2.;
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(released->bg);
|
||||
p.setOpacity(0.5);
|
||||
p.drawRoundedRect(left, 0, full, height, radius, radius);
|
||||
}, button->lifetime());
|
||||
}
|
||||
|
||||
struct GiftView {
|
||||
QImage gradient;
|
||||
|
@ -4417,6 +4551,24 @@ void ShowUniqueGiftSellBox(
|
|||
}));
|
||||
}
|
||||
|
||||
void GiftReleasedByHandler(not_null<PeerData*> peer) {
|
||||
const auto session = &peer->session();
|
||||
const auto window = session->tryResolveWindow(peer);
|
||||
if (window) {
|
||||
window->showPeerHistory(peer);
|
||||
return;
|
||||
}
|
||||
const auto account = not_null(&session->account());
|
||||
if (const auto window = Core::App().windowFor(account)) {
|
||||
window->invokeForSessionController(
|
||||
&session->account(),
|
||||
peer,
|
||||
[=](not_null<Window::SessionController*> window) {
|
||||
window->showPeerHistory(peer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct UpgradeArgs : StarGiftUpgradeArgs {
|
||||
std::vector<Data::UniqueGiftModel> models;
|
||||
std::vector<Data::UniqueGiftPattern> patterns;
|
||||
|
|
|
@ -82,6 +82,8 @@ void ShowUniqueGiftSellBox(
|
|||
Data::SavedStarGiftId savedId,
|
||||
Settings::GiftWearBoxStyleOverride st);
|
||||
|
||||
void GiftReleasedByHandler(not_null<PeerData*> peer);
|
||||
|
||||
struct PatternPoint {
|
||||
QPointF position;
|
||||
float64 scale = 1.;
|
||||
|
|
|
@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
|
|||
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
|
||||
constexpr auto AppName = "AyuGram Desktop"_cs;
|
||||
constexpr auto AppFile = "AyuGram"_cs;
|
||||
constexpr auto AppVersion = 5016002;
|
||||
constexpr auto AppVersionStr = "5.16.2";
|
||||
constexpr auto AppVersion = 5016003;
|
||||
constexpr auto AppVersionStr = "5.16.3";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
|
|
@ -65,6 +65,7 @@ struct CreditsHistoryEntry final {
|
|||
uint64 bareGiveawayMsgId = 0;
|
||||
uint64 bareGiftStickerId = 0;
|
||||
uint64 bareGiftOwnerId = 0;
|
||||
uint64 bareGiftReleasedById = 0;
|
||||
uint64 bareGiftResaleRecipientId = 0;
|
||||
uint64 bareActorId = 0;
|
||||
uint64 bareEntryOwnerId = 0;
|
||||
|
|
|
@ -2569,7 +2569,9 @@ std::unique_ptr<HistoryView::Media> MediaGiftBox::createView(
|
|||
message,
|
||||
HistoryView::GenerateUniqueGiftMedia(message, replacing, unique),
|
||||
HistoryView::MediaGenericDescriptor{
|
||||
.maxWidth = st::msgServiceGiftBoxSize.width(),
|
||||
.maxWidth = (_data.stargiftReleasedBy
|
||||
? st::msgServiceStarGiftByWidth
|
||||
: st::msgServiceGiftBoxSize.width()),
|
||||
.paintBg = HistoryView::UniqueGiftBg(message, unique),
|
||||
.service = true,
|
||||
});
|
||||
|
|
|
@ -144,6 +144,7 @@ struct GiftCode {
|
|||
QString slug;
|
||||
uint64 stargiftId = 0;
|
||||
DocumentData *document = nullptr;
|
||||
PeerData *stargiftReleasedBy = nullptr;
|
||||
std::shared_ptr<UniqueGift> unique;
|
||||
TextWithEntities message;
|
||||
ChannelData *channel = nullptr;
|
||||
|
|
|
@ -655,7 +655,7 @@ bool PeerData::canCreatePolls() const {
|
|||
}
|
||||
|
||||
bool PeerData::canCreateTodoLists() const {
|
||||
if (isMonoforum()) {
|
||||
if (isMonoforum() || isBroadcast()) {
|
||||
return false;
|
||||
}
|
||||
return session().premium()
|
||||
|
|
|
@ -731,6 +731,24 @@ void SavedSublist::applyMonoforumDialog(
|
|||
unreadReactions().setCount(data.vunread_reactions_count().v);
|
||||
setUnreadMark(data.is_unread_mark());
|
||||
applyMaybeLast(topItem);
|
||||
|
||||
if (data.is_nopaid_messages_exception()) {
|
||||
_flags |= Flag::FeeRemoved;
|
||||
} else {
|
||||
_flags &= ~Flag::FeeRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
bool SavedSublist::isFeeRemoved() const {
|
||||
return (_flags & Flag::FeeRemoved);
|
||||
}
|
||||
|
||||
void SavedSublist::toggleFeeRemoved(bool feeRemoved) {
|
||||
if (feeRemoved) {
|
||||
_flags |= Flag::FeeRemoved;
|
||||
} else {
|
||||
_flags &= ~Flag::FeeRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
TimeId SavedSublist::adjustedChatListTimeId() const {
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
~SavedSublist();
|
||||
|
||||
[[nodiscard]] bool inMonoforum() const;
|
||||
[[nodiscard]] bool isFeeRemoved() const;
|
||||
void toggleFeeRemoved(bool feeRemoved);
|
||||
|
||||
void apply(const SublistReadTillUpdate &update);
|
||||
void apply(const MessageUpdate &update);
|
||||
|
@ -125,6 +127,7 @@ private:
|
|||
enum class Flag : uchar {
|
||||
ResolveChatListMessage = (1 << 0),
|
||||
InMonoforum = (1 << 1),
|
||||
FeeRemoved = (1 << 2),
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||
using Flags = base::flags<Flag>;
|
||||
|
|
|
@ -44,6 +44,7 @@ struct UniqueGift {
|
|||
QString ownerAddress;
|
||||
QString ownerName;
|
||||
PeerId ownerId = 0;
|
||||
PeerData *releasedBy = nullptr;
|
||||
int number = 0;
|
||||
int starsForTransfer = -1;
|
||||
int starsForResale = -1;
|
||||
|
@ -68,6 +69,7 @@ struct StarGift {
|
|||
int64 starsToUpgrade = 0;
|
||||
int64 starsResellMin = 0;
|
||||
not_null<DocumentData*> document;
|
||||
PeerData *releasedBy = nullptr;
|
||||
QString resellTitle;
|
||||
int resellCount = 0;
|
||||
int limitedLeft = 0;
|
||||
|
|
|
@ -6531,6 +6531,7 @@ void HistoryItem::applyAction(const MTPMessageAction &action) {
|
|||
fields.stargiftId = gift->id;
|
||||
fields.starsToUpgrade = gift->starsToUpgrade;
|
||||
fields.document = gift->document;
|
||||
fields.stargiftReleasedBy = gift->releasedBy;
|
||||
fields.limitedCount = gift->limitedCount;
|
||||
fields.limitedLeft = gift->limitedLeft;
|
||||
fields.count = gift->stars;
|
||||
|
@ -6566,6 +6567,7 @@ void HistoryItem::applyAction(const MTPMessageAction &action) {
|
|||
if (auto gift = Api::FromTL(&history()->session(), data.vgift())) {
|
||||
fields.stargiftId = gift->id;
|
||||
fields.document = gift->document;
|
||||
fields.stargiftReleasedBy = gift->releasedBy;
|
||||
fields.limitedCount = gift->limitedCount;
|
||||
fields.limitedLeft = gift->limitedLeft;
|
||||
fields.count = gift->stars;
|
||||
|
|
|
@ -1194,6 +1194,7 @@ PaysStatus::PaysStatus(
|
|||
not_null<UserData*> user)
|
||||
: _controller(window)
|
||||
, _user(user)
|
||||
, _paidAlready(std::make_shared<rpl::variable<int>>())
|
||||
, _inner(Ui::CreateChild<Bar>(parent.get(), user))
|
||||
, _bar(parent, object_ptr<Bar>::fromRaw(_inner)) {
|
||||
setupState();
|
||||
|
@ -1220,65 +1221,12 @@ void PaysStatus::setupState() {
|
|||
void PaysStatus::setupHandlers() {
|
||||
_inner->removeClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto user = _user;
|
||||
const auto exception = [=](bool refund) {
|
||||
using Flag = MTPaccount_ToggleNoPaidMessagesException::Flag;
|
||||
const auto api = &user->session().api();
|
||||
const auto require = false;
|
||||
api->request(MTPaccount_ToggleNoPaidMessagesException(
|
||||
MTP_flags((refund ? Flag::f_refund_charged : Flag())
|
||||
| (require ? Flag::f_require_payment : Flag())),
|
||||
MTPInputPeer(), // parent_peer // #TODO monoforum
|
||||
user->inputUser
|
||||
)).done([=] {
|
||||
user->clearPaysPerMessage();
|
||||
}).send();
|
||||
};
|
||||
_controller->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto refund = std::make_shared<QPointer<Ui::Checkbox>>();
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = tr::lng_payment_refund_text(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities),
|
||||
.confirmed = [=](Fn<void()> close) {
|
||||
exception(*refund && (*refund)->checked());
|
||||
close();
|
||||
},
|
||||
.confirmText = tr::lng_payment_refund_confirm(tr::now),
|
||||
.title = tr::lng_payment_refund_title(tr::now),
|
||||
});
|
||||
const auto paid = box->lifetime().make_state<
|
||||
rpl::variable<int>
|
||||
>();
|
||||
*paid = _paidAlready.value();
|
||||
paid->value() | rpl::start_with_next([=](int already) {
|
||||
if (!already) {
|
||||
delete base::take(*refund);
|
||||
} else if (!*refund) {
|
||||
const auto skip = st::defaultCheckbox.margin.top();
|
||||
*refund = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box,
|
||||
tr::lng_payment_refund_also(
|
||||
lt_count,
|
||||
paid->value() | tr::to_count()),
|
||||
false,
|
||||
st::defaultCheckbox),
|
||||
st::boxRowPadding + QMargins(0, skip, 0, skip));
|
||||
}
|
||||
}, box->lifetime());
|
||||
|
||||
user->session().api().request(MTPaccount_GetPaidMessagesRevenue(
|
||||
MTP_flags(0),
|
||||
MTPInputPeer(), // parent_peer // #TODO monoforum
|
||||
user->inputUser
|
||||
)).done(crl::guard(_inner, [=](
|
||||
const MTPaccount_PaidMessagesRevenue &result) {
|
||||
_paidAlready = result.data().vstars_amount().v;
|
||||
})).send();
|
||||
}));
|
||||
Window::PeerMenuConfirmToggleFee(
|
||||
_controller,
|
||||
_paidAlready,
|
||||
_user->session().user(),
|
||||
_user,
|
||||
true);
|
||||
}, _bar.lifetime());
|
||||
}
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ private:
|
|||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<UserData*> _user;
|
||||
rpl::variable<int> _paidAlready;
|
||||
std::shared_ptr<rpl::variable<int>> _paidAlready;
|
||||
State _state;
|
||||
QPointer<Bar> _inner;
|
||||
SlidingBar _bar;
|
||||
|
|
|
@ -1231,6 +1231,11 @@ void TopBarWidget::updateControlsVisibility() {
|
|||
? (hasPollsMenu || hasTodoListsMenu || hasTopicMenu)
|
||||
: (section == Section::ChatsList)
|
||||
? (_activeChat.key.peer() && _activeChat.key.peer()->isForum())
|
||||
: (section == Section::SavedSublist)
|
||||
? (_activeChat.key.peer()
|
||||
&& _activeChat.key.peer()->isChannel()
|
||||
&& _activeChat.key.peer()->owner().commonStarsPerMessage(
|
||||
_activeChat.key.peer()->asChannel()))
|
||||
: false);
|
||||
const auto hasInfo = !_activeChat.key.folder()
|
||||
&& (section == Section::History
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_premium.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/gift_premium_box.h" // ResolveGiftCode
|
||||
#include "boxes/star_gift_box.h" // GiftReleasedByHandler
|
||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||
#include "core/click_handler_types.h" // ClickHandlerContext
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
|
@ -54,7 +55,9 @@ int PremiumGift::top() {
|
|||
}
|
||||
|
||||
int PremiumGift::width() {
|
||||
return st::msgServiceStarGiftBoxWidth;
|
||||
return _data.stargiftReleasedBy
|
||||
? st::msgServiceStarGiftByWidth
|
||||
: st::msgServiceStarGiftBoxWidth;
|
||||
}
|
||||
|
||||
QSize PremiumGift::size() {
|
||||
|
@ -120,6 +123,18 @@ TextWithEntities PremiumGift::title() {
|
|||
: tr::lng_prize_title(tr::now, WithEntities);
|
||||
}
|
||||
|
||||
TextWithEntities PremiumGift::author() {
|
||||
using namespace Ui::Text;
|
||||
if (!_data.stargiftReleasedBy) {
|
||||
return {};
|
||||
}
|
||||
return tr::lng_gift_released_by(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Link('@' + _data.stargiftReleasedBy->username()),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
|
||||
TextWithEntities PremiumGift::subtitle() {
|
||||
if (tonGift()) {
|
||||
return tr::lng_action_gift_got_ton(tr::now, Ui::Text::WithEntities);
|
||||
|
@ -319,6 +334,18 @@ ClickHandlerPtr PremiumGift::createViewLink() {
|
|||
});
|
||||
}
|
||||
|
||||
ClickHandlerPtr PremiumGift::authorLink() {
|
||||
if (const auto by = _data.stargiftReleasedBy) {
|
||||
if (!_authorLink) {
|
||||
_authorLink = std::make_shared<LambdaClickHandler>([=] {
|
||||
Ui::GiftReleasedByHandler(by);
|
||||
});
|
||||
}
|
||||
return _authorLink;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int PremiumGift::buttonSkip() {
|
||||
return st::msgServiceGiftBoxButtonMargins.top();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
int width() override;
|
||||
QSize size() override;
|
||||
TextWithEntities title() override;
|
||||
TextWithEntities author() override;
|
||||
TextWithEntities subtitle() override;
|
||||
rpl::producer<QString> button() override;
|
||||
std::optional<Ui::Premium::MiniStarsType> buttonMinistars() override;
|
||||
|
@ -39,6 +40,7 @@ public:
|
|||
const PaintContext &context,
|
||||
const QRect &geometry) override;
|
||||
ClickHandlerPtr createViewLink() override;
|
||||
ClickHandlerPtr authorLink() override;
|
||||
|
||||
bool hideServiceText() override;
|
||||
void stickerClearLoopPlayed() override;
|
||||
|
@ -63,6 +65,7 @@ private:
|
|||
const not_null<Element*> _parent;
|
||||
const not_null<Data::MediaGiftBox*> _gift;
|
||||
const Data::GiftCode &_data;
|
||||
ClickHandlerPtr _authorLink;
|
||||
QImage _badgeCache;
|
||||
Info::PeerGifts::GiftBadge _badgeKey;
|
||||
mutable std::optional<Sticker> _sticker;
|
||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/rect.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_credits.h"
|
||||
#include "styles/style_premium.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
|
@ -51,6 +52,11 @@ ServiceBox::ServiceBox(
|
|||
.session = &parent->history()->session(),
|
||||
.repaint = [parent] { parent->customEmojiRepaint(); },
|
||||
}))
|
||||
, _author(
|
||||
st::defaultTextStyle,
|
||||
_content->author(),
|
||||
kMarkupTextOptions,
|
||||
_maxWidth)
|
||||
, _subtitle(
|
||||
st::premiumPreviewAbout.style,
|
||||
Ui::Text::Filtered(
|
||||
|
@ -79,6 +85,12 @@ ServiceBox::ServiceBox(
|
|||
? 0
|
||||
: (_title.countHeight(_maxWidth)
|
||||
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
||||
+ (_author.isEmpty()
|
||||
? 0
|
||||
: (st::giftBoxReleasedByMargin.top()
|
||||
+ st::defaultTextStyle.font->height
|
||||
+ st::giftBoxReleasedByMargin.bottom()
|
||||
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
||||
+ _subtitle.countHeight(_maxWidth)
|
||||
+ (!_content->button()
|
||||
? 0
|
||||
|
@ -164,6 +176,37 @@ void ServiceBox::draw(Painter &p, const PaintContext &context) const {
|
|||
});
|
||||
top += _title.countHeight(_maxWidth) + padding.bottom();
|
||||
}
|
||||
if (!_author.isEmpty()) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(context.st->msgServiceBg());
|
||||
const auto use = std::min(_maxWidth, _author.maxWidth())
|
||||
+ st::giftBoxReleasedByMargin.left()
|
||||
+ st::giftBoxReleasedByMargin.right();
|
||||
const auto left = st::msgPadding.left() + (_maxWidth - use) / 2;
|
||||
const auto height = st::giftBoxReleasedByMargin.top()
|
||||
+ st::defaultTextStyle.font->height
|
||||
+ st::giftBoxReleasedByMargin.bottom();
|
||||
const auto radius = height / 2.;
|
||||
p.drawRoundedRect(left, top, use, height, radius, radius);
|
||||
|
||||
auto fg = context.st->msgServiceFg()->c;
|
||||
fg.setAlphaF(0.65 * fg.alphaF());
|
||||
p.setPen(fg);
|
||||
_author.draw(p, {
|
||||
.position = QPoint(
|
||||
left + st::giftBoxReleasedByMargin.left(),
|
||||
top + st::giftBoxReleasedByMargin.top()),
|
||||
.availableWidth = (use
|
||||
- st::giftBoxReleasedByMargin.left()
|
||||
- st::giftBoxReleasedByMargin.right()),
|
||||
.palette = &context.st->serviceTextPalette(),
|
||||
.elisionLines = 1,
|
||||
});
|
||||
p.setPen(context.st->msgServiceFg());
|
||||
|
||||
top += height + st::msgServiceGiftBoxTitlePadding.bottom();
|
||||
}
|
||||
_parent->prepareCustomEmojiPaint(p, context, _subtitle);
|
||||
_subtitle.draw(p, {
|
||||
.position = QPoint(st::msgPadding.left(), top),
|
||||
|
@ -231,6 +274,23 @@ TextState ServiceBox::textState(QPoint point, StateRequest request) const {
|
|||
if (!_title.isEmpty()) {
|
||||
top += _title.countHeight(_maxWidth) + padding.bottom();
|
||||
}
|
||||
if (!_author.isEmpty()) {
|
||||
const auto use = std::min(_maxWidth, _author.maxWidth())
|
||||
+ st::giftBoxReleasedByMargin.left()
|
||||
+ st::giftBoxReleasedByMargin.right();
|
||||
const auto left = st::msgPadding.left() + (_maxWidth - use) / 2;
|
||||
const auto height = st::giftBoxReleasedByMargin.top()
|
||||
+ st::defaultTextStyle.font->height
|
||||
+ st::giftBoxReleasedByMargin.bottom();
|
||||
if (point.x() >= left
|
||||
&& point.y() >= top
|
||||
&& point.x() < left + use
|
||||
&& point.y() < top + height) {
|
||||
result.link = _content->authorLink();
|
||||
}
|
||||
top += height + st::msgServiceGiftBoxTitlePadding.bottom();
|
||||
}
|
||||
|
||||
auto subtitleRequest = request.forText();
|
||||
subtitleRequest.align = style::al_top;
|
||||
const auto state = _subtitle.getState(
|
||||
|
|
|
@ -28,6 +28,9 @@ public:
|
|||
[[nodiscard]] virtual int top() = 0;
|
||||
[[nodiscard]] virtual QSize size() = 0;
|
||||
[[nodiscard]] virtual TextWithEntities title() = 0;
|
||||
[[nodiscard]] virtual TextWithEntities author() {
|
||||
return {};
|
||||
}
|
||||
[[nodiscard]] virtual TextWithEntities subtitle() = 0;
|
||||
[[nodiscard]] virtual int buttonSkip() {
|
||||
return top();
|
||||
|
@ -45,6 +48,9 @@ public:
|
|||
const PaintContext &context,
|
||||
const QRect &geometry) = 0;
|
||||
[[nodiscard]] virtual ClickHandlerPtr createViewLink() = 0;
|
||||
[[nodiscard]] virtual ClickHandlerPtr authorLink() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool hideServiceText() = 0;
|
||||
|
||||
|
@ -123,6 +129,7 @@ private:
|
|||
|
||||
const int _maxWidth = 0;
|
||||
Ui::Text::String _title;
|
||||
Ui::Text::String _author;
|
||||
Ui::Text::String _subtitle;
|
||||
const QSize _size;
|
||||
const QSize _innerSize;
|
||||
|
|
|
@ -81,6 +81,95 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class TextBubblePart final : public MediaGenericTextPart {
|
||||
public:
|
||||
TextBubblePart(
|
||||
TextWithEntities text,
|
||||
QMargins margins,
|
||||
Data::UniqueGiftBackdrop backdrop,
|
||||
ClickHandlerPtr link);
|
||||
|
||||
void draw(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context,
|
||||
int outerWidth) const override;
|
||||
TextState textState(
|
||||
QPoint point,
|
||||
StateRequest request,
|
||||
int outerWidth) const override;
|
||||
|
||||
private:
|
||||
void setupPen(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context) const override;
|
||||
int elisionLines() const override;
|
||||
|
||||
Data::UniqueGiftBackdrop _backdrop;
|
||||
ClickHandlerPtr _link;
|
||||
|
||||
};
|
||||
|
||||
TextBubblePart::TextBubblePart(
|
||||
TextWithEntities text,
|
||||
QMargins margins,
|
||||
Data::UniqueGiftBackdrop backdrop,
|
||||
ClickHandlerPtr link)
|
||||
: MediaGenericTextPart(
|
||||
std::move(text),
|
||||
margins,
|
||||
st::defaultTextStyle,
|
||||
{},
|
||||
{},
|
||||
style::al_top)
|
||||
, _backdrop(backdrop)
|
||||
, _link(std::move(link)) {
|
||||
}
|
||||
|
||||
void TextBubblePart::draw(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context,
|
||||
int outerWidth) const {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setOpacity(0.5);
|
||||
p.setBrush(_backdrop.patternColor);
|
||||
const auto radius = height() / 2.;
|
||||
const auto left = (outerWidth - width()) / 2;
|
||||
const auto r = QRect(left, 0, width(), height());
|
||||
p.drawRoundedRect(r, radius, radius);
|
||||
p.setOpacity(1.);
|
||||
|
||||
MediaGenericTextPart::draw(p, owner, context, outerWidth);
|
||||
}
|
||||
|
||||
TextState TextBubblePart::textState(
|
||||
QPoint point,
|
||||
StateRequest request,
|
||||
int outerWidth) const {
|
||||
auto result = TextState();
|
||||
const auto left = (outerWidth - width()) / 2;
|
||||
if (point.x() >= left
|
||||
&& point.y() >= 0
|
||||
&& point.x() < left + width()
|
||||
&& point.y() < height()) {
|
||||
result.link = _link;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextBubblePart::setupPen(
|
||||
Painter &p,
|
||||
not_null<const MediaGeneric*> owner,
|
||||
const PaintContext &context) const {
|
||||
p.setPen(_backdrop.textColor);
|
||||
}
|
||||
|
||||
int TextBubblePart::elisionLines() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ButtonPart::ButtonPart(
|
||||
const QString &text,
|
||||
QMargins margins,
|
||||
|
@ -284,6 +373,21 @@ auto GenerateUniqueGiftMedia(
|
|||
gift->backdrop.textColor,
|
||||
st::chatUniqueTextPadding);
|
||||
|
||||
if (const auto by = gift->releasedBy) {
|
||||
const auto handler = std::make_shared<LambdaClickHandler>([=] {
|
||||
Ui::GiftReleasedByHandler(by);
|
||||
});
|
||||
push(std::make_unique<TextBubblePart>(
|
||||
tr::lng_gift_released_by(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Link('@' + by->username()),
|
||||
Ui::Text::WithEntities),
|
||||
st::giftBoxReleasedByMargin,
|
||||
gift->backdrop,
|
||||
handler));
|
||||
}
|
||||
|
||||
const auto name = [](const Data::UniqueGiftAttribute &value) {
|
||||
return Ui::Text::Bold(value.name);
|
||||
};
|
||||
|
|
|
@ -1890,11 +1890,11 @@ starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true
|
|||
|
||||
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
|
||||
|
||||
starGift#c62aca28 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string = StarGift;
|
||||
starGiftUnique#6411db89 flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long = StarGift;
|
||||
starGift#7f853c12 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer = StarGift;
|
||||
starGiftUnique#f63778ae flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift;
|
||||
|
||||
payments.starGiftsNotModified#a388a368 = payments.StarGifts;
|
||||
payments.starGifts#901689ea hash:int gifts:Vector<StarGift> = payments.StarGifts;
|
||||
payments.starGifts#2ed82995 hash:int gifts:Vector<StarGift> chats:Vector<Chat> users:Vector<User> = payments.StarGifts;
|
||||
|
||||
messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption;
|
||||
|
||||
|
@ -2720,4 +2720,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;
|
|||
|
||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
||||
|
||||
// LAYER 206
|
||||
// LAYER 207
|
||||
|
|
|
@ -1388,9 +1388,10 @@ void SessionPrivate::handleReceived() {
|
|||
auto sfrom = decryptedInts + 4U; // msg_id + seq_no + length + message
|
||||
MTP_LOG(_shiftedDcId, ("Recv: ")
|
||||
+ DumpToText(sfrom, end)
|
||||
+ QString(" (dc:%1,key:%2)"
|
||||
+ QString(" (dc:%1,key:%2,session:%3)"
|
||||
).arg(AbstractConnection::ProtocolDcDebugId(getProtocolDcId())
|
||||
).arg(_encryptionKey->keyId()));
|
||||
).arg(_encryptionKey->keyId()
|
||||
).arg(_sessionId));
|
||||
|
||||
const auto registered = _receivedMessageIds.registerMsgId(
|
||||
msgId,
|
||||
|
@ -2663,9 +2664,10 @@ bool SessionPrivate::sendSecureRequest(
|
|||
auto from = request->constData() + 4;
|
||||
MTP_LOG(_shiftedDcId, ("Send: ")
|
||||
+ DumpToText(from, from + messageSize)
|
||||
+ QString(" (dc:%1,key:%2)"
|
||||
+ QString(" (dc:%1,key:%2,session:%3)"
|
||||
).arg(AbstractConnection::ProtocolDcDebugId(getProtocolDcId())
|
||||
).arg(_encryptionKey->keyId()));
|
||||
).arg(_encryptionKey->keyId()
|
||||
).arg(_sessionId));
|
||||
|
||||
uchar encryptedSHA256[32];
|
||||
MTPint128 &msgKey(*(MTPint128*)(encryptedSHA256 + 8));
|
||||
|
|
|
@ -1434,7 +1434,23 @@ void GenericCreditsEntryBox(
|
|||
|
||||
Ui::AddSkip(content);
|
||||
}
|
||||
if (!isStarGift || creditsHistoryStarGift || e.soldOutInfo) {
|
||||
if (e.bareGiftReleasedById && !e.uniqueGift) {
|
||||
const auto peer = owner->peer(PeerId(e.bareGiftReleasedById));
|
||||
const auto released = content->add(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
tr::lng_credits_box_history_entry_gift_released(
|
||||
lt_name,
|
||||
rpl::single(Ui::Text::Link('@' + peer->username())),
|
||||
Ui::Text::WithEntities),
|
||||
st::creditsReleasedByLabel)));
|
||||
released->entity()->setClickHandlerFilter([=](const auto &...) {
|
||||
Ui::GiftReleasedByHandler(peer);
|
||||
return false;
|
||||
});
|
||||
} else if (!isStarGift || creditsHistoryStarGift || e.soldOutInfo) {
|
||||
constexpr auto kMinus = QChar(0x2212);
|
||||
auto &lifetime = content->lifetime();
|
||||
const auto text = lifetime.make_state<Ui::Text::String>();
|
||||
|
@ -2282,6 +2298,9 @@ void StarGiftViewBox(
|
|||
.bareGiftOwnerId = (data.unique
|
||||
? data.unique->ownerId.value
|
||||
: toId.value),
|
||||
.bareGiftReleasedById = (data.stargiftReleasedBy
|
||||
? data.stargiftReleasedBy->id.value
|
||||
: 0),
|
||||
.bareActorId = (toChannel ? data.channelFrom->id.value : 0),
|
||||
.bareEntryOwnerId = (toChannel ? data.channel->id.value : 0),
|
||||
.giftChannelSavedId = data.channelSavedId,
|
||||
|
|
|
@ -936,6 +936,7 @@ msgServiceGiftBoxTitlePadding: margins(0px, 20px, 0px, 6px);
|
|||
msgServiceGiftBoxStickerTop: -19px;
|
||||
msgServiceGiftBoxStickerSize: 140px;
|
||||
msgServiceStarGiftBoxWidth: 224px;
|
||||
msgServiceStarGiftByWidth: 272px;
|
||||
msgServiceStarGiftStickerTop: 24px;
|
||||
msgServiceStarGiftStickerSize: 100px;
|
||||
|
||||
|
@ -1105,6 +1106,7 @@ chatIntroWidth: 224px;
|
|||
chatIntroTitleMargin: margins(11px, 16px, 11px, 4px);
|
||||
chatIntroMargin: margins(11px, 0px, 11px, 0px);
|
||||
chatIntroStickerPadding: margins(10px, 8px, 10px, 16px);
|
||||
chatGiftPreviewWidth: 264px;
|
||||
|
||||
liveLocationLongInIcon: icon {{ "chat/live_location_long", msgInServiceFg }};
|
||||
liveLocationLongInIconSelected: icon {{ "chat/live_location_long", msgInServiceFgSelected }};
|
||||
|
|
|
@ -66,6 +66,9 @@ creditsBoxAboutDivider: FlatLabel(boxDividerLabel) {
|
|||
creditsBoxButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||
style: semiboldTextStyle;
|
||||
}
|
||||
creditsReleasedByLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
|
||||
starIconEmoji: IconEmoji {
|
||||
icon: icon{{ "payments/premium_emoji", creditsBg1 }};
|
||||
|
@ -175,6 +178,7 @@ giftBoxButtonBottomByStars: 18px;
|
|||
giftBoxButtonPadding: margins(8px, 4px, 8px, 4px);
|
||||
giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px);
|
||||
giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px);
|
||||
giftBoxReleasedByMargin: margins(12px, 2px, 12px, 2px);
|
||||
giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 4px);
|
||||
giftBoxButtonMargin: margins(12px, 8px, 12px, 12px);
|
||||
giftBoxStickerTop: 0px;
|
||||
|
|
|
@ -56,6 +56,7 @@ menuIconDiscussion: icon {{ "menu/discussion", menuIconColor }};
|
|||
menuIconStats: icon {{ "menu/stats", menuIconColor }};
|
||||
menuIconBoosts: icon {{ "menu/boosts", menuIconColor }};
|
||||
menuIconEarn: icon {{ "menu/earn", menuIconColor }};
|
||||
menuIconCancelFee: icon {{ "menu/cancel_fee", menuIconColor }};
|
||||
menuIconCreatePoll: icon {{ "menu/create_poll", menuIconColor }};
|
||||
menuIconCreateTodoList: icon {{ "menu/select", menuIconColor }};
|
||||
menuIconQrCode: icon {{ "menu/qr_code", menuIconColor }};
|
||||
|
|
|
@ -316,6 +316,14 @@ windowArchiveToast: Toast(defaultToast) {
|
|||
maxWidth: boxWideWidth;
|
||||
}
|
||||
|
||||
windowFeeItem: Menu(defaultMenu) {
|
||||
itemPadding: margins(17px, 3px, 17px, 4px);
|
||||
itemRightSkip: 0px;
|
||||
itemStyle: whenReadStyle;
|
||||
itemFgOver: windowFg;
|
||||
itemFgDisabled: windowFg;
|
||||
}
|
||||
|
||||
ivWidthMin: 380px;
|
||||
ivHeightMin: 480px;
|
||||
ivWidthDefault: 600px;
|
||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/random.h"
|
||||
#include "base/options.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "base/qt/qt_key_modifiers.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/max_invite_box.h"
|
||||
|
@ -83,6 +84,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/stories/info_stories_widget.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_folder.h"
|
||||
|
@ -98,10 +100,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_chat_filters.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "core/application.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "export/export_manager.h"
|
||||
#include "boxes/peers/edit_peer_info_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_credits.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_window.h" // st::windowMinWidth
|
||||
|
@ -282,6 +286,7 @@ private:
|
|||
void fillArchiveActions();
|
||||
void fillSavedSublistActions();
|
||||
void fillContextMenuActions();
|
||||
void fillMonoforumPeerActions();
|
||||
|
||||
void addHidePromotion();
|
||||
void addTogglePin();
|
||||
|
@ -326,6 +331,7 @@ private:
|
|||
void addVideoChat();
|
||||
void addViewStatistics();
|
||||
void addBoostChat();
|
||||
void addToggleFee();
|
||||
|
||||
[[nodiscard]] bool skipCreateActions() const;
|
||||
|
||||
|
@ -1365,6 +1371,7 @@ void Filler::fill() {
|
|||
case Section::Scheduled: fillScheduledActions(); break;
|
||||
case Section::ContextMenu:
|
||||
case Section::SubsectionTabsMenu: fillContextMenuActions(); break;
|
||||
case Section::SavedSublist: fillMonoforumPeerActions(); break;
|
||||
default: Unexpected("_request.section in Filler::fill.");
|
||||
}
|
||||
}
|
||||
|
@ -1660,6 +1667,68 @@ void Filler::fillSavedSublistActions() {
|
|||
addTogglePin();
|
||||
}
|
||||
|
||||
void Filler::fillMonoforumPeerActions() {
|
||||
Expects(_sublist != nullptr);
|
||||
|
||||
addToggleFee();
|
||||
}
|
||||
|
||||
void Filler::addToggleFee() {
|
||||
const auto feeRemoved = _sublist->isFeeRemoved();
|
||||
const auto text = feeRemoved
|
||||
? tr::lng_context_charge_fee(tr::now)
|
||||
: tr::lng_context_remove_fee(tr::now);
|
||||
const auto navigation = _controller;
|
||||
const auto parent = _sublist->parentChat();
|
||||
const auto user = _sublist->sublistPeer()->asUser();
|
||||
if (!parent || !user) {
|
||||
return;
|
||||
}
|
||||
const auto paidAmount = std::make_shared<rpl::variable<int>>();
|
||||
_addAction(text, [=] {
|
||||
const auto removeFee = !feeRemoved;
|
||||
PeerMenuConfirmToggleFee(
|
||||
navigation,
|
||||
paidAmount,
|
||||
parent,
|
||||
user,
|
||||
removeFee);
|
||||
}, feeRemoved ? &st::menuIconEarn : &st::menuIconCancelFee);
|
||||
_addAction({ .isSeparator = true });
|
||||
_addAction({ .make = [=](not_null<Ui::RpWidget*> actionParent) {
|
||||
const auto text = feeRemoved
|
||||
? tr::lng_context_fee_free(
|
||||
tr::now,
|
||||
lt_name,
|
||||
TextWithEntities{ user->shortName() },
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_context_fee_now(
|
||||
tr::now,
|
||||
lt_name,
|
||||
TextWithEntities{ user->shortName() },
|
||||
lt_amount,
|
||||
user->owner().customEmojiManager().ministarEmoji(
|
||||
{ 0, st::giftBoxByStarsStarTop, 0, 0 }
|
||||
).append(Lang::FormatCountDecimal(
|
||||
user->owner().commonStarsPerMessage(parent)
|
||||
)),
|
||||
Ui::Text::WithEntities);
|
||||
const auto action = new QAction(actionParent);
|
||||
action->setDisabled(true);
|
||||
auto result = base::make_unique_q<Ui::Menu::Action>(
|
||||
actionParent,
|
||||
st::windowFeeItem,
|
||||
action,
|
||||
nullptr,
|
||||
nullptr);
|
||||
result->setMarkedText(
|
||||
text,
|
||||
QString(),
|
||||
Core::TextContext({ .session = &user->session() }));
|
||||
return result;
|
||||
} });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void PeerMenuExportChat(
|
||||
|
@ -3752,4 +3821,81 @@ bool CanArchive(History *history, PeerData *peer) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void PeerMenuConfirmToggleFee(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
std::shared_ptr<rpl::variable<int>> paidAmount,
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
bool removeFee) {
|
||||
const auto parent = peer->isChannel() ? peer->asChannel() : nullptr;
|
||||
const auto exception = [=](bool refund) {
|
||||
using Flag = MTPaccount_ToggleNoPaidMessagesException::Flag;
|
||||
const auto api = &user->session().api();
|
||||
api->request(MTPaccount_ToggleNoPaidMessagesException(
|
||||
MTP_flags((refund ? Flag::f_refund_charged : Flag())
|
||||
| (removeFee ? Flag() : Flag::f_require_payment)
|
||||
| (parent ? Flag::f_parent_peer : Flag())),
|
||||
parent->input,
|
||||
user->inputUser
|
||||
)).done([=] {
|
||||
if (!parent) {
|
||||
user->clearPaysPerMessage();
|
||||
} else if (const auto monoforum = peer->monoforum()) {
|
||||
if (const auto sublist = monoforum->sublistLoaded(user)) {
|
||||
sublist->toggleFeeRemoved(removeFee);
|
||||
}
|
||||
}
|
||||
}).send();
|
||||
};
|
||||
if (!removeFee) {
|
||||
exception(false);
|
||||
return;
|
||||
}
|
||||
navigation->uiShow()->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto refund = std::make_shared<QPointer<Ui::Checkbox>>();
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = tr::lng_payment_refund_text(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities),
|
||||
.confirmed = [=](Fn<void()> close) {
|
||||
exception(*refund && (*refund)->checked());
|
||||
close();
|
||||
},
|
||||
.confirmText = tr::lng_payment_refund_confirm(tr::now),
|
||||
.title = tr::lng_payment_refund_title(tr::now),
|
||||
});
|
||||
const auto paid = box->lifetime().make_state<
|
||||
rpl::variable<int>
|
||||
>();
|
||||
*paid = paidAmount->value();
|
||||
paid->value() | rpl::start_with_next([=](int already) {
|
||||
if (!already) {
|
||||
delete base::take(*refund);
|
||||
} else if (!*refund) {
|
||||
const auto skip = st::defaultCheckbox.margin.top();
|
||||
*refund = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box,
|
||||
tr::lng_payment_refund_also(
|
||||
lt_count,
|
||||
paid->value() | tr::to_count()),
|
||||
false,
|
||||
st::defaultCheckbox),
|
||||
st::boxRowPadding + QMargins(0, skip, 0, skip));
|
||||
}
|
||||
}, box->lifetime());
|
||||
|
||||
using Flag = MTPaccount_GetPaidMessagesRevenue::Flag;
|
||||
user->session().api().request(MTPaccount_GetPaidMessagesRevenue(
|
||||
MTP_flags(parent ? Flag::f_parent_peer : Flag()),
|
||||
parent ? parent->input : MTPInputPeer(),
|
||||
user->inputUser
|
||||
)).done([=](const MTPaccount_PaidMessagesRevenue &result) {
|
||||
*paidAmount = result.data().vstars_amount().v;
|
||||
}).send();
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace Window
|
||||
|
|
|
@ -253,4 +253,11 @@ void AddSeparatorAndShiftUp(const PeerMenuCallback &addAction);
|
|||
[[nodiscard]] bool IsArchived(not_null<History*> history);
|
||||
[[nodiscard]] bool CanArchive(History *history, PeerData *peer);
|
||||
|
||||
void PeerMenuConfirmToggleFee(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
std::shared_ptr<rpl::variable<int>> paidAmount,
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
bool removeFee);
|
||||
|
||||
} // namespace Window
|
||||
|
|
|
@ -760,7 +760,6 @@ RUN git clone -b v$QT --depth=1 https://github.com/qt/qt5.git \
|
|||
&& cmake -B build . \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DQT_GENERATE_SBOM=OFF \
|
||||
-DQT_QPA_PLATFORMS="wayland;xcb" \
|
||||
-DINPUT_libpng=qt \
|
||||
-DINPUT_harfbuzz=qt \
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
AppVersion 5016002
|
||||
AppVersion 5016003
|
||||
AppVersionStrMajor 5.16
|
||||
AppVersionStrSmall 5.16.2
|
||||
AppVersionStr 5.16.2
|
||||
AppVersionStrSmall 5.16.3
|
||||
AppVersionStr 5.16.3
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 5.16.2
|
||||
AppVersionOriginal 5.16.3
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
5.16.3 (08.07.25)
|
||||
|
||||
- Allow removing / charging fee in channel direct messages.
|
||||
- Don't offer creating checklists in channels.
|
||||
- Support author channel in gifts.
|
||||
|
||||
5.16.2 (04.07.25)
|
||||
|
||||
- Fix crash in some checklists.
|
||||
|
|
Loading…
Add table
Reference in a new issue