verify_peers_box.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "boxes/peers/verify_peers_box.h"
  8. #include "apiwrap.h"
  9. #include "boxes/peer_list_controllers.h"
  10. #include "data/data_user.h"
  11. #include "history/history.h"
  12. #include "main/main_app_config.h"
  13. #include "main/main_session.h"
  14. #include "ui/boxes/confirm_box.h"
  15. #include "ui/text/text_utilities.h"
  16. #include "ui/toast/toast.h"
  17. #include "ui/widgets/fields/input_field.h"
  18. #include "ui/vertical_list.h"
  19. #include "window/window_session_controller.h"
  20. #include "styles/style_boxes.h"
  21. #include "styles/style_layers.h"
  22. namespace {
  23. constexpr auto kSetupVerificationToastDuration = 4 * crl::time(1000);
  24. class Controller final : public ChatsListBoxController {
  25. public:
  26. Controller(not_null<Main::Session*> session, not_null<UserData*> bot)
  27. : ChatsListBoxController(session)
  28. , _bot(bot) {
  29. }
  30. Main::Session &session() const override;
  31. void rowClicked(gsl::not_null<PeerListRow*> row) override;
  32. private:
  33. std::unique_ptr<Row> createRow(not_null<History*> history) override;
  34. void prepareViewHook() override;
  35. void confirmAdd(not_null<PeerData*> peer);
  36. void confirmRemove(not_null<PeerData*> peer);
  37. const not_null<UserData*> _bot;
  38. };
  39. void Setup(
  40. not_null<UserData*> bot,
  41. not_null<PeerData*> peer,
  42. QString description,
  43. Fn<void(QString)> done) {
  44. using Flag = MTPbots_SetCustomVerification::Flag;
  45. bot->session().api().request(MTPbots_SetCustomVerification(
  46. MTP_flags(Flag::f_bot
  47. | Flag::f_enabled
  48. | (description.isEmpty() ? Flag() : Flag::f_custom_description)),
  49. bot->inputUser,
  50. peer->input,
  51. MTP_string(description)
  52. )).done([=] {
  53. done(QString());
  54. }).fail([=](const MTP::Error &error) {
  55. done(error.type());
  56. }).send();
  57. }
  58. void Remove(
  59. not_null<UserData*> bot,
  60. not_null<PeerData*> peer,
  61. Fn<void(QString)> done) {
  62. bot->session().api().request(MTPbots_SetCustomVerification(
  63. MTP_flags(MTPbots_SetCustomVerification::Flag::f_bot),
  64. bot->inputUser,
  65. peer->input,
  66. MTPstring()
  67. )).done([=] {
  68. done(QString());
  69. }).fail([=](const MTP::Error &error) {
  70. done(error.type());
  71. }).send();
  72. }
  73. Main::Session &Controller::session() const {
  74. return _bot->session();
  75. }
  76. void Controller::rowClicked(gsl::not_null<PeerListRow*> row) {
  77. const auto peer = row->peer();
  78. const auto details = peer->botVerifyDetails();
  79. const auto already = details && (details->botId == peerToUser(_bot->id));
  80. if (already) {
  81. confirmRemove(peer);
  82. } else {
  83. confirmAdd(peer);
  84. }
  85. }
  86. void Controller::confirmAdd(not_null<PeerData*> peer) {
  87. const auto bot = _bot;
  88. const auto show = delegate()->peerListUiShow();
  89. show->show(Box([=](not_null<Ui::GenericBox*> box) {
  90. struct State {
  91. Ui::InputField *field = nullptr;
  92. QString description;
  93. bool sent = false;
  94. };
  95. const auto settings = bot->botInfo
  96. ? bot->botInfo->verifierSettings.get()
  97. : nullptr;
  98. const auto modify = settings && settings->canModifyDescription;
  99. const auto state = std::make_shared<State>(State{
  100. .description = settings ? settings->customDescription : QString()
  101. });
  102. const auto limit = session().appConfig().get<int>(
  103. u"bot_verification_description_length_limit"_q,
  104. 70);
  105. const auto send = [=] {
  106. if (modify && state->description.size() > limit) {
  107. state->field->showError();
  108. return;
  109. } else if (state->sent) {
  110. return;
  111. }
  112. state->sent = true;
  113. const auto weak = Ui::MakeWeak(box);
  114. const auto description = modify ? state->description : QString();
  115. Setup(bot, peer, description, [=](QString error) {
  116. if (error.isEmpty()) {
  117. if (const auto strong = weak.data()) {
  118. strong->closeBox();
  119. }
  120. show->showToast({
  121. .text = PeerVerifyPhrases(peer).sent(
  122. tr::now,
  123. lt_name,
  124. Ui::Text::Bold(peer->shortName()),
  125. Ui::Text::WithEntities),
  126. .duration = kSetupVerificationToastDuration,
  127. });
  128. } else {
  129. state->sent = false;
  130. show->showToast(error);
  131. }
  132. });
  133. };
  134. const auto phrases = PeerVerifyPhrases(peer);
  135. Ui::ConfirmBox(box, {
  136. .text = phrases.text(
  137. lt_name,
  138. rpl::single(Ui::Text::Bold(peer->shortName())),
  139. Ui::Text::WithEntities),
  140. .confirmed = send,
  141. .confirmText = phrases.submit(),
  142. .title = phrases.title(),
  143. });
  144. if (!modify) {
  145. return;
  146. }
  147. Ui::AddSubsectionTitle(
  148. box->verticalLayout(),
  149. tr::lng_bot_verify_description_label(),
  150. QMargins(0, 0, 0, -st::defaultSubsectionTitlePadding.bottom()));
  151. const auto field = box->addRow(object_ptr<Ui::InputField>(
  152. box,
  153. st::createPollField,
  154. Ui::InputField::Mode::NoNewlines,
  155. rpl::single(state->description),
  156. state->description
  157. ), st::createPollFieldPadding);
  158. state->field = field;
  159. box->setFocusCallback([=] {
  160. field->setFocusFast();
  161. });
  162. Ui::AddSkip(box->verticalLayout());
  163. field->changes() | rpl::start_with_next([=] {
  164. state->description = field->getLastText();
  165. }, field->lifetime());
  166. field->setMaxLength(limit * 2);
  167. Ui::AddLengthLimitLabel(field, limit, std::nullopt);
  168. Ui::AddDividerText(box->verticalLayout(), phrases.about());
  169. }));
  170. }
  171. void Controller::confirmRemove(not_null<PeerData*> peer) {
  172. const auto bot = _bot;
  173. const auto show = delegate()->peerListUiShow();
  174. show->show(Box([=](not_null<Ui::GenericBox*> box) {
  175. const auto sent = std::make_shared<bool>();
  176. const auto send = [=] {
  177. if (*sent) {
  178. return;
  179. }
  180. *sent = true;
  181. const auto weak = Ui::MakeWeak(box);
  182. Remove(bot, peer, [=](QString error) {
  183. if (error.isEmpty()) {
  184. if (const auto strong = weak.data()) {
  185. strong->closeBox();
  186. }
  187. show->showToast(tr::lng_bot_verify_remove_done(tr::now));
  188. } else {
  189. *sent = false;
  190. show->showToast(error);
  191. }
  192. });
  193. };
  194. Ui::ConfirmBox(box, {
  195. .text = PeerVerifyPhrases(peer).remove(),
  196. .confirmed = send,
  197. .confirmText = tr::lng_bot_verify_remove_submit(),
  198. .confirmStyle = &st::attentionBoxButton,
  199. .title = tr::lng_bot_verify_remove_title(),
  200. });
  201. }));
  202. }
  203. auto Controller::createRow(not_null<History*> history)
  204. -> std::unique_ptr<Row> {
  205. const auto peer = history->peer;
  206. const auto may = peer->isUser() || peer->isChannel();
  207. return may ? std::make_unique<Row>(history) : nullptr;
  208. }
  209. void Controller::prepareViewHook() {
  210. }
  211. } // namespace
  212. object_ptr<Ui::BoxContent> MakeVerifyPeersBox(
  213. not_null<Window::SessionController*> window,
  214. not_null<UserData*> bot) {
  215. const auto session = &window->session();
  216. auto controller = std::make_unique<Controller>(session, bot);
  217. auto init = [=](not_null<PeerListBox*> box) {
  218. box->setTitle(tr::lng_bot_verify_title());
  219. box->addButton(tr::lng_box_done(), [=] {
  220. box->closeBox();
  221. });
  222. };
  223. return Box<PeerListBox>(std::move(controller), std::move(init));
  224. }
  225. BotVerifyPhrases PeerVerifyPhrases(not_null<PeerData*> peer) {
  226. if (const auto user = peer->asUser()) {
  227. if (user->isBot()) {
  228. return {
  229. .title = tr::lng_bot_verify_bot_title,
  230. .text = tr::lng_bot_verify_bot_text,
  231. .about = tr::lng_bot_verify_bot_about,
  232. .submit = tr::lng_bot_verify_bot_submit,
  233. .sent = tr::lng_bot_verify_bot_sent,
  234. .remove = tr::lng_bot_verify_bot_remove,
  235. };
  236. } else {
  237. return {
  238. .title = tr::lng_bot_verify_user_title,
  239. .text = tr::lng_bot_verify_user_text,
  240. .about = tr::lng_bot_verify_user_about,
  241. .submit = tr::lng_bot_verify_user_submit,
  242. .sent = tr::lng_bot_verify_user_sent,
  243. .remove = tr::lng_bot_verify_user_remove,
  244. };
  245. }
  246. } else if (peer->isBroadcast()) {
  247. return {
  248. .title = tr::lng_bot_verify_channel_title,
  249. .text = tr::lng_bot_verify_channel_text,
  250. .about = tr::lng_bot_verify_channel_about,
  251. .submit = tr::lng_bot_verify_channel_submit,
  252. .sent = tr::lng_bot_verify_channel_sent,
  253. .remove = tr::lng_bot_verify_channel_remove,
  254. };
  255. }
  256. return {
  257. .title = tr::lng_bot_verify_group_title,
  258. .text = tr::lng_bot_verify_group_text,
  259. .about = tr::lng_bot_verify_group_about,
  260. .submit = tr::lng_bot_verify_group_submit,
  261. .sent = tr::lng_bot_verify_group_sent,
  262. .remove = tr::lng_bot_verify_group_remove,
  263. };
  264. }