Star-count button in multi-Forward/CreatePoll.

This commit is contained in:
John Preston 2025-02-28 12:57:39 +04:00
parent b3f9a77ba7
commit 97b021efaf
7 changed files with 111 additions and 41 deletions

View file

@ -30,6 +30,11 @@ ShortInfoBox {
labeledOneLine: FlatLabel; labeledOneLine: FlatLabel;
} }
boxStarIconEmoji: IconEmoji {
icon: icon{{ "payments/small_star", windowFg }};
padding: margins(0px, -2px, 0px, 0px);
}
countryRowHeight: 36px; countryRowHeight: 36px;
countryRowNameFont: semiboldFont; countryRowNameFont: semiboldFont;
countryRowNameFg: boxTextFg; countryRowNameFg: boxTextFg;

View file

@ -817,13 +817,15 @@ CreatePollBox::CreatePollBox(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
PollData::Flags chosen, PollData::Flags chosen,
PollData::Flags disabled, PollData::Flags disabled,
rpl::producer<int> starsRequired,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Details sendMenuDetails) SendMenu::Details sendMenuDetails)
: _controller(controller) : _controller(controller)
, _chosen(chosen) , _chosen(chosen)
, _disabled(disabled) , _disabled(disabled)
, _sendType(sendType) , _sendType(sendType)
, _sendMenuDetails([result = sendMenuDetails] { return result; }) { , _sendMenuDetails([result = sendMenuDetails] { return result; })
, _starsRequired(std::move(starsRequired)) {
} }
rpl::producer<CreatePollBox::Result> CreatePollBox::submitRequests() const { rpl::producer<CreatePollBox::Result> CreatePollBox::submitRequests() const {
@ -1226,10 +1228,18 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
_sendMenuDetails()); _sendMenuDetails());
}; };
const auto submit = addButton( const auto submit = addButton(
(isNormal tr::lng_polls_create_button(),
? tr::lng_polls_create_button()
: tr::lng_schedule_button()),
[=] { isNormal ? send({}) : schedule(); }); [=] { isNormal ? send({}) : schedule(); });
submit->setText(_starsRequired.value() | rpl::map([=](int stars) {
using namespace Ui;
if (!stars) {
return (isNormal
? tr::lng_polls_create_button
: tr::lng_schedule_button)(tr::now, Text::WithEntities);
}
return Text::IconEmoji(&st::boxStarIconEmoji).append(
Lang::FormatCountToShort(stars).string);
}));
const auto sendMenuDetails = [=] { const auto sendMenuDetails = [=] {
collectError(); collectError();
return (*error) ? SendMenu::Details() : _sendMenuDetails(); return (*error) ? SendMenu::Details() : _sendMenuDetails();

View file

@ -42,6 +42,7 @@ public:
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
PollData::Flags chosen, PollData::Flags chosen,
PollData::Flags disabled, PollData::Flags disabled,
rpl::producer<int> starsRequired,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Details sendMenuDetails); SendMenu::Details sendMenuDetails);
@ -76,6 +77,7 @@ private:
const PollData::Flags _disabled = PollData::Flags(); const PollData::Flags _disabled = PollData::Flags();
const Api::SendType _sendType = Api::SendType(); const Api::SendType _sendType = Api::SendType();
const Fn<SendMenu::Details()> _sendMenuDetails; const Fn<SendMenu::Details()> _sendMenuDetails;
rpl::variable<int> _starsRequired;
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel; base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
Fn<void()> _setInnerFocus; Fn<void()> _setInnerFocus;
Fn<rpl::producer<bool>()> _dataIsValidValue; Fn<rpl::producer<bool>()> _dataIsValidValue;

View file

@ -39,7 +39,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/peer_bubble.h" #include "ui/widgets/peer_bubble.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_credits.h" #include "styles/style_credits.h"
#include "styles/style_giveaway.h" #include "styles/style_giveaway.h"
#include "styles/style_info.h" // inviteLinkSubscribeBoxTerms #include "styles/style_info.h" // inviteLinkSubscribeBoxTerms

View file

@ -54,7 +54,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h" #include "core/application.h"
#include "core/core_settings.h" #include "core/core_settings.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "styles/style_menu_icons.h" #include "styles/style_menu_icons.h"

View file

@ -1364,11 +1364,6 @@ defaultComposeControls: ComposeControls {
restrictionLabel: defaultRestrictionLabel; restrictionLabel: defaultRestrictionLabel;
} }
boxStarIconEmoji: IconEmoji {
icon: icon{{ "payments/small_star", windowFg }};
padding: margins(0px, -2px, 0px, 0px);
}
moreChatsBarHeight: 48px; moreChatsBarHeight: 48px;
moreChatsBarTextPosition: point(12px, 4px); moreChatsBarTextPosition: point(12px, 4px);
moreChatsBarStatusPosition: point(12px, 24px); moreChatsBarStatusPosition: point(12px, 24px);

View file

