info_media_inner_widget.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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_inner_widget.h"
  8. #include <rpl/flatten_latest.h>
  9. #include "boxes/abstract_box.h"
  10. #include "info/media/info_media_list_widget.h"
  11. #include "info/media/info_media_buttons.h"
  12. #include "info/media/info_media_empty_widget.h"
  13. #include "info/profile/info_profile_icon.h"
  14. #include "info/info_controller.h"
  15. #include "data/data_forum_topic.h"
  16. #include "data/data_peer.h"
  17. #include "ui/widgets/discrete_sliders.h"
  18. #include "ui/widgets/shadow.h"
  19. #include "ui/widgets/buttons.h"
  20. #include "ui/widgets/box_content_divider.h"
  21. #include "ui/wrap/slide_wrap.h"
  22. #include "ui/wrap/vertical_layout.h"
  23. #include "ui/search_field_controller.h"
  24. #include "styles/style_info.h"
  25. #include "lang/lang_keys.h"
  26. namespace Info {
  27. namespace Media {
  28. InnerWidget::InnerWidget(
  29. QWidget *parent,
  30. not_null<Controller*> controller)
  31. : RpWidget(parent)
  32. , _controller(controller)
  33. , _empty(this) {
  34. _empty->heightValue(
  35. ) | rpl::start_with_next(
  36. [this] { refreshHeight(); },
  37. _empty->lifetime());
  38. _list = setupList();
  39. }
  40. // Allows showing additional shared media links and tabs.
  41. // Used for shared media in Saved Messages.
  42. void InnerWidget::setupOtherTypes() {
  43. if (_controller->key().peer()->sharedMediaInfo() && _isStackBottom) {
  44. createOtherTypes();
  45. } else {
  46. _otherTypes.destroy();
  47. refreshHeight();
  48. }
  49. }
  50. void InnerWidget::createOtherTypes() {
  51. _otherTypes.create(this);
  52. _otherTypes->show();
  53. createTypeButtons();
  54. _otherTypes->add(object_ptr<Ui::BoxContentDivider>(_otherTypes));
  55. _otherTypes->resizeToWidth(width());
  56. _otherTypes->heightValue(
  57. ) | rpl::start_with_next(
  58. [this] { refreshHeight(); },
  59. _otherTypes->lifetime());
  60. }
  61. void InnerWidget::createTypeButtons() {
  62. auto wrap = _otherTypes->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
  63. _otherTypes,
  64. object_ptr<Ui::VerticalLayout>(_otherTypes)));
  65. auto content = wrap->entity();
  66. content->add(object_ptr<Ui::FixedHeightWidget>(
  67. content,
  68. st::infoProfileSkip));
  69. auto tracker = Ui::MultiSlideTracker();
  70. const auto peer = _controller->key().peer();
  71. const auto topic = _controller->key().topic();
  72. const auto topicRootId = topic ? topic->rootId() : MsgId();
  73. const auto migrated = _controller->migrated();
  74. const auto addMediaButton = [&](
  75. Type buttonType,
  76. const style::icon &icon) {
  77. if (buttonType == type()) {
  78. return;
  79. }
  80. auto result = AddButton(
  81. content,
  82. _controller,
  83. peer,
  84. topicRootId,
  85. migrated,
  86. buttonType,
  87. tracker);
  88. object_ptr<Profile::FloatingIcon>(
  89. result,
  90. icon,
  91. st::infoSharedMediaButtonIconPosition)->show();
  92. };
  93. addMediaButton(Type::Photo, st::infoIconMediaPhoto);
  94. addMediaButton(Type::Video, st::infoIconMediaVideo);
  95. addMediaButton(Type::File, st::infoIconMediaFile);
  96. addMediaButton(Type::MusicFile, st::infoIconMediaAudio);
  97. addMediaButton(Type::Link, st::infoIconMediaLink);
  98. addMediaButton(Type::RoundVoiceFile, st::infoIconMediaVoice);
  99. addMediaButton(Type::GIF, st::infoIconMediaGif);
  100. content->add(object_ptr<Ui::FixedHeightWidget>(
  101. content,
  102. st::infoProfileSkip));
  103. wrap->toggleOn(tracker.atLeastOneShownValue());
  104. wrap->finishAnimating();
  105. }
  106. Type InnerWidget::type() const {
  107. return _controller->section().mediaType();
  108. }
  109. void InnerWidget::visibleTopBottomUpdated(
  110. int visibleTop,
  111. int visibleBottom) {
  112. setChildVisibleTopBottom(_list, visibleTop, visibleBottom);
  113. }
  114. bool InnerWidget::showInternal(not_null<Memento*> memento) {
  115. if (!_controller->validateMementoPeer(memento)) {
  116. return false;
  117. }
  118. auto mementoType = memento->section().mediaType();
  119. if (mementoType == type()) {
  120. restoreState(memento);
  121. return true;
  122. }
  123. return false;
  124. }
  125. object_ptr<ListWidget> InnerWidget::setupList() {
  126. auto result = object_ptr<ListWidget>(this, _controller);
  127. result->heightValue(
  128. ) | rpl::start_with_next(
  129. [this] { refreshHeight(); },
  130. result->lifetime());
  131. using namespace rpl::mappers;
  132. result->scrollToRequests(
  133. ) | rpl::map([widget = result.data()](int to) {
  134. return Ui::ScrollToRequest {
  135. widget->y() + to,
  136. -1
  137. };
  138. }) | rpl::start_to_stream(
  139. _scrollToRequests,
  140. result->lifetime());
  141. _selectedLists.fire(result->selectedListValue());
  142. _listTops.fire(result->topValue());
  143. _empty->setType(_controller->section().mediaType());
  144. _controller->mediaSourceQueryValue(
  145. ) | rpl::start_with_next([this](const QString &query) {
  146. _empty->setSearchQuery(query);
  147. }, result->lifetime());
  148. return result;
  149. }
  150. void InnerWidget::saveState(not_null<Memento*> memento) {
  151. _list->saveState(memento);
  152. }
  153. void InnerWidget::restoreState(not_null<Memento*> memento) {
  154. _list->restoreState(memento);
  155. }
  156. rpl::producer<SelectedItems> InnerWidget::selectedListValue() const {
  157. return _selectedLists.events_starting_with(
  158. _list->selectedListValue()
  159. ) | rpl::flatten_latest();
  160. }
  161. void InnerWidget::selectionAction(SelectionAction action) {
  162. _list->selectionAction(action);
  163. }
  164. InnerWidget::~InnerWidget() = default;
  165. int InnerWidget::resizeGetHeight(int newWidth) {
  166. _inResize = true;
  167. auto guard = gsl::finally([this] { _inResize = false; });
  168. if (_otherTypes) {
  169. _otherTypes->resizeToWidth(newWidth);
  170. }
  171. _list->resizeToWidth(newWidth);
  172. _empty->resizeToWidth(newWidth);
  173. return recountHeight();
  174. }
  175. void InnerWidget::refreshHeight() {
  176. if (_inResize) {
  177. return;
  178. }
  179. resize(width(), recountHeight());
  180. }
  181. int InnerWidget::recountHeight() {
  182. auto top = 0;
  183. if (_otherTypes) {
  184. _otherTypes->moveToLeft(0, top);
  185. top += _otherTypes->heightNoMargins() - st::lineWidth;
  186. }
  187. auto listHeight = 0;
  188. if (_list) {
  189. _list->moveToLeft(0, top);
  190. listHeight = _list->heightNoMargins();
  191. top += listHeight;
  192. }
  193. if (listHeight > 0) {
  194. _empty->hide();
  195. } else {
  196. _empty->show();
  197. _empty->moveToLeft(0, top);
  198. top += _empty->heightNoMargins();
  199. }
  200. return top;
  201. }
  202. void InnerWidget::setScrollHeightValue(rpl::producer<int> value) {
  203. using namespace rpl::mappers;
  204. _empty->setFullHeight(rpl::combine(
  205. std::move(value),
  206. _listTops.events_starting_with(
  207. _list->topValue()
  208. ) | rpl::flatten_latest(),
  209. _1 - _2));
  210. }
  211. rpl::producer<Ui::ScrollToRequest> InnerWidget::scrollToRequests() const {
  212. return _scrollToRequests.events();
  213. }
  214. } // namespace Media
  215. } // namespace Info