2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 14:38:15 +00:00

Allow sending videos with covers.

This commit is contained in:
John Preston
2025-01-29 09:24:01 +04:00
parent 6a415cf232
commit e05bb75b8a
42 changed files with 571 additions and 104 deletions

View File

@@ -34,10 +34,10 @@ AbstractSingleMediaPreview::AbstractSingleMediaPreview(
QWidget *parent,
const style::ComposeControls &st,
AttachControls::Type type,
Fn<bool()> canToggleSpoiler)
Fn<bool(AttachActionType)> actionAllowed)
: AbstractSinglePreview(parent)
, _st(st)
, _canToggleSpoiler(std::move(canToggleSpoiler))
, _actionAllowed(std::move(actionAllowed))
, _minThumbH(st::sendBoxAlbumGroupSize.height()
+ st::sendBoxAlbumGroupSkipTop * 2)
, _controls(base::make_unique_q<AttachControlsWidget>(this, type)) {
@@ -57,6 +57,14 @@ rpl::producer<> AbstractSingleMediaPreview::modifyRequests() const {
return _photoEditorRequests.events();
}
rpl::producer<> AbstractSingleMediaPreview::editCoverRequests() const {
return _editCoverRequests.events();
}
rpl::producer<> AbstractSingleMediaPreview::clearCoverRequests() const {
return _clearCoverRequests.events();
}
void AbstractSingleMediaPreview::setSendWay(SendFilesWay way) {
_sendWay = way;
update();
@@ -112,7 +120,7 @@ void AbstractSingleMediaPreview::preparePreview(QImage preview) {
preview = Images::Prepare(
std::move(preview),
QSize(maxW, maxH) * ratio,
{ .options = Images::Option::Blur, .outer = { maxW, maxH } });
{ .outer = { maxW, maxH } });
}
auto originalWidth = preview.width();
auto originalHeight = preview.height();
@@ -273,24 +281,33 @@ void AbstractSingleMediaPreview::applyCursor(style::cursor cursor) {
}
void AbstractSingleMediaPreview::showContextMenu(QPoint position) {
if (!_canToggleSpoiler()
|| !_sendWay.sendImagesAsPhotos()
|| !supportsSpoilers()) {
return;
}
_menu = base::make_unique_q<Ui::PopupMenu>(
this,
_st.tabbed.menu);
const auto &icons = _st.tabbed.icons;
const auto spoilered = hasSpoiler();
_menu->addAction(spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now), [=] {
setSpoiler(!spoilered);
_spoileredChanges.fire_copy(!spoilered);
}, spoilered ? &icons.menuSpoilerOff : &icons.menuSpoiler);
if (_actionAllowed(AttachActionType::ToggleSpoiler)
&& _sendWay.sendImagesAsPhotos()
&& supportsSpoilers()) {
const auto spoilered = hasSpoiler();
_menu->addAction(spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now), [=] {
setSpoiler(!spoilered);
_spoileredChanges.fire_copy(!spoilered);
}, spoilered ? &icons.menuSpoilerOff : &icons.menuSpoiler);
}
if (_actionAllowed(AttachActionType::EditCover)) {
_menu->addAction(tr::lng_context_edit_cover(tr::now), [=] {
_editCoverRequests.fire({});
}, &st::menuIconEdit);
if (_actionAllowed(AttachActionType::ClearCover)) {
_menu->addAction(tr::lng_context_clear_cover(tr::now), [=] {
_clearCoverRequests.fire({});
}, &st::menuIconCancel);
}
}
if (_menu->empty()) {
_menu = nullptr;
} else {

View File

@@ -27,7 +27,7 @@ public:
QWidget *parent,
const style::ComposeControls &st,
AttachControls::Type type,
Fn<bool()> canToggleSpoiler);
Fn<bool(AttachActionType)> actionAllowed);
~AbstractSingleMediaPreview();
void setSendWay(SendFilesWay way);
@@ -36,6 +36,8 @@ public:
[[nodiscard]] rpl::producer<> deleteRequests() const override;
[[nodiscard]] rpl::producer<> editRequests() const override;
[[nodiscard]] rpl::producer<> modifyRequests() const override;
[[nodiscard]] rpl::producer<> editCoverRequests() const;
[[nodiscard]] rpl::producer<> clearCoverRequests() const;
[[nodiscard]] bool isPhoto() const;
@@ -74,7 +76,7 @@ private:
const style::ComposeControls &_st;
SendFilesWay _sendWay;
Fn<bool()> _canToggleSpoiler;
Fn<bool(AttachActionType)> _actionAllowed;
bool _animated = false;
QPixmap _preview;
QPixmap _previewBlurred;
@@ -89,6 +91,8 @@ private:
const int _minThumbH;
const base::unique_qptr<AttachControlsWidget> _controls;
rpl::event_stream<> _photoEditorRequests;
rpl::event_stream<> _editCoverRequests;
rpl::event_stream<> _clearCoverRequests;
style::cursor _cursor = style::cur_default;
bool _pressed = false;

