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:
@@ -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 {
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -56,6 +56,7 @@ private:
|
||||
void startStreamedPlayer();
|
||||
|
||||
const Fn<bool()> _gifPaused;
|
||||
const bool _isVideoFile;
|
||||
const FullMsgId _fullId;
|
||||
|
||||
std::shared_ptr<::Data::PhotoMedia> _photoMedia;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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());
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user