@ -1762,10 +1762,18 @@ void PeerMenuCreatePoll(
chosen &= ~PollData::Flag::PublicVotes; chosen &= ~PollData::Flag::PublicVotes;
disabled |= PollData::Flag::PublicVotes; disabled |= PollData::Flag::PublicVotes;
} }
auto starsRequired = peer->session().changes().peerFlagsValue(
peer,
Data::PeerUpdate::Flag::FullInfo
| Data::PeerUpdate::Flag::StarsPerMessage
) | rpl::map([=] {
return peer->starsPerMessageChecked();
});
auto box = Box<CreatePollBox>( auto box = Box<CreatePollBox>(
controller, controller,
chosen, chosen,
disabled, disabled,
std::move(starsRequired),
sendType, sendType,
sendMenuDetails); sendMenuDetails);
struct State { struct State {
@ -1996,8 +2004,7 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
ChooseRecipientBoxController::rowClicked(row); ChooseRecipientBoxController::rowClicked(row);
} else { } else {
delegate()->peerListSetRowChecked(row, !row->checked()); delegate()->peerListSetRowChecked(row, !row->checked());
_hasSelectedChanges.fire( _selectionChanges.fire({});
delegate()->peerListSelectedRowsCount() > 0);
} }
} }
@ -2015,16 +2022,18 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
st::popupMenuWithIcons); st::popupMenuWithIcons);
menu->addAction(tr::lng_bot_choose_chat(tr::now), [=] { menu->addAction(tr::lng_bot_choose_chat(tr::now), [=] {
delegate()->peerListSetRowChecked(row, true); delegate()->peerListSetRowChecked(row, true);
_hasSelectedChanges.fire( _selectionChanges.fire({});
delegate()->peerListSelectedRowsCount() > 0);
}, &st::menuIconSelect); }, &st::menuIconSelect);
return menu; return menu;
} }
return nullptr; return nullptr;
} }
[[nodiscard]] rpl::producer<bool> hasSelectedChanges() const { [[nodiscard]] rpl::producer<> selectionChanges() const {
return _hasSelectedChanges.events_starting_with(false); return _selectionChanges.events_starting_with({});
}
[[nodiscard]] bool hasSelected() const {
return delegate()->peerListSelectedRowsCount() > 0;
} }
[[nodiscard]] rpl::producer<Chosen> singleChosen() const { [[nodiscard]] rpl::producer<Chosen> singleChosen() const {
@ -2033,7 +2042,7 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
private: private:
rpl::event_stream<Chosen> _singleChosen; rpl::event_stream<Chosen> _singleChosen;
rpl::event_stream<bool> _hasSelectedChanges; rpl::event_stream<> _selectionChanges;
bool _selectable = false; bool _selectable = false;
}; };
@ -2078,13 +2087,24 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
struct State { struct State {
Fn<void(Api::SendOptions)> submit; Fn<void(Api::SendOptions)> submit;
rpl::variable<int> starsToSend;
Fn<void()> refreshStarsToSend;
rpl::lifetime submitLifetime; rpl::lifetime submitLifetime;
}; };
const auto state = std::make_shared<State>(); const auto state = std::make_shared<State>();
auto initBox = [=](not_null<PeerListBox*> box) { auto initBox = [=](not_null<PeerListBox*> box) {
raw->hasSelectedChanges( state->refreshStarsToSend = [=] {
) | rpl::start_with_next([=](bool shown) { auto perMessage = 0;
for (const auto &peer : box->collectSelectedRows()) {
perMessage += peer->starsPerMessageChecked();
}
state->starsToSend = perMessage;
};
raw->selectionChanges(
) | rpl::start_with_next([=] {
box->clearButtons(); box->clearButtons();
state->refreshStarsToSend();
const auto shown = raw->hasSelected();
if (shown) { if (shown) {
const auto weak = Ui::MakeWeak(box); const auto weak = Ui::MakeWeak(box);
state->submit = [=](Api::SendOptions options) { state->submit = [=](Api::SendOptions options) {
@ -2147,11 +2167,21 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
return peer->owner().history(peer); return peer->owner().history(peer);
}) | ranges::to_vector, options); }) | ranges::to_vector, options);
}; };
box->addButton(tr::lng_send_button(), [=] { const auto send = box->addButton(
if (const auto onstack = state->submit) { tr::lng_send_button(),
onstack({}); [=] {
} if (const auto onstack = state->submit) {
}); onstack({});
}
});
send->setText(state->starsToSend.value(
) | rpl::map([=](int stars) {
using namespace Ui;
return stars
? Text::IconEmoji(&st::boxStarIconEmoji).append(
Lang::FormatCountToShort(stars).string)
: tr::lng_send_button(tr::now, Text::WithEntities);
}));
} }
box->addButton(tr::lng_cancel(), [=] { box->addButton(tr::lng_cancel(), [=] {
box->closeBox(); box->closeBox();
@ -2282,8 +2312,7 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
ChooseRecipientBoxController::rowClicked(row); ChooseRecipientBoxController::rowClicked(row);
} else if (count) { } else if (count) {
delegate()->peerListSetRowChecked(row, !row->checked()); delegate()->peerListSetRowChecked(row, !row->checked());
_hasSelectedChanges.fire( _selectionChanges.fire({});
delegate()->peerListSelectedRowsCount() > 0);
} }
} }
@ -2296,16 +2325,18 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
st::popupMenuWithIcons); st::popupMenuWithIcons);
menu->addAction(tr::lng_bot_choose_chat(tr::now), [=] { menu->addAction(tr::lng_bot_choose_chat(tr::now), [=] {
delegate()->peerListSetRowChecked(row, true); delegate()->peerListSetRowChecked(row, true);
_hasSelectedChanges.fire( _selectionChanges.fire({});
delegate()->peerListSelectedRowsCount() > 0);
}, &st::menuIconSelect); }, &st::menuIconSelect);
return menu; return menu;
} }
return nullptr; return nullptr;
} }
[[nodiscard]] rpl::producer<bool> hasSelectedChanges() const { [[nodiscard]] rpl::producer<> selectionChanges() const {
return _hasSelectedChanges.events_starting_with(false); return _selectionChanges.events_starting_with({});
}
[[nodiscard]] bool hasSelected() const {
return delegate()->peerListSelectedRowsCount() > 0;
} }
[[nodiscard]] rpl::producer<Chosen> singleChosen() const{ [[nodiscard]] rpl::producer<Chosen> singleChosen() const{
@ -2314,7 +2345,7 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
private: private:
rpl::event_stream<Chosen> _singleChosen; rpl::event_stream<Chosen> _singleChosen;
rpl::event_stream<bool> _hasSelectedChanges; rpl::event_stream<> _selectionChanges;
}; };
@ -2323,6 +2354,8 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
not_null<Controller*> controller; not_null<Controller*> controller;
base::unique_qptr<Ui::PopupMenu> menu; base::unique_qptr<Ui::PopupMenu> menu;
Fn<void(Api::SendOptions options)> submit; Fn<void(Api::SendOptions options)> submit;
rpl::variable<int> starsToSend;
Fn<void()> refreshStarsToSend;
rpl::lifetime submitLifetime; rpl::lifetime submitLifetime;
}; };
@ -2622,8 +2655,20 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
} }
}; };
state->refreshStarsToSend = [=] {
auto perMessage = 0;
for (const auto &peer : state->box->collectSelectedRows()) {
perMessage += peer->starsPerMessageChecked();
}
state->starsToSend = perMessage
* countMessages(field->getTextWithTags());
};
comment->hide(anim::type::instant); comment->hide(anim::type::instant);
comment->toggleOn(state->controller->hasSelectedChanges()); comment->toggleOn(state->controller->selectionChanges(
) | rpl::map([=] {
return state->controller->hasSelected();
}));
rpl::combine( rpl::combine(
state->box->sizeValue(), state->box->sizeValue(),
@ -2650,6 +2695,9 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
}, },
}); });
field->setSubmitSettings(Core::App().settings().sendSubmitWay()); field->setSubmitSettings(Core::App().settings().sendSubmitWay());
field->changes() | rpl::start_with_next([=] {
state->refreshStarsToSend();
}, field->lifetime());
Ui::SendPendingMoveResizeEvents(comment); Ui::SendPendingMoveResizeEvents(comment);
@ -2660,16 +2708,20 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
} }
}, comment->lifetime()); }, comment->lifetime());
state->controller->hasSelectedChanges( state->controller->selectionChanges(
) | rpl::start_with_next([=](bool shown) { ) | rpl::start_with_next([=] {
const auto shown = state->controller->hasSelected();
state->box->clearButtons(); state->box->clearButtons();
state->refreshStarsToSend();
if (shown) { if (shown) {
auto text = tr::lng_send_button(); const auto send = state->box->addButton(
const auto send = state->box->addButton(std::move(text), [=] { tr::lng_send_button(),
if (const auto onstack = state->submit) { [=] {
onstack({}); if (const auto onstack = state->submit) {
} onstack({});
}); }
});
send->setAcceptBoth(); send->setAcceptBoth();
send->clicks( send->clicks(
) | rpl::start_with_next([=](Qt::MouseButton button) { ) | rpl::start_with_next([=](Qt::MouseButton button) {
@ -2677,6 +2729,14 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
showMenu(send); showMenu(send);
} }
}, send->lifetime()); }, send->lifetime());
send->setText(state->starsToSend.value(
) | rpl::map([=](int stars) {
using namespace Ui;
return stars
? Text::IconEmoji(&st::boxStarIconEmoji).append(
Lang::FormatCountToShort(stars).string)
: tr::lng_send_button(tr::now, Text::WithEntities);
}));
} }
state->box->addButton(tr::lng_cancel(), [=] { state->box->addButton(tr::lng_cancel(), [=] {
state->box->closeBox(); state->box->closeBox();