View File

@@ -38,11 +38,11 @@ AlbumPreview::AlbumPreview(
const style::ComposeControls &st,
gsl::span<Ui::PreparedFile> items,
SendFilesWay way,
Fn<bool()> canToggleSpoiler)
Fn<bool(int, AttachActionType)> actionAllowed)
: RpWidget(parent)
, _st(st)
, _sendWay(way)
, _canToggleSpoiler(std::move(canToggleSpoiler))
, _actionAllowed(std::move(actionAllowed))
, _dragTimer([=] { switchToDrag(); }) {
setMouseTracking(true);
prepareThumbs(items);
@@ -582,19 +582,31 @@ void AlbumPreview::mouseReleaseEvent(QMouseEvent *e) {
void AlbumPreview::showContextMenu(
not_null<AlbumThumbnail*> thumb,
QPoint position) {
if (!_canToggleSpoiler() || !_sendWay.sendImagesAsPhotos()) {
return;
}
_menu = base::make_unique_q<Ui::PopupMenu>(
this,
st::popupMenuWithIcons);
const auto spoilered = thumb->hasSpoiler();
_menu->addAction(spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now), [=] {
thumb->setSpoiler(!spoilered);
}, spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
const auto index = orderIndex(thumb);
if (_actionAllowed(index, AttachActionType::ToggleSpoiler)
&& _sendWay.sendImagesAsPhotos()) {
const auto spoilered = thumb->hasSpoiler();
_menu->addAction(spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now), [=] {
thumb->setSpoiler(!spoilered);
}, spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
}
if (_actionAllowed(index, AttachActionType::EditCover)) {
_menu->addAction(tr::lng_context_edit_cover(tr::now), [=] {
_thumbEditCoverRequested.fire_copy(index);
}, &st::menuIconEdit);
if (_actionAllowed(index, AttachActionType::ClearCover)) {
_menu->addAction(tr::lng_context_clear_cover(tr::now), [=] {
_thumbClearCoverRequested.fire_copy(index);
}, &st::menuIconCancel);
}
}
if (_menu->empty()) {
_menu = nullptr;

View File

@@ -29,7 +29,7 @@ public:
const style::ComposeControls &st,
gsl::span<Ui::PreparedFile> items,
SendFilesWay way,
Fn<bool()> canToggleSpoiler);
Fn<bool(int, AttachActionType)> actionAllowed);
~AlbumPreview();
void setSendWay(SendFilesWay way);
@@ -42,15 +42,18 @@ public:
[[nodiscard]] rpl::producer<int> thumbDeleted() const {
return _thumbDeleted.events();
}
[[nodiscard]] rpl::producer<int> thumbChanged() const {
return _thumbChanged.events();
}
[[nodiscard]] rpl::producer<int> thumbModified() const {
return _thumbModified.events();
}
[[nodiscard]] rpl::producer<int> thumbEditCoverRequested() const {
return _thumbEditCoverRequested.events();
}
[[nodiscard]] rpl::producer<int> thumbClearCoverRequested() const {
return _thumbClearCoverRequested.events();
}
[[nodiscard]] rpl::producer<> orderUpdated() const {
return _orderUpdated.events();
}
@@ -101,7 +104,7 @@ private:
const style::ComposeControls &_st;
SendFilesWay _sendWay;
Fn<bool()> _canToggleSpoiler;
Fn<bool(int, AttachActionType)> _actionAllowed;
style::cursor _cursor = style::cur_default;
std::vector<int> _order;
std::vector<QSize> _itemsShownDimensions;
@@ -124,6 +127,8 @@ private:
rpl::event_stream<int> _thumbDeleted;
rpl::event_stream<int> _thumbChanged;
rpl::event_stream<int> _thumbModified;
rpl::event_stream<int> _thumbEditCoverRequested;
rpl::event_stream<int> _thumbClearCoverRequested;
rpl::event_stream<> _orderUpdated;
base::unique_qptr<PopupMenu> _menu;

View File

@@ -35,7 +35,7 @@ AlbumThumbnail::AlbumThumbnail(
Fn<void()> deleteCallback)
: _st(st)
, _layout(layout)
, _fullPreview(file.preview)
, _fullPreview(file.videoCover ? file.videoCover->preview : file.preview)
, _shrinkSize(int(std::ceil(st::roundRadiusLarge / 1.4)))
, _isPhoto(file.type == PreparedFile::Type::Photo)
, _isVideo(file.type == PreparedFile::Type::Video)

View File

@@ -36,8 +36,15 @@ ItemSingleMediaPreview::ItemSingleMediaPreview(
Fn<bool()> gifPaused,
not_null<HistoryItem*> item,
AttachControls::Type type)
: AbstractSingleMediaPreview(parent, st, type, [] { return true; })
: AbstractSingleMediaPreview(parent, st, type, [=](AttachActionType type) {
if (type == AttachActionType::EditCover) {
return _isVideoFile;
}
return true;
})
, _gifPaused(std::move(gifPaused))
, _isVideoFile(item->media()->document()
&& item->media()->document()->isVideoFile())
, _fullId(item->fullId()) {
const auto media = item->media();
Assert(media != nullptr);

View File

@@ -56,6 +56,7 @@ private:
void startStreamedPlayer();
const Fn<bool()> _gifPaused;
const bool _isVideoFile;
const FullMsgId _fullId;
std::shared_ptr<::Data::PhotoMedia> _photoMedia;

View File

@@ -42,6 +42,15 @@ bool PreparedFile::isSticker() const {
&& Core::IsMimeSticker(information->filemime);
}
bool PreparedFile::isVideoFile() const {
Expects(information != nullptr);
using Video = Ui::PreparedFileInformation::Video;
return (type == PreparedFile::Type::Video)
&& v::is<Video>(information->media)
&& !v::get<Video>(information->media).isGifv;
}
bool PreparedFile::isGifv() const {
Expects(information != nullptr);

View File

@@ -74,12 +74,14 @@ struct PreparedFile {
[[nodiscard]] bool canBeInAlbumType(AlbumType album) const;
[[nodiscard]] AlbumType albumType(bool sendImagesAsPhotos) const;
[[nodiscard]] bool isSticker() const;
[[nodiscard]] bool isVideoFile() const;
[[nodiscard]] bool isGifv() const;
QString path;
QByteArray content;
int64 size = 0;
std::unique_ptr<Ui::PreparedFileInformation> information;
std::unique_ptr<PreparedFileInformation> information;
std::unique_ptr<PreparedFile> videoCover;
QImage preview;
QSize shownDimensions;
QSize originalDimensions;

View File

@@ -11,6 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
enum class AttachActionType {
ToggleSpoiler,
EditCover,
ClearCover,
};
enum class AttachButtonType {
Edit,
Delete,

View File

@@ -19,7 +19,7 @@ SingleMediaPreview *SingleMediaPreview::Create(
const style::ComposeControls &st,
Fn<bool()> gifPaused,
const PreparedFile &file,
Fn<bool()> canToggleSpoiler,
Fn<bool(AttachActionType)> actionAllowed,
AttachControls::Type type) {
auto preview = QImage();
auto animated = false;
@@ -32,7 +32,9 @@ SingleMediaPreview *SingleMediaPreview::Create(
hasModifications = !image->modifications.empty();
} else if (const auto video = std::get_if<PreparedFileInformation::Video>(
&file.information->media)) {
preview = video->thumbnail;
preview = file.videoCover
? file.videoCover->preview
: video->thumbnail;
animated = true;
animationPreview = video->isGifv;
}
@@ -53,7 +55,7 @@ SingleMediaPreview *SingleMediaPreview::Create(
file.spoiler,
animationPreview ? file.path : QString(),
type,
std::move(canToggleSpoiler));
std::move(actionAllowed));
}
SingleMediaPreview::SingleMediaPreview(
@@ -66,8 +68,8 @@ SingleMediaPreview::SingleMediaPreview(
bool spoiler,
const QString &animatedPreviewPath,
AttachControls::Type type,
Fn<bool()> canToggleSpoiler)
: AbstractSingleMediaPreview(parent, st, type, std::move(canToggleSpoiler))
Fn<bool(AttachActionType)> actionAllowed)
: AbstractSingleMediaPreview(parent, st, type, std::move(actionAllowed))
, _gifPaused(std::move(gifPaused))
, _sticker(sticker) {
Expects(!preview.isNull());

View File

@@ -25,7 +25,7 @@ public:
const style::ComposeControls &st,
Fn<bool()> gifPaused,
const PreparedFile &file,
Fn<bool()> canToggleSpoiler,
Fn<bool(AttachActionType)> actionAllowed,
AttachControls::Type type = AttachControls::Type::Full);
SingleMediaPreview(
@@ -38,7 +38,7 @@ public:
bool spoiler,
const QString &animatedPreviewPath,
AttachControls::Type type,
Fn<bool()> canToggleSpoiler);
Fn<bool(AttachActionType)> actionAllowed);
protected:
bool supportsSpoilers() const override;