Update API scheme. Giveaway winners.

This commit is contained in:
John Preston 2023-12-13 08:14:41 +00:00
parent 62f9f3c94b
commit 4b9648d8d9
21 changed files with 552 additions and 156 deletions

Binary file not shown.

View file

@ -2246,6 +2246,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_prizes_cancelled" = "The channel cancelled the prizes by reversing the payment for them.";
"lng_prizes_badge" = "x{amount}";
"lng_prizes_results_title" = "Winners Selected!";
"lng_prizes_results_about#one" = "**{count}** winner of the {link} was randomly selected by Telegram.";
"lng_prizes_results_about#other" = "**{count}** winners of the {link} were randomly selected by Telegram.";
"lng_prizes_results_link" = "Giveaway";
"lng_prizes_results_winners" = "Winners";
"lng_prizes_results_more#one" = "and {count} more!";
"lng_prizes_results_more#other" = "and {count} more!";
"lng_prizes_results_all" = "All winners received gift links in private messages.";
"lng_prizes_results_some" = "Some winners couldn't be selected.";
"lng_gift_link_title" = "Gift Link";
"lng_gift_link_about" = "This link allows you to activate\na **Telegram Premium** subscription.";
"lng_gift_link_label_from" = "From";
@ -3629,6 +3639,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_set_background_emoji" = "{from} set channel background emoji to {emoji}";
"lng_admin_log_change_background_emoji" = "{from} changed channel background emoji from {previous} to {emoji}";
"lng_admin_log_removed_background_emoji" = "{from} removed channel background emoji {emoji}";
"lng_admin_log_change_profile_color" = "{from} changed channel profile color from {previous} to {color}";
"lng_admin_log_set_profile_background_emoji" = "{from} set channel profile background emoji to {emoji}";
"lng_admin_log_change_profile_background_emoji" = "{from} changed channel profile background emoji from {previous} to {emoji}";
"lng_admin_log_removed_profile_background_emoji" = "{from} removed channel profile background emoji {emoji}";
"lng_admin_log_change_wallpaper" = "{from} changed channel wallpaper";
"lng_admin_log_user_with_username" = "{name} ({mention})";
"lng_admin_log_messages_ttl_set" = "{from} enabled messages auto-delete after {duration}";
"lng_admin_log_messages_ttl_changed" = "{from} changed messages auto-delete period from {previous} to {duration}";

View file

@ -15,6 +15,7 @@
<file alias="art/slot_2_idle.tgs">../../art/slot_2_idle.tgs</file>
<file alias="art/slot_back.tgs">../../art/slot_back.tgs</file>
<file alias="art/slot_pull.tgs">../../art/slot_pull.tgs</file>
<file alias="art/winners.tgs">../../art/winners.tgs</file>
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>

View file

@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_boosts.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
#include "data/data_media_types.h" // Data::Giveaway
#include "data/data_media_types.h" // Data::GiveawayStart.
#include "data/data_peer_values.h" // Data::PeerPremiumValue.
#include "data/data_session.h"
#include "data/data_subscription_option.h"
@ -739,8 +739,11 @@ void ResolveGiftCode(
void GiveawayInfoBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionNavigation*> controller,
Data::Giveaway giveaway,
std::optional<Data::GiveawayStart> start,
std::optional<Data::GiveawayResults> results,
Api::GiveawayInfo info) {
Expects(start || results);
using State = Api::GiveawayState;
const auto finished = (info.state == State::Finished)
|| (info.state == State::Refunded);
@ -749,8 +752,10 @@ void GiveawayInfoBox(
? tr::lng_prizes_end_title
: tr::lng_prizes_how_title)());
const auto first = !giveaway.channels.empty()
? giveaway.channels.front()->name()
const auto first = results
? results->channel->name()
: !start->channels.empty()
? start->channels.front()->name()
: u"channel"_q;
auto text = TextWithEntities();
@ -767,6 +772,10 @@ void GiveawayInfoBox(
text.append("\n\n");
}
const auto quantity = start
? start->quantity
: (results->winnersCount + results->unclaimedCount);
const auto months = start ? start->months : results->months;
text.append((finished
? tr::lng_prizes_end_text
: tr::lng_prizes_how_text)(
@ -775,18 +784,21 @@ void GiveawayInfoBox(
tr::lng_prizes_admins(
tr::now,
lt_count,
giveaway.quantity,
quantity,
lt_channel,
Ui::Text::Bold(first),
lt_duration,
TextWithEntities{ GiftDuration(giveaway.months) },
TextWithEntities{ GiftDuration(months) },
Ui::Text::RichLangValue),
Ui::Text::RichLangValue));
const auto many = (giveaway.channels.size() > 1);
const auto many = start
? (start->channels.size() > 1)
: (results->additionalPeersCount > 0);
const auto count = info.winnersCount
? info.winnersCount
: giveaway.quantity;
auto winners = giveaway.all
: quantity;
const auto all = start ? start->all : results->all;
auto winners = all
? (many
? tr::lng_prizes_winners_all_of_many
: tr::lng_prizes_winners_all_of_one)(
@ -808,7 +820,10 @@ void GiveawayInfoBox(
Ui::Text::Bold(
langDateTime(base::unixtime::parse(info.startDate))),
Ui::Text::RichLangValue);
if (!giveaway.additionalPrize.isEmpty()) {
const auto additionalPrize = results
? results->additionalPrize
: start->additionalPrize;
if (!additionalPrize.isEmpty()) {
text.append("\n\n").append(tr::lng_prizes_additional_added(
tr::now,
lt_count,
@ -816,16 +831,19 @@ void GiveawayInfoBox(
lt_channel,
Ui::Text::Bold(first),
lt_prize,
TextWithEntities{ giveaway.additionalPrize },
TextWithEntities{ additionalPrize },
Ui::Text::RichLangValue));
}
const auto untilDate = start
? start->untilDate
: results->untilDate;
text.append("\n\n").append((finished
? tr::lng_prizes_end_when_finish
: tr::lng_prizes_how_when_finish)(
tr::now,
lt_date,
Ui::Text::Bold(langDayOfMonthFull(
base::unixtime::parse(giveaway.untilDate).date())),
base::unixtime::parse(untilDate).date())),
lt_winners,
winners,
Ui::Text::RichLangValue));
@ -876,7 +894,7 @@ void GiveawayInfoBox(
Ui::Text::Bold(first),
lt_date,
Ui::Text::Bold(langDayOfMonthFull(
base::unixtime::parse(giveaway.untilDate).date())),
base::unixtime::parse(untilDate).date())),
Ui::Text::RichLangValue));
}
}
@ -920,14 +938,15 @@ void ResolveGiveawayInfo(
not_null<Window::SessionNavigation*> controller,
not_null<PeerData*> peer,
MsgId messageId,
Data::Giveaway giveaway) {
std::optional<Data::GiveawayStart> start,
std::optional<Data::GiveawayResults> results) {
const auto show = [=](Api::GiveawayInfo info) {
if (!info) {
controller->showToast(
tr::lng_confirm_phone_link_invalid(tr::now));
} else {
controller->uiShow()->showBox(
Box(GiveawayInfoBox, controller, giveaway, info));
Box(GiveawayInfoBox, controller, start, results, info));
}
};
controller->session().api().premium().resolveGiveawayInfo(

View file

@ -16,7 +16,8 @@ struct GiftCode;
} // namespace Api
namespace Data {
struct Giveaway;
struct GiveawayStart;
struct GiveawayResults;
} // namespace Data
namespace Ui {
@ -62,4 +63,5 @@ void ResolveGiveawayInfo(
not_null<Window::SessionNavigation*> controller,
not_null<PeerData*> peer,
MsgId messageId,
Data::Giveaway giveaway);
std::optional<Data::GiveawayStart> start,
std::optional<Data::GiveawayResults> results);

