From 67bbb477c7e0deba3b1b2b987828db9048ca5ce1 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 30 Oct 2023 11:58:25 +0300 Subject: [PATCH] Added ability to select users for awarding in giveaway box. --- .../Resources/icons/boosts/filled_gift.png | Bin 0 -> 727 bytes .../Resources/icons/boosts/filled_gift@2x.png | Bin 0 -> 1374 bytes .../Resources/icons/boosts/filled_gift@3x.png | Bin 0 -> 2147 bytes .../info/boosts/create_giveaway_box.cpp | 96 +++++++++++---- .../boosts/giveaway/giveaway_type_row.cpp | 114 ++++++++++++++++++ .../info/boosts/giveaway/giveaway_type_row.h | 49 ++++++++ .../SourceFiles/statistics/statistics.style | 12 ++ Telegram/cmake/td_ui.cmake | 3 + 8 files changed, 253 insertions(+), 21 deletions(-) create mode 100644 Telegram/Resources/icons/boosts/filled_gift.png create mode 100644 Telegram/Resources/icons/boosts/filled_gift@2x.png create mode 100644 Telegram/Resources/icons/boosts/filled_gift@3x.png create mode 100644 Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp create mode 100644 Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h diff --git a/Telegram/Resources/icons/boosts/filled_gift.png b/Telegram/Resources/icons/boosts/filled_gift.png new file mode 100644 index 0000000000000000000000000000000000000000..123818f74b8d1b7defc9157ceb5241c71876a4cf GIT binary patch literal 727 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyvR+#WBP} z@M?(n>6L*Z|L&wuTCyZXLD+DD=2DGhqlHtHn3bnDc3NttACY&^OjT1BcAY8NRpiMN z!koz3%{xA#8pJNNvx_2SL!ziY2;p11Yet?6IuYW}bvep|LZYVF@Td%6DLl_LGe zCwr*ujLF*=k+c1_+v3E{H}B;u%kbTQ|NZ!5!XebTS@P;0w!3-aR-147+*J`YEo@3S_0%YpVld|YDY8E~jHrMo6{ zo}F8GK;b@D%N-A~=I&%eeP6r8^4)j6%{}JW9=pHCtdL3c(KncX-u<$r44;XzR@c!aor9N`l=rYVm6=NQ`YksW>YU)~ zD8kjcK~}4JE~`#xK!bRWfrN*Hfy5FU#(3W;e#>VD%|HMBtcz5yo8I*QKWrI7w63am z&U@dn)97fY3)A*KGZ(jp6eG{re1=~WwyOF3k-K;%MlLCBm%Ub&*=!&AgFDn>l&05f x)}8ure8ttQHM=_cBL!I|OuWxs-dLYn$Mks87gc44gzKP0<>~6@vd$@?2>{JO91Z{g literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/boosts/filled_gift@2x.png b/Telegram/Resources/icons/boosts/filled_gift@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..13e5102ed47f9c0095ae86fb9103464086cacf96 GIT binary patch literal 1374 zcmV-k1)=(hP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG$Vo&&R9Fe^SW76TQ5YT!7H*A8 z;7E+4b5?NWuLb=3BxfMe0L}TWe|BScy zJLmh3@4qygnX}+I@8x;VIp2HUbI$+i)BpB=1^&(oBqStsbabq*ub-cvKRi6_?Cgw< zjb&wJNzr|Le5$Id78Vxv_xGQlpO21?mY0_s8ykayf+S0~y3NhaPft%j&D!|*xWB)@ zV2_WF-`?Ifv-){>cvw_aFH^qMeMh?H(>nj?CkXO^CPqL^mL4m zNLpH2NaZxZ%qVrPudhQxLnR6X-rCxtU;w?ny^;;OB_$+4IHgN=<1-bH%xuE3}Tlt!FWwftB@ z+ZaUZClmf6d&B~mGM1N@(<=7&_nX?-6;@YQ6W8qQEas|u>Ia1HesXdmNN#U$u{~7= z=OiN|BQz!~7?LI;B7#$x4hWSA#l5Mi>GJZD+-quTxT7gH)S-}&5Nwmu($au{0B%hg zz=a4Sx+y6sB;VWH6IkyeY>);hE3K`qH#axLU;v||qcj`)fK%A_B1;7242BiLH+JC^ zK_e*4BbY$_Ce%J@Cm~ z3(URvNB7Jp`|fBwhG#JDb+jApgM)(uRB$u^`(9*;pnUX(73%5f;X0dmaB%R4qXF1- z;bu}$Lk__XH(#|<3;&#)oYd4*&IOD+WNd7#D77f`xQhh_21+)#a;&bdav_oiDxV^odo4JcoNgp2{i5>479N?Rqn{#t>xZ87fbRmQa z1~4NRT+qV8!nmc=7}bRuF6yAhbrugX>D<-x!Z;%%1D_S{Wo2bVhzFD2(L_s=BLH3( zh@zvTaYPac0h5q=5qWZOdU~3dm#25++RV&M{^a0P+>B#+myr(6ggL-<46jw(V~`ej zWPNosEJJQ??%CNHx2&(P9~v5>cP&=|^Xe?A%)5Lx8jP)rYch7e#M0N-r}46ytwdtz z>gk|;eSPij?hX$RH@G=E$mI{+Rj&^uA2Jpf7i%c!xnjkm@ikXj5efO!)Rei~yVR;e z679R8{NHev$x7?~b;RhL6 za^UoU^z-A?^oYU5gUdA-W+Oll;Am5(IHQ6(fe>?D;{S3_<&Ap9n0Md!ZU6>|Jk zV0uccAA*lh)v6NEf}DHV#g&zncE-f%)bNr7grMav&S6Ytcz77+fF{Q|qZFRHa0dyf gTwEI-<6pHq)$07*qoM6N<$f`;;SfB*mh literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/boosts/filled_gift@3x.png b/Telegram/Resources/icons/boosts/filled_gift@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7e3ad4e24fb933f8ae864c17ce1a99d67eedba18 GIT binary patch literal 2147 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 Z@Grf)GNZUEmwW&K002ovPDHLkV1n3{9n}B; literal 0 HcmV?d00001 diff --git a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp index 828d1283d..3daff6543 100644 --- a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp @@ -10,10 +10,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_participants_box.h" // ParticipantsBoxController #include "data/data_peer.h" #include "data/data_user.h" +#include "info/boosts/giveaway/giveaway_type_row.h" #include "info/info_controller.h" #include "lang/lang_keys.h" #include "ui/layers/generic_box.h" +#include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" +#include "styles/style_layers.h" namespace { @@ -28,8 +31,6 @@ public: QWidget *parent, not_null row) override; -private: - }; void MembersListController::rowClicked(not_null row) { @@ -57,25 +58,78 @@ void CreateGiveawayBox( not_null box, not_null controller, not_null peer) { - box->addButton(tr::lng_box_ok(), [=] { - auto initBox = [=](not_null peersBox) { - peersBox->setTitle(tr::lng_giveaway_award_option()); - peersBox->addButton(tr::lng_settings_save(), [=] { - const auto selected = peersBox->collectSelectedRows(); - peersBox->closeBox(); - }); - peersBox->addButton(tr::lng_cancel(), [=] { - peersBox->closeBox(); - }); - }; + struct State final { + std::vector> selectedToAward; + rpl::event_stream<> toAwardAmountChanged; + }; + const auto state = box->lifetime().make_state(); + using GiveawayType = Giveaway::GiveawayTypeRow::Type; + using GiveawayGroup = Ui::RadioenumGroup; + const auto typeGroup = std::make_shared(); - box->uiShow()->showBox( - Box( - std::make_unique( - controller, - peer, - ParticipantsRole::Members), - std::move(initBox)), - Ui::LayerOption::KeepOther); + box->setWidth(st::boxWideWidth); + + { + const auto row = box->verticalLayout()->add( + object_ptr( + box, + GiveawayType::Random, + tr::lng_giveaway_create_subtitle())); + row->addRadio(typeGroup); + row->setClickedCallback([=] { + typeGroup->setValue(GiveawayType::Random); + }); + } + { + const auto row = box->verticalLayout()->add( + object_ptr( + box, + GiveawayType::SpecificUsers, + state->toAwardAmountChanged.events_starting_with( + rpl::empty_value() + ) | rpl::map([=] { + const auto &selected = state->selectedToAward; + return selected.empty() + ? tr::lng_giveaway_award_subtitle() + : (selected.size() == 1) + ? rpl::single(selected.front()->name()) + : tr::lng_giveaway_award_chosen( + lt_count, + rpl::single(selected.size()) | tr::to_count()); + }) | rpl::flatten_latest())); + row->addRadio(typeGroup); + row->setClickedCallback([=] { + auto initBox = [=](not_null peersBox) { + peersBox->setTitle(tr::lng_giveaway_award_option()); + peersBox->addButton(tr::lng_settings_save(), [=] { + state->selectedToAward = peersBox->collectSelectedRows(); + state->toAwardAmountChanged.fire({}); + peersBox->closeBox(); + }); + peersBox->addButton(tr::lng_cancel(), [=] { + peersBox->closeBox(); + }); + peersBox->boxClosing( + ) | rpl::start_with_next([=] { + typeGroup->setValue(state->selectedToAward.empty() + ? GiveawayType::Random + : GiveawayType::SpecificUsers); + }, peersBox->lifetime()); + }; + + box->uiShow()->showBox( + Box( + std::make_unique( + controller, + peer, + ParticipantsRole::Members), + std::move(initBox)), + Ui::LayerOption::KeepOther); + }); + } + typeGroup->setValue(GiveawayType::Random); + + box->addButton(tr::lng_box_ok(), [=] { + box->closeBox(); }); } diff --git a/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp new file mode 100644 index 000000000..1779b91e1 --- /dev/null +++ b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp @@ -0,0 +1,114 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "info/boosts/giveaway/giveaway_type_row.h" + +#include "lang/lang_keys.h" +#include "ui/painter.h" +#include "ui/rect.h" +#include "ui/text/text_options.h" +#include "ui/widgets/checkbox.h" +#include "styles/style_boxes.h" +#include "styles/style_statistics.h" + +namespace Giveaway { + +constexpr auto kColorIndexSpecific = int(4); +constexpr auto kColorIndexRandom = int(2); + +GiveawayTypeRow::GiveawayTypeRow( + not_null parent, + Type type, + rpl::producer subtitle) +: RippleButton(parent, st::defaultRippleAnimation) +, _st(st::giveawayTypeListItem) +, _type(type) +, _userpic( + Ui::EmptyUserpic::UserpicColor((_type == Type::SpecificUsers) + ? kColorIndexSpecific + : kColorIndexRandom), + QString()) +, _name( + _st.nameStyle, + (type == Type::SpecificUsers) + ? tr::lng_giveaway_award_option(tr::now) + : tr::lng_giveaway_create_option(tr::now), + Ui::NameTextOptions()) { + std::move( + subtitle + ) | rpl::start_with_next([=] (const QString &s) { + _status.setText(st::defaultTextStyle, s, Ui::NameTextOptions()); + }, lifetime()); +} + +int GiveawayTypeRow::resizeGetHeight(int) { + return _st.height; +} + +void GiveawayTypeRow::paintEvent(QPaintEvent *e) { + auto p = Painter(this); + + const auto paintOver = (isOver() || isDown()) && !isDisabled(); + const auto skipRight = _st.photoPosition.x(); + const auto outerWidth = width(); + const auto isSpecific = (_type == Type::SpecificUsers); + + if (paintOver) { + p.fillRect(e->rect(), _st.button.textBgOver); + } + Ui::RippleButton::paintRipple(p, 0, 0); + _userpic.paintCircle( + p, + _st.photoPosition.x(), + _st.photoPosition.y(), + outerWidth, + _st.photoSize); + { + const auto &userpic = isSpecific + ? st::giveawayUserpicGroup + : st::giveawayUserpic; + const auto userpicRect = QRect( + _st.photoPosition + - QPoint( + isSpecific ? -st::giveawayUserpicSkip : 0, + isSpecific ? 0 : st::giveawayUserpicSkip), + Size(_st.photoSize)); + userpic.paintInCenter(p, userpicRect); + } + + const auto namex = _st.namePosition.x(); + const auto namey = _st.namePosition.y(); + const auto namew = outerWidth - namex - skipRight; + + p.setPen(_st.nameFg); + _name.drawLeftElided(p, namex, namey, namew, width()); + + const auto statusx = _st.statusPosition.x(); + const auto statusy = _st.statusPosition.y(); + const auto statusw = outerWidth - statusx - skipRight; + p.setFont(st::contactsStatusFont); + p.setPen(isSpecific ? st::lightButtonFg : _st.statusFg); + _status.drawLeftElided(p, statusx, statusy, statusw, outerWidth); +} + +void GiveawayTypeRow::addRadio( + std::shared_ptr> typeGroup) { + const auto &st = st::defaultCheckbox; + const auto radio = Ui::CreateChild>( + this, + std::move(typeGroup), + _type, + QString(), + st); + radio->moveToLeft( + st::giveawayRadioPosition.x(), + st::giveawayRadioPosition.y()); + radio->setAttribute(Qt::WA_TransparentForMouseEvents); + radio->show(); +} + +} // namespace Giveaway diff --git a/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h new file mode 100644 index 000000000..440b037f6 --- /dev/null +++ b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h @@ -0,0 +1,49 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "ui/empty_userpic.h" +#include "ui/widgets/buttons.h" + +namespace Ui { +template +class RadioenumGroup; +} // namespace Ui + +namespace Giveaway { + +class GiveawayTypeRow final : public Ui::RippleButton { +public: + enum class Type { + Random, + SpecificUsers, + }; + + GiveawayTypeRow( + not_null parent, + Type type, + rpl::producer subtitle); + + void addRadio(std::shared_ptr> typeGroup); + +protected: + void paintEvent(QPaintEvent *e) override; + + int resizeGetHeight(int) override; + +private: + const style::PeerListItem _st; + const Type _type; + + Ui::EmptyUserpic _userpic; + Ui::Text::String _status; + Ui::Text::String _name; + +}; + +} // namespace Giveaway diff --git a/Telegram/SourceFiles/statistics/statistics.style b/Telegram/SourceFiles/statistics/statistics.style index c631a4f30..9f7abbcdd 100644 --- a/Telegram/SourceFiles/statistics/statistics.style +++ b/Telegram/SourceFiles/statistics/statistics.style @@ -148,3 +148,15 @@ getBoostsButton: SettingsButton(reportReasonButton) { textFgOver: lightButtonFg; } getBoostsButtonIcon: icon {{ "menu/gift_premium", lightButtonFg }}; + +giveawayTypeListItem: PeerListItem(defaultPeerListItem) { + height: 52px; + photoPosition: point(58px, 6px); + namePosition: point(110px, 8px); + statusPosition: point(110px, 28px); + photoSize: 42px; +} +giveawayUserpic: icon {{ "boosts/filled_gift", windowFgActive }}; +giveawayUserpicSkip: 1px; +giveawayUserpicGroup: icon {{ "limits/groups", windowFgActive }}; +giveawayRadioPosition: point(21px, 16px); diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 5887ac5a3..8205e5457 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -109,6 +109,9 @@ PRIVATE info/userpic/info_userpic_emoji_builder_layer.cpp info/userpic/info_userpic_emoji_builder_layer.h + info/boosts/giveaway/giveaway_type_row.cpp + info/boosts/giveaway/giveaway_type_row.h + layout/abstract_layout_item.cpp layout/abstract_layout_item.h layout/layout_mosaic.cpp