diff --git a/Telegram/Resources/art/winners.tgs b/Telegram/Resources/art/winners.tgs new file mode 100644 index 000000000..d1112ecbe Binary files /dev/null and b/Telegram/Resources/art/winners.tgs differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index d2333c7cf..6b6b81afa 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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}"; diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc index 0e43acb03..57afe3882 100644 --- a/Telegram/Resources/qrc/telegram/telegram.qrc +++ b/Telegram/Resources/qrc/telegram/telegram.qrc @@ -15,6 +15,7 @@ ../../art/slot_2_idle.tgs ../../art/slot_back.tgs ../../art/slot_pull.tgs + ../../art/winners.tgs ../../day-blue.tdesktop-theme ../../night.tdesktop-theme ../../night-green.tdesktop-theme diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 97cb8a25d..08110dea5 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -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 box, not_null controller, - Data::Giveaway giveaway, + std::optional start, + std::optional 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 controller, not_null peer, MsgId messageId, - Data::Giveaway giveaway) { + std::optional start, + std::optional 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( diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.h b/Telegram/SourceFiles/boxes/gift_premium_box.h index 1891ce5ff..1ea8d21d9 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.h +++ b/Telegram/SourceFiles/boxes/gift_premium_box.h @@ -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 controller, not_null peer, MsgId messageId, - Data::Giveaway giveaway); + std::optional start, + std::optional results); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp index dcebbfdc4..69aaddee1 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp @@ -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 session, const QString &emoji) : _session(session) @@ -35,7 +36,7 @@ DicePack::DicePack(not_null 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); } } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h index 53564363a..3a1c49f46 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h @@ -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); diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index e14f0712e..f716984ad 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -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 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 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 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 MediaStory::createView( } } -MediaGiveaway::MediaGiveaway( +MediaGiveawayStart::MediaGiveawayStart( not_null parent, - const Giveaway &data) + const GiveawayStart &data) : Media(parent) -, _giveaway(data) { +, _data(data) { parent->history()->session().giftBoxStickersPacks().load(); } -std::unique_ptr MediaGiveaway::clone(not_null parent) { - return std::make_unique(parent, _giveaway); +std::unique_ptr MediaGiveawayStart::clone( + not_null parent) { + return std::make_unique(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 MediaGiveaway::createView( +std::unique_ptr MediaGiveawayStart::createView( not_null message, not_null realParent, HistoryView::Element *replacing) { return std::make_unique( message, - HistoryView::GenerateGiveawayStart(message, &_giveaway)); + HistoryView::GenerateGiveawayStart(message, &_data)); +} + +MediaGiveawayResults::MediaGiveawayResults( + not_null parent, + const GiveawayResults &data) +: Media(parent) +, _data(data) { +} + +std::unique_ptr MediaGiveawayResults::clone( + not_null parent) { + return std::make_unique(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 MediaGiveawayResults::createView( + not_null message, + not_null realParent, + HistoryView::Element *replacing) { + return std::make_unique( + message, + HistoryView::GenerateGiveawayResults(message, &_data)); } } // namespace Data diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 667b84ffc..2a4e18e90 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -90,7 +90,7 @@ struct Invoice { bool isTest = false; }; -struct Giveaway { +struct GiveawayStart { std::vector> channels; std::vector countries; QString additionalPrize; @@ -100,6 +100,20 @@ struct Giveaway { bool all = false; }; +struct GiveawayResults { + not_null channel; + std::vector> 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 parent, - const Giveaway &data); + const GiveawayStart &data); std::unique_ptr clone(not_null 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 parent, + const GiveawayResults &data); + + std::unique_ptr clone(not_null 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 createView( + not_null message, + not_null 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 item, const MTPDmessageMediaGiveaway &data); +[[nodiscard]] GiveawayResults ComputeGiveawayResultsData( + not_null item, + const MTPDmessageMediaGiveawayResults &data); + } // namespace Data diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 83e2c10c9..d92b99f94 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -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, diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 272c94f17..0dbb419bc 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -197,7 +197,7 @@ struct Poll { bool closed = false; }; -struct Giveaway { +struct GiveawayStart { std::vector channels; TimeId untilDate = 0; int quantity = 0; @@ -336,7 +336,7 @@ struct Media { Game, Invoice, Poll, - Giveaway, + GiveawayStart, UnsupportedMedia> content; TimeId ttl = 0; diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 624da2dda..3f0b03eaf 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -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(&content)) { return pushPoll(*poll); - } else if (const auto giveaway = std::get_if(&content)) { + } else if (const auto giveaway = std::get_if(&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) {}); diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 8439093a8..a830aceec 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -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 diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index df8819d10..fcbe1cd6c 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -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 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 diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 2861bf26a..b078c358e 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -311,13 +311,13 @@ std::unique_ptr HistoryItem::CreateMedia( media.vid().v, }, media.is_via_mention()); }, [&](const MTPDmessageMediaGiveaway &media) -> Result { - return std::make_unique( + return std::make_unique( item, - Data::ComputeGiveawayData(item, media)); + Data::ComputeGiveawayStartData(item, media)); }, [&](const MTPDmessageMediaGiveawayResults &media) -> Result { - return nullptr;/* std::make_unique( + return std::make_unique( item, - Data::ComputeGiveawayData(item, media));*/ + Data::ComputeGiveawayResultsData(item, media)); }, [](const MTPDmessageMediaEmpty &) -> Result { return nullptr; }, [](const MTPDmessageMediaUnsupported &) -> Result { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 09e6851ab..35546b013 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -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(); diff --git a/Telegram/SourceFiles/history/view/history_view_view_button.cpp b/Telegram/SourceFiles/history/view/history_view_view_button.cpp index 0780e4ddf..52e9847ae 100644 --- a/Telegram/SourceFiles/history/view/history_view_view_button.cpp +++ b/Telegram/SourceFiles/history/view/history_view_view_button.cpp @@ -23,14 +23,21 @@ namespace { [[nodiscard]] ClickHandlerPtr MakeMediaButtonClickHandler( not_null 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(); + const auto maybeResults = results + ? *results + : std::optional(); return std::make_shared([=]( ClickContext context) { const auto my = context.other.value(); @@ -38,13 +45,18 @@ namespace { if (!controller) { return; } - ResolveGiveawayInfo(controller, peer, messageId, info); + ResolveGiveawayInfo( + controller, + peer, + messageId, + maybeStart, + maybeResults); }); } [[nodiscard]] QString MakeMediaButtonText(not_null 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 media) { - return (media->giveaway() != nullptr); + return media->giveawayStart() || media->giveawayResults(); } ViewButton::Inner::Inner( diff --git a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp index 0045f962b..a4d59ad04 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp @@ -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 &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 parent, - Fn lookup, + Fn 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( + 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 parent, - not_null giveaway) + not_null data) -> Fn)>)> { return [=](Fn)> 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( + push(std::make_unique( 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( + auto pushText = [&]( + TextWithEntities text, + QMargins margins = {}, + const base::flat_map &links = {}) { + push(std::make_unique( 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( + push(std::make_unique( 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 channel) { return not_null(channel); }) | ranges::to_vector; - push(std::make_unique( + push(std::make_unique( 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 parent, + not_null data) +-> Fn)>)> { + return [=](Fn)> 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( + parent, + sticker, + tr::lng_prizes_badge( + tr::now, + lt_amount, + QString::number(quantity)))); + + auto pushText = [&]( + TextWithEntities text, + QMargins margins = {}, + const base::flat_map &links = {}) { + push(std::make_unique( + 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( + 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); }; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_giveaway.h b/Telegram/SourceFiles/history/view/media/history_view_giveaway.h index 6f5afb8f7..a6e3faada 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_giveaway.h +++ b/Telegram/SourceFiles/history/view/media/history_view_giveaway.h @@ -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 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 &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 parent, - Fn lookup, + Fn lookup, QString badge); void draw( @@ -153,8 +170,9 @@ private: void paintBadge(Painter &p, const PaintContext &context) const; const not_null _parent; - Fn _lookup; + Fn _lookup; QString _badgeText; + mutable int _skipTop = 0; mutable std::optional _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 _parent; std::vector _peers; + mutable QPoint _lastPoint; mutable bool _subscribed = false; }; [[nodiscard]] auto GenerateGiveawayStart( not_null parent, - not_null giveaway) + not_null data) +-> Fn)>)>; + +[[nodiscard]] auto GenerateGiveawayResults( + not_null parent, + not_null data) -> Fn)>)>; } // namespace HistoryView diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 7afd1cec3..6946a6e56 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -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 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 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 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 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 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 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 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 groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector 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 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 groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector 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 countries_iso2:flags.1?Vector 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 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 months:int prize_description:flags.1?string until_date:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#bd47cbad title:string users:Vector = 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 chats:Vector users:Vector = 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 users:Vector next_offset:flags.0?string = stories.StoryViewsList; +stories.storyViewsList#19a16886 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; stories.storyViews#de9eed1d views:Vector users:Vector = 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.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 chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; +stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector 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 = stories.Stories; stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = 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 = stories.StoryViews; stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; stories.report#1923fa8c peer:InputPeer id:Vector reason:ReportReason message:string = Bool; @@ -2200,7 +2204,7 @@ stories.getAllReadPeerStories#9b5ae7f9 = Updates; stories.getPeerMaxIDs#535983c3 id:Vector = Vector; 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; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index aaec33461..03e6a03c3 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -974,6 +974,7 @@ storyMentionButtonSkip: 5px; chatGiveawayWidth: 292px; chatGiveawayStickerTop: -16px; +chatGiveawayWinnersTopSkip: 25px; chatGiveawayBadgeFont: font(12px bold); chatGiveawayBadgeTop: 106px; chatGiveawayBadgePadding: margins(7px, 1px, 5px, 3px);