info_media_buttons.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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/media/info_media_buttons.h"
  8. #include "base/call_delayed.h"
  9. #include "base/qt/qt_key_modifiers.h"
  10. #include "core/application.h"
  11. #include "data/data_channel.h"
  12. #include "data/data_saved_messages.h"
  13. #include "data/data_session.h"
  14. #include "data/data_stories_ids.h"
  15. #include "data/data_user.h"
  16. #include "history/view/history_view_sublist_section.h"
  17. #include "info/info_controller.h"
  18. #include "info/info_memento.h"
  19. #include "info/profile/info_profile_values.h"
  20. #include "info/stories/info_stories_widget.h"
  21. #include "ui/widgets/buttons.h"
  22. #include "ui/widgets/popup_menu.h"
  23. #include "ui/wrap/slide_wrap.h"
  24. #include "ui/wrap/vertical_layout.h"
  25. #include "window/window_separate_id.h"
  26. #include "window/window_session_controller.h"
  27. #include "styles/style_info.h"
  28. #include "styles/style_menu_icons.h"
  29. namespace Info::Media {
  30. namespace {
  31. [[nodiscard]] Window::SeparateSharedMediaType ToSeparateType(
  32. Storage::SharedMediaType type) {
  33. using Type = Storage::SharedMediaType;
  34. using SeparatedType = Window::SeparateSharedMediaType;
  35. return (type == Type::Photo)
  36. ? SeparatedType::Photos
  37. : (type == Type::Video)
  38. ? SeparatedType::Videos
  39. : (type == Type::File)
  40. ? SeparatedType::Files
  41. : (type == Type::MusicFile)
  42. ? SeparatedType::Audio
  43. : (type == Type::Link)
  44. ? SeparatedType::Links
  45. : (type == Type::RoundVoiceFile)
  46. ? SeparatedType::Voices
  47. : (type == Type::GIF)
  48. ? SeparatedType::GIF
  49. : SeparatedType::None;
  50. }
  51. [[nodiscard]] Window::SeparateId SeparateId(
  52. not_null<PeerData*> peer,
  53. MsgId topicRootId,
  54. Storage::SharedMediaType type) {
  55. if (peer->isSelf()) {
  56. return { nullptr };
  57. }
  58. const auto separateType = ToSeparateType(type);
  59. if (separateType == Window::SeparateSharedMediaType::None) {
  60. return { nullptr };
  61. }
  62. return { Window::SeparateSharedMedia(separateType, peer, topicRootId) };
  63. }
  64. void AddContextMenuToButton(
  65. not_null<Ui::AbstractButton*> button,
  66. Fn<void()> openInWindow) {
  67. if (!openInWindow) {
  68. return;
  69. }
  70. button->setAcceptBoth();
  71. struct State final {
  72. base::unique_qptr<Ui::PopupMenu> menu;
  73. };
  74. const auto state = button->lifetime().make_state<State>();
  75. button->addClickHandler([=](Qt::MouseButton mouse) {
  76. if (mouse != Qt::RightButton) {
  77. return;
  78. }
  79. state->menu = base::make_unique_q<Ui::PopupMenu>(
  80. button.get(),
  81. st::popupMenuWithIcons);
  82. state->menu->addAction(tr::lng_context_new_window(tr::now), [=] {
  83. base::call_delayed(
  84. st::popupMenuWithIcons.showDuration,
  85. crl::guard(button, openInWindow));
  86. }, &st::menuIconNewWindow);
  87. state->menu->popup(QCursor::pos());
  88. });
  89. }
  90. } // namespace
  91. tr::phrase<lngtag_count> MediaTextPhrase(Type type) {
  92. switch (type) {
  93. case Type::Photo: return tr::lng_profile_photos;
  94. case Type::GIF: return tr::lng_profile_gifs;
  95. case Type::Video: return tr::lng_profile_videos;
  96. case Type::File: return tr::lng_profile_files;
  97. case Type::MusicFile: return tr::lng_profile_songs;
  98. case Type::Link: return tr::lng_profile_shared_links;
  99. case Type::RoundVoiceFile: return tr::lng_profile_audios;
  100. }
  101. Unexpected("Type in MediaTextPhrase()");
  102. };
  103. Fn<QString(int)> MediaText(Type type) {
  104. return [phrase = MediaTextPhrase(type)](int count) {
  105. return phrase(tr::now, lt_count, count);
  106. };
  107. }
  108. not_null<Ui::SlideWrap<Ui::SettingsButton>*> AddCountedButton(
  109. Ui::VerticalLayout *parent,
  110. rpl::producer<int> &&count,
  111. Fn<QString(int)> &&textFromCount,
  112. Ui::MultiSlideTracker &tracker) {
  113. using namespace ::Settings;
  114. auto forked = std::move(count)
  115. | start_spawning(parent->lifetime());
  116. auto text = rpl::duplicate(
  117. forked
  118. ) | rpl::map([textFromCount](int count) {
  119. return (count > 0)
  120. ? textFromCount(count)
  121. : QString();
  122. });
  123. auto button = parent->add(object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
  124. parent,
  125. object_ptr<Ui::SettingsButton>(
  126. parent,
  127. std::move(text),
  128. st::infoSharedMediaButton))
  129. )->setDuration(
  130. st::infoSlideDuration
  131. )->toggleOn(
  132. rpl::duplicate(forked) | rpl::map(rpl::mappers::_1 > 0)
  133. );
  134. tracker.track(button);
  135. return button;
  136. };
  137. not_null<Ui::SettingsButton*> AddButton(
  138. Ui::VerticalLayout *parent,
  139. not_null<Window::SessionNavigation*> navigation,
  140. not_null<PeerData*> peer,
  141. MsgId topicRootId,
  142. PeerData *migrated,
  143. Type type,
  144. Ui::MultiSlideTracker &tracker) {
  145. auto result = AddCountedButton(
  146. parent,
  147. Profile::SharedMediaCountValue(peer, topicRootId, migrated, type),
  148. MediaText(type),
  149. tracker)->entity();
  150. const auto separateId = SeparateId(peer, topicRootId, type);
  151. const auto openInWindow = separateId
  152. ? [=] { navigation->parentController()->showInNewWindow(separateId); }
  153. : Fn<void()>(nullptr);
  154. AddContextMenuToButton(result, openInWindow);
  155. result->addClickHandler([=](Qt::MouseButton mouse) {
  156. if (mouse == Qt::RightButton) {
  157. return;
  158. }
  159. if (openInWindow
  160. && (base::IsCtrlPressed() || mouse == Qt::MiddleButton)) {
  161. return openInWindow();
  162. }
  163. const auto topic = topicRootId
  164. ? peer->forumTopicFor(topicRootId)
  165. : nullptr;
  166. if (topicRootId && !topic) {
  167. return;
  168. }
  169. const auto separateId = SeparateId(peer, topicRootId, type);
  170. if (Core::App().separateWindowFor(separateId) && openInWindow) {
  171. openInWindow();
  172. } else {
  173. navigation->showSection(topicRootId
  174. ? std::make_shared<Info::Memento>(topic, Section(type))
  175. : std::make_shared<Info::Memento>(peer, Section(type)));
  176. }
  177. });
  178. return result;
  179. };
  180. not_null<Ui::SettingsButton*> AddCommonGroupsButton(
  181. Ui::VerticalLayout *parent,
  182. not_null<Window::SessionNavigation*> navigation,
  183. not_null<UserData*> user,
  184. Ui::MultiSlideTracker &tracker) {
  185. auto result = AddCountedButton(
  186. parent,
  187. Profile::CommonGroupsCountValue(user),
  188. [](int count) {
  189. return tr::lng_profile_common_groups(tr::now, lt_count, count);
  190. },
  191. tracker)->entity();
  192. result->addClickHandler([=] {
  193. navigation->showSection(
  194. std::make_shared<Info::Memento>(
  195. user,
  196. Section::Type::CommonGroups));
  197. });
  198. return result;
  199. }
  200. not_null<Ui::SettingsButton*> AddSimilarPeersButton(
  201. Ui::VerticalLayout *parent,
  202. not_null<Window::SessionNavigation*> navigation,
  203. not_null<PeerData*> peer,
  204. Ui::MultiSlideTracker &tracker) {
  205. auto result = AddCountedButton(
  206. parent,
  207. Profile::SimilarPeersCountValue(peer),
  208. [=](int count) {
  209. return peer->isBroadcast()
  210. ? tr::lng_profile_similar_channels(tr::now, lt_count, count)
  211. : tr::lng_profile_similar_bots(tr::now, lt_count, count);
  212. },
  213. tracker)->entity();
  214. result->addClickHandler([=] {
  215. navigation->showSection(
  216. std::make_shared<Info::Memento>(
  217. peer,
  218. Section::Type::SimilarPeers));
  219. });
  220. return result;
  221. }
  222. not_null<Ui::SettingsButton*> AddStoriesButton(
  223. Ui::VerticalLayout *parent,
  224. not_null<Window::SessionNavigation*> navigation,
  225. not_null<PeerData*> peer,
  226. Ui::MultiSlideTracker &tracker) {
  227. auto count = rpl::single(0) | rpl::then(Data::SavedStoriesIds(
  228. peer,
  229. ServerMaxStoryId - 1,
  230. 0
  231. ) | rpl::map([](const Data::StoriesIdsSlice &slice) {
  232. return slice.fullCount().value_or(0);
  233. }));
  234. const auto phrase = peer->isChannel() ? (+[](int count) {
  235. return tr::lng_profile_posts(tr::now, lt_count, count);
  236. }) : (+[](int count) {
  237. return tr::lng_profile_saved_stories(tr::now, lt_count, count);
  238. });
  239. auto result = AddCountedButton(
  240. parent,
  241. std::move(count),
  242. phrase,
  243. tracker)->entity();
  244. result->addClickHandler([=] {
  245. navigation->showSection(Info::Stories::Make(peer));
  246. });
  247. return result;
  248. }
  249. not_null<Ui::SettingsButton*> AddSavedSublistButton(
  250. Ui::VerticalLayout *parent,
  251. not_null<Window::SessionNavigation*> navigation,
  252. not_null<PeerData*> peer,
  253. Ui::MultiSlideTracker &tracker) {
  254. auto result = AddCountedButton(
  255. parent,
  256. Profile::SavedSublistCountValue(peer),
  257. [](int count) {
  258. return tr::lng_profile_saved_messages(tr::now, lt_count, count);
  259. },
  260. tracker)->entity();
  261. result->addClickHandler([=] {
  262. navigation->showSection(
  263. std::make_shared<HistoryView::SublistMemento>(
  264. peer->owner().savedMessages().sublist(peer)));
  265. });
  266. return result;
  267. }
  268. not_null<Ui::SettingsButton*> AddPeerGiftsButton(
  269. Ui::VerticalLayout *parent,
  270. not_null<Window::SessionNavigation*> navigation,
  271. not_null<PeerData*> peer,
  272. Ui::MultiSlideTracker &tracker) {
  273. auto result = AddCountedButton(
  274. parent,
  275. Profile::PeerGiftsCountValue(peer),
  276. [](int count) {
  277. return tr::lng_profile_peer_gifts(tr::now, lt_count, count);
  278. },
  279. tracker)->entity();
  280. result->addClickHandler([=] {
  281. navigation->showSection(
  282. std::make_shared<Info::Memento>(
  283. peer,
  284. Section::Type::PeerGifts));
  285. });
  286. return result;
  287. }
  288. } // namespace Info::Media