bot_attach_web_view.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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. #pragma once
  8. #include "api/api_common.h"
  9. #include "base/flags.h"
  10. #include "base/timer.h"
  11. #include "base/weak_ptr.h"
  12. #include "dialogs/dialogs_key.h"
  13. #include "mtproto/sender.h"
  14. #include "ui/chat/attach/attach_bot_webview.h"
  15. #include "ui/rp_widget.h"
  16. namespace Data {
  17. class Thread;
  18. } // namespace Data
  19. namespace Ui {
  20. class Show;
  21. class GenericBox;
  22. class DropdownMenu;
  23. } // namespace Ui
  24. namespace Ui::BotWebView {
  25. class Panel;
  26. struct DownloadsEntry;
  27. } // namespace Ui::BotWebView
  28. namespace Main {
  29. class Session;
  30. class SessionShow;
  31. } // namespace Main
  32. namespace Window {
  33. class SessionController;
  34. } // namespace Window
  35. namespace Data {
  36. class DocumentMedia;
  37. } // namespace Data
  38. namespace Payments {
  39. struct NonPanelPaymentForm;
  40. enum class CheckoutResult;
  41. } // namespace Payments
  42. namespace InlineBots {
  43. class WebViewInstance;
  44. class Downloads;
  45. enum class PeerType : uint8 {
  46. SameBot = 0x01,
  47. Bot = 0x02,
  48. User = 0x04,
  49. Group = 0x08,
  50. Broadcast = 0x10,
  51. };
  52. using PeerTypes = base::flags<PeerType>;
  53. [[nodiscard]] bool PeerMatchesTypes(
  54. not_null<PeerData*> peer,
  55. not_null<UserData*> bot,
  56. PeerTypes types);
  57. [[nodiscard]] PeerTypes ParseChooseTypes(QStringView choose);
  58. struct AttachWebViewBot {
  59. not_null<UserData*> user;
  60. DocumentData *icon = nullptr;
  61. std::shared_ptr<Data::DocumentMedia> media;
  62. QString name;
  63. PeerTypes types = 0;
  64. bool inactive : 1 = false;
  65. bool inMainMenu : 1 = false;
  66. bool inAttachMenu : 1 = false;
  67. bool disclaimerRequired : 1 = false;
  68. bool requestWriteAccess : 1 = false;
  69. };
  70. struct WebViewSourceButton {
  71. bool simple = false;
  72. friend inline bool operator==(
  73. WebViewSourceButton,
  74. WebViewSourceButton) = default;
  75. };
  76. struct WebViewSourceSwitch {
  77. friend inline bool operator==(
  78. const WebViewSourceSwitch &,
  79. const WebViewSourceSwitch &) = default;
  80. };
  81. struct WebViewSourceLinkApp { // t.me/botusername/appname
  82. base::weak_ptr<WebViewInstance> from;
  83. QString appname;
  84. QString token;
  85. friend inline bool operator==(
  86. const WebViewSourceLinkApp &,
  87. const WebViewSourceLinkApp &) = default;
  88. };
  89. struct WebViewSourceLinkAttachMenu { // ?startattach
  90. base::weak_ptr<WebViewInstance> from;
  91. base::weak_ptr<Data::Thread> thread;
  92. PeerTypes choose;
  93. QString token;
  94. friend inline bool operator==(
  95. const WebViewSourceLinkAttachMenu &,
  96. const WebViewSourceLinkAttachMenu &) = default;
  97. };
  98. struct WebViewSourceLinkBotProfile { // t.me/botusername?startapp
  99. base::weak_ptr<WebViewInstance> from;
  100. QString token;
  101. bool compact = false;
  102. friend inline bool operator==(
  103. const WebViewSourceLinkBotProfile &,
  104. const WebViewSourceLinkBotProfile &) = default;
  105. };
  106. struct WebViewSourceMainMenu {
  107. friend inline bool operator==(
  108. WebViewSourceMainMenu,
  109. WebViewSourceMainMenu) = default;
  110. };
  111. struct WebViewSourceAttachMenu {
  112. base::weak_ptr<Data::Thread> thread;
  113. friend inline bool operator==(
  114. const WebViewSourceAttachMenu &,
  115. const WebViewSourceAttachMenu &) = default;
  116. };
  117. struct WebViewSourceBotMenu {
  118. friend inline bool operator==(
  119. WebViewSourceBotMenu,
  120. WebViewSourceBotMenu) = default;
  121. };
  122. struct WebViewSourceGame {
  123. FullMsgId messageId;
  124. QString title;
  125. friend inline bool operator==(
  126. WebViewSourceGame,
  127. WebViewSourceGame) = default;
  128. };
  129. struct WebViewSourceBotProfile {
  130. friend inline bool operator==(
  131. WebViewSourceBotProfile,
  132. WebViewSourceBotProfile) = default;
  133. };
  134. struct WebViewSource : std::variant<
  135. WebViewSourceButton,
  136. WebViewSourceSwitch,
  137. WebViewSourceLinkApp,
  138. WebViewSourceLinkAttachMenu,
  139. WebViewSourceLinkBotProfile,
  140. WebViewSourceMainMenu,
  141. WebViewSourceAttachMenu,
  142. WebViewSourceBotMenu,
  143. WebViewSourceGame,
  144. WebViewSourceBotProfile> {
  145. using variant::variant;
  146. };
  147. struct WebViewButton {
  148. QString text;
  149. QString startCommand;
  150. QByteArray url;
  151. bool fromAttachMenu = false;
  152. bool fromMainMenu = false;
  153. bool fromSwitch = false;
  154. };
  155. struct WebViewContext {
  156. base::weak_ptr<Window::SessionController> controller;
  157. Dialogs::EntryState dialogsEntryState;
  158. std::optional<Api::SendAction> action;
  159. bool fullscreen = false;
  160. bool maySkipConfirmation = false;
  161. };
  162. struct WebViewDescriptor {
  163. not_null<UserData*> bot;
  164. std::shared_ptr<Ui::Show> parentShow;
  165. WebViewContext context;
  166. WebViewButton button;
  167. WebViewSource source;
  168. };
  169. class WebViewInstance final
  170. : public base::has_weak_ptr
  171. , public Ui::BotWebView::Delegate {
  172. public:
  173. explicit WebViewInstance(WebViewDescriptor &&descriptor);
  174. ~WebViewInstance();
  175. [[nodiscard]] Main::Session &session() const;
  176. [[nodiscard]] not_null<UserData*> bot() const;
  177. [[nodiscard]] WebViewSource source() const;
  178. void activate();
  179. void close();
  180. [[nodiscard]] std::shared_ptr<Main::SessionShow> uiShow();
  181. private:
  182. void resolve();
  183. bool openAppFromBotMenuLink();
  184. void requestButton();
  185. void requestSimple();
  186. void requestMain();
  187. void requestApp(bool allowWrite);
  188. void requestWithMainMenuDisclaimer();
  189. void requestWithMenuAdd();
  190. void maybeChooseAndRequestButton(PeerTypes supported);
  191. enum class ConfirmType : uchar {
  192. Always,
  193. Once,
  194. None,
  195. };
  196. void resolveApp(
  197. const QString &appname,
  198. const QString &startparam,
  199. ConfirmType confirmType);
  200. void confirmOpen(Fn<void()> done);
  201. void confirmAppOpen(
  202. bool writeAccess,
  203. Fn<void(bool allowWrite)> done,
  204. bool forceConfirmation);
  205. struct ShowArgs {
  206. QString url;
  207. QString title;
  208. uint64 queryId = 0;
  209. bool fullscreen = false;
  210. };
  211. void show(ShowArgs &&args);
  212. void showGame();
  213. void started(uint64 queryId);
  214. auto nonPanelPaymentFormFactory(
  215. Fn<void(Payments::CheckoutResult)> reactivate)
  216. -> Fn<void(Payments::NonPanelPaymentForm)>;
  217. Webview::ThemeParams botThemeParams() override;
  218. auto botDownloads(bool forceCheck = false)
  219. -> const std::vector<Ui::BotWebView::DownloadsEntry> & override;
  220. void botDownloadsAction(
  221. uint32 id,
  222. Ui::BotWebView::DownloadsAction type) override;
  223. bool botHandleLocalUri(QString uri, bool keepOpen) override;
  224. void botHandleInvoice(QString slug) override;
  225. void botHandleMenuButton(Ui::BotWebView::MenuButton button) override;
  226. bool botValidateExternalLink(QString uri) override;
  227. void botOpenIvLink(QString uri) override;
  228. void botSendData(QByteArray data) override;
  229. void botSwitchInlineQuery(
  230. std::vector<QString> chatTypes,
  231. QString query) override;
  232. void botCheckWriteAccess(Fn<void(bool allowed)> callback) override;
  233. void botAllowWriteAccess(Fn<void(bool allowed)> callback) override;
  234. void botRequestEmojiStatusAccess(
  235. Fn<void(bool allowed)> callback) override;
  236. void botSharePhone(Fn<void(bool shared)> callback) override;
  237. void botInvokeCustomMethod(
  238. Ui::BotWebView::CustomMethodRequest request) override;
  239. void botSendPreparedMessage(
  240. Ui::BotWebView::SendPreparedMessageRequest request) override;
  241. void botSetEmojiStatus(
  242. Ui::BotWebView::SetEmojiStatusRequest request) override;
  243. void botDownloadFile(
  244. Ui::BotWebView::DownloadFileRequest request) override;
  245. void botOpenPrivacyPolicy() override;
  246. void botClose() override;
  247. const std::shared_ptr<Ui::Show> _parentShow;
  248. const not_null<Main::Session*> _session;
  249. const not_null<UserData*> _bot;
  250. const WebViewContext _context;
  251. const WebViewButton _button;
  252. const WebViewSource _source;
  253. BotAppData *_app = nullptr;
  254. QString _appStartParam;
  255. bool _dataSent = false;
  256. bool _confirmingDownload = false;
  257. mtpRequestId _requestId = 0;
  258. mtpRequestId _prolongId = 0;
  259. QString _panelUrl;
  260. std::unique_ptr<Ui::BotWebView::Panel> _panel;
  261. rpl::lifetime _lifetime;
  262. static base::weak_ptr<WebViewInstance> PendingActivation;
  263. };
  264. class AttachWebView final : public base::has_weak_ptr {
  265. public:
  266. explicit AttachWebView(not_null<Main::Session*> session);
  267. ~AttachWebView();
  268. [[nodiscard]] Downloads &downloads() const {
  269. return *_downloads;
  270. }
  271. void open(WebViewDescriptor &&descriptor);
  272. void openByUsername(
  273. not_null<Window::SessionController*> controller,
  274. const Api::SendAction &action,
  275. const QString &botUsername,
  276. const QString &startCommand,
  277. bool fullscreen);
  278. void cancel();
  279. void requestBots(Fn<void()> callback = nullptr);
  280. [[nodiscard]] const std::vector<AttachWebViewBot> &attachBots() const {
  281. return _attachBots;
  282. }
  283. [[nodiscard]] rpl::producer<> attachBotsUpdates() const {
  284. return _attachBotsUpdates.events();
  285. }
  286. void notifyBotIconLoaded() {
  287. _attachBotsUpdates.fire({});
  288. }
  289. [[nodiscard]] bool disclaimerAccepted(
  290. const AttachWebViewBot &bot) const;
  291. [[nodiscard]] bool showMainMenuNewBadge(
  292. const AttachWebViewBot &bot) const;
  293. void removeFromMenu(
  294. std::shared_ptr<Ui::Show> show,
  295. not_null<UserData*> bot);
  296. enum class AddToMenuResult {
  297. AlreadyInMenu,
  298. Added,
  299. Unsupported,
  300. Cancelled,
  301. };
  302. void requestAddToMenu(
  303. not_null<UserData*> bot,
  304. Fn<void(AddToMenuResult, PeerTypes supported)> done);
  305. void acceptMainMenuDisclaimer(
  306. std::shared_ptr<Ui::Show> show,
  307. not_null<UserData*> bot,
  308. Fn<void(AddToMenuResult, PeerTypes supported)> done);
  309. void close(not_null<WebViewInstance*> instance);
  310. void closeAll();
  311. void loadPopularAppBots();
  312. [[nodiscard]] auto popularAppBots() const
  313. -> const std::vector<not_null<UserData*>> &;
  314. [[nodiscard]] rpl::producer<> popularAppBotsLoaded() const;
  315. private:
  316. void resolveUsername(
  317. std::shared_ptr<Ui::Show> show,
  318. Fn<void(not_null<PeerData*>)> done);
  319. enum class ToggledState {
  320. Removed,
  321. Added,
  322. AllowedToWrite,
  323. };
  324. void toggleInMenu(
  325. not_null<UserData*> bot,
  326. ToggledState state,
  327. Fn<void(bool success)> callback = nullptr);
  328. void confirmAddToMenu(
  329. AttachWebViewBot bot,
  330. Fn<void(bool added)> callback = nullptr);
  331. const not_null<Main::Session*> _session;
  332. const std::unique_ptr<Downloads> _downloads;
  333. base::Timer _refreshTimer;
  334. QString _botUsername;
  335. QString _startCommand;
  336. bool _fullScreenRequested = false;
  337. mtpRequestId _requestId = 0;
  338. uint64 _botsHash = 0;
  339. mtpRequestId _botsRequestId = 0;
  340. std::vector<Fn<void()>> _botsRequestCallbacks;
  341. struct AddToMenuProcess {
  342. mtpRequestId requestId = 0;
  343. std::vector<Fn<void(AddToMenuResult, PeerTypes supported)>> done;
  344. };
  345. base::flat_map<not_null<UserData*>, AddToMenuProcess> _addToMenu;
  346. std::vector<AttachWebViewBot> _attachBots;
  347. rpl::event_stream<> _attachBotsUpdates;
  348. base::flat_set<not_null<UserData*>> _disclaimerAccepted;
  349. std::vector<std::unique_ptr<WebViewInstance>> _instances;
  350. std::vector<not_null<UserData*>> _popularAppBots;
  351. mtpRequestId _popularAppBotsRequestId = 0;
  352. rpl::variable<bool> _popularAppBotsLoaded = false;
  353. };
  354. [[nodiscard]] std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
  355. not_null<QWidget*> parent,
  356. not_null<Window::SessionController*> controller,
  357. not_null<PeerData*> peer,
  358. Fn<Api::SendAction()> actionFactory,
  359. Fn<void(bool)> attach);
  360. class MenuBotIcon final : public Ui::RpWidget {
  361. public:
  362. MenuBotIcon(
  363. QWidget *parent,
  364. std::shared_ptr<Data::DocumentMedia> media);
  365. private:
  366. void paintEvent(QPaintEvent *e) override;
  367. void validate();
  368. std::shared_ptr<Data::DocumentMedia> _media;
  369. QImage _image;
  370. QImage _mask;
  371. };
  372. } // namespace InlineBots