info_profile_inner_widget.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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/profile/info_profile_inner_widget.h"
  8. #include "info/info_controller.h"
  9. #include "info/profile/info_profile_widget.h"
  10. #include "info/profile/info_profile_cover.h"
  11. #include "info/profile/info_profile_icon.h"
  12. #include "info/profile/info_profile_members.h"
  13. #include "info/profile/info_profile_actions.h"
  14. #include "info/media/info_media_buttons.h"
  15. #include "data/data_changes.h"
  16. #include "data/data_channel.h"
  17. #include "data/data_forum_topic.h"
  18. #include "data/data_peer.h"
  19. #include "data/data_photo.h"
  20. #include "data/data_file_origin.h"
  21. #include "data/data_user.h"
  22. #include "main/main_session.h"
  23. #include "apiwrap.h"
  24. #include "api/api_peer_photo.h"
  25. #include "lang/lang_keys.h"
  26. #include "ui/widgets/buttons.h"
  27. #include "ui/widgets/checkbox.h"
  28. #include "ui/widgets/scroll_area.h"
  29. #include "ui/widgets/shadow.h"
  30. #include "ui/wrap/vertical_layout.h"
  31. #include "ui/wrap/slide_wrap.h"
  32. #include "ui/ui_utility.h"
  33. #include "styles/style_info.h"
  34. namespace Info {
  35. namespace Profile {
  36. InnerWidget::InnerWidget(
  37. QWidget *parent,
  38. not_null<Controller*> controller,
  39. Origin origin)
  40. : RpWidget(parent)
  41. , _controller(controller)
  42. , _peer(_controller->key().peer())
  43. , _migrated(_controller->migrated())
  44. , _topic(_controller->key().topic())
  45. , _content(setupContent(this, origin)) {
  46. _content->heightValue(
  47. ) | rpl::start_with_next([this](int height) {
  48. if (!_inResize) {
  49. resizeToWidth(width());
  50. updateDesiredHeight();
  51. }
  52. }, lifetime());
  53. }
  54. object_ptr<Ui::RpWidget> InnerWidget::setupContent(
  55. not_null<RpWidget*> parent,
  56. Origin origin) {
  57. if (const auto user = _peer->asUser()) {
  58. user->session().changes().peerFlagsValue(
  59. user,
  60. Data::PeerUpdate::Flag::FullInfo
  61. ) | rpl::start_with_next([=] {
  62. auto &photos = user->session().api().peerPhoto();
  63. if (const auto original = photos.nonPersonalPhoto(user)) {
  64. // Preload it for the edit contact box.
  65. _nonPersonalView = original->createMediaView();
  66. const auto id = peerToUser(user->id);
  67. original->load(Data::FileOriginFullUser{ id });
  68. }
  69. }, lifetime());
  70. }
  71. auto result = object_ptr<Ui::VerticalLayout>(parent);
  72. _cover = AddCover(result, _controller, _peer, _topic);
  73. if (_topic && _topic->creating()) {
  74. return result;
  75. }
  76. AddDetails(result, _controller, _peer, _topic, origin);
  77. result->add(setupSharedMedia(result.data()));
  78. if (_topic) {
  79. return result;
  80. }
  81. {
  82. auto buttons = SetupChannelMembersAndManage(
  83. _controller,
  84. result.data(),
  85. _peer);
  86. if (buttons) {
  87. result->add(std::move(buttons));
  88. }
  89. }
  90. if (auto actions = SetupActions(_controller, result.data(), _peer)) {
  91. result->add(object_ptr<Ui::BoxContentDivider>(result));
  92. result->add(std::move(actions));
  93. }
  94. if (_peer->isChat() || _peer->isMegagroup()) {
  95. setupMembers(result.data());
  96. }
  97. return result;
  98. }
  99. void InnerWidget::setupMembers(not_null<Ui::VerticalLayout*> container) {
  100. auto wrap = container->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
  101. container,
  102. object_ptr<Ui::VerticalLayout>(container)));
  103. const auto inner = wrap->entity();
  104. inner->add(object_ptr<Ui::BoxContentDivider>(inner));
  105. _members = inner->add(object_ptr<Members>(inner, _controller));
  106. _members->scrollToRequests(
  107. ) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
  108. auto min = (request.ymin < 0)
  109. ? request.ymin
  110. : MapFrom(this, _members, QPoint(0, request.ymin)).y();
  111. auto max = (request.ymin < 0)
  112. ? MapFrom(this, _members, QPoint()).y()
  113. : (request.ymax < 0)
  114. ? request.ymax
  115. : MapFrom(this, _members, QPoint(0, request.ymax)).y();
  116. _scrollToRequests.fire({ min, max });
  117. }, _members->lifetime());
  118. _cover->setOnlineCount(_members->onlineCountValue());
  119. using namespace rpl::mappers;
  120. wrap->toggleOn(
  121. _members->fullCountValue() | rpl::map(_1 > 0),
  122. anim::type::instant);
  123. }
  124. object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
  125. not_null<RpWidget*> parent) {
  126. using namespace rpl::mappers;
  127. using MediaType = Media::Type;
  128. auto content = object_ptr<Ui::VerticalLayout>(parent);
  129. auto tracker = Ui::MultiSlideTracker();
  130. auto addMediaButton = [&](
  131. MediaType type,
  132. const style::icon &icon) {
  133. auto result = Media::AddButton(
  134. content,
  135. _controller,
  136. _peer,
  137. _topic ? _topic->rootId() : 0,
  138. _migrated,
  139. type,
  140. tracker);
  141. object_ptr<Profile::FloatingIcon>(
  142. result,
  143. icon,
  144. st::infoSharedMediaButtonIconPosition);
  145. };
  146. auto addCommonGroupsButton = [&](
  147. not_null<UserData*> user,
  148. const style::icon &icon) {
  149. auto result = Media::AddCommonGroupsButton(
  150. content,
  151. _controller,
  152. user,
  153. tracker);
  154. object_ptr<Profile::FloatingIcon>(
  155. result,
  156. icon,
  157. st::infoSharedMediaButtonIconPosition);
  158. };
  159. const auto addSimilarPeersButton = [&](
  160. not_null<PeerData*> peer,
  161. const style::icon &icon) {
  162. auto result = Media::AddSimilarPeersButton(
  163. content,
  164. _controller,
  165. peer,
  166. tracker);
  167. object_ptr<Profile::FloatingIcon>(
  168. result,
  169. icon,
  170. st::infoSharedMediaButtonIconPosition);
  171. };
  172. auto addStoriesButton = [&](
  173. not_null<PeerData*> peer,
  174. const style::icon &icon) {
  175. if (peer->isChat()) {
  176. return;
  177. }
  178. auto result = Media::AddStoriesButton(
  179. content,
  180. _controller,
  181. peer,
  182. tracker);
  183. object_ptr<Profile::FloatingIcon>(
  184. result,
  185. icon,
  186. st::infoSharedMediaButtonIconPosition);
  187. };
  188. auto addSavedSublistButton = [&](
  189. not_null<PeerData*> peer,
  190. const style::icon &icon) {
  191. auto result = Media::AddSavedSublistButton(
  192. content,
  193. _controller,
  194. peer,
  195. tracker);
  196. object_ptr<Profile::FloatingIcon>(
  197. result,
  198. icon,
  199. st::infoSharedMediaButtonIconPosition);
  200. };
  201. auto addPeerGiftsButton = [&](
  202. not_null<PeerData*> peer,
  203. const style::icon &icon) {
  204. auto result = Media::AddPeerGiftsButton(
  205. content,
  206. _controller,
  207. peer,
  208. tracker);
  209. object_ptr<Profile::FloatingIcon>(
  210. result,
  211. icon,
  212. st::infoSharedMediaButtonIconPosition);
  213. };
  214. if (!_topic) {
  215. addStoriesButton(_peer, st::infoIconMediaStories);
  216. addPeerGiftsButton(_peer, st::infoIconMediaGifts);
  217. addSavedSublistButton(_peer, st::infoIconMediaSaved);
  218. }
  219. addMediaButton(MediaType::Photo, st::infoIconMediaPhoto);
  220. addMediaButton(MediaType::Video, st::infoIconMediaVideo);
  221. addMediaButton(MediaType::File, st::infoIconMediaFile);
  222. addMediaButton(MediaType::MusicFile, st::infoIconMediaAudio);
  223. addMediaButton(MediaType::Link, st::infoIconMediaLink);
  224. addMediaButton(MediaType::RoundVoiceFile, st::infoIconMediaVoice);
  225. addMediaButton(MediaType::GIF, st::infoIconMediaGif);
  226. if (const auto bot = _peer->asBot()) {
  227. addCommonGroupsButton(bot, st::infoIconMediaGroup);
  228. addSimilarPeersButton(bot, st::infoIconMediaBot);
  229. } else if (const auto channel = _peer->asBroadcast()) {
  230. addSimilarPeersButton(channel, st::infoIconMediaChannel);
  231. } else if (const auto user = _peer->asUser()) {
  232. addCommonGroupsButton(user, st::infoIconMediaGroup);
  233. }
  234. auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
  235. parent,
  236. object_ptr<Ui::VerticalLayout>(parent)
  237. );
  238. result->setDuration(
  239. st::infoSlideDuration
  240. )->toggleOn(
  241. tracker.atLeastOneShownValue()
  242. );
  243. auto layout = result->entity();
  244. layout->add(object_ptr<Ui::BoxContentDivider>(layout));
  245. layout->add(object_ptr<Ui::FixedHeightWidget>(
  246. layout,
  247. st::infoSharedMediaBottomSkip)
  248. )->setAttribute(Qt::WA_TransparentForMouseEvents);
  249. layout->add(std::move(content));
  250. layout->add(object_ptr<Ui::FixedHeightWidget>(
  251. layout,
  252. st::infoSharedMediaBottomSkip)
  253. )->setAttribute(Qt::WA_TransparentForMouseEvents);
  254. _sharedMediaWrap = result;
  255. return result;
  256. }
  257. int InnerWidget::countDesiredHeight() const {
  258. return _content->height() + (_members
  259. ? (_members->desiredHeight() - _members->height())
  260. : 0);
  261. }
  262. void InnerWidget::visibleTopBottomUpdated(
  263. int visibleTop,
  264. int visibleBottom) {
  265. setChildVisibleTopBottom(_content, visibleTop, visibleBottom);
  266. }
  267. void InnerWidget::saveState(not_null<Memento*> memento) {
  268. if (_members) {
  269. memento->setMembersState(_members->saveState());
  270. }
  271. }
  272. void InnerWidget::restoreState(not_null<Memento*> memento) {
  273. if (_members) {
  274. _members->restoreState(memento->membersState());
  275. }
  276. if (_sharedMediaWrap) {
  277. _sharedMediaWrap->finishAnimating();
  278. }
  279. }
  280. rpl::producer<Ui::ScrollToRequest> InnerWidget::scrollToRequests() const {
  281. return _scrollToRequests.events();
  282. }
  283. rpl::producer<int> InnerWidget::desiredHeightValue() const {
  284. return _desiredHeight.events_starting_with(countDesiredHeight());
  285. }
  286. int InnerWidget::resizeGetHeight(int newWidth) {
  287. _inResize = true;
  288. auto guard = gsl::finally([&] { _inResize = false; });
  289. _content->resizeToWidth(newWidth);
  290. _content->moveToLeft(0, 0);
  291. updateDesiredHeight();
  292. return _content->heightNoMargins();
  293. }
  294. } // namespace Profile
  295. } // namespace Info