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);