new image / file confirm / send codepath made by Task / TaskQueue, sending single file paste and image paste / drop with that new code

This commit is contained in:
John Preston 2015-10-26 22:39:02 -04:00
parent c606d6b459
commit 31b1ecb11c
18 changed files with 778 additions and 135 deletions

View File

@ -676,6 +676,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_really_send_file" = "Do you want to send this file?";
"lng_really_share_contact" = "Do you want to share this contact?";
"lng_send_image_compressed" = "Send compressed image";
"lng_send_image_empty" = "Could not send an empty file :(";
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1.5 GB :(";
"lng_forward_choose" = "Choose recipient..";
"lng_forward_cant" = "Sorry, no way to forward here :(";

View File

@ -515,7 +515,7 @@ void Application::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId)
int32 filesize = 0;
QByteArray data;
ReadyLocalMedia ready(ToPreparePhoto, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, MTP_audioEmpty(MTP_long(0)), photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false, false, 0);
ReadyLocalMedia ready(PreparePhoto, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, MTP_audioEmpty(MTP_long(0)), photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false, false, 0);
connect(App::uploader(), SIGNAL(photoReady(const FullMsgId&, const MTPInputFile&)), App::app(), SLOT(photoUpdated(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);

View File

@ -27,6 +27,92 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "mainwidget.h"
#include "photosendbox.h"
PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxWideWidth)
, _file(file)
, _img(0)
, _thumbx(0)
, _thumby(0)
, _thumbw(0)
, _thumbh(0)
, _namew(0)
, _textw(0)
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
, _compressed(this, lang(lng_send_image_compressed), cCompressPastedImage())
, _send(this, lang(lng_send_button), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _replyTo(_file->to.replyTo) {
connect(&_send, SIGNAL(clicked()), this, SLOT(onSend()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
if (_file->photo.type() != mtpc_photoEmpty) {
_file->type = PreparePhoto;
}
if (_file->type == PreparePhoto) {
int32 maxW = 0, maxH = 0;
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
if (i->width() >= maxW && i->height() >= maxH) {
_thumb = *i;
maxW = _thumb.width();
maxH = _thumb.height();
}
}
int32 tw = _thumb.width(), th = _thumb.height();
if (!tw || !th) {
tw = th = 1;
}
_thumbw = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
if (_thumb.width() < _thumbw) {
_thumbw = (_thumb.width() > 20) ? _thumb.width() : 20;
}
int32 maxthumbh = qMin(qRound(1.5 * _thumbw), int(st::confirmMaxHeight));
_thumbh = qRound(th * float64(_thumbw) / tw);
if (_thumbh > maxthumbh) {
_thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh);
_thumbh = maxthumbh;
if (_thumbw < 10) {
_thumbw = 10;
}
}
_thumbx = (width() - _thumbw) / 2;
_thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly);
_thumb.setDevicePixelRatio(cRetinaFactor());
} else {
_compressed.hide();
if (!_file->thumb.isNull()) {
_thumb = _file->thumb;
int32 tw = _thumb.width(), th = _thumb.height();
if (_thumb.isNull() || !tw || !th) {
_thumbw = _thumbx = _thumby = 0;
} else if (tw > th) {
_thumbw = (tw * st::mediaThumbSize) / th;
_thumbx = (_thumbw - st::mediaThumbSize) / 2;
_thumby = 0;
} else {
_thumbw = st::mediaThumbSize;
_thumbx = 0;
_thumby = ((th * _thumbw) / tw - st::mediaThumbSize) / 2;
}
}
if (_thumbw) {
_thumb = QPixmap::fromImage(_thumb.toImage().scaledToWidth(_thumbw * cIntRetinaFactor(), Qt::SmoothTransformation), Qt::ColorOnly);
_thumb.setDevicePixelRatio(cRetinaFactor());
}
_name = _file->filename;
_namew = st::mediaFont->width(_name);
_size = formatSizeText(_file->filesize);
_textw = qMax(_namew, st::mediaFont->width(_size));
}
updateBoxSize();
_caption.setMaxLength(MaxPhotoCaption);
_caption.setCtrlEnterSubmit(CtrlEnterSubmitBoth);
connect(&_compressed, SIGNAL(changed()), this, SLOT(onCompressedChange()));
connect(&_caption, SIGNAL(resized()), this, SLOT(onCaptionResized()));
connect(&_caption, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
connect(&_caption, SIGNAL(cancelled()), this, SLOT(onClose()));
prepare();
}
PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : AbstractBox(st::boxWideWidth)
, _img(new ReadyLocalMedia(img))
, _thumbx(0)
@ -43,7 +129,7 @@ PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : AbstractBox(st::boxWide
connect(&_send, SIGNAL(clicked()), this, SLOT(onSend()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
if (_img->type == ToPreparePhoto) {
if (_img->type == PreparePhoto) {
int32 maxW = 0, maxH = 0;
for (PreparedPhotoThumbs::const_iterator i = _img->photoThumbs.cbegin(), e = _img->photoThumbs.cend(); i != e; ++i) {
if (i->width() >= maxW && i->height() >= maxH) {
@ -156,7 +242,7 @@ void PhotoSendBox::onCaptionResized() {
}
void PhotoSendBox::updateBoxSize() {
if (_img && _img->type == ToPreparePhoto) {
if ((_file && _file->type == PreparePhoto) || (_img && _img->type == PreparePhoto)) {
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.top() + _compressed.height() + (_compressed.checked() ? (st::boxPhotoCompressedPadding.bottom() + _caption.height()) : 0) + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
} else {
setMaxHeight(st::boxPhotoPadding.top() + st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom() + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
@ -175,7 +261,7 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
if (_img && _img->type == ToPreparePhoto) {
if ((_file && _file->type == PreparePhoto) || (_img && _img->type == PreparePhoto)) {
if (_thumbx > st::boxPhotoPadding.left()) {
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg->b);
}
@ -197,7 +283,7 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
if (_thumbw) {
int32 rf(cIntRetinaFactor());
p.drawPixmap(QPoint(x + st::mediaPadding.left(), y + st::mediaPadding.top()), _thumb, QRect(_thumbx * rf, _thumby * rf, st::mediaThumbSize * rf, st::mediaThumbSize * rf));
} else if (_img) {
} else if (_file || _img) {
p.drawPixmap(QPoint(x + st::mediaPadding.left(), y + st::mediaPadding.top()), App::sprite(), st::mediaDocOutImg);
} else {
p.drawPixmap(x + st::mediaPadding.left(), y + st::mediaPadding.top(), userDefPhoto(1)->pix(st::mediaThumbSize));
@ -225,7 +311,13 @@ void PhotoSendBox::resizeEvent(QResizeEvent *e) {
}
void PhotoSendBox::closePressed() {
if (App::main()) App::main()->cancelSendImage();
if (App::main()) {
if (_file) {
App::main()->onSendFileCancel(_file);
} else {
App::main()->cancelSendImage();
}
}
}
void PhotoSendBox::hideAll() {
@ -238,7 +330,7 @@ void PhotoSendBox::hideAll() {
void PhotoSendBox::showAll() {
_send.show();
_cancel.show();
if (_img && _img->type == ToPreparePhoto) {
if ((_file && _file->type == PreparePhoto) || (_img && _img->type == PreparePhoto)) {
_compressed.show();
if (_compressed.checked()) {
_caption.show();
@ -256,6 +348,30 @@ void PhotoSendBox::showDone() {
}
void PhotoSendBox::onSend(bool ctrlShiftEnter) {
if (_file) {
if (_compressed.isHidden()) {
if (_file->type == PrepareAuto) {
_file->type = PrepareDocument;
}
} else {
if (_compressed.checked() != cCompressPastedImage()) {
cSetCompressPastedImage(_compressed.checked());
Local::writeUserSettings();
}
if (_compressed.checked()) {
_file->type = PreparePhoto;
} else {
_file->type = PrepareDocument;
}
}
if (!_caption.isHidden()) {
_file->photoCaption = prepareText(_caption.getLastText(), true);
}
if (App::main()) App::main()->onSendFileConfirm(_file, ctrlShiftEnter);
onClose();
return;
}
if (!_img) {
if (App::main()) App::main()->confirmShareContact(ctrlShiftEnter, _phone, _fname, _lname, _replyTo);
} else {

View File

@ -28,6 +28,7 @@ class PhotoSendBox : public AbstractBox {
public:
PhotoSendBox(const FileLoadResultPtr &file);
PhotoSendBox(const ReadyLocalMedia &img);
PhotoSendBox(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo);
void keyPressEvent(QKeyEvent *e);
@ -47,6 +48,7 @@ public:
signals:
void confirmed();
void cancelled();
public slots:
@ -65,6 +67,7 @@ private:
void updateBoxSize();
FileLoadResultPtr _file;
ReadyLocalMedia *_img;
int32 _thumbx, _thumby, _thumbw, _thumbh;
QString _name, _size;

View File

@ -312,9 +312,11 @@ enum {
MessagesFirstLoad = 30, // first history part size requested
MessagesPerPage = 50, // next history part size
FileLoaderQueueStopTimeout = 5000,
DownloadPartSize = 64 * 1024, // 64kb for photo
DocumentDownloadPartSize = 128 * 1024, // 128kb for document
MaxUploadPhotoSize = 32 * 1024 * 1024, // 32mb photos max
MaxUploadPhotoSize = 256 * 1024 * 1024, // 256mb photos max
MaxUploadDocumentSize = 1500 * 1024 * 1024, // 1500mb documents max
UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb
MaxFileQueries = 16, // max 16 file parts downloaded at the same time

View File

@ -30,9 +30,9 @@ FileUploader::FileUploader() : sentSize(0) {
}
void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &media) {
if (media.type == ToPreparePhoto) {
if (media.type == PreparePhoto) {
App::feedPhoto(media.photo, media.photoThumbs);
} else if (media.type == ToPrepareDocument) {
} else if (media.type == PrepareDocument) {
DocumentData *document;
if (media.photoThumbs.isEmpty()) {
document = App::feedDocument(media.document);
@ -43,7 +43,7 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
if (!media.file.isEmpty()) {
document->location = FileLocation(StorageFilePartial, media.file);
}
} else if (media.type == ToPrepareAudio) {
} else if (media.type == PrepareAudio) {
AudioData *audio = App::feedAudio(media.audio);
audio->status = FileUploading;
audio->data = media.data;
@ -52,19 +52,42 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
sendNext();
}
void FileUploader::uploadFile(const FullMsgId &msgId, const FileLoadResultPtr &file) {
if (file->type == PreparePhoto) {
App::feedPhoto(file->photo, file->photoThumbs);
} else if (file->type == PrepareDocument) {
DocumentData *document;
if (file->thumb.isNull()) {
document = App::feedDocument(file->document);
} else {
document = App::feedDocument(file->document, file->thumb);
}
document->status = FileUploading;
if (!file->filepath.isEmpty()) {
document->location = FileLocation(StorageFilePartial, file->filepath);
}
} else if (file->type == PrepareAudio) {
AudioData *audio = App::feedAudio(file->audio);
audio->status = FileUploading;
audio->data = file->content;
}
queue.insert(msgId, File(file));
sendNext();
}
void FileUploader::currentFailed() {
Queue::iterator j = queue.find(uploading);
if (j != queue.end()) {
if (j->media.type == ToPreparePhoto) {
if (j->type() == PreparePhoto) {
emit photoFailed(j.key());
} else if (j->media.type == ToPrepareDocument) {
DocumentData *doc = App::document(j->media.id);
} else if (j->type() == PrepareDocument) {
DocumentData *doc = App::document(j->id());
if (doc->status == FileUploading) {
doc->status = FileFailed;
}
emit documentFailed(j.key());
} else if (j->media.type == ToPrepareAudio) {
AudioData *audio = App::audio(j->media.id);
} else if (j->type() == PrepareAudio) {
AudioData *audio = App::audio(j->id());
if (audio->status == FileUploading) {
audio->status = FileFailed;
}
@ -118,26 +141,29 @@ void FileUploader::sendNext() {
todc = dc;
}
}
if (i->media.parts.isEmpty()) {
UploadFileParts &parts(i->file ? (i->type() == PreparePhoto ? i->file->fileparts : i->file->thumbparts) : i->media.parts);
uint64 partsOfId(i->file ? (i->type() == PreparePhoto ? i->file->id : i->file->thumbId) : i->media.thumbId);
if (parts.isEmpty()) {
if (i->docSentParts >= i->docPartsCount) {
if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) {
if (i->media.type == ToPreparePhoto) {
emit photoReady(uploading, MTP_inputFile(MTP_long(i->media.id), MTP_int(i->partsCount), MTP_string(i->media.filename), MTP_string(i->media.jpeg_md5)));
} else if (i->media.type == ToPrepareDocument) {
if (i->type() == PreparePhoto) {
emit photoReady(uploading, MTP_inputFile(MTP_long(i->id()), MTP_int(i->partsCount), MTP_string(i->filename()), MTP_string(i->file ? i->file->filemd5 : i->media.jpeg_md5)));
} else if (i->type() == PrepareDocument) {
QByteArray docMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), docMd5.data());
MTPInputFile doc = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename)) : MTP_inputFile(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename), MTP_string(docMd5));
MTPInputFile doc = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename())) : MTP_inputFile(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename()), MTP_string(docMd5));
if (i->partsCount) {
emit thumbDocumentReady(uploading, doc, MTP_inputFile(MTP_long(i->media.thumbId), MTP_int(i->partsCount), MTP_string(qsl("thumb.") + i->media.thumbExt), MTP_string(i->media.jpeg_md5)));
emit thumbDocumentReady(uploading, doc, MTP_inputFile(MTP_long(i->thumbId()), MTP_int(i->partsCount), MTP_string(i->file ? i->file->thumbname : (qsl("thumb.") + i->media.thumbExt)), MTP_string(i->file ? i->file->thumbmd5 : i->media.jpeg_md5)));
} else {
emit documentReady(uploading, doc);
}
} else if (i->media.type == ToPrepareAudio) {
} else if (i->type() == PrepareAudio) {
QByteArray audioMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), audioMd5.data());
MTPInputFile audio = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename)) : MTP_inputFile(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename), MTP_string(audioMd5));
MTPInputFile audio = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename())) : MTP_inputFile(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename()), MTP_string(audioMd5));
emit audioReady(uploading, audio);
}
queue.remove(uploading);
@ -147,10 +173,11 @@ void FileUploader::sendNext() {
return;
}
QByteArray &content(i->file ? i->file->content : i->media.data);
QByteArray toSend;
if (i->media.data.isEmpty()) {
if (content.isEmpty()) {
if (!i->docFile) {
i->docFile.reset(new QFile(i->media.file));
i->docFile.reset(new QFile(i->file ? i->file->filepath : i->media.file));
if (!i->docFile->open(QIODevice::ReadOnly)) {
currentFailed();
return;
@ -161,8 +188,8 @@ void FileUploader::sendNext() {
i->md5Hash.feed(toSend.constData(), toSend.size());
}
} else {
toSend = i->media.data.mid(i->docSentParts * i->docPartSize, i->docPartSize);
if ((i->media.type == ToPrepareDocument || i->media.type == ToPrepareAudio) && i->docSentParts <= UseBigFilesFrom) {
toSend = content.mid(i->docSentParts * i->docPartSize, i->docPartSize);
if ((i->type() == PrepareDocument || i->type() == PrepareAudio) && i->docSentParts <= UseBigFilesFrom) {
i->md5Hash.feed(toSend.constData(), toSend.size());
}
}
@ -172,9 +199,9 @@ void FileUploader::sendNext() {
}
mtpRequestId requestId;
if (i->docSize > UseBigFilesFrom) {
requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
} else {
requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
}
docRequestsSent.insert(requestId, i->docSentParts);
dcMap.insert(requestId, todc);
@ -183,15 +210,15 @@ void FileUploader::sendNext() {
i->docSentParts++;
} else {
LocalFileParts::iterator part = i->media.parts.begin();
UploadFileParts::iterator part = parts.begin();
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.thumbId), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(partsOfId), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
requestsSent.insert(requestId, part.value());
dcMap.insert(requestId, todc);
sentSize += part.value().size();
sentSizes[todc] += part.value().size();
i->media.parts.erase(part);
parts.erase(part);
}
nextTimer.start(UploadRequestInterval);
}
@ -257,10 +284,10 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
sentSizes[dc] -= k->docPartSize;
docRequestsSent.erase(j);
}
if (k->media.type == ToPreparePhoto) {
if (k->type() == PreparePhoto) {
emit photoProgress(k.key());
} else if (k->media.type == ToPrepareDocument) {
DocumentData *doc = App::document(k->media.id);
} else if (k->type() == PrepareDocument) {
DocumentData *doc = App::document(k->id());
if (doc->status == FileUploading) {
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
if (doc->uploadOffset > doc->size) {
@ -268,8 +295,8 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
}
}
emit documentProgress(k.key());
} else if (k->media.type == ToPrepareAudio) {
AudioData *audio = App::audio(k->media.id);
} else if (k->type() == PrepareAudio) {
AudioData *audio = App::audio(k->id());
if (audio->status == FileUploading) {
audio->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
if (audio->uploadOffset > audio->size) {

View File

@ -29,6 +29,7 @@ public:
FileUploader();
void uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &image);
void uploadFile(const FullMsgId &msgId, const FileLoadResultPtr &file);
int32 currentOffset(const FullMsgId &msgId) const; // -1 means file not found
int32 fullSize(const FullMsgId &msgId) const;
@ -63,21 +64,32 @@ private:
struct File {
File(const ReadyLocalMedia &media) : media(media), docSentParts(0) {
partsCount = media.parts.size();
if (media.type == ToPrepareDocument || media.type == ToPrepareAudio) {
docSize = media.file.isEmpty() ? media.data.size() : media.filesize;
if (docSize >= 1024 * 1024 || !setPartSize(DocumentUploadPartSize0)) {
if (docSize > 32 * 1024 * 1024 || !setPartSize(DocumentUploadPartSize1)) {
if (!setPartSize(DocumentUploadPartSize2)) {
if (!setPartSize(DocumentUploadPartSize3)) {
if (!setPartSize(DocumentUploadPartSize4)) {
LOG(("Upload Error: bad doc size: %1").arg(docSize));
}
if (type() == PrepareDocument || type() == PrepareAudio) {
setDocSize(media.file.isEmpty() ? media.data.size() : media.filesize);
} else {
docSize = docPartSize = docPartsCount = 0;
}
}
File(const FileLoadResultPtr &file) : file(file), docSentParts(0) {
partsCount = (type() == PreparePhoto) ? file->fileparts.size() : file->thumbparts.size();
if (type() == PrepareDocument || type() == PrepareAudio) {
setDocSize(file->filesize);
} else {
docSize = docPartSize = docPartsCount = 0;
}
}
void setDocSize(int32 size) {
docSize = size;
if (docSize >= 1024 * 1024 || !setPartSize(DocumentUploadPartSize0)) {
if (docSize > 32 * 1024 * 1024 || !setPartSize(DocumentUploadPartSize1)) {
if (!setPartSize(DocumentUploadPartSize2)) {
if (!setPartSize(DocumentUploadPartSize3)) {
if (!setPartSize(DocumentUploadPartSize4)) {
LOG(("Upload Error: bad doc size: %1").arg(docSize));
}
}
}
}
} else {
docSize = docPartSize = docPartsCount = 0;
}
}
bool setPartSize(uint32 partSize) {
@ -86,9 +98,23 @@ private:
return (docPartsCount <= DocumentMaxPartsCount);
}
FileLoadResultPtr file;
ReadyLocalMedia media;
int32 partsCount;
const uint64 &id() const {
return file ? file->id : media.id;
}
PrepareMediaType type() const {
return file ? file->type : media.type;
}
const uint64 &thumbId() const {
return file ? file->thumbId : media.thumbId;
}
const QString &filename() const {
return file ? file->filename : media.filename;
}
HashMd5 md5Hash;
QSharedPointer<QFile> docFile;

View File

@ -1696,7 +1696,7 @@ void MessageField::insertFromMimeData(const QMimeData *source) {
if (source->hasImage()) {
QImage img = qvariant_cast<QImage>(source->imageData());
if (!img.isNull()) {
history->uploadImage(img, false, source->text());
history->uploadImage(img, FileLoadAlwaysConfirm, source->text());
return;
}
}
@ -2402,11 +2402,13 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _attachDrag(DragStateNone)
, _attachDragDocument(this)
, _attachDragPhoto(this)
, _fileLoader(this, FileLoaderQueueStopTimeout)
, _imageLoader(this)
, _synthedTextUpdate(false)
, _serviceImageCacheSize(0)
, _confirmImageId(0)
, _confirmWithText(false)
, _confirmWithTextId(0)
, _titlePeerTextWidth(0)
, _a_show(animFunc(this, &HistoryWidget::animStep_show))
, _scrollDelta(0)
@ -2709,7 +2711,7 @@ void HistoryWidget::onRecordDone(QByteArray result, qint32 samples) {
App::wnd()->activateWindow();
int32 duration = samples / AudioVoiceMsgFrequency;
_imageLoader.append(result, duration, _peer->id, _broadcast.checked(), replyToId(), ToPrepareAudio);
_imageLoader.append(result, duration, _peer->id, _broadcast.checked(), replyToId(), PrepareAudio);
cancelReply(lastForceReplyReplied());
}
@ -3989,7 +3991,7 @@ void HistoryWidget::onSendPaths(const PeerId &peer) {
App::main()->showPeerHistory(peer, ShowAtTheEndMsgId);
if (!_history) return;
uploadMedias(cSendPaths(), ToPrepareDocument);
uploadMedias(cSendPaths(), PrepareDocument);
}
History *HistoryWidget::history() const {
@ -4167,11 +4169,11 @@ void HistoryWidget::onPhotoSelect() {
QByteArray file;
if (filedialogGetOpenFiles(files, file, lang(lng_choose_images), filter)) {
if (!file.isEmpty()) {
uploadMedia(file, ToPreparePhoto);
uploadMedia(file, PreparePhoto);
//} else if (files.size() == 1) {
// uploadWithConfirm(files.at(0), false, true);
} else if (!files.isEmpty()) {
uploadMedias(files, ToPreparePhoto);
uploadMedias(files, PreparePhoto);
}
}
}
@ -4197,11 +4199,11 @@ void HistoryWidget::onDocumentSelect() {
QByteArray file;
if (filedialogGetOpenFiles(files, file, lang(lng_choose_images), filter)) {
if (!file.isEmpty()) {
uploadMedia(file, ToPrepareDocument);
uploadMedia(file, PrepareDocument);
//} else if (files.size() == 1) {
// uploadWithConfirm(files.at(0), false, false);
} else if (!files.isEmpty()) {
uploadMedias(files, ToPrepareDocument);
uploadMedias(files, PrepareDocument);
}
}
}
@ -4502,7 +4504,7 @@ void HistoryWidget::onPhotoDrop(const QMimeData *data) {
QImage image = qvariant_cast<QImage>(data->imageData());
if (image.isNull()) return;
uploadImage(image, false, data->text());
uploadImage(image, FileLoadNoForceConfirm, data->text());
}
return;
}
@ -4510,7 +4512,7 @@ void HistoryWidget::onPhotoDrop(const QMimeData *data) {
//if (files.size() == 1) {
// uploadWithConfirm(files.at(0), false, true);
//} else {
uploadMedias(files, ToPreparePhoto);
uploadMedias(files, PreparePhoto);
//}
}
@ -4523,7 +4525,7 @@ void HistoryWidget::onDocumentDrop(const QMimeData *data) {
//if (files.size() == 1) {
// uploadWithConfirm(files.at(0), false, false);
//} else {
uploadMedias(files, ToPrepareDocument);
uploadMedias(files, PrepareDocument);
//}
}
@ -4534,7 +4536,7 @@ void HistoryWidget::onFilesDrop(const QMimeData *data) {
QImage image = qvariant_cast<QImage>(data->imageData());
if (image.isNull()) return;
uploadImage(image, false, data->text());
uploadImage(image, FileLoadNoForceConfirm, data->text());
}
return;
}
@ -4542,7 +4544,7 @@ void HistoryWidget::onFilesDrop(const QMimeData *data) {
//if (files.size() == 1) {
// uploadWithConfirm(files.at(0), false, true);
//} else {
uploadMedias(files, ToPrepareAuto);
uploadMedias(files, PrepareAuto);
//}
}
@ -4804,22 +4806,26 @@ void HistoryWidget::onFieldCursorChanged() {
onDraftSaveDelayed();
}
void HistoryWidget::uploadImage(const QImage &img, bool withText, const QString &source) {
if (!_history || _confirmImageId) return;
void HistoryWidget::uploadImage(const QImage &img, FileLoadForceConfirmType confirm, const QString &source, bool withText) {
if (!_history) return;
App::wnd()->activateWindow();
_confirmImage = img;
_confirmWithText = withText;
_confirmSource = source;
_confirmImageId = _imageLoader.append(img, _peer->id, _broadcast.checked(), replyToId(), ToPreparePhoto);
FileLoadTask *task = new FileLoadTask(img, FileLoadTo(_peer->id, _broadcast.checked(), replyToId()), confirm, source);
if (withText) {
_confirmWithTextId = task->fileid();
}
_fileLoader.addTask(task);
}
void HistoryWidget::uploadFile(const QString &file, bool withText) {
if (!_history || _confirmImageId) return;
void HistoryWidget::uploadFile(const QString &file, FileLoadForceConfirmType confirm, bool withText) {
if (!_history) return;
App::wnd()->activateWindow();
_confirmWithText = withText;
_confirmImageId = _imageLoader.append(file, _peer->id, _broadcast.checked(), replyToId(), ToPrepareDocument);
FileLoadTask *task = new FileLoadTask(file, PrepareAuto, FileLoadTo(_peer->id, _broadcast.checked(), replyToId()), confirm);
if (withText) {
_confirmWithTextId = task->fileid();
}
_fileLoader.addTask(task);
}
void HistoryWidget::shareContactConfirmation(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool withText) {
@ -4840,14 +4846,14 @@ void HistoryWidget::uploadConfirmImageUncompressed(bool ctrlShiftEnter, MsgId re
onSend(ctrlShiftEnter, replyTo);
}
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(_channel, replyTo));
_imageLoader.append(_confirmImage, peerId, _broadcast.checked(), replyTo, ToPrepareDocument, ctrlShiftEnter);
_imageLoader.append(_confirmImage, peerId, _broadcast.checked(), replyTo, PrepareDocument, ctrlShiftEnter);
_confirmImageId = 0;
_confirmWithText = false;
_confirmImage = QImage();
cancelReply(lastKeyboardUsed);
}
void HistoryWidget::uploadMedias(const QStringList &files, ToPrepareMediaType type) {
void HistoryWidget::uploadMedias(const QStringList &files, PrepareMediaType type) {
if (!_history) return;
App::wnd()->activateWindow();
@ -4855,7 +4861,7 @@ void HistoryWidget::uploadMedias(const QStringList &files, ToPrepareMediaType ty
cancelReply(lastForceReplyReplied());
}
void HistoryWidget::uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type, PeerId peer) {
void HistoryWidget::uploadMedia(const QByteArray &fileContent, PrepareMediaType type, PeerId peer) {
if (!peer && !_history) return;
App::wnd()->activateWindow();
@ -4945,11 +4951,11 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) {
} else {
flags |= MTPDmessage::flag_from_id;
}
if (img.type == ToPreparePhoto) {
if (img.type == PreparePhoto) {
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string(img.caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
} else if (img.type == ToPrepareDocument) {
} else if (img.type == PrepareDocument) {
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
} else if (img.type == ToPrepareAudio) {
} else if (img.type == PrepareAudio) {
if (!h->peer->isChannel()) {
flags |= MTPDmessage_flag_media_unread;
}
@ -4970,6 +4976,67 @@ void HistoryWidget::cancelSendImage() {
_confirmImage = QImage();
}
void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShiftEnter) {
if (_confirmWithTextId && _confirmWithTextId == file->id) {
onSend(ctrlShiftEnter, file->to.replyTo);
_confirmWithTextId = 0;
}
FullMsgId newId(peerToChannel(file->to.peer), clientMsgId());
connect(App::uploader(), SIGNAL(photoReady(const FullMsgId&, const MTPInputFile&)), this, SLOT(onPhotoUploaded(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(documentReady(const FullMsgId&, const MTPInputFile&)), this, SLOT(onDocumentUploaded(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(thumbDocumentReady(const FullMsgId&, const MTPInputFile&, const MTPInputFile&)), this, SLOT(onThumbDocumentUploaded(const FullMsgId&, const MTPInputFile&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(audioReady(const FullMsgId&, const MTPInputFile&)), this, SLOT(onAudioUploaded(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(photoProgress(const FullMsgId&)), this, SLOT(onPhotoProgress(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(documentProgress(const FullMsgId&)), this, SLOT(onDocumentProgress(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(audioProgress(const FullMsgId&)), this, SLOT(onAudioProgress(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(photoFailed(const FullMsgId&)), this, SLOT(onPhotoFailed(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(documentFailed(const FullMsgId&)), this, SLOT(onDocumentFailed(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(audioFailed(const FullMsgId&)), this, SLOT(onAudioFailed(const FullMsgId&)), Qt::UniqueConnection);
App::uploader()->uploadFile(newId, file);
History *h = App::history(file->to.peer);
fastShowAtEnd(h);
int32 flags = newMessageFlags(h->peer) | MTPDmessage::flag_media; // unread, out
if (file->to.replyTo) flags |= MTPDmessage::flag_reply_to_msg_id;
bool fromChannelName = h->peer->isChannel() && h->peer->asChannel()->canPublish() && (h->peer->asChannel()->isBroadcast() || file->to.broadcast);
if (fromChannelName) {
flags |= MTPDmessage::flag_views;
} else {
flags |= MTPDmessage::flag_from_id;
}
if (file->type == PreparePhoto) {
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->photoCaption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
} else if (file->type == PrepareDocument) {
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
} else if (file->type == PrepareAudio) {
if (!h->peer->isChannel()) {
flags |= MTPDmessage_flag_media_unread;
}
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaAudio(file->audio), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
}
if (_peer && file->to.peer == _peer->id) {
App::main()->historyToDown(_history);
}
App::main()->dialogsToUp();
peerMessagesUpdated(file->to.peer);
}
void HistoryWidget::cancelSendFile(const FileLoadResultPtr &file) {
if (_confirmWithTextId && file->id == _confirmWithTextId) {
setFieldText(QString());
_confirmWithTextId = 0;
}
if (!file->originalText.isEmpty()) {
_field.textCursor().insertText(file->originalText);
}
}
void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, const MTPInputFile &file) {
if (!MTP::authedId()) return;
HistoryItem *item = App::histItemById(newId);

View File

@ -430,16 +430,19 @@ public:
void sendActionDone(const MTPBool &result, mtpRequestId req);
void destroyData();
void uploadImage(const QImage &img, bool withText = false, const QString &source = QString());
void uploadFile(const QString &file, bool withText = false); // with confirmation
void uploadImage(const QImage &img, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &source = QString(), bool withText = false);
void uploadFile(const QString &file, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, bool withText = false); // with confirmation
void shareContactConfirmation(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool withText = false);
void uploadConfirmImageUncompressed(bool ctrlShiftEnter, MsgId replyTo);
void uploadMedias(const QStringList &files, ToPrepareMediaType type);
void uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type, PeerId peer = 0);
void uploadMedias(const QStringList &files, PrepareMediaType type);
void uploadMedia(const QByteArray &fileContent, PrepareMediaType type, PeerId peer = 0);
void confirmShareContact(bool ctrlShiftEnter, const QString &phone, const QString &fname, const QString &lname, MsgId replyTo);
void confirmSendImage(const ReadyLocalMedia &img);
void cancelSendImage();
void confirmSendFile(const FileLoadResultPtr &file, bool ctrlShiftEnter);
void cancelSendFile(const FileLoadResultPtr &file);
void updateControlsVisibility();
void updateOnlineDisplay(int32 x, int32 w);
void updateOnlineDisplayTimer();
@ -767,6 +770,7 @@ private:
int32 _selCount; // < 0 - text selected, focus list, not _field
TaskQueue _fileLoader;
LocalImageLoader _imageLoader;
bool _synthedTextUpdate;
@ -776,6 +780,8 @@ private:
bool _confirmWithText;
QString _confirmSource;
uint64 _confirmWithTextId;
QString _titlePeerText;
int32 _titlePeerTextWidth;

View File

@ -138,6 +138,18 @@ void BackgroundWidget::replaceInner(LayeredWidget *n) {
update();
}
void BackgroundWidget::showLayerLast(LayeredWidget *n) {
_hidden.push_front(n);
n->setParent(this);
connect(n, SIGNAL(closed()), this, SLOT(onInnerClose()));
connect(n, SIGNAL(resized()), this, SLOT(update()));
connect(n, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
n->parentResized();
n->animStep(1);
n->hide();
update();
}
bool BackgroundWidget::animStep(float64 ms) {
float64 dt = ms / (hiding ? st::layerHideDuration : st::layerSlideDuration);
w->animStep(dt);

View File

@ -74,6 +74,7 @@ public:
void updateWideMode();
void replaceInner(LayeredWidget *n);
void showLayerLast(LayeredWidget *n);
bool animStep(float64 ms);

View File

@ -22,7 +22,12 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "localimageloader.h"
#include "gui/filedialog.h"
#include "audio.h"
#include <libexif/exif-data.h>
#include "boxes/photosendbox.h"
#include "mainwidget.h"
#include "window.h"
#include "lang.h"
#include "boxes/confirmbox.h"
LocalImageLoaderPrivate::LocalImageLoaderPrivate(LocalImageLoader *loader, QThread *thread) : QObject(0)
, loader(loader)
@ -42,7 +47,7 @@ void LocalImageLoaderPrivate::prepareImages() {
uint64 id, thumbId = 0;
int32 duration = 0;
QString thumbExt = "jpg";
ToPrepareMediaType type;
PrepareMediaType type;
bool animated = false;
bool broadcast = false;
bool ctrlShiftEnter = false;
@ -67,53 +72,53 @@ void LocalImageLoaderPrivate::prepareImages() {
if (img.isNull()) {
if (!file.isEmpty()) {
QFileInfo info(file);
if (type == ToPrepareAuto) {
if (type == PrepareAuto) {
QString lower(file.toLower());
const QStringList &photoExtensions(cPhotoExtensions());
for (QStringList::const_iterator i = photoExtensions.cbegin(), e = photoExtensions.cend(); i != e; ++i) {
if (lower.lastIndexOf(*i) == lower.size() - i->size()) {
if (info.size() < MaxUploadPhotoSize) {
type = ToPreparePhoto;
type = PreparePhoto;
break;
}
}
}
if (type == ToPrepareAuto && info.size() < MaxUploadDocumentSize) {
type = ToPrepareDocument;
if (type == PrepareAuto && info.size() < MaxUploadDocumentSize) {
type = PrepareDocument;
}
}
if (type != ToPrepareAuto && info.size() < MaxUploadPhotoSize) {
if (type != PrepareAuto && info.size() < MaxUploadPhotoSize) {
bool opaque = (mime != stickerMime);
img = App::readImage(file, 0, opaque, &animated);
if (animated) {
type = ToPrepareDocument;
type = PrepareDocument;
}
}
if (type == ToPrepareDocument) {
if (type == PrepareDocument) {
mime = mimeTypeForFile(info).name();
}
filename = info.fileName();
filesize = info.size();
} else if (!data.isEmpty()) {
if (type != ToPrepareAudio) {
if (type != PrepareAudio) {
img = App::readImage(data, 0, true, &animated);
if (type == ToPrepareAuto) {
if (type == PrepareAuto) {
if (!img.isNull() && data.size() < MaxUploadPhotoSize) {
type = ToPreparePhoto;
type = PreparePhoto;
} else if (data.size() < MaxUploadDocumentSize) {
type = ToPrepareDocument;
type = PrepareDocument;
} else {
img = QImage();
}
}
}
MimeType mimeType = mimeTypeForData(data);
if (type == ToPrepareDocument || type == ToPrepareAudio) {
if (type == PrepareDocument || type == PrepareAudio) {
mime = mimeType.name();
}
if (mime == "image/jpeg") {
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
} else if (type == ToPrepareAudio) {
} else if (type == PrepareAudio) {
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
mime = "audio/ogg";
} else {
@ -122,12 +127,12 @@ void LocalImageLoaderPrivate::prepareImages() {
if (!patterns.isEmpty()) {
ext = patterns.front().replace('*', QString());
}
filename = filedialogDefaultName((type == ToPrepareAudio) ? qsl("audio") : qsl("doc"), ext, QString(), true);
filename = filedialogDefaultName((type == PrepareAudio) ? qsl("audio") : qsl("doc"), ext, QString(), true);
}
filesize = data.size();
}
} else {
if (type == ToPrepareDocument) {
if (type == PrepareDocument) {
filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
mime = mimeTypeForName("image/png").name();
data = QByteArray();
@ -145,13 +150,13 @@ void LocalImageLoaderPrivate::prepareImages() {
}
img = solid;
}
type = ToPreparePhoto;
type = PreparePhoto;
filename = qsl("Untitled.jpg");
filesize = 0;
}
}
if ((img.isNull() && ((type != ToPrepareDocument && type != ToPrepareAudio) || !filesize)) || type == ToPrepareAuto || (img.isNull() && file.isEmpty() && data.isEmpty())) { // if could not decide what type
if ((img.isNull() && ((type != PrepareDocument && type != PrepareAudio) || !filesize)) || type == PrepareAuto || (img.isNull() && file.isEmpty() && data.isEmpty())) { // if could not decide what type
{
QMutexLocker lock(loader->toPrepareMutex());
ToPrepareMedias &list(loader->toPrepareMedias());
@ -174,7 +179,7 @@ void LocalImageLoaderPrivate::prepareImages() {
bool isSong = false;
QByteArray jpeg;
if (type == ToPrepareDocument) {
if (type == PrepareDocument) {
if (mime == qstr("audio/mp3") || mime == qstr("audio/m4a") || mime == qstr("audio/aac") || mime == qstr("audio/ogg") || mime == qstr("audio/flac") ||
filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
@ -207,7 +212,7 @@ void LocalImageLoaderPrivate::prepareImages() {
}
}
}
if (type == ToPreparePhoto) {
if (type == PreparePhoto) {
int32 w = img.width(), h = img.height();
QPixmap thumb = (w > 100 || h > 100) ? QPixmap::fromImage(img.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img);
@ -231,7 +236,7 @@ void LocalImageLoaderPrivate::prepareImages() {
photo = MTP_photo(MTP_long(id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));
thumbId = id;
} else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull() && !isSong) {
} else if ((type == PrepareVideo || type == PrepareDocument) && !img.isNull() && !isSong) {
int32 w = img.width(), h = img.height();
QByteArray thumbFormat = "JPG";
int32 thumbQuality = 87;
@ -258,9 +263,9 @@ void LocalImageLoaderPrivate::prepareImages() {
}
}
if (type == ToPrepareDocument) {
if (type == PrepareDocument) {
document = MTP_document(MTP_long(id), MTP_long(0), MTP_int(unixtime()), MTP_string(mime), MTP_int(filesize), thumb, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
} else if (type == ToPrepareAudio) {
} else if (type == PrepareAudio) {
audio = MTP_audio(MTP_long(id), MTP_long(0), MTP_int(unixtime()), MTP_int(duration), MTP_string(mime), MTP_int(filesize), MTP_int(MTP::maindc()));
}
@ -288,7 +293,7 @@ LocalImageLoaderPrivate::~LocalImageLoaderPrivate() {
LocalImageLoader::LocalImageLoader(QObject *parent) : QObject(parent), thread(0), priv(0) {
}
void LocalImageLoader::append(const QStringList &files, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t) {
void LocalImageLoader::append(const QStringList &files, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t) {
{
QMutexLocker lock(toPrepareMutex());
for (QStringList::const_iterator i = files.cbegin(), e = files.cend(); i != e; ++i) {
@ -303,7 +308,7 @@ void LocalImageLoader::append(const QStringList &files, const PeerId &peer, bool
emit needToPrepare();
}
PhotoId LocalImageLoader::append(const QByteArray &img, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t) {
PhotoId LocalImageLoader::append(const QByteArray &img, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t) {
PhotoId result = 0;
{
QMutexLocker lock(toPrepareMutex());
@ -319,7 +324,7 @@ PhotoId LocalImageLoader::append(const QByteArray &img, const PeerId &peer, bool
return result;
}
AudioId LocalImageLoader::append(const QByteArray &audio, int32 duration, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t) {
AudioId LocalImageLoader::append(const QByteArray &audio, int32 duration, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t) {
AudioId result = 0;
{
QMutexLocker lock(toPrepareMutex());
@ -335,7 +340,7 @@ AudioId LocalImageLoader::append(const QByteArray &audio, int32 duration, const
return result;
}
PhotoId LocalImageLoader::append(const QImage &img, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t, bool ctrlShiftEnter) {
PhotoId LocalImageLoader::append(const QImage &img, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t, bool ctrlShiftEnter) {
PhotoId result = 0;
{
QMutexLocker lock(toPrepareMutex());
@ -351,7 +356,7 @@ PhotoId LocalImageLoader::append(const QImage &img, const PeerId &peer, bool bro
return result;
}
PhotoId LocalImageLoader::append(const QString &file, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t) {
PhotoId LocalImageLoader::append(const QString &file, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t) {
PhotoId result = 0;
{
QMutexLocker lock(toPrepareMutex());
@ -416,7 +421,6 @@ LocalImageLoader::~LocalImageLoader() {
delete thread;
}
TaskQueue::TaskQueue(QObject *parent, int32 stopTimeoutMs) : QObject(parent), _thread(0), _worker(0), _stopTimer(0) {
if (stopTimeoutMs > 0) {
_stopTimer = new QTimer(this);
@ -534,3 +538,256 @@ void TaskQueueWorker::onTaskAdded() {
_inTaskAdded = false;
}
FileLoadTask::FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm) : _id(MTP::nonce<uint64>())
, _to(to)
, _filepath(filepath)
, _duration(0)
, _type(type)
, _confirm(confirm)
, _result(0) {
}
FileLoadTask::FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to) : _id(MTP::nonce<uint64>())
, _to(to)
, _content(content)
, _duration(0)
, _type(type)
, _confirm(FileLoadNoForceConfirm)
, _result(0) {
}
FileLoadTask::FileLoadTask(const QImage &image, const FileLoadTo &to, FileLoadForceConfirmType confirm, const QString &originalText) : _id(MTP::nonce<uint64>())
, _to(to)
, _image(image)
, _duration(0)
, _type(PrepareAuto)
, _confirm(confirm)
, _originalText(originalText)
, _result(0) {
}
FileLoadTask::FileLoadTask(const QByteArray &audio, int32 duration, const FileLoadTo &to) : _id(MTP::nonce<uint64>())
, _to(to)
, _content(audio)
, _duration(duration)
, _type(PrepareAudio)
, _confirm(FileLoadNoForceConfirm)
, _result(0) {
}
void FileLoadTask::process() {
const QString stickerMime = qsl("image/webp");
_result = FileLoadResultPtr(new FileLoadResult(_id, _to));
QString filename, filemime;
qint64 filesize = 0;
QByteArray filedata;
uint64 thumbId = 0;
QString thumbname = "thumb.jpg";
QByteArray thumbdata;
bool animated = false;
QImage fullimage = _image;
if (!_filepath.isEmpty()) {
QFileInfo info(_filepath);
filesize = info.size();
filemime = mimeTypeForFile(info).name();
filename = info.fileName();
if (filesize <= MaxUploadPhotoSize && _type != PrepareAudio) {
bool opaque = (filemime != stickerMime);
fullimage = App::readImage(_filepath, 0, opaque, &animated);
}
} else if (!_content.isEmpty()) {
filesize = _content.size();
MimeType mimeType = mimeTypeForData(_content);
filemime = mimeType.name();
if (filesize <= MaxUploadPhotoSize && _type != PrepareAudio) {
bool opaque = (filemime != stickerMime);
fullimage = App::readImage(_content, 0, opaque, &animated);
}
if (filemime == "image/jpeg") {
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
} else if (_type == PrepareAudio) {
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
filemime = "audio/ogg";
} else {
QString ext;
QStringList patterns = mimeType.globPatterns();
if (!patterns.isEmpty()) {
ext = patterns.front().replace('*', QString());
}
filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
}
} else if (!_image.isNull()) {
_image = QImage();
filemime = mimeTypeForName("image/png").name();
filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
{
QBuffer buffer(&_content);
fullimage.save(&buffer, "PNG");
}
filesize = _content.size();
if (fullimage.hasAlphaChannel()) {
QImage solid(fullimage.width(), fullimage.height(), QImage::Format_ARGB32_Premultiplied);
solid.fill(st::white->c);
{
QPainter(&solid).drawImage(0, 0, fullimage);
}
fullimage = solid;
}
}
_result->filesize = (int32)qMin(filesize, qint64(INT_MAX));
if (!filesize || filesize > MaxUploadDocumentSize) {
return;
}
PreparedPhotoThumbs photoThumbs;
QVector<MTPPhotoSize> photoSizes;
QPixmap thumb;
QVector<MTPDocumentAttribute> attributes(1, MTP_documentAttributeFilename(MTP_string(filename)));
MTPPhotoSize thumbSize(MTP_photoSizeEmpty(MTP_string("")));
MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
MTPDocument document(MTP_documentEmpty(MTP_long(0)));
MTPAudio audio(MTP_audioEmpty(MTP_long(0)));
bool song = false;
if (_type != PrepareAudio) {
if (filemime == qstr("audio/mp3") || filemime == qstr("audio/m4a") || filemime == qstr("audio/aac") || filemime == qstr("audio/ogg") || filemime == qstr("audio/flac") ||
filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
filename.endsWith(qstr(".flac"), Qt::CaseInsensitive)) {
QImage cover;
QByteArray coverBytes, coverFormat;
MTPDocumentAttribute audioAttribute = audioReadSongAttributes(_filepath, _content, cover, coverBytes, coverFormat);
if (audioAttribute.type() == mtpc_documentAttributeAudio) {
attributes.push_back(audioAttribute);
song = true;
if (!cover.isNull()) { // cover to thumb
int32 cw = cover.width(), ch = cover.height();
if (cw < 20 * ch && ch < 20 * cw) {
QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly);
{
QByteArray thumbFormat = "JPG";
int32 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 = MTP::nonce<uint64>();
}
}
}
}
}
if (!fullimage.isNull() && fullimage.width() > 0 && !song) {
int32 w = fullimage.width(), h = fullimage.height();
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
if (w < 20 * h && h < 20 * w) {
if (animated) {
attributes.push_back(MTP_documentAttributeAnimated());
} else {
QPixmap thumb = (w > 100 || h > 100) ? QPixmap::fromImage(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage);
photoThumbs.insert('s', thumb);
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
QPixmap medium = (w > 320 || h > 320) ? QPixmap::fromImage(fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage);
photoThumbs.insert('m', medium);
photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
QPixmap full = (w > 1280 || h > 1280) ? QPixmap::fromImage(fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage);
photoThumbs.insert('y', full);
photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));
{
QBuffer buffer(&filedata);
full.save(&buffer, "JPG", 77);
}
photo = MTP_photo(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));
}
QByteArray thumbFormat = "JPG";
int32 thumbQuality = 87;
if (!animated && filemime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
attributes.push_back(MTP_documentAttributeSticker(MTP_string(""), MTP_inputStickerSetEmpty()));
thumbFormat = "webp";
thumbname = qsl("thumb.webp");
}
QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(fullimage.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage, Qt::ColorOnly);
{
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 = MTP::nonce<uint64>();
}
}
if (_type == PrepareAudio) {
audio = MTP_audio(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_int(_duration), MTP_string(filemime), MTP_int(filesize), MTP_int(MTP::maindc()));
} else {
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
if (photo.type() == mtpc_photoEmpty) {
_type = PrepareDocument;
}
}
_result->type = _type;
_result->filepath = _filepath;
_result->content = _content;
_result->filename = filename;
_result->setFileData(filedata);
_result->thumbId = thumbId;
_result->thumbname = thumbname;
_result->setThumbData(thumbdata);
_result->thumb = thumb;
_result->photo = photo;
_result->audio = audio;
_result->document = document;
_result->photoThumbs = photoThumbs;
}
void FileLoadTask::finish() {
if (!_result || !_result->filesize) {
if (_result) App::main()->onSendFileCancel(_result);
App::wnd()->replaceLayer(new InformBox(lang(lng_send_image_empty)));
return;
}
if (_result->filesize > MaxUploadDocumentSize) {
App::main()->onSendFileCancel(_result);
App::wnd()->replaceLayer(new InformBox(lang(lng_send_image_too_large)));
return;
}
if (App::main()) {
bool confirm = (_confirm == FileLoadAlwaysConfirm) || (_result->photo.type() != mtpc_photoEmpty && _confirm != FileLoadNeverConfirm);
if (confirm) {
App::wnd()->showLayerLast(new PhotoSendBox(_result));
} else {
App::main()->onSendFileConfirm(_result, false);
}
}
}

View File

@ -20,29 +20,29 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
*/
#pragma once
enum ToPrepareMediaType {
ToPrepareAuto,
ToPreparePhoto,
ToPrepareAudio,
ToPrepareVideo,
ToPrepareDocument,
enum PrepareMediaType {
PrepareAuto,
PreparePhoto,
PrepareAudio,
PrepareVideo,
PrepareDocument,
};
struct ToPrepareMedia {
ToPrepareMedia(const QString &file, const PeerId &peer, ToPrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), file(file), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
ToPrepareMedia(const QString &file, const PeerId &peer, PrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), file(file), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
}
ToPrepareMedia(const QImage &img, const PeerId &peer, ToPrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), img(img), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
ToPrepareMedia(const QImage &img, const PeerId &peer, PrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), img(img), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
}
ToPrepareMedia(const QByteArray &data, const PeerId &peer, ToPrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), data(data), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
ToPrepareMedia(const QByteArray &data, const PeerId &peer, PrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), data(data), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
}
ToPrepareMedia(const QByteArray &data, int32 duration, const PeerId &peer, ToPrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), data(data), peer(peer), type(t), duration(duration), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
ToPrepareMedia(const QByteArray &data, int32 duration, const PeerId &peer, PrepareMediaType t, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) : id(MTP::nonce<PhotoId>()), data(data), peer(peer), type(t), duration(duration), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
}
PhotoId id;
QString file;
QImage img;
QByteArray data;
PeerId peer;
ToPrepareMediaType type;
PrepareMediaType type;
int32 duration;
bool broadcast;
bool ctrlShiftEnter;
@ -50,9 +50,9 @@ struct ToPrepareMedia {
};
typedef QList<ToPrepareMedia> ToPrepareMedias;
typedef QMap<int32, QByteArray> LocalFileParts;
typedef QMap<int32, QByteArray> UploadFileParts;
struct ReadyLocalMedia {
ReadyLocalMedia(ToPrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const MTPAudio &audio, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) :
ReadyLocalMedia(PrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const MTPAudio &audio, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) :
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), audio(audio), photoThumbs(photoThumbs), broadcast(broadcast), ctrlShiftEnter(ctrlShiftEnter) {
if (!jpeg.isEmpty()) {
int32 size = jpeg.size();
@ -64,7 +64,7 @@ struct ReadyLocalMedia {
}
}
MsgId replyTo;
ToPrepareMediaType type;
PrepareMediaType type;
QString file, filename;
int32 filesize;
QByteArray data;
@ -76,12 +76,15 @@ struct ReadyLocalMedia {
MTPDocument document;
MTPAudio audio;
PreparedPhotoThumbs photoThumbs;
LocalFileParts parts;
UploadFileParts parts;
QByteArray jpeg_md5;
bool broadcast;
bool ctrlShiftEnter;
QString caption;
ReadyLocalMedia() : type(PrepareAuto) { // temp
}
};
typedef QList<ReadyLocalMedia> ReadyLocalMedias;
@ -115,11 +118,11 @@ class LocalImageLoader : public QObject {
public:
LocalImageLoader(QObject *parent);
void append(const QStringList &files, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t);
PhotoId append(const QByteArray &img, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t);
AudioId append(const QByteArray &audio, int32 duration, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t);
PhotoId append(const QImage &img, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t, bool ctrlShiftEnter = false);
PhotoId append(const QString &file, const PeerId &peer, bool broadcast, MsgId replyTo, ToPrepareMediaType t);
void append(const QStringList &files, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t);
PhotoId append(const QByteArray &img, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t);
AudioId append(const QByteArray &audio, int32 duration, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t);
PhotoId append(const QImage &img, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t, bool ctrlShiftEnter = false);
PhotoId append(const QString &file, const PeerId &peer, bool broadcast, MsgId replyTo, PrepareMediaType t);
QMutex *readyMutex();
ReadyLocalMedias &readyList();
@ -176,8 +179,7 @@ public:
TaskId addTask(TaskPtr task);
void cancelTask(TaskId id); // this task finish() won't be called
template <typename DerivedTask>
TaskId addTask(DerivedTask *task) {
TaskId addTask(Task *task) {
return addTask(TaskPtr(task));
}
@ -226,3 +228,101 @@ private:
bool _inTaskAdded;
};
struct FileLoadTo {
FileLoadTo(const PeerId &peer, bool broadcast, MsgId replyTo) : peer(peer), broadcast(broadcast), replyTo(replyTo) {
}
PeerId peer;
bool broadcast;
MsgId replyTo;
};
struct FileLoadResult {
FileLoadResult(const uint64 &id, const FileLoadTo &to) : id(id), to(to), type(PrepareAuto), thumbId(0), filesize(0) {
}
uint64 id;
FileLoadTo to;
PrepareMediaType type;
QString filepath;
QByteArray content;
QString filename;
int32 filesize;
UploadFileParts fileparts;
QByteArray filemd5;
uint64 thumbId; // id is always file-id of media, thumbId is file-id of thumb ( == id for photos)
QString thumbname;
UploadFileParts thumbparts;
QByteArray thumbmd5;
QPixmap thumb;
MTPPhoto photo;
MTPAudio audio;
MTPDocument document;
PreparedPhotoThumbs photoThumbs;
QString photoCaption;
QString originalText; // when pasted had an image mime save text mime here to insert if image send was cancelled
void setFileData(const QByteArray &filedata) {
if (!filedata.isEmpty()) {
int32 size = filedata.size();
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
fileparts.insert(part, filedata.mid(i, UploadPartSize));
}
filemd5.resize(32);
hashMd5Hex(filedata.constData(), filedata.size(), filemd5.data());
}
}
void setThumbData(const QByteArray &thumbdata) {
if (!thumbdata.isEmpty()) {
int32 size = thumbdata.size();
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
thumbparts.insert(part, thumbdata.mid(i, UploadPartSize));
}
thumbmd5.resize(32);
hashMd5Hex(thumbdata.constData(), thumbdata.size(), thumbmd5.data());
}
}
};
typedef QSharedPointer<FileLoadResult> FileLoadResultPtr;
enum FileLoadForceConfirmType {
FileLoadNoForceConfirm,
FileLoadNeverConfirm,
FileLoadAlwaysConfirm,
};
class FileLoadTask : public Task {
public:
FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm);
FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to);
FileLoadTask(const QImage &image, const FileLoadTo &to, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &originalText = QString());
FileLoadTask(const QByteArray &audio, int32 duration, const FileLoadTo &to);
uint64 fileid() const {
return _id;
}
void process();
void finish();
protected:
uint64 _id;
FileLoadTo _to;
QString _filepath;
QImage _image;
QByteArray _content;
int32 _duration;
PrepareMediaType _type;
FileLoadForceConfirmType _confirm;
QString _originalText;
FileLoadResultPtr _result;
};

View File

@ -1828,7 +1828,7 @@ namespace Local {
if (!_started) {
_started = true;
_manager = new _local_inner::Manager();
_localLoader = new TaskQueue(0, 5000);
_localLoader = new TaskQueue(0, FileLoaderQueueStopTimeout);
}
}

View File

@ -1108,7 +1108,7 @@ void MainWidget::onResendAsDocument() {
photo->full->forget();
QByteArray data = photo->full->savedData();
if (!data.isEmpty()) {
history.uploadMedia(data, ToPrepareDocument, item->history()->peer->id);
history.uploadMedia(data, PrepareDocument, item->history()->peer->id);
}
}
}
@ -2046,6 +2046,16 @@ void MainWidget::updateOnlineDisplay() {
if (App::wnd()->settingsWidget()) App::wnd()->settingsWidget()->updateOnlineDisplay();
}
void MainWidget::onSendFileConfirm(const FileLoadResultPtr &file, bool ctrlShiftEnter) {
bool lastKeyboardUsed = history.lastForceReplyReplied(FullMsgId(peerToChannel(file->to.peer), file->to.replyTo));
history.confirmSendFile(file, ctrlShiftEnter);
history.cancelReply(lastKeyboardUsed);
}
void MainWidget::onSendFileCancel(const FileLoadResultPtr &file) {
history.cancelSendFile(file);
}
void MainWidget::confirmShareContact(bool ctrlShiftEnter, const QString &phone, const QString &fname, const QString &lname, MsgId replyTo) {
history.confirmShareContact(ctrlShiftEnter, phone, fname, lname, replyTo);
}

View File

@ -265,6 +265,9 @@ public:
void orderWidgets();
QRect historyRect() const;
void onSendFileConfirm(const FileLoadResultPtr &file, bool ctrlShiftEnter);
void onSendFileCancel(const FileLoadResultPtr &file);
void confirmShareContact(bool ctrlShiftEnter, const QString &phone, const QString &fname, const QString &lname, MsgId replyTo);
void confirmSendImage(const ReadyLocalMedia &img);
void confirmSendImageUncompressed(bool ctrlShiftEnter, MsgId replyTo);

View File

@ -810,6 +810,14 @@ void Window::replaceLayer(LayeredWidget *w) {
}
}
void Window::showLayerLast(LayeredWidget *w) {
if (layerBg) {
layerBg->showLayerLast(w);
} else {
layerBg = new BackgroundWidget(this, w);
}
}
void Window::showConnecting(const QString &text, const QString &reconnect) {
if (_connecting) {
_connecting->set(text, reconnect);

View File

@ -181,8 +181,11 @@ public:
void showPhoto(PhotoData *photo, HistoryItem *item);
void showPhoto(PhotoData *photo, PeerData *item);
void showDocument(DocumentData *doc, HistoryItem *item);
void showLayer(LayeredWidget *w, bool forceFast = false);
void replaceLayer(LayeredWidget *w);
void showLayerLast(LayeredWidget *w);
void hideLayer(bool fast = false);
bool hideInnerLayer();