tdesktop/Telegram/SourceFiles/info/statistics/info_statistics_recent_mess...

246 lines
6.7 KiB
C++
Raw Normal View History

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/statistics/info_statistics_recent_message.h"
#include "core/ui_integration.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_file_origin.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_helpers.h"
#include "history/view/history_view_item_preview.h"
#include "info/statistics/info_statistics_common.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/effects/ripple_animation.h"
#include "ui/effects/spoiler_mess.h"
#include "ui/power_saving.h"
#include "ui/rect.h"
#include "ui/text/format_values.h"
#include "ui/text/text_options.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include "styles/style_statistics.h"
namespace Info::Statistics {
namespace {
[[nodiscard]] QImage PreparePreviewImage(
QImage original,
ImageRoundRadius radius,
bool spoiler) {
if (original.width() * 10 < original.height()
|| original.height() * 10 < original.width()) {
return QImage();
}
const auto factor = style::DevicePixelRatio();
const auto size = st::peerListBoxItem.photoSize * factor;
const auto scaled = original.scaled(
QSize(size, size),
Qt::KeepAspectRatioByExpanding,
Qt::FastTransformation);
auto square = scaled.copy(
(scaled.width() - size) / 2,
(scaled.height() - size) / 2,
size,
size
).convertToFormat(QImage::Format_ARGB32_Premultiplied);
if (spoiler) {
square = Images::BlurLargeImage(
std::move(square),
style::ConvertScale(3) * factor);
}
square = Images::Round(std::move(square), radius);
square.setDevicePixelRatio(factor);
return square;
}
} // namespace
MessagePreview::MessagePreview(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
int views,
int shares,
QImage cachedPreview)
: Ui::RpWidget(parent)
, _item(item)
, _date(
st::statisticsHeaderTitleTextStyle,
Ui::FormatDateTime(ItemDateTime(item)))
, _views(
st::defaultPeerListItem.nameStyle,
(views >= 0)
? tr::lng_stats_recent_messages_views(
tr::now,
lt_count_decimal,
views)
: QString())
, _shares(
st::statisticsHeaderTitleTextStyle,
(shares >= 0)
? tr::lng_stats_recent_messages_shares(
tr::now,
lt_count_decimal,
shares)
: QString())
, _viewsWidth(_views.maxWidth())
, _sharesWidth(_shares.maxWidth())
, _preview(std::move(cachedPreview)) {
_text.setMarkedText(
st::defaultPeerListItem.nameStyle,
_item->toPreview({ .generateImages = false }).text,
Ui::DialogTextOptions(),
Core::MarkedTextContext{
.session = &item->history()->session(),
.customEmojiRepaint = [=] { update(); },
});
if (_preview.isNull()) {
processPreview(item);
}
}
void MessagePreview::processPreview(not_null<HistoryItem*> item) {
if (const auto media = item->media()) {
if (item->media()->hasSpoiler()) {
_spoiler = std::make_unique<Ui::SpoilerAnimation>([=] {
update();
});
}
if (const auto photo = media->photo()) {
_photoMedia = photo->createMediaView();
_photoMedia->wanted(Data::PhotoSize::Large, item->fullId());
} else if (const auto document = media->document()) {
_documentMedia = document->createMediaView();
_documentMedia->thumbnailWanted(item->fullId());
}
}
const auto session = _photoMedia
? &_photoMedia->owner()->session()
: _documentMedia
? &_documentMedia->owner()->session()
: nullptr;
if (!session) {
return;
}
struct ThumbInfo final {
bool loaded = false;
Image *image = nullptr;
};
const auto computeThumbInfo = [=]() -> ThumbInfo {
using Size = Data::PhotoSize;
if (_documentMedia) {
return { true, _documentMedia->thumbnail() };
} else if (const auto large = _photoMedia->image(Size::Large)) {
return { true, large };
} else if (const auto thumbnail = _photoMedia->image(
Size::Thumbnail)) {
return { false, thumbnail };
} else if (const auto small = _photoMedia->image(Size::Small)) {
return { false, small };
} else {
return { false, _photoMedia->thumbnailInline() };
}
};
rpl::single(rpl::empty) | rpl::then(
session->downloaderTaskFinished()
) | rpl::start_with_next([=] {
const auto computed = computeThumbInfo();
if (!computed.image) {
if (_documentMedia && !_documentMedia->owner()->hasThumbnail()) {
_preview = QImage();
_lifetimeDownload.destroy();
}
return;
} else if (computed.loaded) {
_lifetimeDownload.destroy();
}
_preview = PreparePreviewImage(
computed.image->original(),
ImageRoundRadius::Large,
!!_spoiler);
}, _lifetimeDownload);
}
int MessagePreview::resizeGetHeight(int newWidth) {
return st::peerListBoxItem.height;
}
void MessagePreview::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
const auto padding = st::boxRowPadding.left() / 2;
const auto rightWidth = std::max(_viewsWidth, _sharesWidth) + padding;
const auto left = _preview.isNull()
? st::peerListBoxItem.photoPosition.x()
: st::peerListBoxItem.namePosition.x();
if (left) {
p.drawImage(st::peerListBoxItem.photoPosition, _preview);
if (_spoiler) {
const auto rect = QRect(
st::peerListBoxItem.photoPosition,
Size(st::peerListBoxItem.photoSize));
const auto paused = On(PowerSaving::kChatSpoiler);
FillSpoilerRect(
p,
rect,
Images::CornersMaskRef(
Images::CornersMask(st::roundRadiusLarge)),
Ui::DefaultImageSpoiler().frame(
_spoiler->index(crl::now(), paused)),
_cornerCache);
}
}
const auto topTextTop = st::peerListBoxItem.namePosition.y();
const auto bottomTextTop = st::peerListBoxItem.statusPosition.y();
p.setBrush(Qt::NoBrush);
p.setPen(st::boxTextFg);
_text.draw(p, {
.position = { left, topTextTop },
.outerWidth = width() - left,
.availableWidth = width() - rightWidth - left,
.spoiler = Ui::Text::DefaultSpoilerCache(),
.now = crl::now(),
.elisionHeight = st::statisticsDetailsPopupHeaderStyle.font->height,
.elisionLines = 1,
});
_views.draw(p, {
.position = { width() - _viewsWidth, topTextTop },
.outerWidth = _viewsWidth,
.availableWidth = _viewsWidth,
});
p.setPen(st::windowSubTextFg);
_date.draw(p, {
.position = { left, bottomTextTop },
.outerWidth = width() - left,
.availableWidth = width() - rightWidth - left,
});
_shares.draw(p, {
.position = { width() - _sharesWidth, bottomTextTop },
.outerWidth = _sharesWidth,
.availableWidth = _sharesWidth,
});
}
void MessagePreview::saveState(SavedState &state) const {
if (!_lifetimeDownload) {
state.recentPostPreviews[_item->fullId().msg] = _preview;
}
}
} // namespace Info::Statistics