Add countries to giveaway messages.

This commit is contained in:
John Preston 2023-10-18 17:27:02 +04:00
parent 84a1fec7b1
commit 486d5b63d3
6 changed files with 135 additions and 13 deletions

View File

@ -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";

View File

@ -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;
}

View File

@ -92,6 +92,7 @@ struct Invoice {
struct Giveaway {
std::vector<not_null<ChannelData*>> channels;
std::vector<QString> countries;
TimeId untilDate = 0;
int quantity = 0;
int months = 0;

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "boxes/gift_premium_box.h"
#include "chat_helpers/stickers_gift_box_pack.h"
#include "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<Data::Giveaway*> 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<Ui::RippleAnimation>(
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<HistoryMessageForwarded>();
}
@ -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);
}

View File

@ -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> thumbnail;
QRect geometry;
ClickHandlerPtr link;
mutable std::unique_ptr<Ui::RippleAnimation> ripple;
};
void paintBadge(Painter &p, const PaintContext &context) const;
@ -78,6 +90,7 @@ private:
Ui::Text::String _participantsTitle;
Ui::Text::String _participants;
std::vector<Channel> _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;
};

View File

@ -957,6 +957,7 @@ chatGiveawayChannelTop: 6px;
chatGiveawayChannelSize: 32px;
chatGiveawayChannelPadding: margins(5px, 7px, 12px, 0px);
chatGiveawayChannelSkip: 8px;
chatGiveawayCountriesSkip: 16px;
chatGiveawayDateTop: 6px;
chatGiveawayDateSkip: 4px;
chatGiveawayBottomSkip: 16px;