Added ability to send webp as compressed image.

This commit is contained in:
23rd 2022-11-10 18:34:37 +03:00 committed by John Preston
parent 57c50c8655
commit 3467fe226f
12 changed files with 161 additions and 45 deletions

View File

@ -3374,7 +3374,10 @@ void ApiWrap::sendFiles(
std::shared_ptr<SendingAlbum> album,
const SendAction &action) {
const auto haveCaption = !caption.text.isEmpty();
if (haveCaption && !list.canAddCaption(album != nullptr)) {
if (haveCaption
&& !list.canAddCaption(
album != nullptr,
type == SendMediaType::Photo)) {
auto message = MessageToSend(action);
message.textWithTags = base::take(caption);
message.action.clearDraft = false;

View File

@ -102,7 +102,9 @@ void FileDialogCallback(
rpl::producer<QString> FieldPlaceholder(
const Ui::PreparedList &list,
SendFilesWay way) {
return list.canAddCaption(way.groupFiles() && way.sendImagesAsPhotos())
return list.canAddCaption(
way.groupFiles() && way.sendImagesAsPhotos(),
way.sendImagesAsPhotos())
? tr::lng_photo_caption()
: tr::lng_photos_comment();
}
@ -390,6 +392,11 @@ void SendFilesBox::refreshAllAfterChanges(int fromItem) {
break;
}
}
{
auto sendWay = _sendWay.current();
sendWay.setHasCompressedStickers(_list.hasSticker());
_sendWay = sendWay;
}
generatePreviewFrom(fromBlock);
_inner->resizeToWidth(st::boxWideWidth);
refreshControls();
@ -427,6 +434,7 @@ void SendFilesBox::openDialogToAddFileToAlbum() {
void SendFilesBox::initSendWay() {
_sendWay = [&] {
auto result = Core::App().settings().sendFilesWay();
result.setHasCompressedStickers(_list.hasSticker());
if (_sendLimit == SendLimit::One) {
result.setGroupFiles(true);
return result;
@ -455,7 +463,9 @@ void SendFilesBox::updateCaptionPlaceholder() {
return;
}
const auto way = _sendWay.current();
if (!_list.canAddCaption(way.groupFiles() && way.sendImagesAsPhotos())
if (!_list.canAddCaption(
way.groupFiles() && way.sendImagesAsPhotos(),
way.sendImagesAsPhotos())
&& _sendLimit == SendLimit::One) {
_caption->hide();
if (_emojiToggle) {
@ -668,7 +678,7 @@ void SendFilesBox::updateSendWayControlsVisibility() {
_hintLabel->setVisible(
_controller->session().settings().photoEditorHintShown()
? _list.hasSendImagesAsPhotosOption(false)
? _list.canHaveEditorHintLabel()
: false);
}
@ -1019,7 +1029,8 @@ bool SendFilesBox::validateLength(const QString &text) const {
const auto way = _sendWay.current();
if (remove <= 0
|| !_list.canAddCaption(
way.groupFiles() && way.sendImagesAsPhotos())) {
way.groupFiles() && way.sendImagesAsPhotos(),
way.sendImagesAsPhotos())) {
return true;
}
_controller->show(Box(CaptionLimitReachedBox, session, remove));

View File

@ -915,7 +915,8 @@ void FileLoadTask::process(Args &&args) {
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
if (ValidateThumbDimensions(w, h)) {
isSticker = Core::IsMimeSticker(filemime)
isSticker = (_type == SendMediaType::File)
&& Core::IsMimeSticker(filemime)
&& (filesize < Storage::kMaxStickerBytesSize)
&& (Core::IsMimeStickerAnimated(filemime)
|| GoodStickerDimensions(w, h));
@ -936,6 +937,9 @@ void FileLoadTask::process(Args &&args) {
attributes.push_back(MTP_documentAttributeAnimated());
} else if (filemime.startsWith(u"image/"_q)
&& _type != SendMediaType::File) {
if (Core::IsMimeSticker(filemime)) {
fullimage = Images::Opaque(std::move(fullimage));
}
auto medium = (w > 320 || h > 320) ? fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage;
const auto downscaled = (w > 1280 || h > 1280);

View File

@ -145,7 +145,8 @@ MimeDataState ComputeMimeDataState(const QMimeData *data) {
return MimeDataState::None;
}
const auto imageExtensions = Ui::ImageExtensions();
auto imageExtensions = Ui::ImageExtensions();
imageExtensions.push_back(u".webp"_q);
auto files = QStringList();
auto allAreSmallImages = true;
for (const auto &url : urls) {
@ -303,11 +304,11 @@ void PrepareDetails(PreparedFile &file, int previewWidth) {
if (const auto image = std::get_if<Image>(
&file.information->media)) {
Assert(!image->data.isNull());
if (ValidPhotoForAlbum(*image, file.information->filemime)) {
if (ValidPhotoForAlbum(*image, file.information->filemime)
|| Core::IsMimeSticker(file.information->filemime)) {
UpdateImageDetails(file, previewWidth);
file.type = PreparedFile::Type::Photo;
} else if (Core::IsMimeSticker(file.information->filemime)
|| image->animated) {
} else if (image->animated) {
file.type = PreparedFile::Type::None;
}
} else if (const auto video = std::get_if<Video>(

View File

@ -52,8 +52,12 @@ void AlbumPreview::updateFileRows() {
Expects(_order.size() == _thumbs.size());
const auto isFile = !_sendWay.sendImagesAsPhotos();
auto top = 0;
for (auto i = 0; i < _order.size(); i++) {
_thumbs[i]->updateFileRow(isFile ? _order[i] : -1);
const auto &thumb = _thumbs[_order[i]];
thumb->setButtonVisible(isFile && !thumb->isCompressedSticker());
thumb->moveButtons(top);
top += thumb->fileHeight() + st::sendMediaRowSkip;
}
}
@ -110,6 +114,9 @@ void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
this,
[=] { changeThumbByIndex(thumbIndex(thumbUnderCursor())); },
[=] { deleteThumbByIndex(thumbIndex(thumbUnderCursor())); }));
if (_thumbs.back()->isCompressedSticker()) {
_hasMixedFileHeights = true;
}
}
_thumbsHeight = countLayoutHeight(layout);
_photosHeight = ranges::accumulate(ranges::views::all(
@ -118,9 +125,16 @@ void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
return thumb->photoHeight();
}), 0) + (count - 1) * st::sendMediaRowSkip;
const auto &st = st::attachPreviewThumbLayout;
_filesHeight = count * st.thumbSize
+ (count - 1) * st::sendMediaRowSkip;
if (!_hasMixedFileHeights) {
_filesHeight = count * _thumbs.front()->fileHeight()
+ (count - 1) * st::sendMediaRowSkip;
} else {
_filesHeight = ranges::accumulate(ranges::views::all(
_thumbs
) | ranges::views::transform([](const auto &thumb) {
return thumb->fileHeight();
}), 0) + (count - 1) * st::sendMediaRowSkip;
}
}
int AlbumPreview::contentLeft() const {
@ -143,7 +157,7 @@ AlbumThumbnail *AlbumPreview::findThumb(QPoint position) const {
} else {
const auto bottom = top + (isPhotosWay
? thumb->photoHeight()
: st::attachPreviewThumbLayout.thumbSize);
: thumb->fileHeight());
const auto isUnderTop = (position.y() > top);
top = bottom + skip;
return isUnderTop && (position.y() < bottom);
@ -319,18 +333,44 @@ void AlbumPreview::paintPhotos(Painter &p, QRect clip) const {
}
void AlbumPreview::paintFiles(Painter &p, QRect clip) const {
const auto fileHeight = st::attachPreviewThumbLayout.thumbSize
+ st::sendMediaRowSkip;
const auto bottom = clip.y() + clip.height();
const auto from = std::clamp(clip.y() / fileHeight, 0, int(_thumbs.size()));
const auto till = std::clamp((bottom + fileHeight - 1) / fileHeight, 0, int(_thumbs.size()));
const auto left = (st::boxWideWidth - st::sendMediaPreviewSize) / 2;
const auto outerWidth = width();
if (!_hasMixedFileHeights) {
const auto fileHeight = st::attachPreviewThumbLayout.thumbSize
+ st::sendMediaRowSkip;
const auto bottom = clip.y() + clip.height();
const auto from = std::clamp(
clip.y() / fileHeight,
0,
int(_thumbs.size()));
const auto till = std::clamp(
(bottom + fileHeight - 1) / fileHeight,
0,
int(_thumbs.size()));
auto top = from * fileHeight;
for (auto i = from; i != till; ++i) {
_thumbs[i]->paintFile(p, left, top, outerWidth);
top += fileHeight;
auto top = from * fileHeight;
for (auto i = from; i != till; ++i) {
_thumbs[i]->paintFile(p, left, top, outerWidth);
top += fileHeight;
}
} else {
auto top = 0;
for (const auto &thumb : _thumbs) {
const auto bottom = top + thumb->fileHeight();
const auto guard = gsl::finally([&] {
top = bottom + st::sendMediaRowSkip;
});
if (top >= clip.y() + clip.height()) {
break;
} else if (bottom <= clip.y()) {
continue;
}
if (thumb->isCompressedSticker()) {
thumb->paintPhoto(p, left, top, outerWidth);
} else {
thumb->paintFile(p, left, top, outerWidth);
}
}
}
}
@ -421,7 +461,7 @@ void AlbumPreview::mousePressEvent(QMouseEvent *e) {
}
void AlbumPreview::mouseMoveEvent(QMouseEvent *e) {
if (!_sendWay.sendImagesAsPhotos()) {
if (!_sendWay.sendImagesAsPhotos() && !_hasMixedFileHeights) {
applyCursor(style::cur_default);
return;
}

View File

@ -88,6 +88,8 @@ private:
int _photosHeight = 0;
int _filesHeight = 0;
bool _hasMixedFileHeights = false;
AlbumThumbnail *_draggedThumb = nullptr;
AlbumThumbnail *_suggestedThumb = nullptr;
AlbumThumbnail *_paintedAbove = nullptr;

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/chat/attach/attach_album_thumbnail.h"
#include "core/mime_type.h" // Core::IsMimeSticker.
#include "ui/chat/attach/attach_prepare.h"
#include "ui/image/image_prepare.h"
#include "ui/text/format_values.h"
@ -31,7 +32,8 @@ AlbumThumbnail::AlbumThumbnail(
, _fullPreview(file.preview)
, _shrinkSize(int(std::ceil(st::roundRadiusLarge / 1.4)))
, _isPhoto(file.type == PreparedFile::Type::Photo)
, _isVideo(file.type == PreparedFile::Type::Video) {
, _isVideo(file.type == PreparedFile::Type::Video)
, _isCompressedSticker(Core::IsMimeSticker(file.information->filemime)) {
Expects(!_fullPreview.isNull());
moveToLayout(layout);
@ -105,21 +107,16 @@ AlbumThumbnail::AlbumThumbnail(
_editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile);
_deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile);
updateFileRow(-1);
setButtonVisible(false);
}
void AlbumThumbnail::updateFileRow(int row) {
if (row < 0) {
_editMedia->hide();
_deleteMedia->hide();
return;
}
_editMedia->show();
_deleteMedia->show();
void AlbumThumbnail::setButtonVisible(bool value) {
_editMedia->setVisible(value);
_deleteMedia->setVisible(value);
}
const auto fileHeight = st::attachPreviewThumbLayout.thumbSize
+ st::sendMediaRowSkip;
const auto top = row * fileHeight + st::sendBoxFileGroupSkipTop;
void AlbumThumbnail::moveButtons(int thumbTop) {
const auto top = thumbTop + st::sendBoxFileGroupSkipTop;
auto right = st::sendBoxFileGroupSkipRight + st::boxPhotoPadding.right();
_deleteMedia->moveToRight(right, top);
@ -173,6 +170,16 @@ int AlbumThumbnail::photoHeight() const {
return _photo.height() / style::DevicePixelRatio();
}
int AlbumThumbnail::fileHeight() const {
return _isCompressedSticker
? photoHeight()
: st::attachPreviewThumbLayout.thumbSize;
}
bool AlbumThumbnail::isCompressedSticker() const {
return _isCompressedSticker;
}
void AlbumThumbnail::paintInAlbum(
QPainter &p,
int left,
@ -422,7 +429,7 @@ bool AlbumThumbnail::containsPoint(QPoint position) const {
}
bool AlbumThumbnail::buttonsContainPoint(QPoint position) const {
return (_isPhoto
return ((_isPhoto && !_isCompressedSticker)
? _lastRectOfModify
: _lastRectOfButtons).contains(position);
}
@ -431,7 +438,7 @@ AttachButtonType AlbumThumbnail::buttonTypeFromPoint(QPoint position) const {
if (!buttonsContainPoint(position)) {
return AttachButtonType::None;
}
return !_lastRectOfButtons.contains(position)
return (!_lastRectOfButtons.contains(position) && !_isCompressedSticker)
? AttachButtonType::Modify
: (position.x() < _lastRectOfButtons.center().x())
? AttachButtonType::Edit

View File

@ -33,6 +33,7 @@ public:
void resetLayoutAnimation();
int photoHeight() const;
int fileHeight() const;
void paintInAlbum(
QPainter &p,
@ -53,7 +54,10 @@ public:
void suggestMove(float64 delta, Fn<void()> callback);
void finishAnimations();
void updateFileRow(int row);
void setButtonVisible(bool value);
void moveButtons(int thumbTop);
bool isCompressedSticker() const;
static constexpr auto kShrinkDuration = crl::time(150);
@ -89,6 +93,8 @@ private:
int _lastShrinkValue = 0;
AttachControls _buttons;
bool _isCompressedSticker = false;
QRect _lastRectOfModify;
QRect _lastRectOfButtons;

View File

@ -138,7 +138,7 @@ bool PreparedList::canBeSentInSlowmodeWith(const PreparedList &other) const {
return !hasNonGrouping && (!hasFiles || !hasVideos);
}
bool PreparedList::canAddCaption(bool sendingAlbum) const {
bool PreparedList::canAddCaption(bool sendingAlbum, bool compress) const {
if (!filesToProcess.empty()
|| files.empty()
|| files.size() > kMaxAlbumCount) {
@ -146,8 +146,8 @@ bool PreparedList::canAddCaption(bool sendingAlbum) const {
}
if (files.size() == 1) {
Assert(files.front().information != nullptr);
const auto isSticker = Core::IsMimeSticker(
files.front().information->filemime)
const auto isSticker = (!compress
&& Core::IsMimeSticker(files.front().information->filemime))
|| files.front().path.endsWith(
qstr(".tgs"),
Qt::CaseInsensitive);
@ -198,6 +198,26 @@ bool PreparedList::hasSendImagesAsPhotosOption(bool slowmode) const {
: ranges::contains(files, Type::Photo, &PreparedFile::type);
}
bool PreparedList::canHaveEditorHintLabel() const {
for (const auto &file : files) {
if ((file.type == PreparedFile::Type::Photo)
&& !Core::IsMimeSticker(file.information->filemime)) {
return true;
}
}
return false;
}
bool PreparedList::hasSticker() const {
for (const auto &file : files) {
if ((file.type == PreparedFile::Type::Photo)
&& Core::IsMimeSticker(file.information->filemime)) {
return true;
}
}
return false;
}
int MaxAlbumItems() {
return kMaxAlbumCount;
}

View File

@ -106,13 +106,15 @@ struct PreparedList {
std::vector<int> order);
void mergeToEnd(PreparedList &&other, bool cutToAlbumSize = false);
[[nodiscard]] bool canAddCaption(bool sendingAlbum) const;
[[nodiscard]] bool canAddCaption(bool sendingAlbum, bool compress) const;
[[nodiscard]] bool canBeSentInSlowmode() const;
[[nodiscard]] bool canBeSentInSlowmodeWith(
const PreparedList &other) const;
[[nodiscard]] bool hasGroupOption(bool slowmode) const;
[[nodiscard]] bool hasSendImagesAsPhotosOption(bool slowmode) const;
[[nodiscard]] bool canHaveEditorHintLabel() const;
[[nodiscard]] bool hasSticker() const;
Error error = Error::None;
QString errorData;

View File

@ -13,6 +13,9 @@ void SendFilesWay::setSendImagesAsPhotos(bool value) {
if (value) {
_flags |= Flag::SendImagesAsPhotos;
} else {
if (hasCompressedStickers()) {
setGroupFiles(false);
}
_flags &= ~Flag::SendImagesAsPhotos;
}
}
@ -20,11 +23,22 @@ void SendFilesWay::setSendImagesAsPhotos(bool value) {
void SendFilesWay::setGroupFiles(bool value) {
if (value) {
_flags |= Flag::GroupFiles;
if (hasCompressedStickers()) {
setSendImagesAsPhotos(true);
}
} else {
_flags &= ~Flag::GroupFiles;
}
}
void SendFilesWay::setHasCompressedStickers(bool value) {
if (value) {
_flags |= Flag::HasCompressedStickers;
} else {
_flags &= ~Flag::HasCompressedStickers;
}
}
//enum class SendFilesWay { // Old way. Serialize should be compatible.
// Album,
// Photos,

View File

@ -28,6 +28,7 @@ public:
}
void setGroupFiles(bool value);
void setSendImagesAsPhotos(bool value);
void setHasCompressedStickers(bool value);
[[nodiscard]] inline bool operator<(const SendFilesWay &other) const {
return _flags < other._flags;
@ -53,9 +54,14 @@ public:
int32 value);
private:
[[nodiscard]] bool hasCompressedStickers() const {
return (_flags & Flag::HasCompressedStickers) != 0;
}
enum class Flag : uchar {
GroupFiles = (1 << 0),
SendImagesAsPhotos = (1 << 1),
HasCompressedStickers = (1 << 2),
Default = GroupFiles | SendImagesAsPhotos,
};