mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 23:00:58 +00:00
Show video thumbnail in SendFileBox.
Read media information (image / song / video) in SendFileBox in the same way it is read in FileLoadTask::process() and reuse it in FileLoadTask if it was loaded already for the box.
This commit is contained in:
parent
9ed8cbe2d1
commit
a1b53c660e
@ -30,20 +30,47 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "media/media_clip_reader.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kMinPreviewWidth = 20;
|
constexpr auto kMinPreviewWidth = 20;
|
||||||
|
|
||||||
|
bool ValidatePhotoDimensions(int width, int height) {
|
||||||
|
return (width > 0) && (height > 0) && (width < 20 * height) && (height < 20 * width);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SendFilesBox::SendFilesBox(QWidget*, const QString &filepath, QImage image, CompressConfirm compressed, bool animated)
|
SendFilesBox::SendFilesBox(QWidget*, QImage image, CompressConfirm compressed)
|
||||||
: _files(filepath)
|
: _image(image)
|
||||||
, _image(image)
|
|
||||||
, _compressConfirm(compressed)
|
, _compressConfirm(compressed)
|
||||||
, _animated(image.isNull() ? false : animated)
|
|
||||||
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption)) {
|
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption)) {
|
||||||
if (!image.isNull()) {
|
_files.push_back(QString());
|
||||||
|
prepareSingleFileLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
SendFilesBox::SendFilesBox(QWidget*, const QStringList &files, CompressConfirm compressed)
|
||||||
|
: _files(files)
|
||||||
|
, _compressConfirm(compressed)
|
||||||
|
, _caption(this, st::confirmCaptionArea, lang(_files.size() > 1 ? lng_photos_comment : lng_photo_caption)) {
|
||||||
|
if (_files.size() == 1) {
|
||||||
|
prepareSingleFileLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendFilesBox::prepareSingleFileLayout() {
|
||||||
|
t_assert(_files.size() == 1);
|
||||||
|
if (!_files.front().isEmpty()) {
|
||||||
|
tryToReadSingleFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_image.isNull() || !ValidatePhotoDimensions(_image.width(), _image.height()) || _animated) {
|
||||||
|
_compressConfirm = CompressConfirm::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_image.isNull()) {
|
||||||
|
auto image = _image;
|
||||||
if (!_animated && _compressConfirm == CompressConfirm::None) {
|
if (!_animated && _compressConfirm == CompressConfirm::None) {
|
||||||
auto originalWidth = image.width();
|
auto originalWidth = image.width();
|
||||||
auto originalHeight = image.height();
|
auto originalHeight = image.height();
|
||||||
@ -99,27 +126,51 @@ SendFilesBox::SendFilesBox(QWidget*, const QString &filepath, QImage image, Comp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_preview.isNull()) {
|
if (_preview.isNull()) {
|
||||||
if (filepath.isEmpty()) {
|
prepareDocumentLayout();
|
||||||
auto filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
|
|
||||||
_nameText.setText(st::semiboldTextStyle, filename, _textNameOptions);
|
|
||||||
_statusText = qsl("%1x%2").arg(_image.width()).arg(_image.height());
|
|
||||||
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
|
||||||
_fileIsImage = true;
|
|
||||||
} else {
|
|
||||||
auto fileinfo = QFileInfo(filepath);
|
|
||||||
auto filename = fileinfo.fileName();
|
|
||||||
_nameText.setText(st::semiboldTextStyle, filename, _textNameOptions);
|
|
||||||
_statusText = formatSizeText(fileinfo.size());
|
|
||||||
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
|
||||||
_fileIsImage = fileIsImage(filename, mimeTypeForFile(fileinfo).name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendFilesBox::SendFilesBox(QWidget*, const QStringList &files, CompressConfirm compressed)
|
void SendFilesBox::prepareDocumentLayout() {
|
||||||
: _files(files)
|
auto filepath = _files.front();
|
||||||
, _compressConfirm(compressed)
|
if (filepath.isEmpty()) {
|
||||||
, _caption(this, st::confirmCaptionArea, lang(lng_photos_comment)) {
|
auto filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
|
||||||
|
_nameText.setText(st::semiboldTextStyle, filename, _textNameOptions);
|
||||||
|
_statusText = qsl("%1x%2").arg(_image.width()).arg(_image.height());
|
||||||
|
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
||||||
|
_fileIsImage = true;
|
||||||
|
} else {
|
||||||
|
auto fileinfo = QFileInfo(filepath);
|
||||||
|
auto filename = fileinfo.fileName();
|
||||||
|
_fileIsImage = fileIsImage(filename, mimeTypeForFile(fileinfo).name());
|
||||||
|
|
||||||
|
auto songTitle = QString();
|
||||||
|
auto songPerformer = QString();
|
||||||
|
if (_information) {
|
||||||
|
if (auto song = base::get_if<FileLoadTask::Song>(&_information->media)) {
|
||||||
|
songTitle = song->title;
|
||||||
|
songPerformer = song->performer;
|
||||||
|
_fileIsAudio = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nameString = DocumentData::composeNameString(filename, songTitle, songPerformer);
|
||||||
|
_nameText.setText(st::semiboldTextStyle, nameString, _textNameOptions);
|
||||||
|
_statusText = formatSizeText(fileinfo.size());
|
||||||
|
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendFilesBox::tryToReadSingleFile() {
|
||||||
|
auto filepath = _files.front();
|
||||||
|
auto filemime = mimeTypeForFile(QFileInfo(filepath)).name();
|
||||||
|
_information = FileLoadTask::ReadMediaInformation(_files.front(), QByteArray(), filemime);
|
||||||
|
if (auto image = base::get_if<FileLoadTask::Image>(&_information->media)) {
|
||||||
|
_image = image->data;
|
||||||
|
_animated = image->animated;
|
||||||
|
} else if (auto video = base::get_if<FileLoadTask::Video>(&_information->media)) {
|
||||||
|
_image = video->thumbnail;
|
||||||
|
_animated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendFilesBox::SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname)
|
SendFilesBox::SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname)
|
||||||
@ -278,7 +329,7 @@ void SendFilesBox::paintEvent(QPaintEvent *e) {
|
|||||||
p.drawEllipse(inner);
|
p.drawEllipse(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &icon = _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument;
|
auto &icon = _fileIsAudio ? st::historyFileOutPlay : _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument;
|
||||||
icon.paintInCenter(p, inner);
|
icon.paintInCenter(p, inner);
|
||||||
} else {
|
} else {
|
||||||
_contactPhotoEmpty.paint(p, x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), st::msgFileSize);
|
_contactPhotoEmpty.paint(p, x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), st::msgFileSize);
|
||||||
@ -333,7 +384,7 @@ void SendFilesBox::onSend(bool ctrlShiftEnter) {
|
|||||||
if (_confirmedCallback) {
|
if (_confirmedCallback) {
|
||||||
auto compressed = _compressed ? _compressed->checked() : false;
|
auto compressed = _compressed ? _compressed->checked() : false;
|
||||||
auto caption = _caption ? prepareText(_caption->getLastText(), true) : QString();
|
auto caption = _caption ? prepareText(_caption->getLastText(), true) : QString();
|
||||||
_confirmedCallback(_files, compressed, caption, ctrlShiftEnter);
|
_confirmedCallback(_files, _animated ? QImage() : _image, std::move(_information), compressed, caption, ctrlShiftEnter);
|
||||||
}
|
}
|
||||||
closeBox();
|
closeBox();
|
||||||
}
|
}
|
||||||
@ -403,11 +454,12 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryItem *msg)
|
|||||||
if (doc->voice()) {
|
if (doc->voice()) {
|
||||||
_name.setText(st::semiboldTextStyle, lang(lng_media_audio), _textNameOptions);
|
_name.setText(st::semiboldTextStyle, lang(lng_media_audio), _textNameOptions);
|
||||||
} else {
|
} else {
|
||||||
_name.setText(st::semiboldTextStyle, documentName(doc), _textNameOptions);
|
_name.setText(st::semiboldTextStyle, doc->composeNameString(), _textNameOptions);
|
||||||
}
|
}
|
||||||
_status = formatSizeText(doc->size);
|
_status = formatSizeText(doc->size);
|
||||||
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
|
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
|
||||||
_isImage = doc->isImage();
|
_isImage = doc->isImage();
|
||||||
|
_isAudio = (doc->voice() || doc->song());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int32 maxW = 0, maxH = 0;
|
int32 maxW = 0, maxH = 0;
|
||||||
@ -579,7 +631,7 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
|||||||
p.drawEllipse(inner);
|
p.drawEllipse(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto icon = &(_isImage ? st::historyFileInImage : st::historyFileInDocument);
|
auto icon = &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument);
|
||||||
icon->paintInCenter(p, inner);
|
icon->paintInCenter(p, inner);
|
||||||
}
|
}
|
||||||
p.setFont(st::semiboldFont);
|
p.setFont(st::semiboldFont);
|
||||||
|
@ -33,11 +33,11 @@ class SendFilesBox : public BoxContent {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SendFilesBox(QWidget*, const QString &filepath, QImage image, CompressConfirm compressed, bool animated = false);
|
SendFilesBox(QWidget*, QImage image, CompressConfirm compressed);
|
||||||
SendFilesBox(QWidget*, const QStringList &files, CompressConfirm compressed);
|
SendFilesBox(QWidget*, const QStringList &files, CompressConfirm compressed);
|
||||||
SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname);
|
SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname);
|
||||||
|
|
||||||
void setConfirmedCallback(base::lambda<void(const QStringList &files, bool compressed, const QString &caption, bool ctrlShiftEnter)> callback) {
|
void setConfirmedCallback(base::lambda<void(const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, bool ctrlShiftEnter)> callback) {
|
||||||
_confirmedCallback = std::move(callback);
|
_confirmedCallback = std::move(callback);
|
||||||
}
|
}
|
||||||
void setCancelledCallback(base::lambda<void()> callback) {
|
void setCancelledCallback(base::lambda<void()> callback) {
|
||||||
@ -63,6 +63,10 @@ private slots:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void prepareSingleFileLayout();
|
||||||
|
void prepareDocumentLayout();
|
||||||
|
void tryToReadSingleFile();
|
||||||
|
|
||||||
void updateTitleText();
|
void updateTitleText();
|
||||||
void updateBoxSize();
|
void updateBoxSize();
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
@ -70,7 +74,8 @@ private:
|
|||||||
|
|
||||||
QString _titleText;
|
QString _titleText;
|
||||||
QStringList _files;
|
QStringList _files;
|
||||||
const QImage _image;
|
QImage _image;
|
||||||
|
std::unique_ptr<FileLoadTask::MediaInformation> _information;
|
||||||
|
|
||||||
CompressConfirm _compressConfirm = CompressConfirm::None;
|
CompressConfirm _compressConfirm = CompressConfirm::None;
|
||||||
bool _animated = false;
|
bool _animated = false;
|
||||||
@ -82,6 +87,7 @@ private:
|
|||||||
|
|
||||||
QPixmap _fileThumb;
|
QPixmap _fileThumb;
|
||||||
Text _nameText;
|
Text _nameText;
|
||||||
|
bool _fileIsAudio = false;
|
||||||
bool _fileIsImage = false;
|
bool _fileIsImage = false;
|
||||||
QString _statusText;
|
QString _statusText;
|
||||||
int _statusWidth = 0;
|
int _statusWidth = 0;
|
||||||
@ -91,7 +97,7 @@ private:
|
|||||||
QString _contactLastName;
|
QString _contactLastName;
|
||||||
EmptyUserpic _contactPhotoEmpty;
|
EmptyUserpic _contactPhotoEmpty;
|
||||||
|
|
||||||
base::lambda<void(const QStringList &files, bool compressed, const QString &caption, bool ctrlShiftEnter)> _confirmedCallback;
|
base::lambda<void(const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, bool ctrlShiftEnter)> _confirmedCallback;
|
||||||
base::lambda<void()> _cancelledCallback;
|
base::lambda<void()> _cancelledCallback;
|
||||||
bool _confirmed = false;
|
bool _confirmed = false;
|
||||||
|
|
||||||
@ -145,6 +151,7 @@ private:
|
|||||||
Text _name;
|
Text _name;
|
||||||
QString _status;
|
QString _status;
|
||||||
int _statusw = 0;
|
int _statusw = 0;
|
||||||
|
bool _isAudio = false;
|
||||||
bool _isImage = false;
|
bool _isImage = false;
|
||||||
|
|
||||||
bool _previewCancelled = false;
|
bool _previewCancelled = false;
|
||||||
|
@ -1010,7 +1010,7 @@ void HistoryDocument::createComponents(bool caption) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HistoryDocument::fillNamedFromData(HistoryDocumentNamed *named) {
|
void HistoryDocument::fillNamedFromData(HistoryDocumentNamed *named) {
|
||||||
auto name = named->_name = documentName(_data);
|
auto name = named->_name = _data->composeNameString();
|
||||||
named->_namew = st::semiboldFont->width(name);
|
named->_namew = st::semiboldFont->width(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6609,14 +6609,14 @@ bool HistoryWidget::showSendFilesBox(object_ptr<SendFilesBox> box, const QString
|
|||||||
App::wnd()->activateWindow();
|
App::wnd()->activateWindow();
|
||||||
|
|
||||||
auto withComment = (addedComment != nullptr);
|
auto withComment = (addedComment != nullptr);
|
||||||
box->setConfirmedCallback(base::lambda_guarded(this, [this, withComment, sendCallback = std::move(callback)](const QStringList &files, bool compressed, const QString &caption, bool ctrlShiftEnter) {
|
box->setConfirmedCallback(base::lambda_guarded(this, [this, withComment, sendCallback = std::move(callback)](const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, bool ctrlShiftEnter) {
|
||||||
if (!canWriteMessage()) return;
|
if (!canWriteMessage()) return;
|
||||||
|
|
||||||
auto replyTo = replyToId();
|
auto replyTo = replyToId();
|
||||||
if (withComment) {
|
if (withComment) {
|
||||||
onSend(ctrlShiftEnter, replyTo);
|
onSend(ctrlShiftEnter, replyTo);
|
||||||
}
|
}
|
||||||
sendCallback(files, compressed, caption, replyTo);
|
sendCallback(files, image, std::move(information), compressed, caption, replyTo);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (withComment) {
|
if (withComment) {
|
||||||
@ -6662,21 +6662,12 @@ bool HistoryWidget::confirmSendingFiles(const QStringList &files, CompressConfir
|
|||||||
|
|
||||||
bool HistoryWidget::confirmSendingFiles(const SendingFilesLists &lists, CompressConfirm compressed, const QString *addedComment) {
|
bool HistoryWidget::confirmSendingFiles(const SendingFilesLists &lists, CompressConfirm compressed, const QString *addedComment) {
|
||||||
return validateSendingFiles(lists, [this, &lists, compressed, addedComment](const QStringList &files) {
|
return validateSendingFiles(lists, [this, &lists, compressed, addedComment](const QStringList &files) {
|
||||||
auto image = QImage();
|
|
||||||
auto insertTextOnCancel = QString();
|
auto insertTextOnCancel = QString();
|
||||||
auto box = ([this, &files, &lists, compressed, &image] {
|
auto sendCallback = [this](const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, MsgId replyTo) {
|
||||||
if (files.size() > 1) {
|
|
||||||
return Box<SendFilesBox>(files, lists.allFilesForCompress ? compressed : CompressConfirm::None);
|
|
||||||
}
|
|
||||||
auto filepath = files.front();
|
|
||||||
auto animated = false;
|
|
||||||
image = App::readImage(filepath, nullptr, false, &animated);
|
|
||||||
return Box<SendFilesBox>(filepath, image, imageCompressConfirm(image, compressed, animated), animated);
|
|
||||||
})();
|
|
||||||
auto sendCallback = [this, image](const QStringList &files, bool compressed, const QString &caption, MsgId replyTo) {
|
|
||||||
auto type = compressed ? SendMediaType::Photo : SendMediaType::File;
|
auto type = compressed ? SendMediaType::Photo : SendMediaType::File;
|
||||||
uploadFilesAfterConfirmation(files, image, QByteArray(), type, caption);
|
uploadFilesAfterConfirmation(files, QByteArray(), image, std::move(information), type, caption);
|
||||||
};
|
};
|
||||||
|
auto box = Box<SendFilesBox>(files, lists.allFilesForCompress ? compressed : CompressConfirm::None);
|
||||||
return showSendFilesBox(std::move(box), insertTextOnCancel, addedComment, std::move(sendCallback));
|
return showSendFilesBox(std::move(box), insertTextOnCancel, addedComment, std::move(sendCallback));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -6685,12 +6676,11 @@ bool HistoryWidget::confirmSendingFiles(const QImage &image, const QByteArray &c
|
|||||||
if (!canWriteMessage() || image.isNull()) return false;
|
if (!canWriteMessage() || image.isNull()) return false;
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
App::wnd()->activateWindow();
|
||||||
auto animated = false;
|
auto sendCallback = [this, content](const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, MsgId replyTo) {
|
||||||
auto sendCallback = [this, content, image](const QStringList &files, bool compressed, const QString &caption, MsgId replyTo) {
|
|
||||||
auto type = compressed ? SendMediaType::Photo : SendMediaType::File;
|
auto type = compressed ? SendMediaType::Photo : SendMediaType::File;
|
||||||
uploadFilesAfterConfirmation(files, image, content, type, caption);
|
uploadFilesAfterConfirmation(files, content, image, std::move(information), type, caption);
|
||||||
};
|
};
|
||||||
auto box = Box<SendFilesBox>(QString(), image, imageCompressConfirm(image, compressed), animated);
|
auto box = Box<SendFilesBox>(image, compressed);
|
||||||
return showSendFilesBox(std::move(box), insertTextOnCancel, nullptr, std::move(sendCallback));
|
return showSendFilesBox(std::move(box), insertTextOnCancel, nullptr, std::move(sendCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6722,7 +6712,7 @@ bool HistoryWidget::confirmShareContact(const QString &phone, const QString &fna
|
|||||||
if (!canWriteMessage()) return false;
|
if (!canWriteMessage()) return false;
|
||||||
|
|
||||||
auto box = Box<SendFilesBox>(phone, fname, lname);
|
auto box = Box<SendFilesBox>(phone, fname, lname);
|
||||||
auto sendCallback = [this, phone, fname, lname](const QStringList &files, bool compressed, const QString &caption, MsgId replyTo) {
|
auto sendCallback = [this, phone, fname, lname](const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, MsgId replyTo) {
|
||||||
shareContact(_peer->id, phone, fname, lname, replyTo);
|
shareContact(_peer->id, phone, fname, lname, replyTo);
|
||||||
};
|
};
|
||||||
auto insertTextOnCancel = QString();
|
auto insertTextOnCancel = QString();
|
||||||
@ -6779,26 +6769,14 @@ void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressConfirm HistoryWidget::imageCompressConfirm(const QImage &image, CompressConfirm compressed, bool animated) {
|
|
||||||
if (animated || image.isNull()) {
|
|
||||||
return CompressConfirm::None;
|
|
||||||
}
|
|
||||||
auto imageWidth = image.width();
|
|
||||||
auto imageHeight = image.height();
|
|
||||||
if (imageWidth >= 20 * imageHeight || imageHeight >= 20 * imageWidth) {
|
|
||||||
return CompressConfirm::None;
|
|
||||||
}
|
|
||||||
return compressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::uploadFiles(const QStringList &files, SendMediaType type) {
|
void HistoryWidget::uploadFiles(const QStringList &files, SendMediaType type) {
|
||||||
if (!canWriteMessage()) return;
|
if (!canWriteMessage()) return;
|
||||||
|
|
||||||
auto caption = QString();
|
auto caption = QString();
|
||||||
uploadFilesAfterConfirmation(files, QImage(), QByteArray(), type, caption);
|
uploadFilesAfterConfirmation(files, QByteArray(), QImage(), std::unique_ptr<FileLoadTask::MediaInformation>(), type, caption);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::uploadFilesAfterConfirmation(const QStringList &files, const QImage &image, const QByteArray &content, SendMediaType type, QString caption) {
|
void HistoryWidget::uploadFilesAfterConfirmation(const QStringList &files, const QByteArray &content, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, SendMediaType type, QString caption) {
|
||||||
t_assert(canWriteMessage());
|
t_assert(canWriteMessage());
|
||||||
|
|
||||||
auto to = FileLoadTo(_peer->id, _silent->checked(), replyToId());
|
auto to = FileLoadTo(_peer->id, _silent->checked(), replyToId());
|
||||||
@ -6818,7 +6796,7 @@ void HistoryWidget::uploadFilesAfterConfirmation(const QStringList &files, const
|
|||||||
if (filepath.isEmpty() && (!image.isNull() || !content.isNull())) {
|
if (filepath.isEmpty() && (!image.isNull() || !content.isNull())) {
|
||||||
tasks.push_back(MakeShared<FileLoadTask>(content, image, type, to, caption));
|
tasks.push_back(MakeShared<FileLoadTask>(content, image, type, to, caption));
|
||||||
} else {
|
} else {
|
||||||
tasks.push_back(MakeShared<FileLoadTask>(filepath, image, type, to, caption));
|
tasks.push_back(MakeShared<FileLoadTask>(filepath, std::move(information), type, to, caption));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_fileLoader.addTasks(tasks);
|
_fileLoader.addTasks(tasks);
|
||||||
|
@ -868,10 +868,9 @@ private:
|
|||||||
bool validateSendingFiles(const SendingFilesLists &lists, Callback callback);
|
bool validateSendingFiles(const SendingFilesLists &lists, Callback callback);
|
||||||
template <typename SendCallback>
|
template <typename SendCallback>
|
||||||
bool showSendFilesBox(object_ptr<SendFilesBox> box, const QString &insertTextOnCancel, const QString *addedComment, SendCallback callback);
|
bool showSendFilesBox(object_ptr<SendFilesBox> box, const QString &insertTextOnCancel, const QString *addedComment, SendCallback callback);
|
||||||
CompressConfirm imageCompressConfirm(const QImage &image, CompressConfirm compressed, bool animated = false);
|
|
||||||
|
|
||||||
// If an empty filepath is found we upload (possible) "image" with (possible) "content".
|
// If an empty filepath is found we upload (possible) "image" with (possible) "content".
|
||||||
void uploadFilesAfterConfirmation(const QStringList &files, const QImage &image, const QByteArray &content, SendMediaType type, QString caption);
|
void uploadFilesAfterConfirmation(const QStringList &files, const QByteArray &content, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, SendMediaType type, QString caption);
|
||||||
|
|
||||||
void itemRemoved(HistoryItem *item);
|
void itemRemoved(HistoryItem *item);
|
||||||
|
|
||||||
|
@ -139,33 +139,6 @@ QString formatPlayedText(qint64 played, qint64 duration) {
|
|||||||
return lng_duration_played(lt_played, formatDurationText(played), lt_duration, formatDurationText(duration));
|
return lng_duration_played(lt_played, formatDurationText(played), lt_duration, formatDurationText(duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString documentName(DocumentData *document) {
|
|
||||||
auto song = document->song();
|
|
||||||
if (!song || (song->title.isEmpty() && song->performer.isEmpty())) {
|
|
||||||
return document->name.isEmpty() ? qsl("Unknown File") : document->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (song->performer.isEmpty()) return song->title;
|
|
||||||
|
|
||||||
return song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWithEntities documentNameWithEntities(DocumentData *document) {
|
|
||||||
TextWithEntities result;
|
|
||||||
auto song = document->song();
|
|
||||||
if (!song || (song->title.isEmpty() && song->performer.isEmpty())) {
|
|
||||||
result.text = document->name.isEmpty() ? qsl("Unknown File") : document->name;
|
|
||||||
result.entities.push_back({ EntityInTextBold, 0, result.text.size() });
|
|
||||||
} else if (song->performer.isEmpty()) {
|
|
||||||
result.text = song->title;
|
|
||||||
result.entities.push_back({ EntityInTextBold, 0, result.text.size() });
|
|
||||||
} else {
|
|
||||||
result.text = song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
|
||||||
result.entities.push_back({ EntityInTextBold, 0, song->performer.size() });
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 documentColorIndex(DocumentData *document, QString &ext) {
|
int32 documentColorIndex(DocumentData *document, QString &ext) {
|
||||||
int32 colorIndex = 0;
|
int32 colorIndex = 0;
|
||||||
|
|
||||||
|
@ -81,8 +81,6 @@ QString formatDurationAndSizeText(qint64 duration, qint64 size);
|
|||||||
QString formatGifAndSizeText(qint64 size);
|
QString formatGifAndSizeText(qint64 size);
|
||||||
QString formatPlayedText(qint64 played, qint64 duration);
|
QString formatPlayedText(qint64 played, qint64 duration);
|
||||||
|
|
||||||
QString documentName(DocumentData *document);
|
|
||||||
TextWithEntities documentNameWithEntities(DocumentData *document);
|
|
||||||
int32 documentColorIndex(DocumentData *document, QString &ext);
|
int32 documentColorIndex(DocumentData *document, QString &ext);
|
||||||
style::color documentColor(int colorIndex);
|
style::color documentColor(int colorIndex);
|
||||||
style::color documentDarkColor(int colorIndex);
|
style::color documentDarkColor(int colorIndex);
|
||||||
|
@ -1656,24 +1656,27 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat) {
|
namespace Media {
|
||||||
|
namespace Player {
|
||||||
|
|
||||||
|
FileLoadTask::Song PrepareForSending(const QString &fname, const QByteArray &data) {
|
||||||
|
auto result = FileLoadTask::Song();
|
||||||
FFMpegAttributesReader reader(FileLocation(fname), data);
|
FFMpegAttributesReader reader(FileLocation(fname), data);
|
||||||
qint64 position = 0;
|
qint64 position = 0;
|
||||||
if (reader.open(position)) {
|
if (reader.open(position) && reader.duration() > 0) {
|
||||||
int32 duration = reader.duration() / reader.frequency();
|
result.duration = reader.duration() / reader.frequency();
|
||||||
if (reader.duration() > 0) {
|
result.title = reader.title();
|
||||||
cover = reader.cover();
|
result.performer = reader.performer();
|
||||||
coverBytes = reader.coverBytes();
|
result.cover = reader.cover();
|
||||||
coverFormat = reader.coverFormat();
|
|
||||||
return MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_title | MTPDdocumentAttributeAudio::Flag::f_performer), MTP_int(duration), MTP_string(reader.title()), MTP_string(reader.performer()), MTPstring());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return MTP_documentAttributeFilename(MTP_string(fname));
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Player
|
||||||
|
} // namespace Media
|
||||||
|
|
||||||
class FFMpegWaveformCounter : public FFMpegLoader {
|
class FFMpegWaveformCounter : public FFMpegLoader {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FFMpegWaveformCounter(const FileLocation &file, const QByteArray &data) : FFMpegLoader(file, data) {
|
FFMpegWaveformCounter(const FileLocation &file, const QByteArray &data) : FFMpegLoader(file, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "storage/localimageloader.h"
|
||||||
|
|
||||||
struct VideoSoundData;
|
struct VideoSoundData;
|
||||||
struct VideoSoundPart;
|
struct VideoSoundPart;
|
||||||
|
|
||||||
@ -278,6 +280,8 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FileLoadTask::Song PrepareForSending(const QString &fname, const QByteArray &data);
|
||||||
|
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
|
|
||||||
@ -291,5 +295,4 @@ bool CheckAudioDeviceConnected();
|
|||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat);
|
|
||||||
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data);
|
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data);
|
||||||
|
@ -839,8 +839,8 @@ Manager::~Manager() {
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SendData PrepareForSending(const QString &fname, const QByteArray &data) {
|
FileLoadTask::Video PrepareForSending(const QString &fname, const QByteArray &data) {
|
||||||
auto result = SendData();
|
auto result = FileLoadTask::Video();
|
||||||
auto localLocation = FileLocation(fname);
|
auto localLocation = FileLocation(fname);
|
||||||
auto localData = QByteArray(data);
|
auto localData = QByteArray(data);
|
||||||
|
|
||||||
@ -859,14 +859,14 @@ SendData PrepareForSending(const QString &fname, const QByteArray &data) {
|
|||||||
auto hasAlpha = false;
|
auto hasAlpha = false;
|
||||||
auto readResult = reader->readFramesTill(-1, getms());
|
auto readResult = reader->readFramesTill(-1, getms());
|
||||||
auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success);
|
auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success);
|
||||||
if (readFrame && reader->renderFrame(result.cover, hasAlpha, QSize())) {
|
if (readFrame && reader->renderFrame(result.thumbnail, hasAlpha, QSize())) {
|
||||||
if (hasAlpha) {
|
if (hasAlpha) {
|
||||||
auto cacheForResize = QImage();
|
auto cacheForResize = QImage();
|
||||||
auto request = FrameRequest();
|
auto request = FrameRequest();
|
||||||
request.framew = request.outerw = result.cover.width();
|
request.framew = request.outerw = result.thumbnail.width();
|
||||||
request.frameh = request.outerh = result.cover.height();
|
request.frameh = request.outerh = result.thumbnail.height();
|
||||||
request.factor = 1;
|
request.factor = 1;
|
||||||
result.cover = PrepareFrameImage(request, result.cover, hasAlpha, cacheForResize);
|
result.thumbnail = PrepareFrameImage(request, result.thumbnail, hasAlpha, cacheForResize);
|
||||||
}
|
}
|
||||||
result.duration = static_cast<int>(durationMs / 1000);
|
result.duration = static_cast<int>(durationMs / 1000);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "storage/localimageloader.h"
|
||||||
|
|
||||||
class FileLocation;
|
class FileLocation;
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
@ -243,12 +245,7 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SendData {
|
FileLoadTask::Video PrepareForSending(const QString &fname, const QByteArray &data);
|
||||||
QImage cover;
|
|
||||||
int duration = 0;
|
|
||||||
bool isGifv = false;
|
|
||||||
};
|
|
||||||
SendData PrepareForSending(const QString &fname, const QByteArray &data);
|
|
||||||
|
|
||||||
void Finish();
|
void Finish();
|
||||||
|
|
||||||
|
@ -47,6 +47,22 @@ TextParseOptions _documentNameOptions = {
|
|||||||
Qt::LayoutDirectionAuto, // dir
|
Qt::LayoutDirectionAuto, // dir
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TextWithEntities ComposeNameWithEntities(DocumentData *document) {
|
||||||
|
TextWithEntities result;
|
||||||
|
auto song = document->song();
|
||||||
|
if (!song || (song->title.isEmpty() && song->performer.isEmpty())) {
|
||||||
|
result.text = document->name.isEmpty() ? qsl("Unknown File") : document->name;
|
||||||
|
result.entities.push_back({ EntityInTextBold, 0, result.text.size() });
|
||||||
|
} else if (song->performer.isEmpty()) {
|
||||||
|
result.text = song->title;
|
||||||
|
result.entities.push_back({ EntityInTextBold, 0, result.text.size() });
|
||||||
|
} else {
|
||||||
|
result.text = song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
||||||
|
result.entities.push_back({ EntityInTextBold, 0, song->performer.size() });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ItemBase::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
|
void ItemBase::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
|
||||||
@ -672,7 +688,7 @@ Document::Document(DocumentData *document, HistoryItem *parent, const style::Ove
|
|||||||
, _date(langDateTime(date(_data->date)))
|
, _date(langDateTime(date(_data->date)))
|
||||||
, _datew(st::normalFont->width(_date))
|
, _datew(st::normalFont->width(_date))
|
||||||
, _colorIndex(documentColorIndex(_data, _ext)) {
|
, _colorIndex(documentColorIndex(_data, _ext)) {
|
||||||
_name.setMarkedText(st::defaultTextStyle, documentNameWithEntities(_data), _documentNameOptions);
|
_name.setMarkedText(st::defaultTextStyle, ComposeNameWithEntities(_data), _documentNameOptions);
|
||||||
|
|
||||||
AddComponents(Info::Bit());
|
AddComponents(Info::Bit());
|
||||||
|
|
||||||
|
@ -179,10 +179,10 @@ void TaskQueueWorker::onTaskAdded() {
|
|||||||
_inTaskAdded = false;
|
_inTaskAdded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QString &filepath, const QImage &image, SendMediaType type, const FileLoadTo &to, const QString &caption) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QString &filepath, std::unique_ptr<MediaInformation> information, SendMediaType type, const FileLoadTo &to, const QString &caption) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _filepath(filepath)
|
, _filepath(filepath)
|
||||||
, _image(image)
|
, _information(std::move(information))
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _caption(caption) {
|
, _caption(caption) {
|
||||||
}
|
}
|
||||||
@ -204,6 +204,115 @@ FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceW
|
|||||||
, _caption(caption) {
|
, _caption(caption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<FileLoadTask::MediaInformation> FileLoadTask::ReadMediaInformation(const QString &filepath, const QByteArray &content, const QString &filemime) {
|
||||||
|
auto result = std::make_unique<MediaInformation>();
|
||||||
|
result->filemime = filemime;
|
||||||
|
|
||||||
|
if (CheckForSong(filepath, content, result)) {
|
||||||
|
return result;
|
||||||
|
} else if (CheckForVideo(filepath, content, result)) {
|
||||||
|
return result;
|
||||||
|
} else if (CheckForImage(filepath, content, result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Mimes, typename Extensions>
|
||||||
|
bool FileLoadTask::CheckMimeOrExtensions(const QString &filepath, const QString &filemime, Mimes &mimes, Extensions &extensions) {
|
||||||
|
if (std::find(std::begin(mimes), std::end(mimes), filemime) != std::end(mimes)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::find_if(std::begin(extensions), std::end(extensions), [&filepath](auto &extension) {
|
||||||
|
return filepath.endsWith(extension, Qt::CaseInsensitive);
|
||||||
|
}) != std::end(extensions)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileLoadTask::CheckForSong(const QString &filepath, const QByteArray &content, std::unique_ptr<MediaInformation> &result) {
|
||||||
|
static const auto mimes = {
|
||||||
|
qstr("audio/mp3"),
|
||||||
|
qstr("audio/m4a"),
|
||||||
|
qstr("audio/aac"),
|
||||||
|
qstr("audio/ogg"),
|
||||||
|
qstr("audio/flac"),
|
||||||
|
};
|
||||||
|
static const auto extensions = {
|
||||||
|
qstr(".mp3"),
|
||||||
|
qstr(".m4a"),
|
||||||
|
qstr(".aac"),
|
||||||
|
qstr(".ogg"),
|
||||||
|
qstr(".flac"),
|
||||||
|
};
|
||||||
|
if (!CheckMimeOrExtensions(filepath, result->filemime, mimes, extensions)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto media = Media::Player::PrepareForSending(filepath, content);
|
||||||
|
if (media.duration <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ValidateThumbDimensions(media.cover.width(), media.cover.height())) {
|
||||||
|
media.cover = QImage();
|
||||||
|
}
|
||||||
|
result->media = std::move(media);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileLoadTask::CheckForVideo(const QString &filepath, const QByteArray &content, std::unique_ptr<MediaInformation> &result) {
|
||||||
|
static const auto mimes = {
|
||||||
|
qstr("video/mp4"),
|
||||||
|
qstr("video/quicktime"),
|
||||||
|
};
|
||||||
|
static const auto extensions = {
|
||||||
|
qstr(".mp4"),
|
||||||
|
qstr(".mov"),
|
||||||
|
};
|
||||||
|
if (!CheckMimeOrExtensions(filepath, result->filemime, mimes, extensions)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto media = Media::Clip::PrepareForSending(filepath, content);
|
||||||
|
if (media.duration <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto coverWidth = media.thumbnail.width();
|
||||||
|
auto coverHeight = media.thumbnail.height();
|
||||||
|
if (!ValidateThumbDimensions(coverWidth, coverHeight)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filepath.endsWith(qstr(".mp4"), Qt::CaseInsensitive)) {
|
||||||
|
result->filemime = qstr("video/mp4");
|
||||||
|
}
|
||||||
|
result->media = std::move(media);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileLoadTask::CheckForImage(const QString &filepath, const QByteArray &content, std::unique_ptr<MediaInformation> &result) {
|
||||||
|
auto animated = false;
|
||||||
|
auto image = ([&filepath, &content, &animated] {
|
||||||
|
if (!content.isEmpty()) {
|
||||||
|
return App::readImage(content, nullptr, false, &animated);
|
||||||
|
} else if (!filepath.isEmpty()) {
|
||||||
|
return App::readImage(filepath, nullptr, false, &animated);
|
||||||
|
}
|
||||||
|
return QImage();
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (image.isNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto media = Image();
|
||||||
|
media.data = std::move(image);
|
||||||
|
media.animated = animated;
|
||||||
|
result->media = media;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void FileLoadTask::process() {
|
void FileLoadTask::process() {
|
||||||
const QString stickerMime = qsl("image/webp");
|
const QString stickerMime = qsl("image/webp");
|
||||||
|
|
||||||
@ -217,10 +326,11 @@ void FileLoadTask::process() {
|
|||||||
QString thumbname = "thumb.jpg";
|
QString thumbname = "thumb.jpg";
|
||||||
QByteArray thumbdata;
|
QByteArray thumbdata;
|
||||||
|
|
||||||
auto animated = false;
|
auto isAnimation = false;
|
||||||
auto song = false;
|
auto isSong = false;
|
||||||
auto video = false;
|
auto isVideo = false;
|
||||||
auto voice = (_type == SendMediaType::Audio);
|
auto isVoice = (_type == SendMediaType::Audio);
|
||||||
|
|
||||||
auto fullimage = base::take(_image);
|
auto fullimage = base::take(_image);
|
||||||
auto info = _filepath.isEmpty() ? QFileInfo() : QFileInfo(_filepath);
|
auto info = _filepath.isEmpty() ? QFileInfo() : QFileInfo(_filepath);
|
||||||
if (info.exists()) {
|
if (info.exists()) {
|
||||||
@ -228,14 +338,28 @@ void FileLoadTask::process() {
|
|||||||
_result->filesize = -1;
|
_result->filesize = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Voice sending is supported only from memory for now.
|
||||||
|
// Because for voice we force mime type and don't read MediaInformation.
|
||||||
|
// For a real file we always read mime type and read MediaInformation.
|
||||||
|
t_assert(!isVoice);
|
||||||
|
|
||||||
filesize = info.size();
|
filesize = info.size();
|
||||||
filemime = mimeTypeForFile(info).name();
|
|
||||||
filename = info.fileName();
|
filename = info.fileName();
|
||||||
auto opaque = (filemime != stickerMime);
|
if (!_information) {
|
||||||
fullimage = App::readImage(_filepath, 0, opaque, &animated);
|
_information = readMediaInformation(mimeTypeForFile(info).name());
|
||||||
|
}
|
||||||
|
filemime = _information->filemime;
|
||||||
|
if (auto image = base::get_if<FileLoadTask::Image>(&_information->media)) {
|
||||||
|
fullimage = base::take(image->data);
|
||||||
|
if (auto opaque = (filemime != stickerMime)) {
|
||||||
|
fullimage = Images::prepareOpaque(std::move(fullimage));
|
||||||
|
}
|
||||||
|
isAnimation = image->animated;
|
||||||
|
}
|
||||||
} else if (!_content.isEmpty()) {
|
} else if (!_content.isEmpty()) {
|
||||||
filesize = _content.size();
|
filesize = _content.size();
|
||||||
if (voice) {
|
if (isVoice) {
|
||||||
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
|
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
|
||||||
filemime = "audio/ogg";
|
filemime = "audio/ogg";
|
||||||
} else {
|
} else {
|
||||||
@ -294,81 +418,65 @@ void FileLoadTask::process() {
|
|||||||
MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
|
MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
|
||||||
MTPDocument document(MTP_documentEmpty(MTP_long(0)));
|
MTPDocument document(MTP_documentEmpty(MTP_long(0)));
|
||||||
|
|
||||||
if (!voice) {
|
if (!isVoice) {
|
||||||
if (filemime == qstr("audio/mp3") || filemime == qstr("audio/m4a") || filemime == qstr("audio/aac") || filemime == qstr("audio/ogg") || filemime == qstr("audio/flac") ||
|
if (!_information) {
|
||||||
filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
|
_information = readMediaInformation(filemime);
|
||||||
filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
|
filemime = _information->filemime;
|
||||||
filename.endsWith(qstr(".flac"), Qt::CaseInsensitive)) {
|
|
||||||
QImage cover;
|
|
||||||
QByteArray coverBytes, coverFormat;
|
|
||||||
auto audioAttribute = audioReadSongAttributes(_filepath, _content, cover, coverBytes, coverFormat);
|
|
||||||
if (audioAttribute.type() == mtpc_documentAttributeAudio) {
|
|
||||||
attributes.push_back(audioAttribute);
|
|
||||||
song = true;
|
|
||||||
if (!cover.isNull()) { // cover to thumb
|
|
||||||
auto coverWidth = cover.width();
|
|
||||||
auto coverHeight = cover.height();
|
|
||||||
if (ValidateThumbDimensions(coverWidth, coverHeight)) {
|
|
||||||
auto full = (coverWidth > 90 || coverHeight > 90) ? App::pixmapFromImageInPlace(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : App::pixmapFromImageInPlace(std::move(cover));
|
|
||||||
{
|
|
||||||
auto thumbFormat = QByteArray("JPG");
|
|
||||||
auto thumbQuality = 87;
|
|
||||||
|
|
||||||
QBuffer buffer(&thumbdata);
|
|
||||||
full.save(&buffer, thumbFormat, thumbQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
thumb = full;
|
|
||||||
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));
|
|
||||||
|
|
||||||
thumbId = rand_value<uint64>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (filemime == qstr("video/mp4") || filemime == qstr("video/quicktime")
|
if (auto song = base::get_if<Song>(&_information->media)) {
|
||||||
|| filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive) || filename.endsWith(qstr(".mov"), Qt::CaseInsensitive)) {
|
isSong = true;
|
||||||
auto sendVideoData = Media::Clip::PrepareForSending(_filepath, _content);
|
auto flags = MTPDdocumentAttributeAudio::Flag::f_title | MTPDdocumentAttributeAudio::Flag::f_performer;
|
||||||
if (sendVideoData.duration > 0) {
|
attributes.push_back(MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(song->duration), MTP_string(song->title), MTP_string(song->performer), MTPstring()));
|
||||||
auto coverWidth = sendVideoData.cover.width();
|
if (!song->cover.isNull()) { // cover to thumb
|
||||||
auto coverHeight = sendVideoData.cover.height();
|
auto coverWidth = song->cover.width();
|
||||||
if (ValidateThumbDimensions(coverWidth, coverHeight)) {
|
auto coverHeight = song->cover.height();
|
||||||
if (sendVideoData.isGifv) {
|
auto full = (coverWidth > 90 || coverHeight > 90) ? App::pixmapFromImageInPlace(song->cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : App::pixmapFromImageInPlace(std::move(song->cover));
|
||||||
attributes.push_back(MTP_documentAttributeAnimated());
|
{
|
||||||
}
|
auto thumbFormat = QByteArray("JPG");
|
||||||
attributes.push_back(MTP_documentAttributeVideo(MTP_int(sendVideoData.duration), MTP_int(coverWidth), MTP_int(coverHeight)));
|
auto thumbQuality = 87;
|
||||||
video = true;
|
|
||||||
|
|
||||||
auto cover = (coverWidth > 90 || coverHeight > 90)
|
QBuffer buffer(&thumbdata);
|
||||||
? sendVideoData.cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)
|
full.save(&buffer, thumbFormat, thumbQuality);
|
||||||
: std::move(sendVideoData.cover);
|
|
||||||
{
|
|
||||||
auto thumbFormat = QByteArray("JPG");
|
|
||||||
auto thumbQuality = 87;
|
|
||||||
|
|
||||||
QBuffer buffer(&thumbdata);
|
|
||||||
cover.save(&buffer, thumbFormat, thumbQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
thumb = App::pixmapFromImageInPlace(std::move(cover));
|
|
||||||
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0));
|
|
||||||
|
|
||||||
thumbId = rand_value<uint64>();
|
|
||||||
|
|
||||||
if (filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive)) {
|
|
||||||
filemime = qstr("video/mp4");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thumb = full;
|
||||||
|
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));
|
||||||
|
|
||||||
|
thumbId = rand_value<uint64>();
|
||||||
}
|
}
|
||||||
|
} else if (auto video = base::get_if<Video>(&_information->media)) {
|
||||||
|
isVideo = true;
|
||||||
|
auto coverWidth = video->thumbnail.width();
|
||||||
|
auto coverHeight = video->thumbnail.height();
|
||||||
|
if (video->isGifv) {
|
||||||
|
attributes.push_back(MTP_documentAttributeAnimated());
|
||||||
|
}
|
||||||
|
attributes.push_back(MTP_documentAttributeVideo(MTP_int(video->duration), MTP_int(coverWidth), MTP_int(coverHeight)));
|
||||||
|
|
||||||
|
auto cover = (coverWidth > 90 || coverHeight > 90)
|
||||||
|
? video->thumbnail.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)
|
||||||
|
: std::move(video->thumbnail);
|
||||||
|
{
|
||||||
|
auto thumbFormat = QByteArray("JPG");
|
||||||
|
auto thumbQuality = 87;
|
||||||
|
|
||||||
|
QBuffer buffer(&thumbdata);
|
||||||
|
cover.save(&buffer, thumbFormat, thumbQuality);
|
||||||
|
}
|
||||||
|
|
||||||
|
thumb = App::pixmapFromImageInPlace(std::move(cover));
|
||||||
|
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0));
|
||||||
|
|
||||||
|
thumbId = rand_value<uint64>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fullimage.isNull() && fullimage.width() > 0 && !song && !video && !voice) {
|
if (!fullimage.isNull() && fullimage.width() > 0 && !isSong && !isVideo && !isVoice) {
|
||||||
auto w = fullimage.width(), h = fullimage.height();
|
auto w = fullimage.width(), h = fullimage.height();
|
||||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
|
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
|
||||||
|
|
||||||
if (ValidateThumbDimensions(w, h)) {
|
if (ValidateThumbDimensions(w, h)) {
|
||||||
if (animated) {
|
if (isAnimation) {
|
||||||
attributes.push_back(MTP_documentAttributeAnimated());
|
attributes.push_back(MTP_documentAttributeAnimated());
|
||||||
} else if (_type != SendMediaType::File) {
|
} else if (_type != SendMediaType::File) {
|
||||||
auto thumb = (w > 100 || h > 100) ? App::pixmapFromImageInPlace(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
|
auto thumb = (w > 100 || h > 100) ? App::pixmapFromImageInPlace(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
|
||||||
@ -398,7 +506,7 @@ void FileLoadTask::process() {
|
|||||||
|
|
||||||
QByteArray thumbFormat = "JPG";
|
QByteArray thumbFormat = "JPG";
|
||||||
int32 thumbQuality = 87;
|
int32 thumbQuality = 87;
|
||||||
if (!animated && filemime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
|
if (!isAnimation && filemime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
|
||||||
MTPDdocumentAttributeSticker::Flags stickerFlags = 0;
|
MTPDdocumentAttributeSticker::Flags stickerFlags = 0;
|
||||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(""), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
|
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(""), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
|
||||||
thumbFormat = "webp";
|
thumbFormat = "webp";
|
||||||
@ -419,7 +527,7 @@ void FileLoadTask::process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (voice) {
|
if (isVoice) {
|
||||||
attributes[0] = MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform), MTP_int(_duration), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform)));
|
attributes[0] = MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform), MTP_int(_duration), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform)));
|
||||||
attributes.resize(1);
|
attributes.resize(1);
|
||||||
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
|
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
|
||||||
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/variant.h"
|
||||||
|
|
||||||
enum class CompressConfirm {
|
enum class CompressConfirm {
|
||||||
Auto,
|
Auto,
|
||||||
Yes,
|
Yes,
|
||||||
@ -235,9 +237,30 @@ struct FileLoadResult {
|
|||||||
};
|
};
|
||||||
typedef QSharedPointer<FileLoadResult> FileLoadResultPtr;
|
typedef QSharedPointer<FileLoadResult> FileLoadResultPtr;
|
||||||
|
|
||||||
class FileLoadTask : public Task {
|
class FileLoadTask final : public Task {
|
||||||
public:
|
public:
|
||||||
FileLoadTask(const QString &filepath, const QImage &image, SendMediaType type, const FileLoadTo &to, const QString &caption);
|
struct Image {
|
||||||
|
QImage data;
|
||||||
|
bool animated = false;
|
||||||
|
};
|
||||||
|
struct Song {
|
||||||
|
int duration = 0;
|
||||||
|
QString title;
|
||||||
|
QString performer;
|
||||||
|
QImage cover;
|
||||||
|
};
|
||||||
|
struct Video {
|
||||||
|
bool isGifv = false;
|
||||||
|
int duration = 0;
|
||||||
|
QImage thumbnail;
|
||||||
|
};
|
||||||
|
struct MediaInformation {
|
||||||
|
QString filemime;
|
||||||
|
base::variant<Image, Song, Video> media;
|
||||||
|
};
|
||||||
|
static std::unique_ptr<MediaInformation> ReadMediaInformation(const QString &filepath, const QByteArray &content, const QString &filemime);
|
||||||
|
|
||||||
|
FileLoadTask(const QString &filepath, std::unique_ptr<MediaInformation> information, SendMediaType type, const FileLoadTo &to, const QString &caption);
|
||||||
FileLoadTask(const QByteArray &content, const QImage &image, SendMediaType type, const FileLoadTo &to, const QString &caption);
|
FileLoadTask(const QByteArray &content, const QImage &image, SendMediaType type, const FileLoadTo &to, const QString &caption);
|
||||||
FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to, const QString &caption);
|
FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to, const QString &caption);
|
||||||
|
|
||||||
@ -248,11 +271,23 @@ public:
|
|||||||
void process();
|
void process();
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
static bool CheckForSong(const QString &filepath, const QByteArray &content, std::unique_ptr<MediaInformation> &result);
|
||||||
|
static bool CheckForVideo(const QString &filepath, const QByteArray &content, std::unique_ptr<MediaInformation> &result);
|
||||||
|
static bool CheckForImage(const QString &filepath, const QByteArray &content, std::unique_ptr<MediaInformation> &result);
|
||||||
|
|
||||||
|
template <typename Mimes, typename Extensions>
|
||||||
|
static bool CheckMimeOrExtensions(const QString &filepath, const QString &filemime, Mimes &mimes, Extensions &extensions);
|
||||||
|
|
||||||
|
std::unique_ptr<MediaInformation> readMediaInformation(const QString &filemime) const {
|
||||||
|
return ReadMediaInformation(_filepath, _content, filemime);
|
||||||
|
}
|
||||||
|
|
||||||
uint64 _id;
|
uint64 _id;
|
||||||
FileLoadTo _to;
|
FileLoadTo _to;
|
||||||
QString _filepath;
|
QString _filepath;
|
||||||
QByteArray _content;
|
QByteArray _content;
|
||||||
|
std::unique_ptr<MediaInformation> _information;
|
||||||
QImage _image;
|
QImage _image;
|
||||||
int32 _duration = 0;
|
int32 _duration = 0;
|
||||||
VoiceWaveform _waveform;
|
VoiceWaveform _waveform;
|
||||||
|
@ -1844,6 +1844,19 @@ DocumentData::~DocumentData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString DocumentData::composeNameString(const QString &filename, const QString &songTitle, const QString &songPerformer) {
|
||||||
|
if (songTitle.isEmpty() && songPerformer.isEmpty()) {
|
||||||
|
return filename.isEmpty() ? qsl("Unknown File") : filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (songPerformer.isEmpty()) {
|
||||||
|
return songTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto trackTitle = (songTitle.isEmpty() ? qsl("Unknown Track") : songTitle);
|
||||||
|
return songPerformer + QString::fromUtf8(" \xe2\x80\x93 ") + trackTitle;
|
||||||
|
}
|
||||||
|
|
||||||
WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, DocumentData *document, PhotoData *photo, int32 duration, const QString &author, int32 pendingTill) : id(id)
|
WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, DocumentData *document, PhotoData *photo, int32 duration, const QString &author, int32 pendingTill) : id(id)
|
||||||
, type(type)
|
, type(type)
|
||||||
, url(url)
|
, url(url)
|
||||||
|
@ -1258,6 +1258,14 @@ public:
|
|||||||
return ::mediaKey(locationType(), _dc, id, _version);
|
return ::mediaKey(locationType(), _dc, id, _version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString composeNameString(const QString &filename, const QString &songTitle, const QString &songPerformer);
|
||||||
|
QString composeNameString() const {
|
||||||
|
if (auto songData = song()) {
|
||||||
|
return composeNameString(name, songData->title, songData->performer);
|
||||||
|
}
|
||||||
|
return composeNameString(name, QString(), QString());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector<MTPDocumentAttribute> &attributes);
|
DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector<MTPDocumentAttribute> &attributes);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user