dialogs_video_userpic.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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 "dialogs/ui/dialogs_video_userpic.h"
  8. #include "core/file_location.h"
  9. #include "data/data_peer.h"
  10. #include "data/data_photo.h"
  11. #include "data/data_photo_media.h"
  12. #include "data/data_file_origin.h"
  13. #include "data/data_session.h"
  14. #include "dialogs/dialogs_entry.h"
  15. #include "dialogs/ui/dialogs_layout.h"
  16. #include "ui/painter.h"
  17. #include "styles/style_dialogs.h"
  18. namespace Dialogs::Ui {
  19. VideoUserpic::VideoUserpic(not_null<PeerData*> peer, Fn<void()> repaint)
  20. : _peer(peer)
  21. , _repaint(std::move(repaint)) {
  22. }
  23. VideoUserpic::~VideoUserpic() = default;
  24. int VideoUserpic::frameIndex() const {
  25. return -1;
  26. }
  27. void VideoUserpic::paintLeft(
  28. Painter &p,
  29. Ui::PeerUserpicView &view,
  30. int x,
  31. int y,
  32. int w,
  33. int size,
  34. bool paused) {
  35. _lastSize = size;
  36. const auto photoId = _peer->userpicPhotoId();
  37. if (_videoPhotoId != photoId) {
  38. _videoPhotoId = photoId;
  39. _video = nullptr;
  40. _videoPhotoMedia = nullptr;
  41. const auto photo = _peer->owner().photo(photoId);
  42. if (photo->isNull()) {
  43. _peer->updateFullForced();
  44. } else {
  45. _videoPhotoMedia = photo->createMediaView();
  46. _videoPhotoMedia->videoWanted(
  47. Data::PhotoSize::Small,
  48. _peer->userpicPhotoOrigin());
  49. }
  50. }
  51. if (!_video) {
  52. if (!_videoPhotoMedia) {
  53. const auto photo = _peer->owner().photo(photoId);
  54. if (!photo->isNull()) {
  55. _videoPhotoMedia = photo->createMediaView();
  56. _videoPhotoMedia->videoWanted(
  57. Data::PhotoSize::Small,
  58. _peer->userpicPhotoOrigin());
  59. }
  60. }
  61. if (_videoPhotoMedia) {
  62. auto small = _videoPhotoMedia->videoContent(
  63. Data::PhotoSize::Small);
  64. auto bytes = small.isEmpty()
  65. ? _videoPhotoMedia->videoContent(Data::PhotoSize::Large)
  66. : small;
  67. if (!bytes.isEmpty()) {
  68. auto callback = [=](Media::Clip::Notification notification) {
  69. clipCallback(notification);
  70. };
  71. _video = Media::Clip::MakeReader(
  72. Core::FileLocation(),
  73. std::move(bytes),
  74. std::move(callback));
  75. }
  76. }
  77. }
  78. if (rtl()) {
  79. x = w - x - size;
  80. }
  81. if (_video && _video->ready()) {
  82. startReady();
  83. const auto now = paused ? crl::time(0) : crl::now();
  84. p.drawImage(x, y, _video->current(request(size), now));
  85. } else {
  86. _peer->paintUserpicLeft(p, view, x, y, w, size);
  87. }
  88. }
  89. Media::Clip::FrameRequest VideoUserpic::request(int size) const {
  90. return {
  91. .frame = { size, size },
  92. .outer = { size, size },
  93. .factor = style::DevicePixelRatio(),
  94. .radius = ImageRoundRadius::Ellipse,
  95. };
  96. }
  97. bool VideoUserpic::startReady(int size) {
  98. if (!_video->ready() || _video->started()) {
  99. return false;
  100. } else if (!_lastSize) {
  101. _lastSize = size ? size : _video->width();
  102. }
  103. _video->start(request(_lastSize));
  104. _repaint();
  105. return true;
  106. }
  107. void VideoUserpic::clipCallback(Media::Clip::Notification notification) {
  108. using namespace Media::Clip;
  109. switch (notification) {
  110. case Notification::Reinit: {
  111. if (_video->state() == State::Error) {
  112. _video.setBad();
  113. } else if (startReady()) {
  114. _repaint();
  115. }
  116. } break;
  117. case Notification::Repaint: _repaint(); break;
  118. }
  119. }
  120. void PaintUserpic(
  121. Painter &p,
  122. not_null<Entry*> entry,
  123. PeerData *peer,
  124. VideoUserpic *videoUserpic,
  125. PeerUserpicView &view,
  126. const Ui::PaintContext &context) {
  127. if (peer) {
  128. PaintUserpic(
  129. p,
  130. peer,
  131. videoUserpic,
  132. view,
  133. context.st->padding.left(),
  134. context.st->padding.top(),
  135. context.width,
  136. context.st->photoSize,
  137. context.paused);
  138. } else {
  139. entry->paintUserpic(p, view, context);
  140. }
  141. }
  142. void PaintUserpic(
  143. Painter &p,
  144. not_null<PeerData*> peer,
  145. Ui::VideoUserpic *videoUserpic,
  146. Ui::PeerUserpicView &view,
  147. int x,
  148. int y,
  149. int outerWidth,
  150. int size,
  151. bool paused) {
  152. if (videoUserpic) {
  153. videoUserpic->paintLeft(p, view, x, y, outerWidth, size, paused);
  154. } else {
  155. peer->paintUserpicLeft(p, view, x, y, outerWidth, size);
  156. }
  157. }
  158. } // namespace Dialogs::Ui