From ff65daa9feefc84d3697ee7e267f89a75e5e4849 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 21 Dec 2017 20:15:37 +0400 Subject: [PATCH] Remove special case in SendFilesBox for an image. --- Telegram/SourceFiles/apiwrap.cpp | 30 ++-- Telegram/SourceFiles/apiwrap.h | 2 - Telegram/SourceFiles/app.cpp | 42 ++--- Telegram/SourceFiles/boxes/abstract_box.cpp | 1 - Telegram/SourceFiles/boxes/send_files_box.cpp | 150 ++++++++---------- Telegram/SourceFiles/boxes/send_files_box.h | 34 ++-- Telegram/SourceFiles/core/file_utilities.cpp | 89 ++++++++--- Telegram/SourceFiles/core/file_utilities.h | 51 +++++- .../SourceFiles/history/history_widget.cpp | 112 ++++--------- Telegram/SourceFiles/history/history_widget.h | 33 ++-- .../SourceFiles/storage/localimageloader.cpp | 34 ++-- .../SourceFiles/storage/localimageloader.h | 28 ++-- .../storage/storage_media_prepare.cpp | 53 +++++-- .../storage/storage_media_prepare.h | 7 +- 14 files changed, 367 insertions(+), 299 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 5847501237..3fb18c170c 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2729,8 +2729,6 @@ void ApiWrap::sendVoiceMessage( void ApiWrap::sendFiles( Storage::PreparedList &&list, - const QByteArray &content, - const QImage &image, SendMediaType type, QString caption, std::shared_ptr album, @@ -2759,23 +2757,14 @@ void ApiWrap::sendFiles( default: Unexpected("AlbumType in uploadFilesAfterConfirmation"); } } - if (file.path.isEmpty() && (!image.isNull() || !content.isNull())) { - tasks.push_back(std::make_unique( - content, - image, - type, - to, - caption, - album)); - } else { - tasks.push_back(std::make_unique( - file.path, - std::move(file.information), - type, - to, - caption, - album)); - } + tasks.push_back(std::make_unique( + file.path, + file.content, + std::move(file.information), + type, + to, + caption, + album)); } if (album) { _sendingAlbums.emplace(album->groupId, album); @@ -2794,8 +2783,9 @@ void ApiWrap::sendFile( auto to = FileLoadTaskOptions(options); auto caption = QString(); _fileLoader->addTask(std::make_unique( + QString(), fileContent, - QImage(), + nullptr, type, to, caption)); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 9b035cea78..b5c1df1b94 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -197,8 +197,6 @@ public: const SendOptions &options); void sendFiles( Storage::PreparedList &&list, - const QByteArray &content, - const QImage &image, SendMediaType type, QString caption, std::shared_ptr album, diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 6f8fadea5e..9d39b63339 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2508,19 +2508,26 @@ namespace { #endif // !TDESKTOP_DISABLE_NETWORK_PROXY } - void complexAdjustRect(RectParts corners, QRect &rect, RectParts &parts) { - if (corners & RectPart::TopLeft) { - if (!(corners & RectPart::BottomLeft)) { - parts = RectPart::NoTopBottom | RectPart::FullTop; - rect.setHeight(rect.height() + msgRadius()); + void rectWithCorners(Painter &p, QRect rect, const style::color &bg, RoundCorners index, RectParts corners) { + auto parts = RectPart::Top + | RectPart::NoTopBottom + | RectPart::Bottom + | corners; + roundRect(p, rect, bg, index, nullptr, parts); + if ((corners & RectPart::AllCorners) != RectPart::AllCorners) { + const auto size = ::corners[index].p[0].width() / cIntRetinaFactor(); + if (!(corners & RectPart::TopLeft)) { + p.fillRect(rect.x(), rect.y(), size, size, bg); + } + if (!(corners & RectPart::TopRight)) { + p.fillRect(rect.x() + rect.width() - size, rect.y(), size, size, bg); + } + if (!(corners & RectPart::BottomLeft)) { + p.fillRect(rect.x(), rect.y() + rect.height() - size, size, size, bg); + } + if (!(corners & RectPart::BottomRight)) { + p.fillRect(rect.x() + rect.width() - size, rect.y() + rect.height() - size, size, size, bg); } - } else if (corners & RectPart::BottomLeft) { - parts = RectPart::NoTopBottom | RectPart::FullBottom; - rect.setTop(rect.y() - msgRadius()); - } else { - parts = RectPart::NoTopBottom; - rect.setTop(rect.y() - msgRadius()); - rect.setHeight(rect.height() + msgRadius()); } } @@ -2534,18 +2541,13 @@ namespace { auto overlayCorners = (radius == ImageRoundRadius::Small) ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners; - auto overlayParts = RectPart::Full | RectPart::None; - if (radius == ImageRoundRadius::Large) { - complexAdjustRect(corners, rect, overlayParts); - } - roundRect(p, rect, p.textPalette().selectOverlay, overlayCorners, nullptr, overlayParts); + const auto bg = p.textPalette().selectOverlay; + rectWithCorners(p, rect, bg, overlayCorners, corners); } } void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners) { - auto parts = RectPart::Full | RectPart::None; - complexAdjustRect(corners, rect, parts); - roundRect(p, rect, st::msgInBg, MessageInCorners, nullptr, parts); + rectWithCorners(p, rect, st::msgInBg, MessageInCorners, corners); } QImage *cornersMask(ImageRoundRadius radius) { diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp index 33b3032668..0bdfed9c77 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.cpp +++ b/Telegram/SourceFiles/boxes/abstract_box.cpp @@ -250,7 +250,6 @@ void AbstractBox::paintEvent(QPaintEvent *e) { auto paintBottomRounded = clip.intersects(QRect(0, height() - st::boxRadius, width(), st::boxRadius)); if (paintTopRounded || paintBottomRounded) { auto parts = RectPart::None | 0; - parts |= RectPart::None; if (paintTopRounded) parts |= RectPart::FullTop; if (paintBottomRounded) parts |= RectPart::FullBottom; App::roundRect(p, rect(), st::boxBg, BoxCorners, nullptr, parts); diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index b533224afd..6972ed09de 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -29,7 +29,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" -#include "ui/empty_userpic.h" #include "ui/grouped_layout.h" #include "styles/style_history.h" #include "styles/style_boxes.h" @@ -42,15 +41,10 @@ constexpr auto kMinPreviewWidth = 20; } // namespace -SendFilesBox::SendFilesBox(QWidget*, QImage image, CompressConfirm compressed) -: _image(image) -, _compressConfirm(compressed) -, _caption(this, st::confirmCaptionArea, langFactory(lng_photo_caption)) { - _list.files.push_back({ QString() }); - prepareSingleFileLayout(); -} - -SendFilesBox::SendFilesBox(QWidget*, Storage::PreparedList &&list, CompressConfirm compressed) +SendFilesBox::SendFilesBox( + QWidget*, + Storage::PreparedList &&list, + CompressConfirm compressed) : _list(std::move(list)) , _compressConfirm(compressed) , _caption( @@ -66,34 +60,54 @@ SendFilesBox::SendFilesBox(QWidget*, Storage::PreparedList &&list, CompressConfi void SendFilesBox::prepareSingleFileLayout() { Expects(_list.files.size() == 1); - if (!_list.files.front().path.isEmpty()) { - tryToReadSingleFile(); + + const auto &file = _list.files[0]; + auto preview = QImage(); + if (const auto image = base::get_if( + &file.information->media)) { + preview = image->data; + _animated = image->animated; + } else if (const auto video = base::get_if( + &file.information->media)) { + preview = video->thumbnail; + _animated = true; } - if (!Storage::ValidateThumbDimensions(_image.width(), _image.height()) + if (!Storage::ValidateThumbDimensions(preview.width(), preview.height()) || _animated) { _compressConfirm = CompressConfirm::None; } - if (!_image.isNull()) { - auto image = _image; + if (!preview.isNull()) { if (!_animated && _compressConfirm == CompressConfirm::None) { - auto originalWidth = image.width(); - auto originalHeight = image.height(); + auto originalWidth = preview.width(); + auto originalHeight = preview.height(); auto thumbWidth = st::msgFileThumbSize; if (originalWidth > originalHeight) { - thumbWidth = (originalWidth * st::msgFileThumbSize) / originalHeight; + thumbWidth = (originalWidth * st::msgFileThumbSize) + / originalHeight; } - auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | Images::Option::RoundedBottomRight; - _fileThumb = Images::pixmap(image, thumbWidth * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize); + auto options = Images::Option::Smooth + | Images::Option::RoundedSmall + | Images::Option::RoundedTopLeft + | Images::Option::RoundedTopRight + | Images::Option::RoundedBottomLeft + | Images::Option::RoundedBottomRight; + _fileThumb = Images::pixmap( + preview, + thumbWidth * cIntRetinaFactor(), + 0, + options, + st::msgFileThumbSize, + st::msgFileThumbSize); } else { auto maxW = 0; auto maxH = 0; if (_animated) { auto limitW = st::sendMediaPreviewSize; auto limitH = st::confirmMaxHeight; - maxW = qMax(image.width(), 1); - maxH = qMax(image.height(), 1); + maxW = qMax(preview.width(), 1); + maxH = qMax(preview.height(), 1); if (maxW * limitH > maxH * limitW) { if (maxW < limitW) { maxH = maxH * limitW / maxW; @@ -105,16 +119,22 @@ void SendFilesBox::prepareSingleFileLayout() { maxH = limitH; } } - image = Images::prepare(image, maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth | Images::Option::Blurred, maxW, maxH); + preview = Images::prepare( + preview, + maxW * cIntRetinaFactor(), + maxH * cIntRetinaFactor(), + Images::Option::Smooth | Images::Option::Blurred, + maxW, + maxH); } - auto originalWidth = image.width(); - auto originalHeight = image.height(); + auto originalWidth = preview.width(); + auto originalHeight = preview.height(); if (!originalWidth || !originalHeight) { originalWidth = originalHeight = 1; } _previewWidth = st::sendMediaPreviewSize; - if (image.width() < _previewWidth) { - _previewWidth = qMax(image.width(), kMinPreviewWidth); + if (preview.width() < _previewWidth) { + _previewWidth = qMax(preview.width(), kMinPreviewWidth); } auto maxthumbh = qMin(qRound(1.5 * _previewWidth), st::confirmMaxHeight); _previewHeight = qRound(originalHeight * float64(_previewWidth) / originalWidth); @@ -125,9 +145,13 @@ void SendFilesBox::prepareSingleFileLayout() { } _previewLeft = (st::boxWideWidth - _previewWidth) / 2; - image = std::move(image).scaled(_previewWidth * cIntRetinaFactor(), _previewHeight * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - image = Images::prepareOpaque(std::move(image)); - _preview = App::pixmapFromImageInPlace(std::move(image)); + preview = std::move(preview).scaled( + _previewWidth * cIntRetinaFactor(), + _previewHeight * cIntRetinaFactor(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + preview = Images::prepareOpaque(std::move(preview)); + _preview = App::pixmapFromImageInPlace(std::move(preview)); _preview.setDevicePixelRatio(cRetinaFactor()); prepareGifPreview(); @@ -191,9 +215,12 @@ void SendFilesBox::prepareDocumentLayout() { const auto &file = _list.files.front(); const auto filepath = file.path; if (filepath.isEmpty()) { + const auto data = base::get_if( + &file.information->media); + const auto image = data ? data->data : QImage(); 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()); + _statusText = qsl("%1x%2").arg(image.width()).arg(image.height()); _statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText)); _fileIsImage = true; } else { @@ -227,40 +254,6 @@ void SendFilesBox::prepareDocumentLayout() { } } -void SendFilesBox::tryToReadSingleFile() { - auto &file = _list.files.front(); - auto filepath = file.path; - auto filemime = mimeTypeForFile(QFileInfo(filepath)).name(); - if (!file.information) { - file.information = FileLoadTask::ReadMediaInformation( - filepath, - QByteArray(), - filemime); - } - if (const auto image = base::get_if( - &file.information->media)) { - _image = image->data; - _animated = image->animated; - } else if (const auto video = base::get_if( - &file.information->media)) { - _image = video->thumbnail; - _animated = true; - } -} - -SendFilesBox::SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname) -: _contactPhone(phone) -, _contactFirstName(firstname) -, _contactLastName(lastname) { - auto name = lng_full_name(lt_first_name, _contactFirstName, lt_last_name, _contactLastName); - _nameText.setText(st::semiboldTextStyle, name, _textNameOptions); - _statusText = _contactPhone; - _statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText)); - _contactPhotoEmpty = std::make_unique( - Data::PeerUserpicColor(0), - name); -} - void SendFilesBox::prepare() { Expects(controller() != nullptr); @@ -304,9 +297,7 @@ void SendFilesBox::prepare() { } base::lambda SendFilesBox::getSendButtonText() const { - if (!_contactPhone.isEmpty()) { - return langFactory(lng_send_button); - } else if (_compressed && _compressed->checked()) { + if (_compressed && _compressed->checked()) { return [count = _list.files.size()] { return lng_send_photos(lt_count, count); }; @@ -429,21 +420,17 @@ void SendFilesBox::paintEvent(QPaintEvent *e) { App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow); if (_fileThumb.isNull()) { - if (_contactPhone.isNull()) { - QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width())); - p.setPen(Qt::NoPen); - p.setBrush(st::msgFileOutBg); + QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width())); + p.setPen(Qt::NoPen); + p.setBrush(st::msgFileOutBg); - { - PainterHighQualityEnabler hq(p); - p.drawEllipse(inner); - } - - auto &icon = _fileIsAudio ? st::historyFileOutPlay : _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument; - icon.paintInCenter(p, inner); - } else { - _contactPhotoEmpty->paint(p, x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), st::msgFileSize); + { + PainterHighQualityEnabler hq(p); + p.drawEllipse(inner); } + + auto &icon = _fileIsAudio ? st::historyFileOutPlay : _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument; + icon.paintInCenter(p, inner); } else { QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width())); p.drawPixmap(rthumb.topLeft(), _fileThumb); @@ -496,7 +483,6 @@ void SendFilesBox::send(bool ctrlShiftEnter) { auto caption = _caption ? TextUtilities::PrepareForSending(_caption->getLastText(), TextUtilities::PrepareTextOption::CheckLinks) : QString(); _confirmedCallback( std::move(_list), - _animated ? QImage() : _image, compressed, caption, ctrlShiftEnter); diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index be762c72de..a432786b6f 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -28,17 +28,22 @@ namespace Ui { class Checkbox; class RoundButton; class InputArea; -class EmptyUserpic; struct GroupMediaLayout; } // namespace Ui class SendFilesBox : public BoxContent { public: - SendFilesBox(QWidget*, QImage image, CompressConfirm compressed); - SendFilesBox(QWidget*, Storage::PreparedList &&list, CompressConfirm compressed); - SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname); + SendFilesBox( + QWidget*, + Storage::PreparedList &&list, + CompressConfirm compressed); - void setConfirmedCallback(base::lambda callback) { + void setConfirmedCallback( + base::lambda callback) { _confirmedCallback = std::move(callback); } void setCancelledCallback(base::lambda callback) { @@ -58,7 +63,6 @@ protected: private: void prepareSingleFileLayout(); void prepareDocumentLayout(); - void tryToReadSingleFile(); void prepareGifPreview(); void clipCallback(Media::Clip::Notification notification); @@ -73,7 +77,6 @@ private: QString _titleText; Storage::PreparedList _list; - QImage _image; CompressConfirm _compressConfirm = CompressConfirm::None; bool _animated = false; @@ -91,12 +94,11 @@ private: QString _statusText; int _statusWidth = 0; - QString _contactPhone; - QString _contactFirstName; - QString _contactLastName; - std::unique_ptr _contactPhotoEmpty; - - base::lambda _confirmedCallback; + base::lambda _confirmedCallback; base::lambda _cancelledCallback; bool _confirmed = false; @@ -111,7 +113,11 @@ class SendAlbumBox : public BoxContent { public: SendAlbumBox(QWidget*, Storage::PreparedList &&list); - void setConfirmedCallback(base::lambda callback) { + void setConfirmedCallback( + base::lambda callback) { _confirmedCallback = std::move(callback); } void setCancelledCallback(base::lambda callback) { diff --git a/Telegram/SourceFiles/core/file_utilities.cpp b/Telegram/SourceFiles/core/file_utilities.cpp index 0045d449cc..cc622560c9 100644 --- a/Telegram/SourceFiles/core/file_utilities.cpp +++ b/Telegram/SourceFiles/core/file_utilities.cpp @@ -26,7 +26,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "base/task_queue.h" #include "messenger.h" -bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &initialPath) { +bool filedialogGetSaveFile( + QString &file, + const QString &caption, + const QString &filter, + const QString &initialPath) { QStringList files; QByteArray remoteContent; bool result = Platform::FileDialog::Get(files, remoteContent, caption, filter, FileDialog::internal::Type::WriteFile, initialPath); @@ -34,7 +38,12 @@ bool filedialogGetSaveFile(QString &file, const QString &caption, const QString return result; } -QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path, bool skipExistance, int fileTime) { +QString filedialogDefaultName( + const QString &prefix, + const QString &extension, + const QString &path, + bool skipExistance, + int fileTime) { auto directoryPath = path; if (directoryPath.isEmpty()) { if (cDialogLastPath().isEmpty()) { @@ -69,7 +78,10 @@ QString filedialogDefaultName(const QString &prefix, const QString &extension, c return name; } -QString filedialogNextFilename(const QString &name, const QString &cur, const QString &path) { +QString filedialogNextFilename( + const QString &name, + const QString &cur, + const QString &path) { QDir dir(path.isEmpty() ? cDialogLastPath() : path); int32 extIndex = name.lastIndexOf('.'); QString prefix = name, extension; @@ -130,19 +142,30 @@ void UnsafeLaunchDefault(const QString &filepath) { namespace FileDialog { -void GetOpenPath(const QString &caption, const QString &filter, base::lambda callback, base::lambda failed) { - base::TaskQueue::Main().Put([caption, filter, callback = std::move(callback), failed = std::move(failed)] { +void GetOpenPath( + const QString &caption, + const QString &filter, + base::lambda callback, + base::lambda failed) { + base::TaskQueue::Main().Put([=] { auto files = QStringList(); auto remoteContent = QByteArray(); - if (Platform::FileDialog::Get(files, remoteContent, caption, filter, FileDialog::internal::Type::ReadFile) - && ((!files.isEmpty() && !files[0].isEmpty()) || !remoteContent.isEmpty())) { + const auto success = Platform::FileDialog::Get( + files, + remoteContent, + caption, + filter, + FileDialog::internal::Type::ReadFile); + if (success + && ((!files.isEmpty() && !files[0].isEmpty()) + || !remoteContent.isEmpty())) { if (callback) { auto result = OpenResult(); if (!files.isEmpty() && !files[0].isEmpty()) { result.paths.push_back(files[0]); } result.remoteContent = remoteContent; - callback(result); + callback(std::move(result)); } } else if (failed) { failed(); @@ -150,17 +173,26 @@ void GetOpenPath(const QString &caption, const QString &filter, base::lambda callback, base::lambda failed) { - base::TaskQueue::Main().Put([caption, filter, callback = std::move(callback), failed = std::move(failed)] { +void GetOpenPaths( + const QString &caption, + const QString &filter, + base::lambda callback, + base::lambda failed) { + base::TaskQueue::Main().Put([=] { auto files = QStringList(); auto remoteContent = QByteArray(); - if (Platform::FileDialog::Get(files, remoteContent, caption, filter, FileDialog::internal::Type::ReadFiles) - && (!files.isEmpty() || !remoteContent.isEmpty())) { + const auto success = Platform::FileDialog::Get( + files, + remoteContent, + caption, + filter, + FileDialog::internal::Type::ReadFiles); + if (success && (!files.isEmpty() || !remoteContent.isEmpty())) { if (callback) { auto result = OpenResult(); result.paths = files; result.remoteContent = remoteContent; - callback(result); + callback(std::move(result)); } } else if (failed) { failed(); @@ -168,12 +200,17 @@ void GetOpenPaths(const QString &caption, const QString &filter, base::lambda callback, base::lambda failed) { - base::TaskQueue::Main().Put([caption, filter, initialPath, callback = std::move(callback), failed = std::move(failed)] { +void GetWritePath( + const QString &caption, + const QString &filter, + const QString &initialPath, + base::lambda callback, + base::lambda failed) { + base::TaskQueue::Main().Put([=] { auto file = QString(); if (filedialogGetSaveFile(file, caption, filter, initialPath)) { if (callback) { - callback(file); + callback(std::move(file)); } } else if (failed) { failed(); @@ -181,14 +218,24 @@ void GetWritePath(const QString &caption, const QString &filter, const QString & }); } -void GetFolder(const QString &caption, const QString &initialPath, base::lambda callback, base::lambda failed) { - base::TaskQueue::Main().Put([caption, initialPath, callback = std::move(callback), failed = std::move(failed)] { +void GetFolder( + const QString &caption, + const QString &initialPath, + base::lambda callback, + base::lambda failed) { + base::TaskQueue::Main().Put([=] { auto files = QStringList(); auto remoteContent = QByteArray(); - if (Platform::FileDialog::Get(files, remoteContent, caption, QString(), FileDialog::internal::Type::ReadFolder, initialPath) - && !files.isEmpty() && !files[0].isEmpty()) { + const auto success = Platform::FileDialog::Get( + files, + remoteContent, + caption, + QString(), + FileDialog::internal::Type::ReadFolder, + initialPath); + if (success && !files.isEmpty() && !files[0].isEmpty()) { if (callback) { - callback(files[0]); + callback(std::move(files[0])); } } else if (failed) { failed(); diff --git a/Telegram/SourceFiles/core/file_utilities.h b/Telegram/SourceFiles/core/file_utilities.h index 922021f3de..f5a37472f4 100644 --- a/Telegram/SourceFiles/core/file_utilities.h +++ b/Telegram/SourceFiles/core/file_utilities.h @@ -23,10 +23,22 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "base/observer.h" // legacy -bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &initialPath); +bool filedialogGetSaveFile( + QString &file, + const QString &caption, + const QString &filter, + const QString &initialPath); -QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path = QString(), bool skipExistance = false, int fileTime = 0); -QString filedialogNextFilename(const QString &name, const QString &cur, const QString &path = QString()); +QString filedialogDefaultName( + const QString &prefix, + const QString &extension, + const QString &path = QString(), + bool skipExistance = false, + int fileTime = 0); +QString filedialogNextFilename( + const QString &name, + const QString &cur, + const QString &path = QString()); namespace File { @@ -54,10 +66,27 @@ struct OpenResult { QStringList paths; QByteArray remoteContent; }; -void GetOpenPath(const QString &caption, const QString &filter, base::lambda callback, base::lambda failed = base::lambda()); -void GetOpenPaths(const QString &caption, const QString &filter, base::lambda callback, base::lambda failed = base::lambda()); -void GetWritePath(const QString &caption, const QString &filter, const QString &initialPath, base::lambda callback, base::lambda failed = base::lambda()); -void GetFolder(const QString &caption, const QString &initialPath, base::lambda callback, base::lambda failed = base::lambda()); +void GetOpenPath( + const QString &caption, + const QString &filter, + base::lambda callback, + base::lambda failed = base::lambda()); +void GetOpenPaths( + const QString &caption, + const QString &filter, + base::lambda callback, + base::lambda failed = base::lambda()); +void GetWritePath( + const QString &caption, + const QString &filter, + const QString &initialPath, + base::lambda callback, + base::lambda failed = base::lambda()); +void GetFolder( + const QString &caption, + const QString &initialPath, + base::lambda callback, + base::lambda failed = base::lambda()); QString AllFilesFilter(); @@ -72,7 +101,13 @@ enum class Type { void InitLastPathDefault(); -bool GetDefault(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile); +bool GetDefault( + QStringList &files, + QByteArray &remoteContent, + const QString &caption, + const QString &filter, + ::FileDialog::internal::Type type, + QString startFile); } // namespace internal } // namespace FileDialog diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 62cee01d06..b1df1fdbe5 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -498,7 +498,10 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont connect(_fieldAutocomplete, SIGNAL(moderateKeyActivate(int,bool*)), this, SLOT(onModerateKeyActivate(int,bool*))); _field->installEventFilter(_fieldAutocomplete); _field->setInsertFromMimeDataHook([this](const QMimeData *data) { - return confirmSendingFiles(data, CompressConfirm::Auto, data->text()); + return confirmSendingFiles( + data, + CompressConfirm::Auto, + data->text()); }); _emojiSuggestions.create(this, _field.data()); updateFieldSubmitSettings(); @@ -3094,18 +3097,22 @@ void HistoryWidget::chooseAttach() { auto filter = FileDialog::AllFilesFilter() + qsl(";;Image files (*") + cImgExtensions().join(qsl(" *")) + qsl(")"); - FileDialog::GetOpenPaths(lang(lng_choose_files), filter, base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) { + FileDialog::GetOpenPaths(lang(lng_choose_files), filter, base::lambda_guarded(this, [this](FileDialog::OpenResult &&result) { if (result.paths.isEmpty() && result.remoteContent.isEmpty()) { return; } if (!result.remoteContent.isEmpty()) { auto animated = false; - auto image = App::readImage(result.remoteContent, nullptr, false, &animated); + auto image = App::readImage( + result.remoteContent, + nullptr, + false, + &animated); if (!image.isNull() && !animated) { confirmSendingFiles( - image, - result.remoteContent, + std::move(image), + std::move(result.remoteContent), CompressConfirm::Auto); } else { uploadFile(result.remoteContent, SendMediaType::File); @@ -3936,42 +3943,27 @@ template bool HistoryWidget::showSendFilesBox( object_ptr box, const QString &insertTextOnCancel, - const QString *addedComment, SendCallback callback) { App::wnd()->activateWindow(); - auto withComment = (addedComment != nullptr); const auto confirmedCallback = [=, sendCallback = std::move(callback)]( Storage::PreparedList &&list, - const QImage &image, bool compressed, const QString &caption, bool ctrlShiftEnter) { if (!canWriteMessage()) return; - const auto replyTo = replyToId(); - if (withComment) { - // This call will clear replyToId(). - onSend(ctrlShiftEnter); - } sendCallback( std::move(list), - image, compressed, caption, - replyTo); + replyToId()); }; box->setConfirmedCallback( base::lambda_guarded(this, std::move(confirmedCallback))); - if (withComment) { - auto was = _field->getTextWithTags(); - setFieldText({ *addedComment, TextWithTags::Tags() }); - box->setCancelledCallback(base::lambda_guarded(this, [this, was] { - setFieldText(was); - })); - } else if (!insertTextOnCancel.isEmpty()) { - box->setCancelledCallback(base::lambda_guarded(this, [this, insertTextOnCancel] { + if (!insertTextOnCancel.isEmpty()) { + box->setCancelledCallback(base::lambda_guarded(this, [=] { _field->textCursor().insertText(insertTextOnCancel); })); } @@ -4013,37 +4005,32 @@ bool HistoryWidget::showSendingFilesError( } bool HistoryWidget::confirmSendingFiles(const QStringList &files) { - return confirmSendingFiles(files, CompressConfirm::Auto, nullptr); + return confirmSendingFiles(files, CompressConfirm::Auto); } bool HistoryWidget::confirmSendingFiles(const QMimeData *data) { - return confirmSendingFiles(data, CompressConfirm::Auto, nullptr); + return confirmSendingFiles(data, CompressConfirm::Auto); } bool HistoryWidget::confirmSendingFiles( const QList &files, - CompressConfirm compressed, - const QString *addedComment) { + CompressConfirm compressed) { return confirmSendingFiles( Storage::PrepareMediaList(files, st::sendMediaPreviewSize), - compressed, - addedComment); + compressed); } bool HistoryWidget::confirmSendingFiles( const QStringList &files, - CompressConfirm compressed, - const QString *addedComment) { + CompressConfirm compressed) { return confirmSendingFiles( Storage::PrepareMediaList(files, st::sendMediaPreviewSize), - compressed, - addedComment); + compressed); } bool HistoryWidget::confirmSendingFiles( Storage::PreparedList &&list, - CompressConfirm compressed, - const QString *addedComment) { + CompressConfirm compressed) { if (showSendingFilesError(list)) { return false; } @@ -4057,8 +4044,6 @@ bool HistoryWidget::confirmSendingFiles( uploadFilesAfterConfirmation( std::move(list), - QByteArray(), - QImage(), SendMediaType::Photo, caption, replyToId(), @@ -4071,7 +4056,6 @@ bool HistoryWidget::confirmSendingFiles( const auto insertTextOnCancel = QString(); auto sendCallback = [this]( Storage::PreparedList &&list, - const QImage &image, bool compressed, const QString &caption, MsgId replyTo) { @@ -4080,8 +4064,6 @@ bool HistoryWidget::confirmSendingFiles( : SendMediaType::File; uploadFilesAfterConfirmation( std::move(list), - QByteArray(), - image, type, caption, replyTo); @@ -4094,22 +4076,20 @@ bool HistoryWidget::confirmSendingFiles( return showSendFilesBox( Box(std::move(list), boxCompressConfirm), insertTextOnCancel, - addedComment, std::move(sendCallback)); } } bool HistoryWidget::confirmSendingFiles( - const QImage &image, - const QByteArray &content, + QImage &&image, + QByteArray &&content, CompressConfirm compressed, const QString &insertTextOnCancel) { if (!canWriteMessage() || image.isNull()) return false; App::wnd()->activateWindow(); - auto sendCallback = [this, content]( + auto sendCallback = [this]( Storage::PreparedList &&list, - const QImage &image, bool compressed, const QString &caption, MsgId replyTo) { @@ -4118,16 +4098,17 @@ bool HistoryWidget::confirmSendingFiles( : SendMediaType::File; uploadFilesAfterConfirmation( std::move(list), - content, - image, type, caption, replyTo); }; + auto list = Storage::PrepareMediaFromImage( + std::move(image), + std::move(content), + st::sendMediaPreviewSize); return showSendFilesBox( - Box(image, compressed), + Box(std::move(list), compressed), insertTextOnCancel, - nullptr, std::move(sendCallback)); } @@ -4152,7 +4133,7 @@ bool HistoryWidget::confirmSendingFiles( auto image = qvariant_cast(data->imageData()); if (!image.isNull()) { confirmSendingFiles( - image, + std::move(image), QByteArray(), compressed, insertTextOnCancel); @@ -4162,31 +4143,6 @@ bool HistoryWidget::confirmSendingFiles( return false; } -bool HistoryWidget::confirmShareContact( - const QString &phone, - const QString &fname, - const QString &lname, - const QString *addedComment) { - if (!canWriteMessage()) return false; - - auto sendCallback = [=]( - Storage::PreparedList &&list, - const QImage &image, - bool compressed, - const QString &caption, - MsgId replyTo) { - auto options = ApiWrap::SendOptions(_history); - options.replyTo = replyTo; - Auth().api().shareContact(phone, fname, lname, options); - }; - const auto insertTextOnCancel = QString(); - return showSendFilesBox( - Box(phone, fname, lname), - insertTextOnCancel, - addedComment, - std::move(sendCallback)); -} - void HistoryWidget::uploadFiles( Storage::PreparedList &&list, SendMediaType type) { @@ -4195,8 +4151,6 @@ void HistoryWidget::uploadFiles( auto caption = QString(); uploadFilesAfterConfirmation( std::move(list), - QByteArray(), - QImage(), type, caption, replyToId()); @@ -4204,8 +4158,6 @@ void HistoryWidget::uploadFiles( void HistoryWidget::uploadFilesAfterConfirmation( Storage::PreparedList &&list, - const QByteArray &content, - const QImage &image, SendMediaType type, QString caption, MsgId replyTo, @@ -4216,8 +4168,6 @@ void HistoryWidget::uploadFilesAfterConfirmation( options.replyTo = replyTo; Auth().api().sendFiles( std::move(list), - content, - image, type, caption, album, diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index d8b69ed8eb..fec7f5c339 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -497,24 +497,37 @@ private: void unreadMentionsAnimationFinish(); void sendButtonClicked(); - bool confirmShareContact(const QString &phone, const QString &fname, const QString &lname, const QString *addedComment = nullptr); - bool confirmSendingFiles(const QList &files, CompressConfirm compressed, const QString *addedComment = nullptr); - bool confirmSendingFiles(const QStringList &files, CompressConfirm compressed, const QString *addedComment = nullptr); - bool confirmSendingFiles(const QImage &image, const QByteArray &content, CompressConfirm compressed, const QString &insertTextOnCancel = QString()); - bool confirmSendingFiles(const QMimeData *data, CompressConfirm compressed, const QString &insertTextOnCancel = QString()); - bool confirmSendingFiles(Storage::PreparedList &&list, CompressConfirm compressed, const QString *addedComment = nullptr); + bool confirmSendingFiles( + const QList &files, + CompressConfirm compressed); + bool confirmSendingFiles( + const QStringList &files, + CompressConfirm compressed); + bool confirmSendingFiles( + QImage &&image, + QByteArray &&content, + CompressConfirm compressed, + const QString &insertTextOnCancel = QString()); + bool confirmSendingFiles( + const QMimeData *data, + CompressConfirm compressed, + const QString &insertTextOnCancel = QString()); + bool confirmSendingFiles( + Storage::PreparedList &&list, + CompressConfirm compressed); bool showSendingFilesError(const Storage::PreparedList &list) const; + template - bool showSendFilesBox(object_ptr box, const QString &insertTextOnCancel, const QString *addedComment, SendCallback callback); + bool showSendFilesBox( + object_ptr box, + const QString &insertTextOnCancel, + SendCallback callback); void uploadFiles(Storage::PreparedList &&list, SendMediaType type); void uploadFile(const QByteArray &fileContent, SendMediaType type); - // If an empty filepath is found we upload (possible) "image" with (possible) "content". void uploadFilesAfterConfirmation( Storage::PreparedList &&list, - const QByteArray &content, - const QImage &image, SendMediaType type, QString caption, MsgId replyTo, diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp index a6b272766a..79327aad46 100644 --- a/Telegram/SourceFiles/storage/localimageloader.cpp +++ b/Telegram/SourceFiles/storage/localimageloader.cpp @@ -202,6 +202,7 @@ FileLoadResult::FileLoadResult( FileLoadTask::FileLoadTask( const QString &filepath, + const QByteArray &content, std::unique_ptr information, SendMediaType type, const FileLoadTo &to, @@ -211,23 +212,8 @@ FileLoadTask::FileLoadTask( , _to(to) , _album(std::move(album)) , _filepath(filepath) -, _information(std::move(information)) -, _type(type) -, _caption(caption) { -} - -FileLoadTask::FileLoadTask( - const QByteArray &content, - const QImage &image, - SendMediaType type, - const FileLoadTo &to, - const QString &caption, - std::shared_ptr album) -: _id(rand_value()) -, _to(to) -, _album(std::move(album)) , _content(content) -, _image(image) +, _information(std::move(information)) , _type(type) , _caption(caption) { } @@ -361,6 +347,14 @@ bool FileLoadTask::CheckForImage( } return QImage(); })(); + return FillImageInformation(std::move(image), animated, result); +} + +bool FileLoadTask::FillImageInformation( + QImage &&image, + bool animated, + std::unique_ptr &result) { + Expects(result != nullptr); if (image.isNull()) { return false; @@ -395,7 +389,7 @@ void FileLoadTask::process() { auto isVideo = false; auto isVoice = (_type == SendMediaType::Audio); - auto fullimage = base::take(_image); + auto fullimage = QImage(); auto info = _filepath.isEmpty() ? QFileInfo() : QFileInfo(_filepath); if (info.exists()) { if (info.isDir()) { @@ -428,6 +422,12 @@ void FileLoadTask::process() { filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true); filemime = "audio/ogg"; } else { + if (_information) { + if (auto image = base::get_if( + &_information->media)) { + fullimage = base::take(image->data); + } + } auto mimeType = mimeTypeForData(_content); filemime = mimeType.name(); if (filemime != stickerMime) { diff --git a/Telegram/SourceFiles/storage/localimageloader.h b/Telegram/SourceFiles/storage/localimageloader.h index 7d864b761c..d9c5473708 100644 --- a/Telegram/SourceFiles/storage/localimageloader.h +++ b/Telegram/SourceFiles/storage/localimageloader.h @@ -282,17 +282,15 @@ public: const QString &filepath, const QByteArray &content, const QString &filemime); + static bool FillImageInformation( + QImage &&image, + bool animated, + std::unique_ptr &result); FileLoadTask( const QString &filepath, - std::unique_ptr information, - SendMediaType type, - const FileLoadTo &to, - const QString &caption, - std::shared_ptr album = nullptr); - FileLoadTask( const QByteArray &content, - const QImage &image, + std::unique_ptr information, SendMediaType type, const FileLoadTo &to, const QString &caption, @@ -312,9 +310,18 @@ public: void finish(); private: - static bool CheckForSong(const QString &filepath, const QByteArray &content, std::unique_ptr &result); - static bool CheckForVideo(const QString &filepath, const QByteArray &content, std::unique_ptr &result); - static bool CheckForImage(const QString &filepath, const QByteArray &content, std::unique_ptr &result); + static bool CheckForSong( + const QString &filepath, + const QByteArray &content, + std::unique_ptr &result); + static bool CheckForVideo( + const QString &filepath, + const QByteArray &content, + std::unique_ptr &result); + static bool CheckForImage( + const QString &filepath, + const QByteArray &content, + std::unique_ptr &result); template static bool CheckMimeOrExtensions(const QString &filepath, const QString &filemime, Mimes &mimes, Extensions &extensions); @@ -330,7 +337,6 @@ private: QString _filepath; QByteArray _content; std::unique_ptr _information; - QImage _image; int32 _duration = 0; VoiceWaveform _waveform; SendMediaType _type; diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.cpp b/Telegram/SourceFiles/storage/storage_media_prepare.cpp index 968178449b..39ddf142e7 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.cpp +++ b/Telegram/SourceFiles/storage/storage_media_prepare.cpp @@ -61,11 +61,22 @@ bool PrepareAlbumMediaIsWaiting( // Use some special thread queue, like a separate QThreadPool. base::TaskQueue::Normal().Put([&, previewWidth] { const auto guard = gsl::finally([&] { semaphore.release(); }); - const auto filemime = mimeTypeForFile(QFileInfo(file.path)).name(); - file.information = FileLoadTask::ReadMediaInformation( - file.path, - QByteArray(), - filemime); + if (!file.path.isEmpty()) { + file.mime = mimeTypeForFile(QFileInfo(file.path)).name(); + file.information = FileLoadTask::ReadMediaInformation( + file.path, + QByteArray(), + file.mime); + } else if (!file.content.isEmpty()) { + file.mime = mimeTypeForData(file.content).name(); + file.information = FileLoadTask::ReadMediaInformation( + QString(), + file.content, + file.mime); + } else { + Assert(file.information != nullptr); + } + using Image = FileMediaInformation::Image; using Video = FileMediaInformation::Video; if (const auto image = base::get_if( @@ -94,17 +105,14 @@ bool PrepareAlbumMediaIsWaiting( void PrepareAlbum(PreparedList &result, int previewWidth) { const auto count = int(result.files.size()); - if ((count < 2) || (count > kMaxAlbumCount)) { + if (count > kMaxAlbumCount) { return; } - result.albumIsPossible = true; + result.albumIsPossible = (count > 1); auto waiting = 0; QSemaphore semaphore; for (auto &file : result.files) { - if (!result.albumIsPossible) { - break; - } if (PrepareAlbumMediaIsWaiting(semaphore, file, previewWidth)) { ++waiting; } @@ -226,11 +234,34 @@ PreparedList PrepareMediaList(const QStringList &files, int previewWidth) { if (filesize > App::kImageSizeLimit || !toCompress) { result.allFilesForCompress = false; } - result.files.push_back({ file }); + result.files.emplace_back(file); } PrepareAlbum(result, previewWidth); return result; } +PreparedList PrepareMediaFromImage( + QImage &&image, + QByteArray &&content, + int previewWidth) { + auto result = Storage::PreparedList(); + result.allFilesForCompress = ValidateThumbDimensions( + image.width(), + image.height()); + auto file = PreparedFile(QString()); + file.content = content; + if (file.content.isEmpty()) { + file.information = std::make_unique(); + const auto animated = false; + FileLoadTask::FillImageInformation( + std::move(image), + animated, + file.information); + } + result.files.push_back(std::move(file)); + PrepareAlbum(result, previewWidth); + return result; +} + } // namespace Storage diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.h b/Telegram/SourceFiles/storage/storage_media_prepare.h index 5b7887f43f..16daf75a8c 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.h +++ b/Telegram/SourceFiles/storage/storage_media_prepare.h @@ -46,8 +46,9 @@ struct PreparedFile { ~PreparedFile(); QString path; + QByteArray content; + QString mime; std::unique_ptr information; - base::optional large; QImage preview; AlbumType type = AlbumType::None; @@ -79,5 +80,9 @@ struct PreparedList { bool ValidateThumbDimensions(int width, int height); PreparedList PrepareMediaList(const QList &files, int previewWidth); PreparedList PrepareMediaList(const QStringList &files, int previewWidth); +PreparedList PrepareMediaFromImage( + QImage &&image, + QByteArray &&content, + int previewWidth); } // namespace Storage