mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Allow sending media with spoilers.
This commit is contained in:
parent
3a38497c4c
commit
5bee6310c0
25 changed files with 465 additions and 111 deletions
|
@ -2327,6 +2327,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_context_animated_reactions_many#one" = "Reactions contain emoji from **{count} pack**.";
|
"lng_context_animated_reactions_many#one" = "Reactions contain emoji from **{count} pack**.";
|
||||||
"lng_context_animated_reactions_many#other" = "Reactions contain emoji from **{count} packs**.";
|
"lng_context_animated_reactions_many#other" = "Reactions contain emoji from **{count} packs**.";
|
||||||
|
|
||||||
|
"lng_context_spoiler_effect" = "Spoiler Effect";
|
||||||
|
"lng_context_disable_spoiler" = "Disable Spoiler Effect";
|
||||||
|
|
||||||
"lng_downloads_section" = "Downloads";
|
"lng_downloads_section" = "Downloads";
|
||||||
"lng_downloads_view_in_chat" = "View in chat";
|
"lng_downloads_view_in_chat" = "View in chat";
|
||||||
"lng_downloads_view_in_section" = "View in downloads";
|
"lng_downloads_view_in_section" = "View in downloads";
|
||||||
|
|
|
@ -206,7 +206,7 @@ void EditMessageWithUploadedPhoto(
|
||||||
EditMessageWithUploadedMedia(
|
EditMessageWithUploadedMedia(
|
||||||
item,
|
item,
|
||||||
options,
|
options,
|
||||||
PrepareUploadedPhoto(std::move(info)));
|
PrepareUploadedPhoto(item, std::move(info)));
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpRequestId EditCaption(
|
mtpRequestId EditCaption(
|
||||||
|
|
|
@ -75,10 +75,14 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MTPInputMedia PrepareUploadedPhoto(RemoteFileInfo info) {
|
MTPInputMedia PrepareUploadedPhoto(
|
||||||
const auto flags = info.attachedStickers.empty()
|
not_null<HistoryItem*> item,
|
||||||
? MTPDinputMediaUploadedPhoto::Flags(0)
|
RemoteFileInfo info) {
|
||||||
: MTPDinputMediaUploadedPhoto::Flag::f_stickers;
|
using Flag = MTPDinputMediaUploadedPhoto::Flag;
|
||||||
|
const auto spoiler = item->media()
|
||||||
|
&& item->media()->hasSpoiler();
|
||||||
|
const auto flags = (spoiler ? Flag::f_spoiler : Flag())
|
||||||
|
| (info.attachedStickers.empty() ? Flag() : Flag::f_stickers);
|
||||||
return MTP_inputMediaUploadedPhoto(
|
return MTP_inputMediaUploadedPhoto(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
info.file,
|
info.file,
|
||||||
|
@ -93,12 +97,13 @@ MTPInputMedia PrepareUploadedDocument(
|
||||||
if (!item || !item->media() || !item->media()->document()) {
|
if (!item || !item->media() || !item->media()->document()) {
|
||||||
return MTP_inputMediaEmpty();
|
return MTP_inputMediaEmpty();
|
||||||
}
|
}
|
||||||
const auto emptyFlag = MTPDinputMediaUploadedDocument::Flags(0);
|
using Flag = MTPDinputMediaUploadedDocument::Flag;
|
||||||
using DocFlags = MTPDinputMediaUploadedDocument::Flag;
|
const auto spoiler = item->media()
|
||||||
const auto flags = emptyFlag
|
&& item->media()->hasSpoiler();
|
||||||
| (info.thumb ? DocFlags::f_thumb : emptyFlag)
|
const auto flags = (spoiler ? Flag::f_spoiler : Flag())
|
||||||
| (item->groupId() ? DocFlags::f_nosound_video : emptyFlag)
|
| (info.thumb ? Flag::f_thumb : Flag())
|
||||||
| (info.attachedStickers.empty() ? DocFlags::f_stickers : emptyFlag);
|
| (item->groupId() ? Flag::f_nosound_video : Flag())
|
||||||
|
| (info.attachedStickers.empty() ? Flag::f_stickers : Flag());
|
||||||
const auto document = item->media()->document();
|
const auto document = item->media()->document();
|
||||||
return MTP_inputMediaUploadedDocument(
|
return MTP_inputMediaUploadedDocument(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
|
|
|
@ -13,7 +13,9 @@ namespace Api {
|
||||||
|
|
||||||
struct RemoteFileInfo;
|
struct RemoteFileInfo;
|
||||||
|
|
||||||
MTPInputMedia PrepareUploadedPhoto(RemoteFileInfo info);
|
MTPInputMedia PrepareUploadedPhoto(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
RemoteFileInfo info);
|
||||||
|
|
||||||
MTPInputMedia PrepareUploadedDocument(
|
MTPInputMedia PrepareUploadedDocument(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
|
|
|
@ -441,13 +441,17 @@ void SendConfirmedFile(
|
||||||
|
|
||||||
const auto media = MTPMessageMedia([&] {
|
const auto media = MTPMessageMedia([&] {
|
||||||
if (file->type == SendMediaType::Photo) {
|
if (file->type == SendMediaType::Photo) {
|
||||||
|
using Flag = MTPDmessageMediaPhoto::Flag;
|
||||||
return MTP_messageMediaPhoto(
|
return MTP_messageMediaPhoto(
|
||||||
MTP_flags(MTPDmessageMediaPhoto::Flag::f_photo),
|
MTP_flags(Flag::f_photo
|
||||||
|
| (file->spoiler ? Flag::f_spoiler : Flag())),
|
||||||
file->photo,
|
file->photo,
|
||||||
MTPint());
|
MTPint());
|
||||||
} else if (file->type == SendMediaType::File) {
|
} else if (file->type == SendMediaType::File) {
|
||||||
|
using Flag = MTPDmessageMediaDocument::Flag;
|
||||||
return MTP_messageMediaDocument(
|
return MTP_messageMediaDocument(
|
||||||
MTP_flags(MTPDmessageMediaDocument::Flag::f_document),
|
MTP_flags(Flag::f_document
|
||||||
|
| (file->spoiler ? Flag::f_spoiler : Flag())),
|
||||||
file->document,
|
file->document,
|
||||||
MTPint());
|
MTPint());
|
||||||
} else if (file->type == SendMediaType::Audio) {
|
} else if (file->type == SendMediaType::Audio) {
|
||||||
|
|
|
@ -3365,7 +3365,8 @@ void ApiWrap::editMedia(
|
||||||
std::move(file.information),
|
std::move(file.information),
|
||||||
type,
|
type,
|
||||||
to,
|
to,
|
||||||
caption));
|
caption,
|
||||||
|
file.spoiler));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::sendFiles(
|
void ApiWrap::sendFiles(
|
||||||
|
@ -3406,6 +3407,7 @@ void ApiWrap::sendFiles(
|
||||||
uploadWithType,
|
uploadWithType,
|
||||||
to,
|
to,
|
||||||
caption,
|
caption,
|
||||||
|
file.spoiler,
|
||||||
album));
|
album));
|
||||||
caption = TextWithTags();
|
caption = TextWithTags();
|
||||||
}
|
}
|
||||||
|
@ -3425,14 +3427,17 @@ void ApiWrap::sendFile(
|
||||||
const SendAction &action) {
|
const SendAction &action) {
|
||||||
const auto to = fileLoadTaskOptions(action);
|
const auto to = fileLoadTaskOptions(action);
|
||||||
auto caption = TextWithTags();
|
auto caption = TextWithTags();
|
||||||
|
const auto spoiler = false;
|
||||||
|
const auto information = nullptr;
|
||||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||||
&session(),
|
&session(),
|
||||||
QString(),
|
QString(),
|
||||||
fileContent,
|
fileContent,
|
||||||
nullptr,
|
information,
|
||||||
type,
|
type,
|
||||||
to,
|
to,
|
||||||
caption));
|
caption,
|
||||||
|
spoiler));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::sendUploadedPhoto(
|
void ApiWrap::sendUploadedPhoto(
|
||||||
|
@ -3440,7 +3445,7 @@ void ApiWrap::sendUploadedPhoto(
|
||||||
Api::RemoteFileInfo info,
|
Api::RemoteFileInfo info,
|
||||||
Api::SendOptions options) {
|
Api::SendOptions options) {
|
||||||
if (const auto item = _session->data().message(localId)) {
|
if (const auto item = _session->data().message(localId)) {
|
||||||
const auto media = Api::PrepareUploadedPhoto(std::move(info));
|
const auto media = Api::PrepareUploadedPhoto(item, std::move(info));
|
||||||
if (const auto groupId = item->groupId()) {
|
if (const auto groupId = item->groupId()) {
|
||||||
uploadAlbumMedia(item, groupId, media);
|
uploadAlbumMedia(item, groupId, media);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -215,19 +215,35 @@ rpl::producer<int> SendFilesBox::Block::itemModifyRequest() const {
|
||||||
|
|
||||||
void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) {
|
void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) {
|
||||||
if (!_isAlbum) {
|
if (!_isAlbum) {
|
||||||
|
if (_isSingleMedia) {
|
||||||
|
const auto media = static_cast<Ui::SingleMediaPreview*>(
|
||||||
|
_preview.get());
|
||||||
|
media->setSendWay(way);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
applyAlbumOrder();
|
applyChanges();
|
||||||
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
|
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
|
||||||
album->setSendWay(way);
|
album->setSendWay(way);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendFilesBox::Block::applyAlbumOrder() {
|
void SendFilesBox::Block::applyChanges() {
|
||||||
if (!_isAlbum) {
|
if (!_isAlbum) {
|
||||||
|
if (_isSingleMedia) {
|
||||||
|
const auto media = static_cast<Ui::SingleMediaPreview*>(
|
||||||
|
_preview.get());
|
||||||
|
(*_items)[_from].spoiler = media->hasSpoiler();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
|
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
|
||||||
const auto order = album->takeOrder();
|
const auto order = album->takeOrder();
|
||||||
|
const auto spoilered = album->collectSpoileredIndices();
|
||||||
|
const auto guard = gsl::finally([&] {
|
||||||
|
for (auto i = 0, count = int(order.size()); i != count; ++i) {
|
||||||
|
(*_items)[_from + i].spoiler = spoilered.contains(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
const auto isIdentity = [&] {
|
const auto isIdentity = [&] {
|
||||||
for (auto i = 0, count = int(order.size()); i != count; ++i) {
|
for (auto i = 0, count = int(order.size()); i != count; ++i) {
|
||||||
if (order[i] != i) {
|
if (order[i] != i) {
|
||||||
|
@ -385,19 +401,25 @@ void SendFilesBox::setupDragArea() {
|
||||||
areas.photo->setDroppedCallback(droppedCallback(true));
|
areas.photo->setDroppedCallback(droppedCallback(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendFilesBox::refreshAllAfterChanges(int fromItem) {
|
void SendFilesBox::refreshAllAfterChanges(int fromItem, Fn<void()> perform) {
|
||||||
auto fromBlock = 0;
|
auto fromBlock = 0;
|
||||||
for (auto count = int(_blocks.size()); fromBlock != count; ++fromBlock) {
|
for (auto count = int(_blocks.size()); fromBlock != count; ++fromBlock) {
|
||||||
if (_blocks[fromBlock].tillIndex() >= fromItem) {
|
if (_blocks[fromBlock].tillIndex() >= fromItem) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto index = fromBlock; index < _blocks.size(); ++index) {
|
||||||
|
_blocks[index].applyChanges();
|
||||||
|
}
|
||||||
|
if (perform) {
|
||||||
|
perform();
|
||||||
|
}
|
||||||
|
generatePreviewFrom(fromBlock);
|
||||||
{
|
{
|
||||||
auto sendWay = _sendWay.current();
|
auto sendWay = _sendWay.current();
|
||||||
sendWay.setHasCompressedStickers(_list.hasSticker());
|
sendWay.setHasCompressedStickers(_list.hasSticker());
|
||||||
_sendWay = sendWay;
|
_sendWay = sendWay;
|
||||||
}
|
}
|
||||||
generatePreviewFrom(fromBlock);
|
|
||||||
_inner->resizeToWidth(st::boxWideWidth);
|
_inner->resizeToWidth(st::boxWideWidth);
|
||||||
refreshControls();
|
refreshControls();
|
||||||
captionResized();
|
captionResized();
|
||||||
|
@ -489,11 +511,7 @@ void SendFilesBox::generatePreviewFrom(int fromBlock) {
|
||||||
|
|
||||||
using Type = Ui::PreparedFile::Type;
|
using Type = Ui::PreparedFile::Type;
|
||||||
|
|
||||||
const auto eraseFrom = _blocks.begin() + fromBlock;
|
_blocks.erase(_blocks.begin() + fromBlock, _blocks.end());
|
||||||
for (auto i = eraseFrom; i != _blocks.end(); ++i) {
|
|
||||||
i->applyAlbumOrder();
|
|
||||||
}
|
|
||||||
_blocks.erase(eraseFrom, _blocks.end());
|
|
||||||
|
|
||||||
const auto fromItem = _blocks.empty() ? 0 : _blocks.back().tillIndex();
|
const auto fromItem = _blocks.empty() ? 0 : _blocks.back().tillIndex();
|
||||||
Assert(fromItem <= _list.files.size());
|
Assert(fromItem <= _list.files.size());
|
||||||
|
@ -559,8 +577,9 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||||
closeBox();
|
closeBox();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_list.files.erase(_list.files.begin() + index);
|
refreshAllAfterChanges(index, [&] {
|
||||||
refreshAllAfterChanges(from);
|
_list.files.erase(_list.files.begin() + index);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, widget->lifetime());
|
}, widget->lifetime());
|
||||||
|
|
||||||
|
@ -571,8 +590,9 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||||
if (list.files.empty()) {
|
if (list.files.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_list.files[index] = std::move(list.files.front());
|
refreshAllAfterChanges(from, [&] {
|
||||||
refreshAllAfterChanges(from);
|
_list.files[index] = std::move(list.files.front());
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const auto checkResult = [=](const Ui::PreparedList &list) {
|
const auto checkResult = [=](const Ui::PreparedList &list) {
|
||||||
if (_sendLimit != SendLimit::One) {
|
if (_sendLimit != SendLimit::One) {
|
||||||
|
@ -1076,7 +1096,7 @@ void SendFilesBox::send(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &block : _blocks) {
|
for (auto &block : _blocks) {
|
||||||
block.applyAlbumOrder();
|
block.applyChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::ApplyModifications(_list);
|
Storage::ApplyModifications(_list);
|
||||||
|
|
|
@ -106,7 +106,7 @@ private:
|
||||||
[[nodiscard]] rpl::producer<int> itemModifyRequest() const;
|
[[nodiscard]] rpl::producer<int> itemModifyRequest() const;
|
||||||
|
|
||||||
void setSendWay(Ui::SendFilesWay way);
|
void setSendWay(Ui::SendFilesWay way);
|
||||||
void applyAlbumOrder();
|
void applyChanges();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
base::unique_qptr<Ui::RpWidget> _preview;
|
base::unique_qptr<Ui::RpWidget> _preview;
|
||||||
|
@ -152,7 +152,7 @@ private:
|
||||||
void pushBlock(int from, int till);
|
void pushBlock(int from, int till);
|
||||||
|
|
||||||
void openDialogToAddFileToAlbum();
|
void openDialogToAddFileToAlbum();
|
||||||
void refreshAllAfterChanges(int fromItem);
|
void refreshAllAfterChanges(int fromItem, Fn<void()> perform = nullptr);
|
||||||
|
|
||||||
void enqueueNextPrepare();
|
void enqueueNextPrepare();
|
||||||
void addPreparedAsyncFile(Ui::PreparedFile &&file);
|
void addPreparedAsyncFile(Ui::PreparedFile &&file);
|
||||||
|
|
|
@ -129,7 +129,8 @@ void DicePack::generateLocal(int index, const QString &name) {
|
||||||
nullptr,
|
nullptr,
|
||||||
SendMediaType::File,
|
SendMediaType::File,
|
||||||
FileLoadTo(0, {}, 0, 0, 0),
|
FileLoadTo(0, {}, 0, 0, 0),
|
||||||
{});
|
{},
|
||||||
|
false);
|
||||||
task.process({ .generateGoodThumbnail = false });
|
task.process({ .generateGoodThumbnail = false });
|
||||||
const auto result = task.peekResult();
|
const auto result = task.peekResult();
|
||||||
Assert(result != nullptr);
|
Assert(result != nullptr);
|
||||||
|
|
|
@ -446,6 +446,10 @@ QString Media::errorTextForForward(not_null<PeerData*> peer) const {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Media::hasSpoiler() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Media::consumeMessageText(const TextWithEntities &text) {
|
bool Media::consumeMessageText(const TextWithEntities &text) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -663,6 +667,10 @@ QString MediaPhoto::errorTextForForward(not_null<PeerData*> peer) const {
|
||||||
).value_or(QString());
|
).value_or(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MediaPhoto::hasSpoiler() const {
|
||||||
|
return _spoiler;
|
||||||
|
}
|
||||||
|
|
||||||
bool MediaPhoto::updateInlineResultMedia(const MTPMessageMedia &media) {
|
bool MediaPhoto::updateInlineResultMedia(const MTPMessageMedia &media) {
|
||||||
if (media.type() != mtpc_messageMediaPhoto) {
|
if (media.type() != mtpc_messageMediaPhoto) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1037,6 +1045,10 @@ QString MediaFile::errorTextForForward(not_null<PeerData*> peer) const {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MediaFile::hasSpoiler() const {
|
||||||
|
return _spoiler;
|
||||||
|
}
|
||||||
|
|
||||||
bool MediaFile::updateInlineResultMedia(const MTPMessageMedia &media) {
|
bool MediaFile::updateInlineResultMedia(const MTPMessageMedia &media) {
|
||||||
if (media.type() != mtpc_messageMediaDocument) {
|
if (media.type() != mtpc_messageMediaDocument) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
virtual bool dropForwardedInfo() const;
|
virtual bool dropForwardedInfo() const;
|
||||||
virtual bool forceForwardedInfo() const;
|
virtual bool forceForwardedInfo() const;
|
||||||
virtual QString errorTextForForward(not_null<PeerData*> peer) const;
|
virtual QString errorTextForForward(not_null<PeerData*> peer) const;
|
||||||
|
[[nodiscard]] virtual bool hasSpoiler() const;
|
||||||
|
|
||||||
[[nodiscard]] virtual bool consumeMessageText(
|
[[nodiscard]] virtual bool consumeMessageText(
|
||||||
const TextWithEntities &text);
|
const TextWithEntities &text);
|
||||||
|
@ -190,6 +191,7 @@ public:
|
||||||
bool allowsEditCaption() const override;
|
bool allowsEditCaption() const override;
|
||||||
bool allowsEditMedia() const override;
|
bool allowsEditMedia() const override;
|
||||||
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
||||||
|
bool hasSpoiler() const override;
|
||||||
|
|
||||||
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
bool updateSentMedia(const MTPMessageMedia &media) override;
|
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
@ -233,6 +235,7 @@ public:
|
||||||
bool forwardedBecomesUnread() const override;
|
bool forwardedBecomesUnread() const override;
|
||||||
bool dropForwardedInfo() const override;
|
bool dropForwardedInfo() const override;
|
||||||
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
||||||
|
bool hasSpoiler() const override;
|
||||||
|
|
||||||
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
bool updateSentMedia(const MTPMessageMedia &media) override;
|
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
|
@ -834,12 +834,27 @@ void Gif::validateSpoilerImageCache(
|
||||||
&& _spoiler->backgroundRounding == rounding) {
|
&& _spoiler->backgroundRounding == rounding) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto normal = _dataMedia->thumbnail();
|
||||||
|
auto container = std::optional<Image>();
|
||||||
|
const auto downscale = [&](Image *image) {
|
||||||
|
if (!image || (image->width() <= 40 && image->height() <= 40)) {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
container.emplace(image->original().scaled(
|
||||||
|
{ 40, 40 },
|
||||||
|
Qt::KeepAspectRatio,
|
||||||
|
Qt::SmoothTransformation));
|
||||||
|
return &*container;
|
||||||
|
};
|
||||||
|
const auto videothumb = _videoThumbnailFrame.get();
|
||||||
|
const auto embedded = _dataMedia->thumbnailInline();
|
||||||
|
const auto blurred = embedded ? embedded : downscale(normal);
|
||||||
_spoiler->background = Images::Round(
|
_spoiler->background = Images::Round(
|
||||||
PrepareWithBlurredBackground(
|
PrepareWithBlurredBackground(
|
||||||
outer,
|
outer,
|
||||||
::Media::Streaming::ExpandDecision(),
|
::Media::Streaming::ExpandDecision(),
|
||||||
nullptr,
|
nullptr,
|
||||||
_dataMedia->thumbnailInline()),
|
blurred),
|
||||||
MediaRoundingMask(rounding));
|
MediaRoundingMask(rounding));
|
||||||
_spoiler->backgroundRounding = rounding;
|
_spoiler->backgroundRounding = rounding;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1588,6 +1588,7 @@ void FormController::uploadEncryptedFile(
|
||||||
file.uploadData->fileId,
|
file.uploadData->fileId,
|
||||||
FileLoadTo(PeerId(), Api::SendOptions(), MsgId(), MsgId(), MsgId()),
|
FileLoadTo(PeerId(), Api::SendOptions(), MsgId(), MsgId(), MsgId()),
|
||||||
TextWithTags(),
|
TextWithTags(),
|
||||||
|
false,
|
||||||
std::shared_ptr<SendingAlbum>(nullptr));
|
std::shared_ptr<SendingAlbum>(nullptr));
|
||||||
prepared->type = SendMediaType::Secure;
|
prepared->type = SendMediaType::Secure;
|
||||||
prepared->content = QByteArray::fromRawData(
|
prepared->content = QByteArray::fromRawData(
|
||||||
|
|
|
@ -488,12 +488,14 @@ FileLoadResult::FileLoadResult(
|
||||||
uint64 id,
|
uint64 id,
|
||||||
const FileLoadTo &to,
|
const FileLoadTo &to,
|
||||||
const TextWithTags &caption,
|
const TextWithTags &caption,
|
||||||
|
bool spoiler,
|
||||||
std::shared_ptr<SendingAlbum> album)
|
std::shared_ptr<SendingAlbum> album)
|
||||||
: taskId(taskId)
|
: taskId(taskId)
|
||||||
, id(id)
|
, id(id)
|
||||||
, to(to)
|
, to(to)
|
||||||
, album(std::move(album))
|
, album(std::move(album))
|
||||||
, caption(caption) {
|
, caption(caption)
|
||||||
|
, spoiler(spoiler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLoadResult::setFileData(const QByteArray &filedata) {
|
void FileLoadResult::setFileData(const QByteArray &filedata) {
|
||||||
|
@ -530,6 +532,7 @@ FileLoadTask::FileLoadTask(
|
||||||
SendMediaType type,
|
SendMediaType type,
|
||||||
const FileLoadTo &to,
|
const FileLoadTo &to,
|
||||||
const TextWithTags &caption,
|
const TextWithTags &caption,
|
||||||
|
bool spoiler,
|
||||||
std::shared_ptr<SendingAlbum> album)
|
std::shared_ptr<SendingAlbum> album)
|
||||||
: _id(base::RandomValue<uint64>())
|
: _id(base::RandomValue<uint64>())
|
||||||
, _session(session)
|
, _session(session)
|
||||||
|
@ -540,7 +543,8 @@ FileLoadTask::FileLoadTask(
|
||||||
, _content(content)
|
, _content(content)
|
||||||
, _information(std::move(information))
|
, _information(std::move(information))
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _caption(caption) {
|
, _caption(caption)
|
||||||
|
, _spoiler(spoiler) {
|
||||||
Expects(to.options.scheduled
|
Expects(to.options.scheduled
|
||||||
|| !to.replaceMediaOf
|
|| !to.replaceMediaOf
|
||||||
|| IsServerMsgId(to.replaceMediaOf));
|
|| IsServerMsgId(to.replaceMediaOf));
|
||||||
|
@ -736,6 +740,7 @@ void FileLoadTask::process(Args &&args) {
|
||||||
_id,
|
_id,
|
||||||
_to,
|
_to,
|
||||||
_caption,
|
_caption,
|
||||||
|
_spoiler,
|
||||||
_album);
|
_album);
|
||||||
|
|
||||||
QString filename, filemime;
|
QString filename, filemime;
|
||||||
|
|
|
@ -224,6 +224,7 @@ struct FileLoadResult {
|
||||||
uint64 id,
|
uint64 id,
|
||||||
const FileLoadTo &to,
|
const FileLoadTo &to,
|
||||||
const TextWithTags &caption,
|
const TextWithTags &caption,
|
||||||
|
bool spoiler,
|
||||||
std::shared_ptr<SendingAlbum> album);
|
std::shared_ptr<SendingAlbum> album);
|
||||||
|
|
||||||
TaskId taskId;
|
TaskId taskId;
|
||||||
|
@ -256,6 +257,7 @@ struct FileLoadResult {
|
||||||
|
|
||||||
PreparedPhotoThumbs photoThumbs;
|
PreparedPhotoThumbs photoThumbs;
|
||||||
TextWithTags caption;
|
TextWithTags caption;
|
||||||
|
bool spoiler = false;
|
||||||
|
|
||||||
std::vector<MTPInputDocument> attachedStickers;
|
std::vector<MTPInputDocument> attachedStickers;
|
||||||
|
|
||||||
|
@ -285,6 +287,7 @@ public:
|
||||||
SendMediaType type,
|
SendMediaType type,
|
||||||
const FileLoadTo &to,
|
const FileLoadTo &to,
|
||||||
const TextWithTags &caption,
|
const TextWithTags &caption,
|
||||||
|
bool spoiler,
|
||||||
std::shared_ptr<SendingAlbum> album = nullptr);
|
std::shared_ptr<SendingAlbum> album = nullptr);
|
||||||
FileLoadTask(
|
FileLoadTask(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
|
@ -343,6 +346,7 @@ private:
|
||||||
VoiceWaveform _waveform;
|
VoiceWaveform _waveform;
|
||||||
SendMediaType _type;
|
SendMediaType _type;
|
||||||
TextWithTags _caption;
|
TextWithTags _caption;
|
||||||
|
bool _spoiler = false;
|
||||||
|
|
||||||
std::shared_ptr<FileLoadResult> _result;
|
std::shared_ptr<FileLoadResult> _result;
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "editor/photo_editor_common.h"
|
#include "editor/photo_editor_common.h"
|
||||||
#include "ui/chat/attach/attach_controls.h"
|
#include "ui/chat/attach/attach_controls.h"
|
||||||
|
#include "ui/chat/attach/attach_prepare.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/effects/spoiler_mess.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
#include "styles/style_menu_icons.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -29,7 +33,6 @@ AbstractSingleMediaPreview::AbstractSingleMediaPreview(
|
||||||
: AbstractSinglePreview(parent)
|
: AbstractSinglePreview(parent)
|
||||||
, _minThumbH(st::sendBoxAlbumGroupSize.height()
|
, _minThumbH(st::sendBoxAlbumGroupSize.height()
|
||||||
+ st::sendBoxAlbumGroupSkipTop * 2)
|
+ st::sendBoxAlbumGroupSkipTop * 2)
|
||||||
, _photoEditorButton(base::make_unique_q<AbstractButton>(this))
|
|
||||||
, _controls(base::make_unique_q<AttachControlsWidget>(this, type)) {
|
, _controls(base::make_unique_q<AttachControlsWidget>(this, type)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +47,25 @@ rpl::producer<> AbstractSingleMediaPreview::editRequests() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<> AbstractSingleMediaPreview::modifyRequests() const {
|
rpl::producer<> AbstractSingleMediaPreview::modifyRequests() const {
|
||||||
return _photoEditorButton->clicks() | rpl::to_empty;
|
return _photoEditorRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::setSendWay(SendFilesWay way) {
|
||||||
|
if (_sendWay != way) {
|
||||||
|
_sendWay = way;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::setSpoiler(bool spoiler) {
|
||||||
|
_spoiler = spoiler
|
||||||
|
? std::make_unique<SpoilerAnimation>([=] { update(); })
|
||||||
|
: nullptr;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractSingleMediaPreview::hasSpoiler() const {
|
||||||
|
return _spoiler != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractSingleMediaPreview::preparePreview(QImage preview) {
|
void AbstractSingleMediaPreview::preparePreview(QImage preview) {
|
||||||
|
@ -105,16 +126,17 @@ void AbstractSingleMediaPreview::preparePreview(QImage preview) {
|
||||||
preview = Images::Opaque(std::move(preview));
|
preview = Images::Opaque(std::move(preview));
|
||||||
_preview = PixmapFromImage(std::move(preview));
|
_preview = PixmapFromImage(std::move(preview));
|
||||||
_preview.setDevicePixelRatio(style::DevicePixelRatio());
|
_preview.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
_previewBlurred = QPixmap();
|
||||||
updatePhotoEditorButton();
|
|
||||||
|
|
||||||
resize(width(), std::max(_previewHeight, _minThumbH));
|
resize(width(), std::max(_previewHeight, _minThumbH));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractSingleMediaPreview::updatePhotoEditorButton() {
|
bool AbstractSingleMediaPreview::isOverPreview(QPoint position) const {
|
||||||
_photoEditorButton->resize(_previewWidth, _previewHeight);
|
return QRect(
|
||||||
_photoEditorButton->moveToLeft(_previewLeft, _previewTop);
|
_previewLeft,
|
||||||
_photoEditorButton->setVisible(isPhoto());
|
_previewTop,
|
||||||
|
_previewWidth,
|
||||||
|
_previewHeight).contains(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractSingleMediaPreview::resizeEvent(QResizeEvent *e) {
|
void AbstractSingleMediaPreview::resizeEvent(QResizeEvent *e) {
|
||||||
|
@ -127,6 +149,15 @@ void AbstractSingleMediaPreview::resizeEvent(QResizeEvent *e) {
|
||||||
void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
||||||
auto p = QPainter(this);
|
auto p = QPainter(this);
|
||||||
|
|
||||||
|
auto takenSpoiler = (drawBackground() || _sendWay.sendImagesAsPhotos())
|
||||||
|
? nullptr
|
||||||
|
: base::take(_spoiler);
|
||||||
|
const auto guard = gsl::finally([&] {
|
||||||
|
if (takenSpoiler) {
|
||||||
|
_spoiler = base::take(takenSpoiler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (drawBackground()) {
|
if (drawBackground()) {
|
||||||
const auto &padding = st::boxPhotoPadding;
|
const auto &padding = st::boxPhotoPadding;
|
||||||
if (_previewLeft > padding.left()) {
|
if (_previewLeft > padding.left()) {
|
||||||
|
@ -154,10 +185,23 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
||||||
st::confirmBg);
|
st::confirmBg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tryPaintAnimation(p)) {
|
|
||||||
p.drawPixmap(_previewLeft, _previewTop, _preview);
|
if (_spoiler && _previewBlurred.isNull()) {
|
||||||
|
_previewBlurred = BlurredPreviewFromPixmap(_preview, RectPart::None);
|
||||||
}
|
}
|
||||||
if (_animated && !isAnimatedPreviewReady()) {
|
if (_spoiler || !tryPaintAnimation(p)) {
|
||||||
|
const auto &pixmap = _spoiler ? _previewBlurred : _preview;
|
||||||
|
const auto position = QPoint(_previewLeft, _previewTop);
|
||||||
|
p.drawPixmap(position, pixmap);
|
||||||
|
if (_spoiler) {
|
||||||
|
FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
QRect(position, pixmap.size() / pixmap.devicePixelRatio()),
|
||||||
|
DefaultImageSpoiler().frame(
|
||||||
|
_spoiler->index(crl::now(), false)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_animated && !isAnimatedPreviewReady() && !_spoiler) {
|
||||||
const auto innerSize = st::msgFileLayout.thumbSize;
|
const auto innerSize = st::msgFileLayout.thumbSize;
|
||||||
auto inner = QRect(
|
auto inner = QRect(
|
||||||
_previewLeft + (_previewWidth - innerSize) / 2,
|
_previewLeft + (_previewWidth - innerSize) / 2,
|
||||||
|
@ -177,6 +221,56 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::mousePressEvent(QMouseEvent *e) {
|
||||||
|
if (isOverPreview(e->pos())) {
|
||||||
|
_pressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
applyCursor((isPhoto() && isOverPreview(e->pos()))
|
||||||
|
? style::cur_pointer
|
||||||
|
: style::cur_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
if (base::take(_pressed) && isOverPreview(e->pos())) {
|
||||||
|
if (e->button() == Qt::RightButton) {
|
||||||
|
showContextMenu(e->globalPos());
|
||||||
|
} else if (isPhoto()) {
|
||||||
|
_photoEditorRequests.fire({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::applyCursor(style::cursor cursor) {
|
||||||
|
if (_cursor != cursor) {
|
||||||
|
_cursor = cursor;
|
||||||
|
setCursor(_cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSingleMediaPreview::showContextMenu(QPoint position) {
|
||||||
|
if (!_sendWay.sendImagesAsPhotos()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||||
|
this,
|
||||||
|
st::popupMenuWithIcons);
|
||||||
|
|
||||||
|
_menu->addAction(hasSpoiler()
|
||||||
|
? tr::lng_context_disable_spoiler(tr::now)
|
||||||
|
: tr::lng_context_spoiler_effect(tr::now), [=] {
|
||||||
|
setSpoiler(!hasSpoiler());
|
||||||
|
}, &st::menuIconCopy);
|
||||||
|
|
||||||
|
if (_menu->empty()) {
|
||||||
|
_menu = nullptr;
|
||||||
|
} else {
|
||||||
|
_menu->popup(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int AbstractSingleMediaPreview::previewLeft() const {
|
int AbstractSingleMediaPreview::previewLeft() const {
|
||||||
return _previewLeft;
|
return _previewLeft;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,27 +9,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/chat/attach/attach_abstract_single_preview.h"
|
#include "ui/chat/attach/attach_abstract_single_preview.h"
|
||||||
#include "ui/chat/attach/attach_controls.h"
|
#include "ui/chat/attach/attach_controls.h"
|
||||||
|
#include "ui/chat/attach/attach_send_files_way.h"
|
||||||
#include "ui/abstract_button.h"
|
#include "ui/abstract_button.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
class PopupMenu;
|
||||||
|
|
||||||
class AbstractSingleMediaPreview : public AbstractSinglePreview {
|
class AbstractSingleMediaPreview : public AbstractSinglePreview {
|
||||||
public:
|
public:
|
||||||
AbstractSingleMediaPreview(QWidget *parent, AttachControls::Type type);
|
AbstractSingleMediaPreview(QWidget *parent, AttachControls::Type type);
|
||||||
~AbstractSingleMediaPreview();
|
~AbstractSingleMediaPreview();
|
||||||
|
|
||||||
|
void setSendWay(SendFilesWay way);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> deleteRequests() const override;
|
[[nodiscard]] rpl::producer<> deleteRequests() const override;
|
||||||
[[nodiscard]] rpl::producer<> editRequests() const override;
|
[[nodiscard]] rpl::producer<> editRequests() const override;
|
||||||
[[nodiscard]] rpl::producer<> modifyRequests() const override;
|
[[nodiscard]] rpl::producer<> modifyRequests() const override;
|
||||||
|
|
||||||
[[nodiscard]] bool isPhoto() const;
|
[[nodiscard]] bool isPhoto() const;
|
||||||
|
|
||||||
|
void setSpoiler(bool spoiler);
|
||||||
|
[[nodiscard]] bool hasSpoiler() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool drawBackground() const = 0;
|
virtual bool drawBackground() const = 0;
|
||||||
virtual bool tryPaintAnimation(QPainter &p) = 0;
|
virtual bool tryPaintAnimation(QPainter &p) = 0;
|
||||||
virtual bool isAnimatedPreviewReady() const = 0;
|
virtual bool isAnimatedPreviewReady() const = 0;
|
||||||
|
|
||||||
void updatePhotoEditorButton();
|
|
||||||
void preparePreview(QImage preview);
|
void preparePreview(QImage preview);
|
||||||
|
|
||||||
int previewLeft() const;
|
int previewLeft() const;
|
||||||
|
@ -42,17 +49,33 @@ protected:
|
||||||
private:
|
private:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isOverPreview(QPoint position) const;
|
||||||
|
void applyCursor(style::cursor cursor);
|
||||||
|
void showContextMenu(QPoint position);
|
||||||
|
|
||||||
|
SendFilesWay _sendWay;
|
||||||
bool _animated = false;
|
bool _animated = false;
|
||||||
QPixmap _preview;
|
QPixmap _preview;
|
||||||
|
QPixmap _previewBlurred;
|
||||||
int _previewLeft = 0;
|
int _previewLeft = 0;
|
||||||
int _previewTop = 0;
|
int _previewTop = 0;
|
||||||
int _previewWidth = 0;
|
int _previewWidth = 0;
|
||||||
int _previewHeight = 0;
|
int _previewHeight = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<SpoilerAnimation> _spoiler;
|
||||||
|
|
||||||
const int _minThumbH;
|
const int _minThumbH;
|
||||||
const base::unique_qptr<AbstractButton> _photoEditorButton;
|
|
||||||
const base::unique_qptr<AttachControlsWidget> _controls;
|
const base::unique_qptr<AttachControlsWidget> _controls;
|
||||||
|
rpl::event_stream<> _photoEditorRequests;
|
||||||
|
|
||||||
|
style::cursor _cursor = style::cur_default;
|
||||||
|
bool _pressed = false;
|
||||||
|
|
||||||
|
base::unique_qptr<PopupMenu> _menu;
|
||||||
|
|
||||||
rpl::event_stream<> _modifyRequests;
|
rpl::event_stream<> _modifyRequests;
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/chat/attach/attach_album_thumbnail.h"
|
#include "ui/chat/attach/attach_album_thumbnail.h"
|
||||||
#include "ui/chat/attach/attach_prepare.h"
|
#include "ui/chat/attach/attach_prepare.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
#include "styles/style_menu_icons.h"
|
||||||
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
|
|
||||||
|
@ -61,6 +64,19 @@ void AlbumPreview::updateFileRows() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::flat_set<int> AlbumPreview::collectSpoileredIndices() {
|
||||||
|
auto result = base::flat_set<int>();
|
||||||
|
result.reserve(_thumbs.size());
|
||||||
|
auto i = 0;
|
||||||
|
for (const auto &thumb : _thumbs) {
|
||||||
|
if (thumb->hasSpoiler()) {
|
||||||
|
result.emplace(i);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> AlbumPreview::takeOrder() {
|
std::vector<int> AlbumPreview::takeOrder() {
|
||||||
//Expects(_thumbs.size() == _order.size());
|
//Expects(_thumbs.size() == _order.size());
|
||||||
//Expects(_itemsShownDimensions.size() == _order.size());
|
//Expects(_itemsShownDimensions.size() == _order.size());
|
||||||
|
@ -112,6 +128,7 @@ void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
|
||||||
items[i],
|
items[i],
|
||||||
layout[i],
|
layout[i],
|
||||||
this,
|
this,
|
||||||
|
[=] { update(); },
|
||||||
[=] { changeThumbByIndex(thumbIndex(thumbUnderCursor())); },
|
[=] { changeThumbByIndex(thumbIndex(thumbUnderCursor())); },
|
||||||
[=] { deleteThumbByIndex(thumbIndex(thumbUnderCursor())); }));
|
[=] { deleteThumbByIndex(thumbIndex(thumbUnderCursor())); }));
|
||||||
if (_thumbs.back()->isCompressedSticker()) {
|
if (_thumbs.back()->isCompressedSticker()) {
|
||||||
|
@ -365,11 +382,7 @@ void AlbumPreview::paintFiles(Painter &p, QRect clip) const {
|
||||||
} else if (bottom <= clip.y()) {
|
} else if (bottom <= clip.y()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (thumb->isCompressedSticker()) {
|
thumb->paintFile(p, left, top, outerWidth);
|
||||||
thumb->paintPhoto(p, left, top, outerWidth);
|
|
||||||
} else {
|
|
||||||
thumb->paintFile(p, left, top, outerWidth);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -393,15 +406,6 @@ void AlbumPreview::deleteThumbByIndex(int index) {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto orderIt = ranges::find(_order, index);
|
|
||||||
Expects(orderIt != _order.end());
|
|
||||||
|
|
||||||
_order.erase(orderIt);
|
|
||||||
ranges::for_each(_order, [=](auto &i) {
|
|
||||||
if (i > index) {
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_thumbDeleted.fire(std::move(index));
|
_thumbDeleted.fire(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,7 +452,8 @@ void AlbumPreview::mousePressEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
const auto isAlbum = _sendWay.sendImagesAsPhotos()
|
const auto isAlbum = _sendWay.sendImagesAsPhotos()
|
||||||
&& _sendWay.groupFiles();
|
&& _sendWay.groupFiles();
|
||||||
if (!isAlbum) {
|
if (!isAlbum || e->button() != Qt::LeftButton) {
|
||||||
|
_dragTimer.cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,13 +559,38 @@ void AlbumPreview::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
} else if (const auto thumb = base::take(_pressedThumb)) {
|
} else if (const auto thumb = base::take(_pressedThumb)) {
|
||||||
const auto was = _pressedButtonType;
|
const auto was = _pressedButtonType;
|
||||||
const auto now = thumb->buttonTypeFromPoint(e->pos());
|
const auto now = thumb->buttonTypeFromPoint(e->pos());
|
||||||
if (was == now) {
|
if (e->button() == Qt::RightButton) {
|
||||||
|
showContextMenu(thumb, e->globalPos());
|
||||||
|
} else if (was == now) {
|
||||||
thumbButtonsCallback(thumb, now);
|
thumbButtonsCallback(thumb, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_pressedButtonType = AttachButtonType::None;
|
_pressedButtonType = AttachButtonType::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AlbumPreview::showContextMenu(
|
||||||
|
not_null<AlbumThumbnail*> thumb,
|
||||||
|
QPoint position) {
|
||||||
|
if (!_sendWay.sendImagesAsPhotos()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||||
|
this,
|
||||||
|
st::popupMenuWithIcons);
|
||||||
|
|
||||||
|
_menu->addAction(thumb->hasSpoiler()
|
||||||
|
? tr::lng_context_disable_spoiler(tr::now)
|
||||||
|
: tr::lng_context_spoiler_effect(tr::now), [=] {
|
||||||
|
thumb->setSpoiler(!thumb->hasSpoiler());
|
||||||
|
}, &st::menuIconCopy);
|
||||||
|
|
||||||
|
if (_menu->empty()) {
|
||||||
|
_menu = nullptr;
|
||||||
|
} else {
|
||||||
|
_menu->popup(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AlbumPreview::switchToDrag() {
|
void AlbumPreview::switchToDrag() {
|
||||||
_paintedAbove
|
_paintedAbove
|
||||||
= _suggestedThumb
|
= _suggestedThumb
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Ui {
|
||||||
struct PreparedFile;
|
struct PreparedFile;
|
||||||
struct GroupMediaLayout;
|
struct GroupMediaLayout;
|
||||||
class AlbumThumbnail;
|
class AlbumThumbnail;
|
||||||
|
class PopupMenu;
|
||||||
|
|
||||||
class AlbumPreview final : public RpWidget {
|
class AlbumPreview final : public RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -26,7 +27,9 @@ public:
|
||||||
~AlbumPreview();
|
~AlbumPreview();
|
||||||
|
|
||||||
void setSendWay(SendFilesWay way);
|
void setSendWay(SendFilesWay way);
|
||||||
std::vector<int> takeOrder();
|
|
||||||
|
[[nodiscard]] base::flat_set<int> collectSpoileredIndices();
|
||||||
|
[[nodiscard]] std::vector<int> takeOrder();
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<int> thumbDeleted() const {
|
[[nodiscard]] rpl::producer<int> thumbDeleted() const {
|
||||||
return _thumbDeleted.events();
|
return _thumbDeleted.events();
|
||||||
|
@ -79,6 +82,8 @@ private:
|
||||||
void cancelDrag();
|
void cancelDrag();
|
||||||
void finishDrag();
|
void finishDrag();
|
||||||
|
|
||||||
|
void showContextMenu(not_null<AlbumThumbnail*> thumb, QPoint position);
|
||||||
|
|
||||||
SendFilesWay _sendWay;
|
SendFilesWay _sendWay;
|
||||||
style::cursor _cursor = style::cur_default;
|
style::cursor _cursor = style::cur_default;
|
||||||
std::vector<int> _order;
|
std::vector<int> _order;
|
||||||
|
@ -103,6 +108,8 @@ private:
|
||||||
rpl::event_stream<int> _thumbChanged;
|
rpl::event_stream<int> _thumbChanged;
|
||||||
rpl::event_stream<int> _thumbModified;
|
rpl::event_stream<int> _thumbModified;
|
||||||
|
|
||||||
|
base::unique_qptr<PopupMenu> _menu;
|
||||||
|
|
||||||
mutable Animations::Simple _thumbsHeightAnimation;
|
mutable Animations::Simple _thumbsHeightAnimation;
|
||||||
mutable Animations::Simple _shrinkAnimation;
|
mutable Animations::Simple _shrinkAnimation;
|
||||||
mutable Animations::Simple _finishDragAnimation;
|
mutable Animations::Simple _finishDragAnimation;
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
#include "ui/text/format_values.h"
|
#include "ui/text/format_values.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/effects/spoiler_mess.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
|
@ -26,6 +27,7 @@ AlbumThumbnail::AlbumThumbnail(
|
||||||
const PreparedFile &file,
|
const PreparedFile &file,
|
||||||
const GroupMediaLayout &layout,
|
const GroupMediaLayout &layout,
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
Fn<void()> repaint,
|
||||||
Fn<void()> editCallback,
|
Fn<void()> editCallback,
|
||||||
Fn<void()> deleteCallback)
|
Fn<void()> deleteCallback)
|
||||||
: _layout(layout)
|
: _layout(layout)
|
||||||
|
@ -33,7 +35,8 @@ AlbumThumbnail::AlbumThumbnail(
|
||||||
, _shrinkSize(int(std::ceil(st::roundRadiusLarge / 1.4)))
|
, _shrinkSize(int(std::ceil(st::roundRadiusLarge / 1.4)))
|
||||||
, _isPhoto(file.type == PreparedFile::Type::Photo)
|
, _isPhoto(file.type == PreparedFile::Type::Photo)
|
||||||
, _isVideo(file.type == PreparedFile::Type::Video)
|
, _isVideo(file.type == PreparedFile::Type::Video)
|
||||||
, _isCompressedSticker(Core::IsMimeSticker(file.information->filemime)) {
|
, _isCompressedSticker(Core::IsMimeSticker(file.information->filemime))
|
||||||
|
, _repaint(std::move(repaint)) {
|
||||||
Expects(!_fullPreview.isNull());
|
Expects(!_fullPreview.isNull());
|
||||||
|
|
||||||
moveToLayout(layout);
|
moveToLayout(layout);
|
||||||
|
@ -107,9 +110,23 @@ AlbumThumbnail::AlbumThumbnail(
|
||||||
_editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile);
|
_editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile);
|
||||||
_deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile);
|
_deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile);
|
||||||
|
|
||||||
|
setSpoiler(file.spoiler);
|
||||||
setButtonVisible(false);
|
setButtonVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AlbumThumbnail::setSpoiler(bool spoiler) {
|
||||||
|
Expects(_repaint != nullptr);
|
||||||
|
|
||||||
|
_spoiler = spoiler
|
||||||
|
? std::make_unique<SpoilerAnimation>(_repaint)
|
||||||
|
: nullptr;
|
||||||
|
_repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlbumThumbnail::hasSpoiler() const {
|
||||||
|
return _spoiler != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void AlbumThumbnail::setButtonVisible(bool value) {
|
void AlbumThumbnail::setButtonVisible(bool value) {
|
||||||
_editMedia->setVisible(value);
|
_editMedia->setVisible(value);
|
||||||
_deleteMedia->setVisible(value);
|
_deleteMedia->setVisible(value);
|
||||||
|
@ -135,7 +152,7 @@ void AlbumThumbnail::animateLayoutToInitial() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumThumbnail::moveToLayout(const GroupMediaLayout &layout) {
|
void AlbumThumbnail::moveToLayout(const GroupMediaLayout &layout) {
|
||||||
using Option = Images::Option;
|
using namespace Images;
|
||||||
|
|
||||||
animateLayoutToInitial();
|
animateLayoutToInitial();
|
||||||
_layout = layout;
|
_layout = layout;
|
||||||
|
@ -143,27 +160,20 @@ void AlbumThumbnail::moveToLayout(const GroupMediaLayout &layout) {
|
||||||
const auto width = _layout.geometry.width();
|
const auto width = _layout.geometry.width();
|
||||||
const auto height = _layout.geometry.height();
|
const auto height = _layout.geometry.height();
|
||||||
_albumCorners = GetCornersFromSides(_layout.sides);
|
_albumCorners = GetCornersFromSides(_layout.sides);
|
||||||
const auto corner = [&](RectPart part, Option skip) {
|
|
||||||
return !(_albumCorners & part) ? skip : Option();
|
|
||||||
};
|
|
||||||
const auto options = Option::RoundLarge
|
|
||||||
| corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
|
|
||||||
| corner(RectPart::TopRight, Option::RoundSkipTopRight)
|
|
||||||
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
|
|
||||||
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
|
|
||||||
const auto pixSize = GetImageScaleSizeForGeometry(
|
const auto pixSize = GetImageScaleSizeForGeometry(
|
||||||
{ _fullPreview.width(), _fullPreview.height() },
|
{ _fullPreview.width(), _fullPreview.height() },
|
||||||
{ width, height });
|
{ width, height });
|
||||||
const auto pixWidth = pixSize.width() * style::DevicePixelRatio();
|
const auto pixWidth = pixSize.width() * style::DevicePixelRatio();
|
||||||
const auto pixHeight = pixSize.height() * style::DevicePixelRatio();
|
const auto pixHeight = pixSize.height() * style::DevicePixelRatio();
|
||||||
|
|
||||||
_albumImage = PixmapFromImage(Images::Prepare(
|
_albumImage = PixmapFromImage(Prepare(
|
||||||
_fullPreview,
|
_fullPreview,
|
||||||
QSize(pixWidth, pixHeight),
|
QSize(pixWidth, pixHeight),
|
||||||
{
|
{
|
||||||
.options = options,
|
.options = RoundOptions(ImageRoundRadius::Large, _albumCorners),
|
||||||
.outer = { width, height },
|
.outer = { width, height },
|
||||||
}));
|
}));
|
||||||
|
_albumImageBlurred = QPixmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AlbumThumbnail::photoHeight() const {
|
int AlbumThumbnail::photoHeight() const {
|
||||||
|
@ -188,46 +198,83 @@ void AlbumThumbnail::paintInAlbum(
|
||||||
float64 moveProgress) {
|
float64 moveProgress) {
|
||||||
const auto shrink = anim::interpolate(0, _shrinkSize, shrinkProgress);
|
const auto shrink = anim::interpolate(0, _shrinkSize, shrinkProgress);
|
||||||
_lastShrinkValue = shrink;
|
_lastShrinkValue = shrink;
|
||||||
const auto geometry = countCurrentGeometry(moveProgress);
|
const auto geometry = countCurrentGeometry(
|
||||||
const auto x = left + geometry.x();
|
moveProgress
|
||||||
const auto y = top + geometry.y();
|
).translated(left, top);
|
||||||
if (shrink > 0 || moveProgress < 1.) {
|
auto paintedTo = geometry;
|
||||||
const auto size = geometry.size();
|
const auto revealed = _spoiler ? shrinkProgress : 1.;
|
||||||
if (shrinkProgress < 1 && _albumCorners != RectPart::None) {
|
if (revealed > 0.) {
|
||||||
prepareCache(size, shrink);
|
if (shrink > 0 || moveProgress < 1.) {
|
||||||
p.drawImage(x, y, _albumCache);
|
const auto size = geometry.size();
|
||||||
} else {
|
paintedTo = geometry.marginsRemoved(
|
||||||
const auto to = QRect({ x, y }, size).marginsRemoved(
|
|
||||||
{ shrink, shrink, shrink, shrink }
|
{ shrink, shrink, shrink, shrink }
|
||||||
);
|
);
|
||||||
drawSimpleFrame(p, to, size);
|
if (shrinkProgress < 1 && _albumCorners != RectPart::None) {
|
||||||
|
prepareCache(size, shrink);
|
||||||
|
p.drawImage(geometry.topLeft(), _albumCache);
|
||||||
|
} else {
|
||||||
|
drawSimpleFrame(p, paintedTo, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.drawPixmap(geometry.topLeft(), _albumImage);
|
||||||
|
}
|
||||||
|
if (_isVideo) {
|
||||||
|
paintPlayVideo(p, geometry);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
p.drawPixmap(x, y, _albumImage);
|
|
||||||
}
|
}
|
||||||
if (_isVideo) {
|
if (revealed < 1.) {
|
||||||
const auto innerSize = st::msgFileLayout.thumbSize;
|
auto corners = Images::CornersMaskRef(
|
||||||
const auto inner = QRect(
|
Images::CornersMask(ImageRoundRadius::Large));
|
||||||
x + (geometry.width() - innerSize) / 2,
|
if (!(_albumCorners & RectPart::TopLeft)) {
|
||||||
y + (geometry.height() - innerSize) / 2,
|
corners.p[0] = nullptr;
|
||||||
innerSize,
|
|
||||||
innerSize);
|
|
||||||
{
|
|
||||||
PainterHighQualityEnabler hq(p);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(st::msgDateImgBg);
|
|
||||||
p.drawEllipse(inner);
|
|
||||||
}
|
}
|
||||||
st::historyFileThumbPlay.paintInCenter(p, inner);
|
if (!(_albumCorners & RectPart::TopRight)) {
|
||||||
|
corners.p[1] = nullptr;
|
||||||
|
}
|
||||||
|
if (!(_albumCorners & RectPart::BottomLeft)) {
|
||||||
|
corners.p[2] = nullptr;
|
||||||
|
}
|
||||||
|
if (!(_albumCorners & RectPart::BottomRight)) {
|
||||||
|
corners.p[3] = nullptr;
|
||||||
|
}
|
||||||
|
p.setOpacity(1. - revealed);
|
||||||
|
if (_albumImageBlurred.isNull()) {
|
||||||
|
_albumImageBlurred = BlurredPreviewFromPixmap(
|
||||||
|
_albumImage,
|
||||||
|
_albumCorners);
|
||||||
|
}
|
||||||
|
p.drawPixmap(paintedTo, _albumImageBlurred);
|
||||||
|
FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
paintedTo,
|
||||||
|
corners,
|
||||||
|
DefaultImageSpoiler().frame(_spoiler->index(crl::now(), false)),
|
||||||
|
_cornerCache);
|
||||||
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastRectOfButtons = paintButtons(
|
_lastRectOfButtons = paintButtons(
|
||||||
p,
|
p,
|
||||||
{ x, y },
|
geometry.topLeft(),
|
||||||
geometry.width(),
|
geometry.width(),
|
||||||
shrinkProgress);
|
shrinkProgress);
|
||||||
|
_lastRectOfModify = geometry;
|
||||||
|
}
|
||||||
|
|
||||||
_lastRectOfModify = QRect(QPoint(x, y), geometry.size());
|
void AlbumThumbnail::paintPlayVideo(QPainter &p, QRect geometry) {
|
||||||
|
const auto innerSize = st::msgFileLayout.thumbSize;
|
||||||
|
const auto inner = QRect(
|
||||||
|
geometry.x() + (geometry.width() - innerSize) / 2,
|
||||||
|
geometry.y() + (geometry.height() - innerSize) / 2,
|
||||||
|
innerSize,
|
||||||
|
innerSize);
|
||||||
|
{
|
||||||
|
PainterHighQualityEnabler hq(p);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::msgDateImgBg);
|
||||||
|
p.drawEllipse(inner);
|
||||||
|
}
|
||||||
|
st::historyFileThumbPlay.paintInCenter(p, inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumThumbnail::prepareCache(QSize size, int shrink) {
|
void AlbumThumbnail::prepareCache(QSize size, int shrink) {
|
||||||
|
@ -376,11 +423,33 @@ void AlbumThumbnail::drawSimpleFrame(QPainter &p, QRect to, QSize size) const {
|
||||||
|
|
||||||
void AlbumThumbnail::paintPhoto(Painter &p, int left, int top, int outerWidth) {
|
void AlbumThumbnail::paintPhoto(Painter &p, int left, int top, int outerWidth) {
|
||||||
const auto size = _photo.size() / style::DevicePixelRatio();
|
const auto size = _photo.size() / style::DevicePixelRatio();
|
||||||
|
if (_spoiler && _photoBlurred.isNull()) {
|
||||||
|
_photoBlurred = BlurredPreviewFromPixmap(
|
||||||
|
_photo,
|
||||||
|
RectPart::AllCorners);
|
||||||
|
}
|
||||||
|
const auto &pixmap = _spoiler ? _photoBlurred : _photo;
|
||||||
|
const auto rect = QRect(
|
||||||
|
left + (st::sendMediaPreviewSize - size.width()) / 2,
|
||||||
|
top,
|
||||||
|
pixmap.width() / pixmap.devicePixelRatio(),
|
||||||
|
pixmap.height() / pixmap.devicePixelRatio());
|
||||||
p.drawPixmapLeft(
|
p.drawPixmapLeft(
|
||||||
left + (st::sendMediaPreviewSize - size.width()) / 2,
|
left + (st::sendMediaPreviewSize - size.width()) / 2,
|
||||||
top,
|
top,
|
||||||
outerWidth,
|
outerWidth,
|
||||||
_photo);
|
pixmap);
|
||||||
|
if (_spoiler) {
|
||||||
|
FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
rect,
|
||||||
|
Images::CornersMaskRef(
|
||||||
|
Images::CornersMask(ImageRoundRadius::Large)),
|
||||||
|
DefaultImageSpoiler().frame(_spoiler->index(crl::now(), false)),
|
||||||
|
_cornerCache);
|
||||||
|
} else if (_isVideo) {
|
||||||
|
paintPlayVideo(p, rect);
|
||||||
|
}
|
||||||
|
|
||||||
const auto topLeft = QPoint{ left, top };
|
const auto topLeft = QPoint{ left, top };
|
||||||
|
|
||||||
|
@ -398,6 +467,13 @@ void AlbumThumbnail::paintFile(
|
||||||
int left,
|
int left,
|
||||||
int top,
|
int top,
|
||||||
int outerWidth) {
|
int outerWidth) {
|
||||||
|
|
||||||
|
if (isCompressedSticker()) {
|
||||||
|
auto spoiler = base::take(_spoiler);
|
||||||
|
paintPhoto(p, left, top, outerWidth);
|
||||||
|
_spoiler = base::take(spoiler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto &st = st::attachPreviewThumbLayout;
|
const auto &st = st::attachPreviewThumbLayout;
|
||||||
const auto textLeft = left + st.thumbSize + st.thumbSkip;
|
const auto textLeft = left + st.thumbSize + st.thumbSkip;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Ui {
|
||||||
|
|
||||||
struct PreparedFile;
|
struct PreparedFile;
|
||||||
class IconButton;
|
class IconButton;
|
||||||
|
class SpoilerAnimation;
|
||||||
|
|
||||||
class AlbumThumbnail final {
|
class AlbumThumbnail final {
|
||||||
public:
|
public:
|
||||||
|
@ -25,6 +26,7 @@ public:
|
||||||
const PreparedFile &file,
|
const PreparedFile &file,
|
||||||
const GroupMediaLayout &layout,
|
const GroupMediaLayout &layout,
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
Fn<void()> repaint,
|
||||||
Fn<void()> editCallback,
|
Fn<void()> editCallback,
|
||||||
Fn<void()> deleteCallback);
|
Fn<void()> deleteCallback);
|
||||||
|
|
||||||
|
@ -32,6 +34,9 @@ public:
|
||||||
void animateLayoutToInitial();
|
void animateLayoutToInitial();
|
||||||
void resetLayoutAnimation();
|
void resetLayoutAnimation();
|
||||||
|
|
||||||
|
void setSpoiler(bool spoiler);
|
||||||
|
[[nodiscard]] bool hasSpoiler() const;
|
||||||
|
|
||||||
int photoHeight() const;
|
int photoHeight() const;
|
||||||
int fileHeight() const;
|
int fileHeight() const;
|
||||||
|
|
||||||
|
@ -71,6 +76,7 @@ private:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
int outerWidth,
|
int outerWidth,
|
||||||
float64 shrinkProgress);
|
float64 shrinkProgress);
|
||||||
|
void paintPlayVideo(QPainter &p, QRect geometry);
|
||||||
|
|
||||||
GroupMediaLayout _layout;
|
GroupMediaLayout _layout;
|
||||||
std::optional<QRect> _animateFromGeometry;
|
std::optional<QRect> _animateFromGeometry;
|
||||||
|
@ -79,10 +85,12 @@ private:
|
||||||
const bool _isPhoto;
|
const bool _isPhoto;
|
||||||
const bool _isVideo;
|
const bool _isVideo;
|
||||||
QPixmap _albumImage;
|
QPixmap _albumImage;
|
||||||
|
QPixmap _albumImageBlurred;
|
||||||
QImage _albumCache;
|
QImage _albumCache;
|
||||||
QPoint _albumPosition;
|
QPoint _albumPosition;
|
||||||
RectParts _albumCorners = RectPart::None;
|
RectParts _albumCorners = RectPart::None;
|
||||||
QPixmap _photo;
|
QPixmap _photo;
|
||||||
|
QPixmap _photoBlurred;
|
||||||
QPixmap _fileThumb;
|
QPixmap _fileThumb;
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _status;
|
QString _status;
|
||||||
|
@ -94,6 +102,9 @@ private:
|
||||||
AttachControls _buttons;
|
AttachControls _buttons;
|
||||||
|
|
||||||
bool _isCompressedSticker = false;
|
bool _isCompressedSticker = false;
|
||||||
|
std::unique_ptr<SpoilerAnimation> _spoiler;
|
||||||
|
QImage _cornerCache;
|
||||||
|
Fn<void()> _repaint;
|
||||||
|
|
||||||
QRect _lastRectOfModify;
|
QRect _lastRectOfModify;
|
||||||
QRect _lastRectOfButtons;
|
QRect _lastRectOfButtons;
|
||||||
|
|
|
@ -295,4 +295,28 @@ QPixmap PrepareSongCoverForThumbnail(QImage image, int size) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPixmap BlurredPreviewFromPixmap(QPixmap pixmap, RectParts corners) {
|
||||||
|
const auto image = pixmap.toImage();
|
||||||
|
const auto skip = st::roundRadiusLarge * image.devicePixelRatio();
|
||||||
|
auto small = image.copy(
|
||||||
|
skip,
|
||||||
|
skip,
|
||||||
|
image.width() - 2 * skip,
|
||||||
|
image.height() - 2 * skip
|
||||||
|
).scaled(
|
||||||
|
40,
|
||||||
|
40,
|
||||||
|
Qt::KeepAspectRatioByExpanding,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
|
||||||
|
using namespace Images;
|
||||||
|
return PixmapFromImage(Prepare(
|
||||||
|
Blur(std::move(small), true),
|
||||||
|
image.size() / style::DevicePixelRatio(),
|
||||||
|
{
|
||||||
|
.options = RoundOptions(ImageRoundRadius::Large, corners),
|
||||||
|
.outer = image.size() / style::DevicePixelRatio(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "editor/photo_editor_common.h"
|
#include "editor/photo_editor_common.h"
|
||||||
|
#include "ui/rect_part.h"
|
||||||
|
|
||||||
#include <QtCore/QSemaphore>
|
#include <QtCore/QSemaphore>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
@ -80,6 +81,7 @@ struct PreparedFile {
|
||||||
QImage preview;
|
QImage preview;
|
||||||
QSize shownDimensions;
|
QSize shownDimensions;
|
||||||
Type type = Type::File;
|
Type type = Type::File;
|
||||||
|
bool spoiler = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] bool CanBeInAlbumType(PreparedFile::Type type, AlbumType album);
|
[[nodiscard]] bool CanBeInAlbumType(PreparedFile::Type type, AlbumType album);
|
||||||
|
@ -143,4 +145,8 @@ struct PreparedGroup {
|
||||||
|
|
||||||
[[nodiscard]] QPixmap PrepareSongCoverForThumbnail(QImage image, int size);
|
[[nodiscard]] QPixmap PrepareSongCoverForThumbnail(QImage image, int size);
|
||||||
|
|
||||||
|
[[nodiscard]] QPixmap BlurredPreviewFromPixmap(
|
||||||
|
QPixmap pixmap,
|
||||||
|
RectParts corners);
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -47,6 +47,7 @@ SingleMediaPreview *SingleMediaPreview::Create(
|
||||||
preview,
|
preview,
|
||||||
animated,
|
animated,
|
||||||
Core::IsMimeSticker(file.information->filemime),
|
Core::IsMimeSticker(file.information->filemime),
|
||||||
|
file.spoiler,
|
||||||
animationPreview ? file.path : QString(),
|
animationPreview ? file.path : QString(),
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
|
@ -57,6 +58,7 @@ SingleMediaPreview::SingleMediaPreview(
|
||||||
QImage preview,
|
QImage preview,
|
||||||
bool animated,
|
bool animated,
|
||||||
bool sticker,
|
bool sticker,
|
||||||
|
bool spoiler,
|
||||||
const QString &animatedPreviewPath,
|
const QString &animatedPreviewPath,
|
||||||
AttachControls::Type type)
|
AttachControls::Type type)
|
||||||
: AbstractSingleMediaPreview(parent, type)
|
: AbstractSingleMediaPreview(parent, type)
|
||||||
|
@ -67,7 +69,7 @@ SingleMediaPreview::SingleMediaPreview(
|
||||||
|
|
||||||
preparePreview(preview);
|
preparePreview(preview);
|
||||||
prepareAnimatedPreview(animatedPreviewPath, animated);
|
prepareAnimatedPreview(animatedPreviewPath, animated);
|
||||||
updatePhotoEditorButton();
|
setSpoiler(spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SingleMediaPreview::drawBackground() const {
|
bool SingleMediaPreview::drawBackground() const {
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
QImage preview,
|
QImage preview,
|
||||||
bool animated,
|
bool animated,
|
||||||
bool sticker,
|
bool sticker,
|
||||||
|
bool spoiler,
|
||||||
const QString &animatedPreviewPath,
|
const QString &animatedPreviewPath,
|
||||||
AttachControls::Type type);
|
AttachControls::Type type);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue