mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-23 11:47:57 +00:00
Support creating polls from bot keyboards.
This commit is contained in:
parent
c3aa2abe11
commit
d0597407d8
@ -547,6 +547,7 @@ keyboardButtonGame#50f41ccf text:string = KeyboardButton;
|
|||||||
keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
|
keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
|
||||||
keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
|
keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
|
||||||
inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
|
inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
|
||||||
|
keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton;
|
||||||
|
|
||||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ public:
|
|||||||
Options(
|
Options(
|
||||||
not_null<QWidget*> outer,
|
not_null<QWidget*> outer,
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
not_null<Main::Session*> session);
|
not_null<Main::Session*> session,
|
||||||
|
bool chooseCorrectEnabled);
|
||||||
|
|
||||||
[[nodiscard]] bool isValid() const;
|
[[nodiscard]] bool isValid() const;
|
||||||
[[nodiscard]] rpl::producer<bool> isValidChanged() const;
|
[[nodiscard]] rpl::producer<bool> isValidChanged() const;
|
||||||
@ -128,6 +129,8 @@ private:
|
|||||||
void destroy(std::unique_ptr<Option> option);
|
void destroy(std::unique_ptr<Option> option);
|
||||||
void removeDestroyed(not_null<Option*> field);
|
void removeDestroyed(not_null<Option*> field);
|
||||||
int findField(not_null<Ui::InputField*> field) const;
|
int findField(not_null<Ui::InputField*> field) const;
|
||||||
|
[[nodiscard]] auto createChooseCorrectGroup()
|
||||||
|
-> std::shared_ptr<Ui::RadiobuttonGroup>;
|
||||||
|
|
||||||
not_null<QWidget*> _outer;
|
not_null<QWidget*> _outer;
|
||||||
not_null<Ui::VerticalLayout*> _container;
|
not_null<Ui::VerticalLayout*> _container;
|
||||||
@ -236,9 +239,11 @@ Options::Option::Option(
|
|||||||
createRemove();
|
createRemove();
|
||||||
createWarning();
|
createWarning();
|
||||||
enableChooseCorrect(group);
|
enableChooseCorrect(group);
|
||||||
|
_correctShown.stop();
|
||||||
if (_correct) {
|
if (_correct) {
|
||||||
_correct->finishAnimating();
|
_correct->finishAnimating();
|
||||||
}
|
}
|
||||||
|
updateFieldGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Options::Option::hasShadow() const {
|
bool Options::Option::hasShadow() const {
|
||||||
@ -449,10 +454,14 @@ rpl::producer<Qt::MouseButton> Options::Option::removeClicks() const {
|
|||||||
Options::Options(
|
Options::Options(
|
||||||
not_null<QWidget*> outer,
|
not_null<QWidget*> outer,
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
not_null<Main::Session*> session)
|
not_null<Main::Session*> session,
|
||||||
|
bool chooseCorrectEnabled)
|
||||||
: _outer(outer)
|
: _outer(outer)
|
||||||
, _container(container)
|
, _container(container)
|
||||||
, _session(session)
|
, _session(session)
|
||||||
|
, _chooseCorrectGroup(chooseCorrectEnabled
|
||||||
|
? createChooseCorrectGroup()
|
||||||
|
: nullptr)
|
||||||
, _position(_container->count()) {
|
, _position(_container->count()) {
|
||||||
checkLastOption();
|
checkLastOption();
|
||||||
}
|
}
|
||||||
@ -518,15 +527,18 @@ void Options::focusFirst() {
|
|||||||
_list.front()->setFocus();
|
_list.front()->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Ui::RadiobuttonGroup> Options::createChooseCorrectGroup() {
|
||||||
|
auto result = std::make_shared<Ui::RadiobuttonGroup>(0);
|
||||||
|
result->setChangedCallback([=](int) {
|
||||||
|
validateState();
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Options::enableChooseCorrect(bool enabled) {
|
void Options::enableChooseCorrect(bool enabled) {
|
||||||
_chooseCorrectGroup = enabled
|
_chooseCorrectGroup = enabled
|
||||||
? std::make_shared<Ui::RadiobuttonGroup>(0)
|
? createChooseCorrectGroup()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (_chooseCorrectGroup) {
|
|
||||||
_chooseCorrectGroup->setChangedCallback([=](int) {
|
|
||||||
validateState();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
validateState();
|
validateState();
|
||||||
for (auto &option : _list) {
|
for (auto &option : _list) {
|
||||||
option->enableChooseCorrect(_chooseCorrectGroup);
|
option->enableChooseCorrect(_chooseCorrectGroup);
|
||||||
@ -712,10 +724,12 @@ void Options::checkLastOption() {
|
|||||||
CreatePollBox::CreatePollBox(
|
CreatePollBox::CreatePollBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PublicVotes publicVotes,
|
PollData::Flags chosen,
|
||||||
|
PollData::Flags disabled,
|
||||||
Api::SendType sendType)
|
Api::SendType sendType)
|
||||||
: _session(session)
|
: _session(session)
|
||||||
, _publicVotes(publicVotes)
|
, _chosen(chosen)
|
||||||
|
, _disabled(disabled)
|
||||||
, _sendType(sendType) {
|
, _sendType(sendType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,7 +806,8 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
|||||||
const auto options = lifetime().make_state<Options>(
|
const auto options = lifetime().make_state<Options>(
|
||||||
getDelegate()->outerContainer(),
|
getDelegate()->outerContainer(),
|
||||||
container,
|
container,
|
||||||
_session);
|
_session,
|
||||||
|
(_chosen & PollData::Flag::Quiz));
|
||||||
auto limit = options->usedCount() | rpl::after_next([=](int count) {
|
auto limit = options->usedCount() | rpl::after_next([=](int count) {
|
||||||
setCloseByEscape(!count);
|
setCloseByEscape(!count);
|
||||||
setCloseByOutsideClick(!count);
|
setCloseByOutsideClick(!count);
|
||||||
@ -815,12 +830,12 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
|||||||
AddSkip(container);
|
AddSkip(container);
|
||||||
AddSubsectionTitle(container, tr::lng_polls_create_settings());
|
AddSubsectionTitle(container, tr::lng_polls_create_settings());
|
||||||
|
|
||||||
const auto anonymous = (_publicVotes == PublicVotes::Enabled)
|
const auto anonymous = (!(_disabled & PollData::Flag::PublicVotes))
|
||||||
? container->add(
|
? container->add(
|
||||||
object_ptr<Ui::Checkbox>(
|
object_ptr<Ui::Checkbox>(
|
||||||
container,
|
container,
|
||||||
tr::lng_polls_create_anonymous(tr::now),
|
tr::lng_polls_create_anonymous(tr::now),
|
||||||
true,
|
!(_chosen & PollData::Flag::PublicVotes),
|
||||||
st::defaultCheckbox),
|
st::defaultCheckbox),
|
||||||
st::createPollCheckboxMargin)
|
st::createPollCheckboxMargin)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
@ -828,16 +843,19 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
|||||||
object_ptr<Ui::Checkbox>(
|
object_ptr<Ui::Checkbox>(
|
||||||
container,
|
container,
|
||||||
tr::lng_polls_create_multiple_choice(tr::now),
|
tr::lng_polls_create_multiple_choice(tr::now),
|
||||||
false,
|
(_chosen & PollData::Flag::MultiChoice),
|
||||||
st::defaultCheckbox),
|
st::defaultCheckbox),
|
||||||
st::createPollCheckboxMargin);
|
st::createPollCheckboxMargin);
|
||||||
const auto quiz = container->add(
|
const auto quiz = container->add(
|
||||||
object_ptr<Ui::Checkbox>(
|
object_ptr<Ui::Checkbox>(
|
||||||
container,
|
container,
|
||||||
tr::lng_polls_create_quiz_mode(tr::now),
|
tr::lng_polls_create_quiz_mode(tr::now),
|
||||||
false,
|
(_chosen & PollData::Flag::Quiz),
|
||||||
st::defaultCheckbox),
|
st::defaultCheckbox),
|
||||||
st::createPollCheckboxMargin);
|
st::createPollCheckboxMargin);
|
||||||
|
quiz->setDisabled(_disabled & PollData::Flag::Quiz);
|
||||||
|
multiple->setDisabled((_disabled & PollData::Flag::MultiChoice)
|
||||||
|
|| (_chosen & PollData::Flag::Quiz));
|
||||||
|
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
quiz->checkedChanges(
|
quiz->checkedChanges(
|
||||||
@ -845,14 +863,14 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
|||||||
if (checked && multiple->checked()) {
|
if (checked && multiple->checked()) {
|
||||||
multiple->setChecked(false);
|
multiple->setChecked(false);
|
||||||
}
|
}
|
||||||
multiple->setDisabled(checked);
|
multiple->setDisabled(checked
|
||||||
|
|| (_disabled & PollData::Flag::MultiChoice));
|
||||||
options->enableChooseCorrect(checked);
|
options->enableChooseCorrect(checked);
|
||||||
}, quiz->lifetime());
|
}, quiz->lifetime());
|
||||||
|
|
||||||
multiple->events(
|
multiple->events(
|
||||||
) | rpl::filter([=](not_null<QEvent*> e) {
|
) | rpl::filter([=](not_null<QEvent*> e) {
|
||||||
return (e->type() == QEvent::MouseButtonPress)
|
return (e->type() == QEvent::MouseButtonPress) && quiz->checked();
|
||||||
&& multiple->isDisabled();
|
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
Ui::Toast::Show("Quiz has only one right answer.");
|
Ui::Toast::Show("Quiz has only one right answer.");
|
||||||
}, multiple->lifetime());
|
}, multiple->lifetime());
|
||||||
|
@ -27,15 +27,12 @@ public:
|
|||||||
PollData poll;
|
PollData poll;
|
||||||
Api::SendOptions options;
|
Api::SendOptions options;
|
||||||
};
|
};
|
||||||
enum class PublicVotes {
|
|
||||||
Enabled,
|
|
||||||
Disabled,
|
|
||||||
};
|
|
||||||
|
|
||||||
CreatePollBox(
|
CreatePollBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PublicVotes publicVotes,
|
PollData::Flags chosen,
|
||||||
|
PollData::Flags disabled,
|
||||||
Api::SendType sendType);
|
Api::SendType sendType);
|
||||||
|
|
||||||
rpl::producer<Result> submitRequests() const;
|
rpl::producer<Result> submitRequests() const;
|
||||||
@ -52,7 +49,8 @@ private:
|
|||||||
not_null<Ui::VerticalLayout*> container);
|
not_null<Ui::VerticalLayout*> container);
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
const PublicVotes _publicVotes = PublicVotes();
|
const PollData::Flags _chosen = PollData::Flags();
|
||||||
|
const PollData::Flags _disabled = PollData::Flags();
|
||||||
const Api::SendType _sendType = Api::SendType();
|
const Api::SendType _sendType = Api::SendType();
|
||||||
Fn<void()> _setInnerFocus;
|
Fn<void()> _setInnerFocus;
|
||||||
Fn<rpl::producer<bool>()> _dataIsValidValue;
|
Fn<rpl::producer<bool>()> _dataIsValidValue;
|
||||||
|
@ -751,6 +751,17 @@ int PeerData::slowmodeSecondsLeft() const {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PeerData::canSendPolls() const {
|
||||||
|
if (const auto user = asUser()) {
|
||||||
|
return user->isBot();
|
||||||
|
} else if (const auto chat = asChat()) {
|
||||||
|
return chat->canSendPolls();
|
||||||
|
} else if (const auto channel = asChannel()) {
|
||||||
|
return channel->canSendPolls();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
std::vector<ChatRestrictions> ListOfRestrictions() {
|
std::vector<ChatRestrictions> ListOfRestrictions() {
|
||||||
|
@ -191,6 +191,7 @@ public:
|
|||||||
[[nodiscard]] bool canRevokeFullHistory() const;
|
[[nodiscard]] bool canRevokeFullHistory() const;
|
||||||
[[nodiscard]] bool slowmodeApplied() const;
|
[[nodiscard]] bool slowmodeApplied() const;
|
||||||
[[nodiscard]] int slowmodeSecondsLeft() const;
|
[[nodiscard]] int slowmodeSecondsLeft() const;
|
||||||
|
[[nodiscard]] bool canSendPolls() const;
|
||||||
|
|
||||||
[[nodiscard]] UserData *asUser();
|
[[nodiscard]] UserData *asUser();
|
||||||
[[nodiscard]] const UserData *asUser() const;
|
[[nodiscard]] const UserData *asUser() const;
|
||||||
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "media/clip/media_clip_reader.h"
|
#include "media/clip/media_clip_reader.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
#include "window/window_peer_menu.h"
|
||||||
#include "history/history_item_components.h"
|
#include "history/history_item_components.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
@ -115,6 +116,19 @@ void activateBotCommand(
|
|||||||
}));
|
}));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case ButtonType::RequestPoll: {
|
||||||
|
hideSingleUseKeyboard(msg);
|
||||||
|
auto chosen = PollData::Flags();
|
||||||
|
auto disabled = PollData::Flags();
|
||||||
|
if (!button->data.isEmpty()) {
|
||||||
|
disabled |= PollData::Flag::Quiz;
|
||||||
|
if (button->data[0]) {
|
||||||
|
chosen |= PollData::Flag::Quiz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Window::PeerMenuCreatePoll(msg->history()->peer, chosen, disabled);
|
||||||
|
} break;
|
||||||
|
|
||||||
case ButtonType::SwitchInlineSame:
|
case ButtonType::SwitchInlineSame:
|
||||||
case ButtonType::SwitchInline: {
|
case ButtonType::SwitchInline: {
|
||||||
if (auto m = App::main()) {
|
if (auto m = App::main()) {
|
||||||
|
@ -843,6 +843,21 @@ void HistoryMessageReplyMarkup::createFromButtonRows(
|
|||||||
}, [&](const MTPDinputKeyboardButtonUrlAuth &data) {
|
}, [&](const MTPDinputKeyboardButtonUrlAuth &data) {
|
||||||
LOG(("API Error: inputKeyboardButtonUrlAuth received."));
|
LOG(("API Error: inputKeyboardButtonUrlAuth received."));
|
||||||
// Should not get those for the users.
|
// Should not get those for the users.
|
||||||
|
}, [&](const MTPDkeyboardButtonRequestPoll &data) {
|
||||||
|
const auto quiz = [&] {
|
||||||
|
if (!data.vquiz()) {
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
return data.vquiz()->match([&](const MTPDboolTrue&) {
|
||||||
|
return QByteArray(1, 1);
|
||||||
|
}, [&](const MTPDboolFalse&) {
|
||||||
|
return QByteArray(1, 0);
|
||||||
|
});
|
||||||
|
}();
|
||||||
|
row.emplace_back(
|
||||||
|
Type::RequestPoll,
|
||||||
|
qs(data.vtext()),
|
||||||
|
quiz);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!row.empty()) {
|
if (!row.empty()) {
|
||||||
|
@ -164,6 +164,7 @@ struct HistoryMessageMarkupButton {
|
|||||||
Callback,
|
Callback,
|
||||||
RequestPhone,
|
RequestPhone,
|
||||||
RequestLocation,
|
RequestLocation,
|
||||||
|
RequestPoll,
|
||||||
SwitchInline,
|
SwitchInline,
|
||||||
SwitchInlineSame,
|
SwitchInlineSame,
|
||||||
Game,
|
Game,
|
||||||
|
@ -413,6 +413,11 @@ void Filler::addUserActions(not_null<UserData*> user) {
|
|||||||
tr::lng_profile_invite_to_group(tr::now),
|
tr::lng_profile_invite_to_group(tr::now),
|
||||||
[=] { AddBotToGroup::Start(controller, user); });
|
[=] { AddBotToGroup::Start(controller, user); });
|
||||||
}
|
}
|
||||||
|
if (user->canSendPolls()) {
|
||||||
|
_addAction(
|
||||||
|
tr::lng_polls_create(tr::now),
|
||||||
|
[=] { PeerMenuCreatePoll(user); });
|
||||||
|
}
|
||||||
if (user->canExportChatHistory()) {
|
if (user->canExportChatHistory()) {
|
||||||
_addAction(
|
_addAction(
|
||||||
tr::lng_profile_export_chat(tr::now),
|
tr::lng_profile_export_chat(tr::now),
|
||||||
@ -707,12 +712,18 @@ void PeerMenuShareContactBox(
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerMenuCreatePoll(not_null<PeerData*> peer) {
|
void PeerMenuCreatePoll(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
PollData::Flags chosen,
|
||||||
|
PollData::Flags disabled) {
|
||||||
|
if (peer->isChannel() && !peer->isMegagroup()) {
|
||||||
|
chosen &= ~PollData::Flag::PublicVotes;
|
||||||
|
disabled |= PollData::Flag::PublicVotes;
|
||||||
|
}
|
||||||
const auto box = Ui::show(Box<CreatePollBox>(
|
const auto box = Ui::show(Box<CreatePollBox>(
|
||||||
&peer->session(),
|
&peer->session(),
|
||||||
((peer->isChannel() && !peer->isMegagroup())
|
chosen,
|
||||||
? CreatePollBox::PublicVotes::Disabled
|
disabled,
|
||||||
: CreatePollBox::PublicVotes::Enabled),
|
|
||||||
Api::SendType::Normal));
|
Api::SendType::Normal));
|
||||||
const auto lock = box->lifetime().make_state<bool>(false);
|
const auto lock = box->lifetime().make_state<bool>(false);
|
||||||
box->submitRequests(
|
box->submitRequests(
|
||||||
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "data/data_poll.h"
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -58,7 +60,10 @@ void PeerMenuAddChannelMembers(
|
|||||||
not_null<Window::SessionNavigation*> navigation,
|
not_null<Window::SessionNavigation*> navigation,
|
||||||
not_null<ChannelData*> channel);
|
not_null<ChannelData*> channel);
|
||||||
//void PeerMenuUngroupFeed(not_null<Data::Feed*> feed); // #feed
|
//void PeerMenuUngroupFeed(not_null<Data::Feed*> feed); // #feed
|
||||||
void PeerMenuCreatePoll(not_null<PeerData*> peer);
|
void PeerMenuCreatePoll(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
PollData::Flags chosen = PollData::Flags(),
|
||||||
|
PollData::Flags disabled = PollData::Flags());
|
||||||
void PeerMenuBlockUserBox(
|
void PeerMenuBlockUserBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
|
Loading…
Reference in New Issue
Block a user