View file

@ -26,6 +26,7 @@ const QString DicePacks::kDartString = QString::fromUtf8("\xF0\x9F\x8E\xAF");
const QString DicePacks::kSlotString = QString::fromUtf8("\xF0\x9F\x8E\xB0");
const QString DicePacks::kFballString = QString::fromUtf8("\xE2\x9A\xBD");
const QString DicePacks::kBballString = QString::fromUtf8("\xF0\x9F\x8F\x80");
const QString DicePacks::kPartyPopper = QString::fromUtf8("\xf0\x9f\x8e\x89");
DicePack::DicePack(not_null<Main::Session*> session, const QString &emoji)
: _session(session)
@ -35,7 +36,7 @@ DicePack::DicePack(not_null<Main::Session*> session, const QString &emoji)
DicePack::~DicePack() = default;
DocumentData *DicePack::lookup(int value) {
if (!_requestId) {
if (!_requestId && _emoji != DicePacks::kPartyPopper) {
load();
}
tryGenerateLocalZero();
@ -117,6 +118,8 @@ void DicePack::tryGenerateLocalZero() {
generateLocal(8, u"slot_0_idle"_q);
generateLocal(14, u"slot_1_idle"_q);
generateLocal(20, u"slot_2_idle"_q);
} else if (_emoji == DicePacks::kPartyPopper) {
generateLocal(0, u"winners"_q);
}
}

View file

@ -44,6 +44,7 @@ public:
static const QString kSlotString;
static const QString kFballString;
static const QString kBballString;
static const QString kPartyPopper;
[[nodiscard]] static bool IsSlot(const QString &emoji) {
return (emoji == kSlotString);

View file

@ -61,6 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_origin.h"
#include "data/data_stories.h"
#include "data/data_story.h"
#include "data/data_user.h"
#include "main/main_session.h"
#include "main/main_session_settings.h"
#include "core/application.h"
@ -363,10 +364,10 @@ Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
return result;
}
Giveaway ComputeGiveawayData(
GiveawayStart ComputeGiveawayStartData(
not_null<HistoryItem*> item,
const MTPDmessageMediaGiveaway &data) {
auto result = Giveaway{
auto result = GiveawayStart{
.untilDate = data.vuntil_date().v,
.quantity = data.vquantity().v,
.months = data.vmonths().v,
@ -389,6 +390,32 @@ Giveaway ComputeGiveawayData(
return result;
}
GiveawayResults ComputeGiveawayResultsData(
not_null<HistoryItem*> item,
const MTPDmessageMediaGiveawayResults &data) {
const auto additional = data.vadditional_peers_count();
auto result = GiveawayResults{
.channel = item->history()->owner().channel(data.vchannel_id()),
.untilDate = data.vuntil_date().v,
.launchId = data.vlaunch_msg_id().v,
.additionalPeersCount = additional.value_or_empty(),
.winnersCount = data.vwinners_count().v,
.unclaimedCount = data.vunclaimed_count().v,
.months = data.vmonths().v,
.refunded = data.is_refunded(),
.all = !data.is_only_new_subscribers(),
};
result.winners.reserve(data.vwinners().v.size());
const auto owner = &item->history()->owner();
for (const auto &id : data.vwinners().v) {
result.winners.push_back(owner->user(UserId(id)));
}
if (const auto additional = data.vprize_description()) {
result.additionalPrize = qs(*additional);
}
return result;
}
Media::Media(not_null<HistoryItem*> parent) : _parent(parent) {
}
@ -456,7 +483,11 @@ bool Media::storyMention() const {
return false;
}
const Giveaway *Media::giveaway() const {
const GiveawayStart *Media::giveawayStart() const {
return nullptr;
}
const GiveawayResults *Media::giveawayResults() const {
return nullptr;
}
@ -2241,53 +2272,103 @@ std::unique_ptr<HistoryView::Media> MediaStory::createView(
}
}
MediaGiveaway::MediaGiveaway(
MediaGiveawayStart::MediaGiveawayStart(
not_null<HistoryItem*> parent,
const Giveaway &data)
const GiveawayStart &data)
: Media(parent)
, _giveaway(data) {
, _data(data) {
parent->history()->session().giftBoxStickersPacks().load();
}
std::unique_ptr<Media> MediaGiveaway::clone(not_null<HistoryItem*> parent) {
return std::make_unique<MediaGiveaway>(parent, _giveaway);
std::unique_ptr<Media> MediaGiveawayStart::clone(
not_null<HistoryItem*> parent) {
return std::make_unique<MediaGiveawayStart>(parent, _data);
}
const Giveaway *MediaGiveaway::giveaway() const {
return &_giveaway;
const GiveawayStart *MediaGiveawayStart::giveawayStart() const {
return &_data;
}
TextWithEntities MediaGiveaway::notificationText() const {
TextWithEntities MediaGiveawayStart::notificationText() const {
return {
.text = tr::lng_prizes_title(tr::now, lt_count, _giveaway.quantity),
.text = tr::lng_prizes_title(tr::now, lt_count, _data.quantity),
};
}
QString MediaGiveaway::pinnedTextSubstring() const {
QString MediaGiveawayStart::pinnedTextSubstring() const {
return QString::fromUtf8("\xC2\xAB")
+ notificationText().text
+ QString::fromUtf8("\xC2\xBB");
}
TextForMimeData MediaGiveaway::clipboardText() const {
TextForMimeData MediaGiveawayStart::clipboardText() const {
return TextForMimeData();
}
bool MediaGiveaway::updateInlineResultMedia(const MTPMessageMedia &media) {
bool MediaGiveawayStart::updateInlineResultMedia(const MTPMessageMedia &media) {
return true;
}
bool MediaGiveaway::updateSentMedia(const MTPMessageMedia &media) {
bool MediaGiveawayStart::updateSentMedia(const MTPMessageMedia &media) {
return true;
}
std::unique_ptr<HistoryView::Media> MediaGiveaway::createView(
std::unique_ptr<HistoryView::Media> MediaGiveawayStart::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::MediaInBubble>(
message,
HistoryView::GenerateGiveawayStart(message, &_giveaway));
HistoryView::GenerateGiveawayStart(message, &_data));
}
MediaGiveawayResults::MediaGiveawayResults(
not_null<HistoryItem*> parent,
const GiveawayResults &data)
: Media(parent)
, _data(data) {
}
std::unique_ptr<Media> MediaGiveawayResults::clone(
not_null<HistoryItem*> parent) {
return std::make_unique<MediaGiveawayResults>(parent, _data);
}
const GiveawayResults *MediaGiveawayResults::giveawayResults() const {
return &_data;
}
TextWithEntities MediaGiveawayResults::notificationText() const {
return {
.text = tr::lng_prizes_results_title(tr::now),
};
}
QString MediaGiveawayResults::pinnedTextSubstring() const {
return QString::fromUtf8("\xC2\xAB")
+ notificationText().text
+ QString::fromUtf8("\xC2\xBB");
}
TextForMimeData MediaGiveawayResults::clipboardText() const {
return TextForMimeData();
}
bool MediaGiveawayResults::updateInlineResultMedia(const MTPMessageMedia &media) {
return true;
}
bool MediaGiveawayResults::updateSentMedia(const MTPMessageMedia &media) {
return true;
}
std::unique_ptr<HistoryView::Media> MediaGiveawayResults::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::MediaInBubble>(
message,
HistoryView::GenerateGiveawayResults(message, &_data));
}
} // namespace Data

View file

@ -90,7 +90,7 @@ struct Invoice {
bool isTest = false;
};
struct Giveaway {
struct GiveawayStart {
std::vector<not_null<ChannelData*>> channels;
std::vector<QString> countries;
QString additionalPrize;
@ -100,6 +100,20 @@ struct Giveaway {
bool all = false;
};
struct GiveawayResults {
not_null<ChannelData*> channel;
std::vector<not_null<PeerData*>> winners;
QString additionalPrize;
TimeId untilDate = 0;
MsgId launchId = 0;
int additionalPeersCount = 0;
int winnersCount = 0;
int unclaimedCount = 0;
int months = 0;
bool refunded = false;
bool all = false;
};
struct GiftCode {
QString slug;
ChannelData *channel = nullptr;
@ -136,7 +150,8 @@ public:
virtual FullStoryId storyId() const;
virtual bool storyExpired(bool revalidate = false);
virtual bool storyMention() const;
virtual const Giveaway *giveaway() const;
virtual const GiveawayStart *giveawayStart() const;
virtual const GiveawayResults *giveawayResults() const;
virtual bool uploading() const;
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const;
@ -635,15 +650,15 @@ private:
};
class MediaGiveaway final : public Media {
class MediaGiveawayStart final : public Media {
public:
MediaGiveaway(
MediaGiveawayStart(
not_null<HistoryItem*> parent,
const Giveaway &data);
const GiveawayStart &data);
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
const Giveaway *giveaway() const override;
const GiveawayStart *giveawayStart() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
@ -657,7 +672,33 @@ public:
HistoryView::Element *replacing = nullptr) override;
private:
Giveaway _giveaway;
GiveawayStart _data;
};
class MediaGiveawayResults final : public Media {
public:
MediaGiveawayResults(
not_null<HistoryItem*> parent,
const GiveawayResults &data);
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
const GiveawayResults *giveawayResults() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
GiveawayResults _data;
};
@ -671,8 +712,12 @@ private:
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call);
[[nodiscard]] Giveaway ComputeGiveawayData(
[[nodiscard]] GiveawayStart ComputeGiveawayStartData(
not_null<HistoryItem*> item,
const MTPDmessageMediaGiveaway &data);
[[nodiscard]] GiveawayResults ComputeGiveawayResultsData(
not_null<HistoryItem*> item,
const MTPDmessageMediaGiveawayResults &data);
} // namespace Data

View file

@ -681,8 +681,8 @@ Poll ParsePoll(const MTPDmessageMediaPoll &data) {
return result;
}
Giveaway ParseGiveaway(const MTPDmessageMediaGiveaway &data) {
auto result = Giveaway{
GiveawayStart ParseGiveaway(const MTPDmessageMediaGiveaway &data) {
auto result = GiveawayStart{
.untilDate = data.vuntil_date().v,
.quantity = data.vquantity().v,
.months = data.vmonths().v,

View file

@ -197,7 +197,7 @@ struct Poll {
bool closed = false;
};
struct Giveaway {
struct GiveawayStart {
std::vector<ChannelId> channels;
TimeId untilDate = 0;
int quantity = 0;
@ -336,7 +336,7 @@ struct Media {
Game,
Invoice,
Poll,
Giveaway,
GiveawayStart,
UnsupportedMedia> content;
TimeId ttl = 0;

View file

@ -613,7 +613,7 @@ private:
[[nodiscard]] QByteArray pushPoll(const Data::Poll &data);
[[nodiscard]] QByteArray pushGiveaway(
const PeersMap &peers,
const Data::Giveaway &data);
const Data::GiveawayStart &data);
File _file;
QByteArray _composedStart;
@ -1501,7 +1501,7 @@ QByteArray HtmlWriter::Wrap::pushMedia(
return pushPhotoMedia(*photo, basePath);
} else if (const auto poll = std::get_if<Poll>(&content)) {
return pushPoll(*poll);
} else if (const auto giveaway = std::get_if<Giveaway>(&content)) {
} else if (const auto giveaway = std::get_if<GiveawayStart>(&content)) {
return pushGiveaway(peers, *giveaway);
}
Assert(v::is_null(content));
@ -1826,7 +1826,7 @@ QByteArray HtmlWriter::Wrap::pushPoll(const Data::Poll &data) {
QByteArray HtmlWriter::Wrap::pushGiveaway(
const PeersMap &peers,
const Data::Giveaway &data) {
const Data::GiveawayStart &data) {
auto result = pushDiv("media_wrap clearfix");
result.append(pushDiv("media_giveaway"));
@ -2028,7 +2028,7 @@ MediaData HtmlWriter::Wrap::prepareMediaData(
result.description = data.description;
result.status = Data::FormatMoneyAmount(data.amount, data.currency);
}, [](const Poll &data) {
}, [](const Giveaway &data) {
}, [](const GiveawayStart &data) {
}, [](const UnsupportedMedia &data) {
Unexpected("Unsupported message.");
}, [](v::null_t) {});

View file

@ -753,7 +753,7 @@ QByteArray SerializeMessage(
{ "total_voters", NumberToString(data.totalVotes) },
{ "answers", serialized }
}));
}, [&](const Giveaway &data) {
}, [&](const GiveawayStart &data) {
context.nesting.push_back(Context::kObject);
const auto channels = ranges::views::all(
data.channels

View file

@ -767,8 +767,9 @@ void GenerateItems(
using LogDeleteTopic = MTPDchannelAdminLogEventActionDeleteTopic;
using LogPinTopic = MTPDchannelAdminLogEventActionPinTopic;
using LogToggleAntiSpam = MTPDchannelAdminLogEventActionToggleAntiSpam;
using LogChangeColor = MTPDchannelAdminLogEventActionChangeColor;
using LogChangeBackgroundEmoji = MTPDchannelAdminLogEventActionChangeBackgroundEmoji;
using LogChangePeerColor = MTPDchannelAdminLogEventActionChangePeerColor;
using LogChangeProfilePeerColor = MTPDchannelAdminLogEventActionChangeProfilePeerColor;
using LogChangeWallpaper = MTPDchannelAdminLogEventActionChangeWallpaper;
const auto session = &history->session();
const auto id = event.vid().v;
@ -1817,52 +1818,94 @@ void GenerateItems(
addSimpleServiceMessage(text);
};
const auto createChangeColor = [&](const LogChangeColor &data) {
const auto text = tr::lng_admin_log_change_color(
tr::now,
lt_from,
fromLinkText,
lt_previous,
{ '#' + QString::number(data.vprev_value().v + 1) },
lt_color,
{ '#' + QString::number(data.vnew_value().v + 1) },
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createChangeBackgroundEmoji = [&](const LogChangeBackgroundEmoji &data) {
const auto was = data.vprev_value().v;
const auto now = data.vnew_value().v;
const auto text = !was
? tr::lng_admin_log_set_background_emoji(
tr::now,
lt_from,
fromLinkText,
lt_emoji,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(now)),
Ui::Text::WithEntities)
: !now
? tr::lng_admin_log_removed_background_emoji(
tr::now,
lt_from,
fromLinkText,
lt_emoji,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(was)),
Ui::Text::WithEntities)
: tr::lng_admin_log_change_background_emoji(
const auto createColorChange = [&](
const MTPPeerColor &was,
const MTPPeerColor &now,
const auto &colorPhrase,
const auto &setEmoji,
const auto &removeEmoji,
const auto &changeEmoji) {
const auto prevColor = was.data().vcolor();
const auto nextColor = now.data().vcolor();
if (prevColor != nextColor) {
const auto wrap = [&](tl::conditional<MTPint> value) {
return value
? value->v
: Data::DecideColorIndex(history->peer->id);
};
const auto text = colorPhrase(
tr::now,
lt_from,
fromLinkText,
lt_previous,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(was)),
lt_emoji,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(now)),
{ '#' + QString::number(wrap(prevColor) + 1) },
lt_color,
{ '#' + QString::number(wrap(nextColor) + 1) },
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
addSimpleServiceMessage(text);
}
const auto prevEmoji = was.data().vbackground_emoji_id().value_or_empty();
const auto nextEmoji = now.data().vbackground_emoji_id().value_or_empty();
if (prevEmoji != nextEmoji) {
const auto text = !prevEmoji
? setEmoji(
tr::now,
lt_from,
fromLinkText,
lt_emoji,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(nextEmoji)),
Ui::Text::WithEntities)
: !nextEmoji
? removeEmoji(
tr::now,
lt_from,
fromLinkText,
lt_emoji,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(prevEmoji)),
Ui::Text::WithEntities)
: changeEmoji(
tr::now,
lt_from,
fromLinkText,
lt_previous,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(prevEmoji)),
lt_emoji,
Ui::Text::SingleCustomEmoji(
Data::SerializeCustomEmojiId(nextEmoji)),
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
}
};
const auto createChangePeerColor = [&](const LogChangePeerColor &data) {
createColorChange(
data.vprev_value(),
data.vnew_value(),
tr::lng_admin_log_change_color,
tr::lng_admin_log_set_background_emoji,
tr::lng_admin_log_removed_background_emoji,
tr::lng_admin_log_change_background_emoji);
};
const auto createChangeProfilePeerColor = [&](const LogChangeProfilePeerColor &data) {
createColorChange(
data.vprev_value(),
data.vnew_value(),
tr::lng_admin_log_change_profile_color,
tr::lng_admin_log_set_profile_background_emoji,
tr::lng_admin_log_removed_profile_background_emoji,
tr::lng_admin_log_change_profile_background_emoji);
};
const auto createChangeWallpaper = [&](const LogChangeWallpaper &data) {
addSimpleServiceMessage(tr::lng_admin_log_change_wallpaper(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities));
};
action.match(
@ -1909,8 +1952,9 @@ void GenerateItems(
createDeleteTopic,
createPinTopic,
createToggleAntiSpam,
createChangeColor,
createChangeBackgroundEmoji);
createChangePeerColor,
createChangeProfilePeerColor,
createChangeWallpaper);
}
} // namespace AdminLog

View file

@ -311,13 +311,13 @@ std::unique_ptr<Data::Media> HistoryItem::CreateMedia(
media.vid().v,
}, media.is_via_mention());
}, [&](const MTPDmessageMediaGiveaway &media) -> Result {
return std::make_unique<Data::MediaGiveaway>(
return std::make_unique<Data::MediaGiveawayStart>(
item,
Data::ComputeGiveawayData(item, media));
Data::ComputeGiveawayStartData(item, media));
}, [&](const MTPDmessageMediaGiveawayResults &media) -> Result {
return nullptr;/* std::make_unique<Data::MediaGiveaway>(
return std::make_unique<Data::MediaGiveawayResults>(
item,
Data::ComputeGiveawayData(item, media));*/
Data::ComputeGiveawayResultsData(item, media));
}, [](const MTPDmessageMediaEmpty &) -> Result {
return nullptr;
}, [](const MTPDmessageMediaUnsupported &) -> Result {

View file

@ -403,6 +403,11 @@ Message::Message(
, _bottomInfo(
&data->history()->owner().reactions(),
BottomInfoDataFromMessage(this)) {
if (const auto media = data->media()) {
if (media->giveawayResults()) {
_hideReply = 1;
}
}
initLogEntryOriginal();
initPsa();
refreshReactions();

View file

@ -23,14 +23,21 @@ namespace {
[[nodiscard]] ClickHandlerPtr MakeMediaButtonClickHandler(
not_null<Data::Media*> media) {
const auto giveaway = media->giveaway();
Assert(giveaway != nullptr);
const auto start = media->giveawayStart();
const auto results = media->giveawayResults();
Assert(start || results);
const auto peer = media->parent()->history()->peer;
const auto messageId = media->parent()->id;
if (media->parent()->isSending() || media->parent()->hasFailed()) {
return nullptr;
}
const auto info = *giveaway;
const auto maybeStart = start
? *start
: std::optional<Data::GiveawayStart>();
const auto maybeResults = results
? *results
: std::optional<Data::GiveawayResults>();
return std::make_shared<LambdaClickHandler>([=](
ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
@ -38,13 +45,18 @@ namespace {
if (!controller) {
return;
}
ResolveGiveawayInfo(controller, peer, messageId, info);
ResolveGiveawayInfo(
controller,
peer,
messageId,
maybeStart,
maybeResults);
});
}
[[nodiscard]] QString MakeMediaButtonText(not_null<Data::Media*> media) {
const auto giveaway = media->giveaway();
Assert(giveaway != nullptr);
Expects(media->giveawayStart() || media->giveawayResults());
return Ui::Text::Upper(tr::lng_prizes_how_works(tr::now));
}
@ -72,7 +84,7 @@ struct ViewButton::Inner {
};
bool ViewButton::MediaHasViewButton(not_null<Data::Media*> media) {
return (media->giveaway() != nullptr);
return media->giveawayStart() || media->giveawayResults();
}
ViewButton::Inner::Inner(

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "boxes/gift_premium_box.h"
#include "chat_helpers/stickers_gift_box_pack.h"
#include "chat_helpers/stickers_dice_pack.h"
#include "countries/countries_instance.h"
#include "data/data_channel.h"
#include "data/data_document.h"
@ -19,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_components.h"
#include "history/history_item_helpers.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "lang/lang_keys.h"
@ -54,7 +56,8 @@ constexpr auto kAdditionalPrizesWithLineOpacity = 0.6;
TextState MediaInBubble::Part::textState(
QPoint point,
StateRequest request) const {
StateRequest request,
int outerWidth) const {
return {};
}
@ -127,7 +130,8 @@ TextState MediaInBubble::textState(
StateRequest request) const {
auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
const auto outer = width();
if (outer < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result;
}
@ -135,7 +139,7 @@ TextState MediaInBubble::textState(
const auto raw = entry.object.get();
const auto height = raw->height();
if (point.y() >= 0 && point.y() < height) {
const auto part = raw->textState(point, request);
const auto part = raw->textState(point, request, outer);
result.link = part.link;
return result;
}
@ -186,10 +190,14 @@ QMargins MediaInBubble::inBubblePadding() const {
TextMediaInBubblePart::TextMediaInBubblePart(
TextWithEntities text,
QMargins margins)
QMargins margins,
const base::flat_map<uint16, ClickHandlerPtr> &links)
: _text(st::msgMinWidth)
, _margins(margins) {
_text.setMarkedText(st::defaultTextStyle, text);
for (const auto &[index, link] : links) {
_text.setLink(index, link);
}
}
void TextMediaInBubblePart::draw(
@ -207,6 +215,18 @@ void TextMediaInBubblePart::draw(
});
}
TextState TextMediaInBubblePart::textState(
QPoint point,
StateRequest request,
int outerWidth) const {
point -= QPoint{ (outerWidth - width()) / 2, _margins.top() };
auto result = TextState();
auto forText = request.forText();
forText.align = style::al_top;
result.link = _text.getState(point, width(), forText).link;
return result;
}
QSize TextMediaInBubblePart::countOptimalSize() {
return {
_margins.left() + _text.maxWidth() + _margins.right(),
@ -278,7 +298,7 @@ QSize TextDelimeterPart::countCurrentSize(int newWidth) {
StickerWithBadgePart::StickerWithBadgePart(
not_null<Element*> parent,
Fn<DocumentData*()> lookup,
Fn<Data()> lookup,
QString badge)
: _parent(parent)
, _lookup(std::move(lookup))
@ -293,7 +313,7 @@ void StickerWithBadgePart::draw(
const auto stickerSize = st::msgServiceGiftBoxStickerSize;
const auto sticker = QRect(
(outerWidth - stickerSize.width()) / 2,
st::chatGiveawayStickerTop,
st::chatGiveawayStickerTop + _skipTop,
stickerSize.width(),
stickerSize.height());
@ -327,12 +347,14 @@ QSize StickerWithBadgePart::countCurrentSize(int newWidth) {
void StickerWithBadgePart::ensureCreated() const {
if (_sticker) {
return;
} else if (const auto document = _lookup()) {
} else if (const auto data = _lookup()) {
const auto document = data.sticker;
if (const auto sticker = document->sticker()) {
const auto skipPremiumEffect = false;
_skipTop = data.skipTop;
_sticker.emplace(_parent, document, skipPremiumEffect, _parent);
_sticker->setDiceIndex(sticker->alt, 1);
_sticker->setGiftBoxSticker(true);
_sticker->setGiftBoxSticker(data.isGiftBoxSticker);
_sticker->initSize();
}
}
@ -427,6 +449,7 @@ PeerBubbleListPart::PeerBubbleListPart(
kDefaultTextOptions,
st::msgMinWidth),
.thumbnail = Dialogs::Stories::MakeUserpicThumbnail(peer),
.link = peer->openLink(),
.colorIndex = peer->colorIndex(),
});
}
@ -528,9 +551,43 @@ int PeerBubbleListPart::layout(int x, int y, int available) {
return y + size + skip;
}
TextState PeerBubbleListPart::textState(
QPoint point,
StateRequest request,
int outerWidth) const {
auto result = TextState(_parent);
for (const auto &peer : _peers) {
if (peer.geometry.contains(point)) {
result.link = peer.link;
_lastPoint = point;
break;
}
}
return result;
}
void PeerBubbleListPart::clickHandlerPressedChanged(
const ClickHandlerPtr &p,
bool pressed) {
const ClickHandlerPtr &p,
bool pressed) {
for (auto &peer : _peers) {
if (peer.link != p) {
continue;
}
if (pressed) {
if (!peer.ripple) {
peer.ripple = std::make_unique<Ui::RippleAnimation>(
st::defaultRippleAnimation,
Ui::RippleAnimation::RoundRectMask(
peer.geometry.size(),
peer.geometry.height() / 2),
[=] { _parent->repaint(); });
}
peer.ripple->add(_lastPoint - peer.geometry.topLeft());
} else if (peer.ripple) {
peer.ripple->lastStop();
}
break;
}
}
bool PeerBubbleListPart::hasHeavyPart() {
@ -579,18 +636,19 @@ QSize PeerBubbleListPart::countCurrentSize(int newWidth) {
auto GenerateGiveawayStart(
not_null<Element*> parent,
not_null<Data::Giveaway*> giveaway)
not_null<Data::GiveawayStart*> data)
-> Fn<void(Fn<void(std::unique_ptr<MediaInBubble::Part>)>)> {
return [=](Fn<void(std::unique_ptr<MediaInBubble::Part>)> push) {
const auto months = giveaway->months;
const auto quantity = giveaway->quantity;
const auto months = data->months;
const auto quantity = data->quantity;
using Data = StickerWithBadgePart::Data;
const auto sticker = [=] {
const auto &session = parent->history()->session();
auto &packs = session.giftBoxStickersPacks();
return packs.lookup(months);
return Data{ packs.lookup(months), 0, true };
};
push(std::make_unique<HistoryView::StickerWithBadgePart>(
push(std::make_unique<StickerWithBadgePart>(
parent,
sticker,
tr::lng_prizes_badge(
@ -598,27 +656,31 @@ auto GenerateGiveawayStart(
lt_amount,
QString::number(quantity))));
auto pushText = [&](TextWithEntities text, QMargins margins = {}) {
push(std::make_unique<HistoryView::TextMediaInBubblePart>(
auto pushText = [&](
TextWithEntities text,
QMargins margins = {},
const base::flat_map<uint16, ClickHandlerPtr> &links = {}) {
push(std::make_unique<TextMediaInBubblePart>(
std::move(text),
margins));
margins,
links));
};
pushText(
Ui::Text::Bold(
tr::lng_prizes_title(tr::now, lt_count, quantity)),
st::chatGiveawayPrizesTitleMargin);
if (!giveaway->additionalPrize.isEmpty()) {
if (!data->additionalPrize.isEmpty()) {
pushText(
tr::lng_prizes_additional(
tr::now,
lt_count,
quantity,
lt_prize,
TextWithEntities{ giveaway->additionalPrize },
TextWithEntities{ data->additionalPrize },
Ui::Text::RichLangValue),
st::chatGiveawayPrizesMargin);
push(std::make_unique<HistoryView::TextDelimeterPart>(
push(std::make_unique<TextDelimeterPart>(
tr::lng_prizes_additional_with(tr::now),
st::chatGiveawayPrizesWithPadding));
}
@ -636,26 +698,26 @@ auto GenerateGiveawayStart(
Ui::Text::Bold(tr::lng_prizes_participants(tr::now)),
st::chatGiveawayPrizesTitleMargin);
pushText({ (giveaway->all
pushText({ (data->all
? tr::lng_prizes_participants_all
: tr::lng_prizes_participants_new)(
tr::now,
lt_count,
giveaway->channels.size()),
data->channels.size()),
}, st::chatGiveawayParticipantsMargin);
auto list = ranges::views::all(
giveaway->channels
data->channels
) | ranges::views::transform([](not_null<ChannelData*> channel) {
return not_null<PeerData*>(channel);
}) | ranges::to_vector;
push(std::make_unique<HistoryView::PeerBubbleListPart>(
push(std::make_unique<PeerBubbleListPart>(
parent,
std::move(list)));
const auto &instance = Countries::Instance();
auto countries = QStringList();
for (const auto &country : giveaway->countries) {
for (const auto &country : data->countries) {
const auto name = instance.countryNameByISO2(country);
const auto flag = instance.flagEmojiByISO2(country);
countries.push_back(flag + QChar(0xA0) + name);
@ -683,7 +745,80 @@ auto GenerateGiveawayStart(
? st::chatGiveawayNoCountriesTitleMargin
: st::chatGiveawayPrizesMargin));
pushText({
langDateTime(base::unixtime::parse(giveaway->untilDate)),
langDateTime(base::unixtime::parse(data->untilDate)),
}, st::chatGiveawayEndDateMargin);
};
}
auto GenerateGiveawayResults(
not_null<Element*> parent,
not_null<Data::GiveawayResults*> data)
-> Fn<void(Fn<void(std::unique_ptr<MediaInBubble::Part>)>)> {
return [=](Fn<void(std::unique_ptr<MediaInBubble::Part>)> push) {
const auto months = data->months;
const auto quantity = data->winnersCount;
using Data = StickerWithBadgePart::Data;
const auto sticker = [=] {
const auto &session = parent->history()->session();
auto &packs = session.diceStickersPacks();
const auto &emoji = Stickers::DicePacks::kPartyPopper;
const auto skip = st::chatGiveawayWinnersTopSkip;
return Data{ packs.lookup(emoji, 0), skip };
};
push(std::make_unique<StickerWithBadgePart>(
parent,
sticker,
tr::lng_prizes_badge(
tr::now,
lt_amount,
QString::number(quantity))));
auto pushText = [&](
TextWithEntities text,
QMargins margins = {},
const base::flat_map<uint16, ClickHandlerPtr> &links = {}) {
push(std::make_unique<TextMediaInBubblePart>(
std::move(text),
margins,
links));
};
pushText(
Ui::Text::Bold(
tr::lng_prizes_results_title(tr::now)),
st::chatGiveawayPrizesTitleMargin);
const auto showGiveawayHandler = JumpToMessageClickHandler(
data->channel,
data->launchId,
parent->data()->fullId());
pushText(
tr::lng_prizes_results_about(
tr::now,
lt_count,
quantity,
lt_link,
Ui::Text::Link(tr::lng_prizes_results_link(tr::now)),
Ui::Text::RichLangValue),
st::chatGiveawayPrizesMargin,
{ { 1, showGiveawayHandler } });
pushText(
Ui::Text::Bold(tr::lng_prizes_results_winners(tr::now)),
st::chatGiveawayPrizesTitleMargin);
push(std::make_unique<PeerBubbleListPart>(
parent,
data->winners));
if (data->winnersCount > data->winners.size()) {
pushText(
Ui::Text::Bold(tr::lng_prizes_results_more(
tr::now,
lt_count,
data->winnersCount - data->winners.size())),
st::chatGiveawayNoCountriesTitleMargin);
}
pushText({ data->unclaimedCount
? tr::lng_prizes_results_some(tr::now)
: tr::lng_prizes_results_all(tr::now)
}, st::chatGiveawayEndDateMargin);
};
}

View file

@ -11,7 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_sticker.h"
namespace Data {
struct Giveaway;
struct GiveawayStart;
struct GiveawayResults;
} // namespace Data
namespace Dialogs::Stories {
@ -36,7 +37,8 @@ public:
int outerWidth) const = 0;
[[nodiscard]] virtual TextState textState(
QPoint point,
StateRequest request) const;
StateRequest request,
int outerWidth) const;
virtual void clickHandlerPressedChanged(
const ClickHandlerPtr &p,
bool pressed);
@ -82,7 +84,6 @@ public:
private:
struct Entry {
std::unique_ptr<Part> object;
int top = 0;
};
QSize countOptimalSize() override;
@ -96,12 +97,19 @@ private:
class TextMediaInBubblePart final : public MediaInBubble::Part {
public:
TextMediaInBubblePart(TextWithEntities text, QMargins margins);
TextMediaInBubblePart(
TextWithEntities text,
QMargins margins,
const base::flat_map<uint16, ClickHandlerPtr> &links = {});
void draw(
Painter &p,
const PaintContext &context,
int outerWidth) const override;
TextState textState(
QPoint point,
StateRequest request,
int outerWidth) const override;
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;
@ -132,9 +140,18 @@ private:
class StickerWithBadgePart final : public MediaInBubble::Part {
public:
struct Data {
DocumentData *sticker = nullptr;
int skipTop = 0;
bool isGiftBoxSticker = false;
explicit operator bool() const {
return sticker != nullptr;
}
};
StickerWithBadgePart(
not_null<Element*> parent,
Fn<DocumentData*()> lookup,
Fn<Data()> lookup,
QString badge);
void draw(
@ -153,8 +170,9 @@ private:
void paintBadge(Painter &p, const PaintContext &context) const;
const not_null<Element*> _parent;
Fn<DocumentData*()> _lookup;
Fn<Data()> _lookup;
QString _badgeText;
mutable int _skipTop = 0;
mutable std::optional<Sticker> _sticker;
mutable QColor _badgeFg;
mutable QColor _badgeBorder;
@ -173,6 +191,10 @@ public:
Painter &p,
const PaintContext &context,
int outerWidth) const override;
TextState textState(
QPoint point,
StateRequest request,
int outerWidth) const override;
void clickHandlerPressedChanged(
const ClickHandlerPtr &p,
bool pressed) override;
@ -199,13 +221,19 @@ private:
const not_null<Element*> _parent;
std::vector<Peer> _peers;
mutable QPoint _lastPoint;
mutable bool _subscribed = false;
};
[[nodiscard]] auto GenerateGiveawayStart(
not_null<Element*> parent,
not_null<Data::Giveaway*> giveaway)
not_null<Data::GiveawayStart*> data)
-> Fn<void(Fn<void(std::unique_ptr<MediaInBubble::Part>)>)>;
[[nodiscard]] auto GenerateGiveawayResults(
not_null<Element*> parent,
not_null<Data::GiveawayResults*> data)
-> Fn<void(Fn<void(std::unique_ptr<MediaInBubble::Part>)>)>;
} // namespace HistoryView

View file

@ -97,11 +97,11 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#29562865 id:long = Chat;
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#6592a1a7 id:long title:string = Chat;
channel#8e87ccd8 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor = Chat;
channel#a636a3e2 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor = Chat;
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
channelFull#723027bd flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories = ChatFull;
channelFull#f2bcb6f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper = ChatFull;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
@ -132,7 +132,7 @@ messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia;
messageMediaGiveawayResults#b11ff5a1 flags:# refunded:flags.0?true channel_id:long launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string = MessageMedia;
messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string until_date:int = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction;
@ -172,7 +172,7 @@ messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags
messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
messageActionRequestedPeer#fe77345d button_id:int peer:Peer = MessageAction;
messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction;
messageActionGiftCode#d2cfdb0e flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string = MessageAction;
messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction;
messageActionGiveawayLaunch#332ba9ed = MessageAction;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction;
@ -970,8 +970,9 @@ channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:For
channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeColor#3c2b247b prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeBackgroundEmoji#445fc434 prev_value:long new_value:long = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@ -1554,8 +1555,10 @@ stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string
stories.stories#5dd8c3c8 count:int stories:Vector<StoryItem> chats:Vector<Chat> users:Vector<User> = stories.Stories;
storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView;
//storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView;
//storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView;
stories.storyViewsList#46e9b9ec flags:# count:int reactions_count:int views:Vector<StoryView> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList;
stories.storyViewsList#19a16886 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector<StoryView> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList;
stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews;
@ -1620,10 +1623,11 @@ help.peerColorOption#135bd42f flags:# hidden:flags.0?true color_id:int colors:fl
help.peerColorsNotModified#2ba1f5ce = help.PeerColors;
help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors;
storyPeerReaction#7decc433 peer_id:Peer date:int reaction:Reaction = StoryPeerReaction;
storyPeerPublicRepost#f7fbc17d peer_id:Peer story:StoryItem = StoryPeerReaction;
storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction;
storyReactionPublicForward#bbab2643 message:Message = StoryReaction;
storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction;
stories.storyReactionsList#d86c162a flags:# count:int reactions:Vector<StoryPeerReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryReactionsList;
stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector<StoryReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryReactionsList;
---functions---
@ -2068,7 +2072,7 @@ channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates;
channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool;
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool;
channels.updateColor#621a201f flags:# channel:InputChannel color:int background_emoji_id:flags.0?long = Updates;
channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates;
channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats;
@ -2189,7 +2193,7 @@ stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector<int> = stories.Stories;
stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool;
stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector<int>;
stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector<int> = Bool;
stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList;
stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList;
stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector<int> = stories.StoryViews;
stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink;
stories.report#1923fa8c peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool;
@ -2200,7 +2204,7 @@ stories.getAllReadPeerStories#9b5ae7f9 = Updates;
stories.getPeerMaxIDs#535983c3 id:Vector<InputPeer> = Vector<int>;
stories.getChatsToSend#a56a8b60 = messages.Chats;
stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool;
stories.getStoryReactionsList#b9b2881f flags:# reposts_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList;
stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList;
premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
premium.getMyBoosts#be77b4a = premium.MyBoosts;

View file

@ -974,6 +974,7 @@ storyMentionButtonSkip: 5px;
chatGiveawayWidth: 292px;
chatGiveawayStickerTop: -16px;
chatGiveawayWinnersTopSkip: 25px;
chatGiveawayBadgeFont: font(12px bold);
chatGiveawayBadgeTop: 106px;
chatGiveawayBadgePadding: margins(7px, 1px, 5px, 3px);