From 486d5b63d3d29358ac9b603bcc58c4ed4b9cf05e Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 18 Oct 2023 17:27:02 +0400 Subject: [PATCH] Add countries to giveaway messages. --- Telegram/Resources/langs/lang.strings | 3 + .../SourceFiles/data/data_media_types.cpp | 7 ++ Telegram/SourceFiles/data/data_media_types.h | 1 + .../view/media/history_view_giveaway.cpp | 117 ++++++++++++++++-- .../view/media/history_view_giveaway.h | 19 ++- Telegram/SourceFiles/ui/chat/chat.style | 1 + 6 files changed, 135 insertions(+), 13 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 0f77401b7..f03c46f20 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2090,6 +2090,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_prizes_participants_all#other" = "All subscribers of the channels:"; "lng_prizes_participants_new#one" = "All users who joined the channel below after this date:"; "lng_prizes_participants_new#other" = "All users who joined the channels below after this date:"; +"lng_prizes_countries" = "from {countries}"; +"lng_prizes_countries_and_one" = "{countries}, {country}"; +"lng_prizes_countries_and_last" = "{countries} and {country}"; "lng_prizes_date" = "Winners Selection Date"; "lng_prizes_how_works" = "Learn more"; "lng_prizes_how_title" = "About this giveaway"; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 916d9e5bc..9ca2dd394 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -375,6 +375,13 @@ Giveaway ComputeGiveawayData( for (const auto &id : data.vchannels().v) { result.channels.push_back(owner->channel(ChannelId(id))); } + if (const auto countries = data.vcountries_iso2()) { + result.countries.reserve(countries->v.size()); + for (const auto &country : countries->v) { + result.countries.push_back(qs(country)); + } + } + result.countries = { u"FR"_q, u"FI"_q, u"UA"_q, u"IT"_q }; return result; } diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 1704e2ad3..aea83ef41 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -92,6 +92,7 @@ struct Invoice { struct Giveaway { std::vector> channels; + std::vector countries; TimeId untilDate = 0; int quantity = 0; int months = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp index 2d9a81fd8..47ecb030d 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 "countries/countries_instance.h" #include "data/data_channel.h" #include "data/data_document.h" #include "data/data_media_types.h" @@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "ui/chat/chat_style.h" #include "ui/chat/message_bubble.h" +#include "ui/effects/ripple_animation.h" #include "ui/text/text_utilities.h" #include "ui/widgets/tooltip.h" #include "ui/painter.h" @@ -34,8 +36,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { -constexpr auto kChannelBgAlpha = 32; - [[nodiscard]] QSize CountOptimalTextSize( const Ui::Text::String &text, int minWidth, @@ -59,8 +59,10 @@ Giveaway::Giveaway( , _prizes(st::msgMinWidth) , _participantsTitle(st::msgMinWidth) , _participants(st::msgMinWidth) +, _countries(st::msgMinWidth) , _winnersTitle(st::msgMinWidth) -, _winners(st::msgMinWidth) { +, _winners(st::msgMinWidth) +, _colorIndex(parent->data()->computeColorIndex()) { fillFromData(giveaway); } @@ -108,6 +110,33 @@ void Giveaway::fillFromData(not_null giveaway) { } const auto channels = int(_channels.size()); + const auto &instance = Countries::Instance(); ; + auto countries = QStringList(); + for (const auto &country : giveaway->countries) { + const auto name = instance.countryNameByISO2(country); + const auto flag = instance.flagEmojiByISO2(country); + countries.push_back(flag + QChar(0xA0) + name); + } + if (const auto count = countries.size()) { + auto united = countries.front(); + for (auto i = 1; i != count; ++i) { + united = ((i + 1 == count) + ? tr::lng_prizes_countries_and_last + : tr::lng_prizes_countries_and_one)( + tr::now, + lt_countries, + united, + lt_country, + countries[i]); + } + _countries.setText( + st::defaultTextStyle, + tr::lng_prizes_countries(tr::now, lt_countries, united), + kDefaultTextOptions); + } else { + _countries.clear(); + } + _participants.setText( st::defaultTextStyle, (giveaway->all @@ -161,7 +190,19 @@ QSize Giveaway::countOptimalSize() { padding.left(), channelsTop, available); - _winnersTitleTop = channelsBottom + st::chatGiveawayDateTop; + _countriesTop = channelsBottom; + if (_countries.isEmpty()) { + _winnersTitleTop = _countriesTop + st::chatGiveawayDateTop; + } else { + const auto countriesSize = CountOptimalTextSize( + _countries, + st::msgMinWidth, + available); + _countriesWidth = countriesSize.width(); + _winnersTitleTop = _countriesTop + + _countries.countHeight(available) + + st::chatGiveawayCountriesSkip; + } _winnersTop = _winnersTitleTop + _winnersTitle.countHeight(available) + st::chatGiveawayDateSkip; @@ -252,6 +293,9 @@ void Giveaway::draw(Painter &p, const PaintContext &context) const { paintText(_prizes, _prizesTop, _prizesWidth); paintText(_participantsTitle, _participantsTitleTop, paintw); paintText(_participants, _participantsTop, _participantsWidth); + if (!_countries.isEmpty()) { + paintText(_countries, _countriesTop, _countriesWidth); + } paintText(_winnersTitle, _winnersTitleTop, paintw); paintText(_winners, _winnersTop, paintw); paintChannels(p, context); @@ -302,16 +346,18 @@ void Giveaway::paintChannels( const auto size = _channels[0].geometry.height(); const auto ratio = style::DevicePixelRatio(); const auto stm = context.messageStyle(); - auto bg = stm->msgReplyBarColor->c; - bg.setAlpha(kChannelBgAlpha); - if (_channelCorners[0].isNull() || _channelBg != bg) { - _channelBg = bg; + const auto selected = context.selected(); + const auto cache = context.outbg + ? stm->replyCache.get() + : context.st->coloredReplyCache(selected, _colorIndex).get(); + if (_channelCorners[0].isNull() || _channelBg != cache->bg) { + _channelBg = cache->bg; _channelCorners = Images::CornersMask(size / 2); for (auto &image : _channelCorners) { - style::colorizeImage(image, bg, &image); + style::colorizeImage(image, cache->bg, &image); } } - p.setPen(stm->msgReplyBarColor); + p.setPen(cache->outline); const auto padding = st::chatGiveawayChannelPadding; for (const auto &channel : _channels) { const auto &thumbnail = channel.thumbnail; @@ -321,7 +367,20 @@ void Giveaway::paintChannels( view->history()->owner().requestViewRepaint(view); }); } + Ui::DrawRoundedRect(p, geometry, _channelBg, _channelCorners); + if (channel.ripple) { + channel.ripple->paint( + p, + geometry.x(), + geometry.y(), + width(), + &cache->bg); + if (channel.ripple->empty()) { + channel.ripple = nullptr; + } + } + p.drawImage(geometry.topLeft(), thumbnail->image(size)); const auto left = size + padding.left(); const auto top = padding.top(); @@ -337,7 +396,7 @@ void Giveaway::paintChannels( .elisionBreakEverywhere = true, }); } - _subscribedToThumbnails = true; + _subscribedToThumbnails = 1; } void Giveaway::ensureStickerCreated() const { @@ -410,12 +469,45 @@ TextState Giveaway::textState(QPoint point, StateRequest request) const { for (const auto &channel : _channels) { if (channel.geometry.contains(point)) { result.link = channel.link; + _lastPoint = point; return result; } } return result; } +void Giveaway::clickHandlerActiveChanged( + const ClickHandlerPtr &p, + bool active) { +} + +void Giveaway::clickHandlerPressedChanged( + const ClickHandlerPtr &p, + bool pressed) { + for (auto &channel : _channels) { + if (channel.link != p) { + continue; + } + if (pressed) { + if (!channel.ripple) { + const auto full = QRect(0, 0, width(), height()); + const auto outer = full.marginsRemoved(inBubblePadding()); + const auto owner = &parent()->history()->owner(); + channel.ripple = std::make_unique( + st::defaultRippleAnimation, + Ui::RippleAnimation::RoundRectMask( + channel.geometry.size(), + channel.geometry.height() / 2), + [=] { owner->requestViewRepaint(parent()); }); + } + channel.ripple->add(_lastPoint - channel.geometry.topLeft()); + } else if (channel.ripple) { + channel.ripple->lastStop(); + } + break; + } +} + bool Giveaway::hideFromName() const { return !parent()->data()->Has(); } @@ -425,7 +517,8 @@ bool Giveaway::hasHeavyPart() const { } void Giveaway::unloadHeavyPart() { - if (base::take(_subscribedToThumbnails)) { + if (_subscribedToThumbnails) { + _subscribedToThumbnails = 0; for (const auto &channel : _channels) { channel.thumbnail->subscribeToUpdates(nullptr); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_giveaway.h b/Telegram/SourceFiles/history/view/media/history_view_giveaway.h index 1135396ed..437c94c5c 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_giveaway.h +++ b/Telegram/SourceFiles/history/view/media/history_view_giveaway.h @@ -18,6 +18,10 @@ namespace Dialogs::Stories { class Thumbnail; } // namespace Dialogs::Stories +namespace Ui { +class RippleAnimation; +} // namespace Ui + namespace HistoryView { class Giveaway final : public Media { @@ -30,6 +34,13 @@ public: void draw(Painter &p, const PaintContext &context) const override; TextState textState(QPoint point, StateRequest request) const override; + void clickHandlerActiveChanged( + const ClickHandlerPtr &p, + bool active) override; + void clickHandlerPressedChanged( + const ClickHandlerPtr &p, + bool pressed) override; + bool needsBubble() const override { return true; } @@ -57,6 +68,7 @@ private: std::shared_ptr thumbnail; QRect geometry; ClickHandlerPtr link; + mutable std::unique_ptr ripple; }; void paintBadge(Painter &p, const PaintContext &context) const; @@ -78,6 +90,7 @@ private: Ui::Text::String _participantsTitle; Ui::Text::String _participants; std::vector _channels; + Ui::Text::String _countries; Ui::Text::String _winnersTitle; Ui::Text::String _winners; @@ -88,6 +101,7 @@ private: mutable QImage _badge; mutable QImage _badgeCache; + mutable QPoint _lastPoint; int _months = 0; int _quantity = 0; int _stickerTop = 0; @@ -97,9 +111,12 @@ private: int _participantsTitleTop = 0; int _participantsTop = 0; int _participantsWidth = 0; + int _countriesTop = 0; + int _countriesWidth = 0; int _winnersTitleTop = 0; int _winnersTop = 0; - mutable bool _subscribedToThumbnails = false; + uint8 _colorIndex : 7 = 0; + mutable uint8 _subscribedToThumbnails : 1 = 0; }; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 6c2f61c27..7050667ae 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -957,6 +957,7 @@ chatGiveawayChannelTop: 6px; chatGiveawayChannelSize: 32px; chatGiveawayChannelPadding: margins(5px, 7px, 12px, 0px); chatGiveawayChannelSkip: 8px; +chatGiveawayCountriesSkip: 16px; chatGiveawayDateTop: 6px; chatGiveawayDateSkip: 4px; chatGiveawayBottomSkip: 16px;