diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 1571ba826e..298f31ffba 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -1329,8 +1329,7 @@ SendFilesBox::SendFilesBox( Storage::PreparedList &&list, CompressConfirm compressed) : _list(std::move(list)) -, _compressConfirm(compressed) -, _caption(this, st::confirmCaptionArea, FieldPlaceholder(_list)) { +, _compressConfirm(compressed) { } void SendFilesBox::initPreview(rpl::producer desiredPreviewHeight) { @@ -1398,7 +1397,7 @@ void SendFilesBox::setupShadows( const auto topShadow = Ui::CreateChild(this); const auto bottomShadow = Ui::CreateChild(this); wrap->geometryValue( - ) | rpl::start_with_next([=](const QRect &geometry) { + ) | rpl::start_with_next_done([=](const QRect &geometry) { topShadow->resizeToWidth(geometry.width()); topShadow->move( geometry.x(), @@ -1407,7 +1406,11 @@ void SendFilesBox::setupShadows( bottomShadow->move( geometry.x(), geometry.y() + geometry.height() - st::lineWidth); + }, [t = make_weak(topShadow), b = make_weak(bottomShadow)] { + Ui::DestroyChild(t.data()); + Ui::DestroyChild(b.data()); }, topShadow->lifetime()); + topShadow->toggleOn(wrap->scrollTopValue() | rpl::map(_1 > 0)); bottomShadow->toggleOn(rpl::combine( wrap->scrollTopValue(), @@ -1422,17 +1425,7 @@ void SendFilesBox::prepare() { _send = addButton(langFactory(lng_send_button), [this] { send(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); initSendWay(); - if (_list.files.size() == 1) { - prepareSingleFilePreview(); - } else { - if (_list.albumIsPossible) { - prepareAlbumPreview(); - } else { - auto desiredPreviewHeight = rpl::single(0); - initPreview(std::move(desiredPreviewHeight)); - } - } - + preparePreview(); subscribe(boxClosing, [this] { if (!_confirmed && _cancelledCallback) { _cancelledCallback(); @@ -1473,6 +1466,26 @@ void SendFilesBox::initSendWay() { : SendFilesWay::Photos; }(); _sendWay = std::make_shared>(value); + _sendWay->setChangedCallback([this](SendFilesWay value) { + applyAlbumOrder(); + if (_albumPreview) { + _albumPreview->setSendWay(value); + } + setInnerFocus(); + }); +} + +void SendFilesBox::preparePreview() { + if (_list.files.size() == 1) { + prepareSingleFilePreview(); + } else { + if (_list.albumIsPossible) { + prepareAlbumPreview(); + } else { + auto desiredPreviewHeight = rpl::single(0); + initPreview(std::move(desiredPreviewHeight)); + } + } } void SendFilesBox::setupControls() { @@ -1482,15 +1495,19 @@ void SendFilesBox::setupControls() { } void SendFilesBox::setupSendWayControls() { + _sendAlbum.destroy(); + _sendPhotos.destroy(); + _sendFiles.destroy(); if (_compressConfirm == CompressConfirm::None) { return; } const auto addRadio = [&]( - object_ptr> &button, - SendFilesWay value, - const QString &text) { + object_ptr> &button, + SendFilesWay value, + const QString &text) { const auto &style = st::defaultBoxCheckbox; button.create(this, _sendWay, value, text, style); + button->show(); }; if (_list.albumIsPossible) { addRadio(_sendAlbum, SendFilesWay::Album, lang(lng_send_album)); @@ -1507,17 +1524,12 @@ void SendFilesBox::setupSendWayControls() { addRadio(_sendFiles, SendFilesWay::Files, (_list.files.size() == 1) ? lang(lng_send_file) : lng_send_files(lt_count, _list.files.size())); - _sendWay->setChangedCallback([this](SendFilesWay value) { - if (_albumPreview) { - applyAlbumOrder(); - _albumPreview->setSendWay(value); - } - setInnerFocus(); - }); } void SendFilesBox::applyAlbumOrder() { - Expects(_albumPreview != nullptr); + if (!_albumPreview) { + return; + } const auto order = _albumPreview->takeOrder(); const auto isDefault = [&] { @@ -1536,10 +1548,12 @@ void SendFilesBox::applyAlbumOrder() { } void SendFilesBox::setupCaption() { - if (!_caption) { + if (_caption) { + _caption->setPlaceholder(FieldPlaceholder(_list)); return; } + _caption.create(this, st::confirmCaptionArea, FieldPlaceholder(_list)); _caption->setMaxLength(MaxPhotoCaption); _caption->setCtrlEnterSubmit(Ui::CtrlEnterSubmit::Both); connect(_caption, &Ui::InputArea::resized, this, [this] { @@ -1552,6 +1566,16 @@ void SendFilesBox::setupCaption() { connect(_caption, &Ui::InputArea::cancelled, this, [this] { closeBox(); }); + _caption->setMimeDataHook([this]( + not_null data, + Ui::InputArea::MimeAction action) { + if (action == Ui::InputArea::MimeAction::Check) { + return canAddFiles(data); + } else if (action == Ui::InputArea::MimeAction::Insert) { + return addFiles(data); + } + Unexpected("action in MimeData hook."); + }); } void SendFilesBox::captionResized() { @@ -1560,6 +1584,73 @@ void SendFilesBox::captionResized() { update(); } +bool SendFilesBox::canAddFiles(not_null data) const { + auto files = 0; + if (data->hasUrls()) { + for (const auto &url : data->urls()) { + if (url.isLocalFile()) { + ++files; + } + } + } else if (data->hasImage()) { + ++files; + } + if (_list.files.size() + files > Storage::MaxAlbumItems()) { + return false; + } else if (_list.files.size() > 1 && !_albumPreview) { + return false; + } else if (_list.files.front().type + == Storage::PreparedFile::AlbumType::None) { + return false; + } + return true; +} + +bool SendFilesBox::addFiles(not_null data) { + auto list = [&] { + if (data->hasUrls()) { + return Storage::PrepareMediaList( + data->urls(), + st::sendMediaPreviewSize); + } else if (data->hasImage()) { + auto image = qvariant_cast(data->imageData()); + if (!image.isNull()) { + return Storage::PrepareMediaFromImage( + std::move(image), + QByteArray(), + st::sendMediaPreviewSize); + } + } + return Storage::PreparedList( + Storage::PreparedList::Error::EmptyFile, + QString()); + }(); + if (_list.files.size() + list.files.size() > Storage::MaxAlbumItems()) { + return false; + } else if (list.error != Storage::PreparedList::Error::None) { + return false; + } else if (list.files.size() != 1 && !list.albumIsPossible) { + return false; + } else if (list.files.front().type + == Storage::PreparedFile::AlbumType::None) { + return false; + } else if (_list.files.size() > 1 && !_albumPreview) { + return false; + } + applyAlbumOrder(); + delete base::take(_preview); + _albumPreview = nullptr; + + if (_list.files.size() == 1 + && _sendWay->value() == SendFilesWay::Photos) { + _sendWay->setValue(SendFilesWay::Album); + } + _list.mergeToEnd(std::move(list)); + preparePreview(); + updateControlsGeometry(); + return true; +} + void SendFilesBox::setupTitleText() { if (_list.files.size() > 1) { const auto onlyImages = (_compressConfirm != CompressConfirm::None) @@ -1681,9 +1772,7 @@ void SendFilesBox::send(bool ctrlShiftEnter) { } } - if (_albumPreview) { - applyAlbumOrder(); - } + applyAlbumOrder(); _confirmed = true; if (_confirmedCallback) { auto caption = _caption diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index 015ea5f7a8..a7d5c01f80 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -83,6 +83,7 @@ private: not_null wrap, not_null content); + void preparePreview(); void prepareSingleFilePreview(); void prepareAlbumPreview(); void applyAlbumOrder(); @@ -94,6 +95,9 @@ private: void updateBoxSize(); void updateControlsGeometry(); + bool canAddFiles(not_null data) const; + bool addFiles(not_null data); + QString _titleText; int _titleHeight = 0; diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.h b/Telegram/SourceFiles/media/view/media_view_group_thumbs.h index 7b31f5a305..af92c38531 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.h +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.h @@ -104,7 +104,6 @@ private: std::vector> _dying; base::flat_map> _cache; int _width = 0; - int _limit = 0; QRect _updatedRect; rpl::event_stream _updateRequests; diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.cpp b/Telegram/SourceFiles/storage/storage_media_prepare.cpp index d4df88d57b..31d01d4412 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.cpp +++ b/Telegram/SourceFiles/storage/storage_media_prepare.cpp @@ -287,5 +287,34 @@ PreparedList PreparedList::Reordered( return result; } +void PreparedList::mergeToEnd(PreparedList &&other) { + if (error != Error::None) { + return; + } + if (other.error != Error::None) { + error = other.error; + errorData = other.errorData; + return; + } + allFilesForCompress = allFilesForCompress && other.allFilesForCompress; + files.reserve(files.size() + other.files.size()); + for (auto &file : other.files) { + files.push_back(std::move(file)); + } + if (files.size() > 1 && files.size() <= kMaxAlbumCount) { + const auto badIt = ranges::find( + files, + PreparedFile::AlbumType::None, + [](const PreparedFile &file) { return file.type; }); + albumIsPossible = (badIt == files.end()); + } else { + albumIsPossible = false; + } +} + +int MaxAlbumItems() { + return kMaxAlbumCount; +} + } // namespace Storage diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.h b/Telegram/SourceFiles/storage/storage_media_prepare.h index 79600814f5..26855fbe88 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.h +++ b/Telegram/SourceFiles/storage/storage_media_prepare.h @@ -71,6 +71,7 @@ struct PreparedList { static PreparedList Reordered( PreparedList &&list, std::vector order); + void mergeToEnd(PreparedList &&other); Error error = Error::None; QString errorData; @@ -87,5 +88,6 @@ PreparedList PrepareMediaFromImage( QImage &&image, QByteArray &&content, int previewWidth); +int MaxAlbumItems(); } // namespace Storage diff --git a/Telegram/SourceFiles/ui/rp_widget.h b/Telegram/SourceFiles/ui/rp_widget.h index 88d115cf79..c481f1fc8c 100644 --- a/Telegram/SourceFiles/ui/rp_widget.h +++ b/Telegram/SourceFiles/ui/rp_widget.h @@ -59,6 +59,10 @@ inline Widget *CreateChild( return new Widget(parent, std::forward(args)...); } +inline void DestroyChild(QWidget *child) { + delete child; +} + template inline void AttachAsChild(not_null parent, Value &&value) { using PlainValue = std::decay_t; diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.cpp b/Telegram/SourceFiles/ui/widgets/input_fields.cpp index 657538df39..6962b7929c 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.cpp +++ b/Telegram/SourceFiles/ui/widgets/input_fields.cpp @@ -2467,6 +2467,24 @@ void InputArea::Inner::contextMenuEvent(QContextMenuEvent *e) { } } +bool InputArea::Inner::canInsertFromMimeData(const QMimeData *source) const { + if (source + && f()->_mimeDataHook + && f()->_mimeDataHook(source, MimeAction::Check)) { + return true; + } + return QTextEdit::canInsertFromMimeData(source); +} + +void InputArea::Inner::insertFromMimeData(const QMimeData *source) { + if (source + && f()->_mimeDataHook + && f()->_mimeDataHook(source, MimeAction::Insert)) { + return; + } + return QTextEdit::insertFromMimeData(source); +} + void InputArea::resizeEvent(QResizeEvent *e) { refreshPlaceholder(); _inner->setGeometry(rect().marginsRemoved(_st.textMargins)); diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.h b/Telegram/SourceFiles/ui/widgets/input_fields.h index a6fdd20e54..5faa643881 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.h +++ b/Telegram/SourceFiles/ui/widgets/input_fields.h @@ -387,6 +387,17 @@ public: _inner->clearFocus(); } + enum class MimeAction { + Check, + Insert, + }; + using MimeDataHook = base::lambda data, + MimeAction action)>; + void setMimeDataHook(MimeDataHook hook) { + _mimeDataHook = std::move(hook); + } + private slots: void onTouchTimer(); @@ -441,6 +452,8 @@ private: void keyPressEvent(QKeyEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override; + bool canInsertFromMimeData(const QMimeData *source) const override; + void insertFromMimeData(const QMimeData *source) override; QMimeData *createMimeDataFromSelection() const override; private: @@ -504,6 +517,7 @@ private: QPoint _touchStart; bool _correcting = false; + MimeDataHook _mimeDataHook; };