diff --git a/Telegram/Resources/icons/boosts/filled_gift.png b/Telegram/Resources/icons/boosts/filled_gift.png new file mode 100644 index 0000000000..123818f74b Binary files /dev/null and b/Telegram/Resources/icons/boosts/filled_gift.png differ 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 0000000000..13e5102ed4 Binary files /dev/null and b/Telegram/Resources/icons/boosts/filled_gift@2x.png differ 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 0000000000..7e3ad4e24f Binary files /dev/null and b/Telegram/Resources/icons/boosts/filled_gift@3x.png differ diff --git a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp index 828d1283d5..3daff65434 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 0000000000..1779b91e11 --- /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 0000000000..440b037f66 --- /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 c631a4f304..9f7abbcddf 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 5887ac5a30..8205e54576 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