info_controller.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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 "info/info_controller.h"
  8. #include "ui/search_field_controller.h"
  9. #include "data/data_shared_media.h"
  10. #include "info/info_content_widget.h"
  11. #include "info/info_memento.h"
  12. #include "info/global_media/info_global_media_widget.h"
  13. #include "info/media/info_media_widget.h"
  14. #include "core/application.h"
  15. #include "data/data_changes.h"
  16. #include "data/data_peer.h"
  17. #include "data/data_channel.h"
  18. #include "data/data_chat.h"
  19. #include "data/data_forum_topic.h"
  20. #include "data/data_forum.h"
  21. #include "data/data_session.h"
  22. #include "data/data_media_types.h"
  23. #include "data/data_download_manager.h"
  24. #include "history/history_item.h"
  25. #include "main/main_session.h"
  26. #include "window/window_session_controller.h"
  27. namespace Info {
  28. Key::Key(not_null<PeerData*> peer) : _value(peer) {
  29. }
  30. Key::Key(not_null<Data::ForumTopic*> topic) : _value(topic) {
  31. }
  32. Key::Key(Settings::Tag settings) : _value(settings) {
  33. }
  34. Key::Key(Downloads::Tag downloads) : _value(downloads) {
  35. }
  36. Key::Key(Stories::Tag stories) : _value(stories) {
  37. }
  38. Key::Key(Statistics::Tag statistics) : _value(statistics) {
  39. }
  40. Key::Key(BotStarRef::Tag starref) : _value(starref) {
  41. }
  42. Key::Key(GlobalMedia::Tag global) : _value(global) {
  43. }
  44. Key::Key(not_null<PollData*> poll, FullMsgId contextId)
  45. : _value(PollKey{ poll, contextId }) {
  46. }
  47. Key::Key(
  48. std::shared_ptr<Api::WhoReadList> whoReadIds,
  49. Data::ReactionId selected,
  50. FullMsgId contextId)
  51. : _value(ReactionsKey{ whoReadIds, selected, contextId }) {
  52. }
  53. PeerData *Key::peer() const {
  54. if (const auto peer = std::get_if<not_null<PeerData*>>(&_value)) {
  55. return *peer;
  56. } else if (const auto topic = this->topic()) {
  57. return topic->channel();
  58. }
  59. return nullptr;
  60. }
  61. Data::ForumTopic *Key::topic() const {
  62. if (const auto topic = std::get_if<not_null<Data::ForumTopic*>>(
  63. &_value)) {
  64. return *topic;
  65. }
  66. return nullptr;
  67. }
  68. UserData *Key::settingsSelf() const {
  69. if (const auto tag = std::get_if<Settings::Tag>(&_value)) {
  70. return tag->self;
  71. }
  72. return nullptr;
  73. }
  74. bool Key::isDownloads() const {
  75. return v::is<Downloads::Tag>(_value);
  76. }
  77. bool Key::isGlobalMedia() const {
  78. return v::is<GlobalMedia::Tag>(_value);
  79. }
  80. PeerData *Key::storiesPeer() const {
  81. if (const auto tag = std::get_if<Stories::Tag>(&_value)) {
  82. return tag->peer;
  83. }
  84. return nullptr;
  85. }
  86. Stories::Tab Key::storiesTab() const {
  87. if (const auto tag = std::get_if<Stories::Tag>(&_value)) {
  88. return tag->tab;
  89. }
  90. return Stories::Tab();
  91. }
  92. Statistics::Tag Key::statisticsTag() const {
  93. if (const auto tag = std::get_if<Statistics::Tag>(&_value)) {
  94. return *tag;
  95. }
  96. return Statistics::Tag();
  97. }
  98. PeerData *Key::starrefPeer() const {
  99. if (const auto tag = std::get_if<BotStarRef::Tag>(&_value)) {
  100. return tag->peer;
  101. }
  102. return nullptr;
  103. }
  104. BotStarRef::Type Key::starrefType() const {
  105. if (const auto tag = std::get_if<BotStarRef::Tag>(&_value)) {
  106. return tag->type;
  107. }
  108. return BotStarRef::Type();
  109. }
  110. PollData *Key::poll() const {
  111. if (const auto data = std::get_if<PollKey>(&_value)) {
  112. return data->poll;
  113. }
  114. return nullptr;
  115. }
  116. FullMsgId Key::pollContextId() const {
  117. if (const auto data = std::get_if<PollKey>(&_value)) {
  118. return data->contextId;
  119. }
  120. return FullMsgId();
  121. }
  122. std::shared_ptr<Api::WhoReadList> Key::reactionsWhoReadIds() const {
  123. if (const auto data = std::get_if<ReactionsKey>(&_value)) {
  124. return data->whoReadIds;
  125. }
  126. return nullptr;
  127. }
  128. Data::ReactionId Key::reactionsSelected() const {
  129. if (const auto data = std::get_if<ReactionsKey>(&_value)) {
  130. return data->selected;
  131. }
  132. return Data::ReactionId();
  133. }
  134. FullMsgId Key::reactionsContextId() const {
  135. if (const auto data = std::get_if<ReactionsKey>(&_value)) {
  136. return data->contextId;
  137. }
  138. return FullMsgId();
  139. }
  140. rpl::producer<SparseIdsMergedSlice> AbstractController::mediaSource(
  141. SparseIdsMergedSlice::UniversalMsgId aroundId,
  142. int limitBefore,
  143. int limitAfter) const {
  144. Expects(peer() != nullptr);
  145. const auto isScheduled = [&] {
  146. const auto peerId = peer()->id;
  147. if (const auto item = session().data().message(peerId, aroundId)) {
  148. return item->isScheduled();
  149. }
  150. return false;
  151. }();
  152. const auto mediaViewer = isScheduled
  153. ? SharedScheduledMediaViewer
  154. : SharedMediaMergedViewer;
  155. const auto topicId = isScheduled
  156. ? SparseIdsMergedSlice::kScheduledTopicId
  157. : topic()
  158. ? topic()->rootId()
  159. : MsgId(0);
  160. return mediaViewer(
  161. &session(),
  162. SharedMediaMergedKey(
  163. SparseIdsMergedSlice::Key(
  164. peer()->id,
  165. topicId,
  166. migratedPeerId(),
  167. aroundId),
  168. section().mediaType()),
  169. limitBefore,
  170. limitAfter);
  171. }
  172. rpl::producer<QString> AbstractController::mediaSourceQueryValue() const {
  173. return rpl::single(QString());
  174. }
  175. rpl::producer<QString> AbstractController::searchQueryValue() const {
  176. return rpl::single(QString());
  177. }
  178. AbstractController::AbstractController(
  179. not_null<Window::SessionController*> parent)
  180. : SessionNavigation(&parent->session())
  181. , _parent(parent) {
  182. }
  183. PeerData *AbstractController::peer() const {
  184. return key().peer();
  185. }
  186. PeerId AbstractController::migratedPeerId() const {
  187. if (const auto peer = migrated()) {
  188. return peer->id;
  189. }
  190. return PeerId(0);
  191. }
  192. PollData *AbstractController::poll() const {
  193. if (const auto item = session().data().message(pollContextId())) {
  194. if (const auto media = item->media()) {
  195. return media->poll();
  196. }
  197. }
  198. return nullptr;
  199. }
  200. auto AbstractController::reactionsWhoReadIds() const
  201. -> std::shared_ptr<Api::WhoReadList> {
  202. return key().reactionsWhoReadIds();
  203. }
  204. Data::ReactionId AbstractController::reactionsSelected() const {
  205. return key().reactionsSelected();
  206. }
  207. FullMsgId AbstractController::reactionsContextId() const {
  208. return key().reactionsContextId();
  209. }
  210. void AbstractController::showSection(
  211. std::shared_ptr<Window::SectionMemento> memento,
  212. const Window::SectionShow &params) {
  213. return parentController()->showSection(std::move(memento), params);
  214. }
  215. void AbstractController::showBackFromStack(
  216. const Window::SectionShow &params) {
  217. return parentController()->showBackFromStack(params);
  218. }
  219. void AbstractController::showPeerHistory(
  220. PeerId peerId,
  221. const Window::SectionShow &params,
  222. MsgId msgId) {
  223. return parentController()->showPeerHistory(peerId, params, msgId);
  224. }
  225. Controller::Controller(
  226. not_null<WrapWidget*> widget,
  227. not_null<Window::SessionController*> window,
  228. not_null<ContentMemento*> memento)
  229. : AbstractController(window)
  230. , _widget(widget)
  231. , _key(memento->key())
  232. , _migrated(memento->migratedPeerId()
  233. ? window->session().data().peer(memento->migratedPeerId()).get()
  234. : nullptr)
  235. , _section(memento->section()) {
  236. updateSearchControllers(memento);
  237. setupMigrationViewer();
  238. setupTopicViewer();
  239. }
  240. void Controller::setupMigrationViewer() {
  241. const auto peer = _key.peer();
  242. if (_key.topic()
  243. || !peer
  244. || (!peer->isChat() && !peer->isChannel())
  245. || _migrated) {
  246. return;
  247. }
  248. peer->session().changes().peerFlagsValue(
  249. peer,
  250. Data::PeerUpdate::Flag::Migration
  251. ) | rpl::filter([=] {
  252. return peer->migrateTo() || (peer->migrateFrom() != _migrated);
  253. }) | rpl::start_with_next([=] {
  254. replaceWith(std::make_shared<Memento>(peer, _section));
  255. }, lifetime());
  256. }
  257. void Controller::replaceWith(std::shared_ptr<Memento> memento) {
  258. const auto window = parentController();
  259. auto params = Window::SectionShow(
  260. Window::SectionShow::Way::Backward,
  261. anim::type::instant,
  262. anim::activation::background);
  263. if (wrap() == Wrap::Side) {
  264. params.thirdColumn = true;
  265. }
  266. InvokeQueued(_widget, [=, memento = std::move(memento)]() mutable {
  267. window->showSection(std::move(memento), params);
  268. });
  269. }
  270. void Controller::setupTopicViewer() {
  271. session().data().itemIdChanged(
  272. ) | rpl::start_with_next([=](const Data::Session::IdChange &change) {
  273. if (const auto topic = _key.topic()) {
  274. if (topic->rootId() == change.oldId
  275. || (topic->peer()->id == change.newId.peer
  276. && topic->rootId() == change.newId.msg)) {
  277. const auto now = topic->forum()->topicFor(change.newId.msg);
  278. _key = Key(now);
  279. replaceWith(std::make_shared<Memento>(now, _section));
  280. }
  281. }
  282. }, _lifetime);
  283. }
  284. Wrap Controller::wrap() const {
  285. return _widget->wrap();
  286. }
  287. rpl::producer<Wrap> Controller::wrapValue() const {
  288. return _widget->wrapValue();
  289. }
  290. not_null<Ui::RpWidget*> Controller::wrapWidget() const {
  291. return _widget;
  292. }
  293. bool Controller::validateMementoPeer(
  294. not_null<ContentMemento*> memento) const {
  295. return memento->peer() == peer()
  296. && memento->migratedPeerId() == migratedPeerId()
  297. && memento->settingsSelf() == settingsSelf()
  298. && memento->storiesPeer() == storiesPeer()
  299. && memento->statisticsTag().peer == statisticsTag().peer
  300. && memento->starrefPeer() == starrefPeer()
  301. && memento->starrefType() == starrefType();
  302. }
  303. void Controller::setSection(not_null<ContentMemento*> memento) {
  304. _section = memento->section();
  305. updateSearchControllers(memento);
  306. }
  307. bool Controller::hasBackButton() const {
  308. return _widget->hasBackButton();
  309. }
  310. void Controller::updateSearchControllers(
  311. not_null<ContentMemento*> memento) {
  312. using Type = Section::Type;
  313. const auto type = _section.type();
  314. const auto isMedia = (type == Type::Media)
  315. || (type == Type::GlobalMedia);
  316. const auto mediaType = isMedia
  317. ? _section.mediaType()
  318. : Section::MediaType::kCount;
  319. const auto hasMediaSearch = isMedia
  320. && SharedMediaAllowSearch(mediaType);
  321. const auto hasRequestsListSearch = (type == Type::RequestsList);
  322. const auto hasCommonGroupsSearch = (type == Type::CommonGroups);
  323. const auto hasDownloadsSearch = (type == Type::Downloads);
  324. const auto hasMembersSearch = (type == Type::Members)
  325. || (type == Type::Profile);
  326. const auto searchQuery = memento->searchFieldQuery();
  327. if (type == Type::Media) {
  328. _searchController
  329. = std::make_unique<Api::DelayedSearchController>(&session());
  330. auto mediaMemento = dynamic_cast<Media::Memento*>(memento.get());
  331. Assert(mediaMemento != nullptr);
  332. _searchController->restoreState(mediaMemento->searchState());
  333. } else {
  334. _searchController = nullptr;
  335. }
  336. if (hasMediaSearch
  337. || hasRequestsListSearch
  338. || hasCommonGroupsSearch
  339. || hasDownloadsSearch
  340. || hasMembersSearch) {
  341. _searchFieldController
  342. = std::make_unique<Ui::SearchFieldController>(
  343. searchQuery);
  344. if (_searchController) {
  345. _searchFieldController->queryValue(
  346. ) | rpl::start_with_next([=](QString &&query) {
  347. _searchController->setQuery(
  348. produceSearchQuery(std::move(query)));
  349. }, _searchFieldController->lifetime());
  350. }
  351. _seachEnabledByContent = memento->searchEnabledByContent();
  352. _searchStartsFocused = memento->searchStartsFocused();
  353. } else {
  354. _searchFieldController = nullptr;
  355. }
  356. }
  357. void Controller::saveSearchState(not_null<ContentMemento*> memento) {
  358. if (_searchFieldController) {
  359. memento->setSearchFieldQuery(
  360. _searchFieldController->query());
  361. memento->setSearchEnabledByContent(
  362. _seachEnabledByContent.current());
  363. }
  364. if (_searchController) {
  365. auto mediaMemento = dynamic_cast<Media::Memento*>(
  366. memento.get());
  367. Assert(mediaMemento != nullptr);
  368. mediaMemento->setSearchState(_searchController->saveState());
  369. }
  370. }
  371. void Controller::showSection(
  372. std::shared_ptr<Window::SectionMemento> memento,
  373. const Window::SectionShow &params) {
  374. if (!_widget->showInternal(memento.get(), params)) {
  375. AbstractController::showSection(std::move(memento), params);
  376. }
  377. }
  378. void Controller::showBackFromStack(const Window::SectionShow &params) {
  379. if (!_widget->showBackFromStackInternal(params)) {
  380. AbstractController::showBackFromStack(params);
  381. }
  382. }
  383. void Controller::removeFromStack(const std::vector<Section> &sections) const {
  384. _widget->removeFromStack(sections);
  385. }
  386. auto Controller::produceSearchQuery(
  387. const QString &query) const -> SearchQuery {
  388. Expects(_key.peer() != nullptr);
  389. auto result = SearchQuery();
  390. result.type = _section.mediaType();
  391. result.peerId = _key.peer()->id;
  392. result.topicRootId = _key.topic() ? _key.topic()->rootId() : 0;
  393. result.query = query;
  394. result.migratedPeerId = _migrated ? _migrated->id : PeerId(0);
  395. return result;
  396. }
  397. rpl::producer<bool> Controller::searchEnabledByContent() const {
  398. return _seachEnabledByContent.value();
  399. }
  400. rpl::producer<QString> Controller::mediaSourceQueryValue() const {
  401. return _searchController->currentQueryValue();
  402. }
  403. rpl::producer<QString> Controller::searchQueryValue() const {
  404. const auto controller = searchFieldController();
  405. return controller ? controller->queryValue() : rpl::single(QString());
  406. }
  407. rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
  408. SparseIdsMergedSlice::UniversalMsgId aroundId,
  409. int limitBefore,
  410. int limitAfter) const {
  411. auto query = _searchController->currentQuery();
  412. if (!query.query.isEmpty()) {
  413. return _searchController->idsSlice(
  414. aroundId,
  415. limitBefore,
  416. limitAfter);
  417. }
  418. return SharedMediaMergedViewer(
  419. &session(),
  420. SharedMediaMergedKey(
  421. SparseIdsMergedSlice::Key(
  422. query.peerId,
  423. query.topicRootId,
  424. query.migratedPeerId,
  425. aroundId),
  426. query.type),
  427. limitBefore,
  428. limitAfter);
  429. }
  430. std::any &Controller::stepDataReference() {
  431. return _stepData;
  432. }
  433. void Controller::takeStepData(not_null<Controller*> another) {
  434. _stepData = base::take(another->_stepData);
  435. }
  436. Controller::~Controller() = default;
  437. } // namespace Info