From 0539cc9448c18bfd4cd7a829c0ef9d48eac13738 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 16 Oct 2020 13:38:12 +0300 Subject: [PATCH] Add a way to recreate SendFilesBox content. --- Telegram/SourceFiles/apiwrap.cpp | 1 + Telegram/SourceFiles/boxes/boxes.style | 6 +- .../SourceFiles/boxes/edit_caption_box.cpp | 2 +- Telegram/SourceFiles/boxes/send_files_box.cpp | 254 ++++++++++-------- Telegram/SourceFiles/boxes/send_files_box.h | 36 ++- .../storage/storage_media_prepare.cpp | 11 +- .../ui/chat/attach/attach_album_preview.cpp | 41 +-- .../ui/chat/attach/attach_album_preview.h | 8 +- .../ui/chat/attach/attach_album_thumbnail.cpp | 6 +- .../ui/chat/attach/attach_prepare.cpp | 6 +- .../ui/chat/attach/attach_prepare.h | 1 + 11 files changed, 217 insertions(+), 155 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 1830eee54d..7de96c1ad8 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -4235,6 +4235,7 @@ void ApiWrap::sendFiles( type = SendMediaType::Photo; break; case Ui::PreparedFile::AlbumType::Video: + case Ui::PreparedFile::AlbumType::File: type = SendMediaType::File; break; default: Unexpected("AlbumType in uploadFilesAfterConfirmation"); diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index ac791872f6..528cd1f703 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -489,7 +489,7 @@ backgroundScroll: ScrollArea(boxScroll) { deltab: 10px; } -editMediaButtonSize: 29px; +editMediaButtonSize: 28px; editMediaButtonSkip: 8px; editMediaButtonFileSkipRight: 1px; editMediaButtonFileSkipTop: 7px; @@ -514,6 +514,10 @@ sendBoxAlbumGroupSkipTop: 6px; sendBoxAlbumGroupRadius: 12px; sendBoxAlbumGroupHeight: 25px; +sendBoxFileGroupSkipTop: 2px; +sendBoxFileGroupSkipRight: 0px; +sendBoxFileGroupEditInternalSkip: 4px; + sendBoxAlbumGroupEditButtonIcon: editMediaButtonIconPhoto; sendBoxAlbumGroupEditButtonIconPosition: point(4px, -1px); diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index 659151e98d..03e2f9e473 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -689,7 +689,7 @@ bool EditCaptionBox::fileFromClipboard(not_null data) { } const auto file = &list.files.front(); - if (_isAlbum && (file->type == AlbumType::File)) { + if (_isAlbum && (file->type == AlbumType::File || file->type == AlbumType::None)) { const auto imageAsDoc = [&] { using Info = Ui::PreparedFileInformation; const auto fileMedia = &file->information->media; diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index f0accfe2e2..f405c48a18 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -100,6 +100,95 @@ rpl::producer FieldPlaceholder( } // namespace +SendFilesBox::Block::Block( + not_null parent, + not_null*> items, + int from, + int till, + Fn gifPaused, + SendFilesWay way) +: _items(items) +, _from(from) +, _till(till) { + Expects(from >= 0); + Expects(till > from); + Expects(till <= items->size()); + + const auto count = till - from; + const auto my = gsl::make_span(*items).subspan(from, count); + const auto &first = my.front(); + _isAlbum = (my.size() > 1) + || (first.type == Ui::PreparedFile::AlbumType::Photo); + if (_isAlbum) { + const auto preview = Ui::CreateChild( + parent.get(), + my, + way); + _preview.reset(preview); + } else { + const auto media = Ui::SingleMediaPreview::Create( + parent, + gifPaused, + first); + if (media) { + _preview.reset(media); + } else { + _preview.reset( + Ui::CreateChild(parent.get(), first)); + } + } + _preview->show(); +} + +int SendFilesBox::Block::fromIndex() const { + return _from; +} + +int SendFilesBox::Block::tillIndex() const { + return _till; +} + +object_ptr SendFilesBox::Block::takeWidget() { + return object_ptr::fromRaw(_preview.get()); +} + +void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) { + if (!_isAlbum) { + return; + } + applyAlbumOrder(); + const auto album = static_cast(_preview.get()); + album->setSendWay(way); +} + +void SendFilesBox::Block::applyAlbumOrder() { + if (!_isAlbum) { + return; + } + const auto album = static_cast(_preview.get()); + const auto order = album->takeOrder(); + const auto isIdentity = [&] { + for (auto i = 0, count = int(order.size()); i != count; ++i) { + if (order[i] != i) { + return false; + } + } + return true; + }(); + if (isIdentity) { + return; + } + + auto elements = std::vector(); + elements.reserve(order.size()); + for (const auto index : order) { + elements.push_back(std::move((*_items)[_from + index])); + } + for (auto i = 0, count = int(order.size()); i != count; ++i) { + (*_items)[_from + i] = std::move(elements[i]); + } +} + SendFilesBox::SendFilesBox( QWidget*, not_null controller, @@ -147,36 +236,6 @@ void SendFilesBox::initPreview() { }, _dimensionsLifetime); } -//void SendFilesBox::prepareSingleFilePreview() { -// const auto &file = _list.files[0]; -// const auto controller = _controller; -// const auto media = Ui::SingleMediaPreview::Create(this, [=] { -// return controller->isGifPausedAtLeastFor( -// Window::GifPauseReason::Layer); -// }, file); -// if (media) { -// _preview = media; -// initPreview(media->desiredHeightValue()); -// } else { -// const auto preview = Ui::CreateChild(this, file); -// _preview = preview; -// initPreview(preview->desiredHeightValue()); -// } -//} - -//void SendFilesBox::prepareAlbumPreview() { -// addThumbButtonHandlers(wrap); // #TODO files -// -// setupShadows(wrap, _albumPreview); -// -// initPreview(_albumPreview->desiredHeightValue()); -// -// crl::on_main([=] { -// wrap->scrollToY(_lastScrollTop); -// _lastScrollTop = 0; -// }); -//} - void SendFilesBox::addThumbButtonHandlers(not_null wrap) { // #TODO files //_albumPreview->thumbDeleted( @@ -224,14 +283,12 @@ void SendFilesBox::addThumbButtonHandlers(not_null wrap) { //}, _albumPreview->lifetime()); } -void SendFilesBox::setupShadows( - not_null wrap, - not_null content) { +void SendFilesBox::setupShadows() { using namespace rpl::mappers; const auto topShadow = Ui::CreateChild(this); const auto bottomShadow = Ui::CreateChild(this); - wrap->geometryValue( + _scroll->geometryValue( ) | rpl::start_with_next_done([=](const QRect &geometry) { topShadow->resizeToWidth(geometry.width()); topShadow->move( @@ -246,11 +303,11 @@ void SendFilesBox::setupShadows( Ui::DestroyChild(b.data()); }, topShadow->lifetime()); - topShadow->toggleOn(wrap->scrollTopValue() | rpl::map(_1 > 0)); + topShadow->toggleOn(_scroll->scrollTopValue() | rpl::map(_1 > 0)); bottomShadow->toggleOn(rpl::combine( - wrap->scrollTopValue(), - wrap->heightValue(), - content->heightValue(), + _scroll->scrollTopValue(), + _scroll->heightValue(), + _inner->heightValue(), _1 + _2 < _3)); } @@ -269,9 +326,7 @@ void SendFilesBox::prepare() { setupSendWayControls(); preparePreview(); initPreview(); - - _scroll->show(); - _inner->show(); + setupShadows(); boxClosing() | rpl::start_with_next([=] { if (!_confirmed && _cancelledCallback) { @@ -364,6 +419,9 @@ void SendFilesBox::initSendWay() { ) | rpl::start_with_next([=](SendFilesWay value) { updateCaptionPlaceholder(); updateEmojiPanelGeometry(); + for (auto &block : _blocks) { + block.setSendWay(value); + } setInnerFocus(); }, lifetime()); } @@ -389,73 +447,59 @@ void SendFilesBox::updateCaptionPlaceholder() { } void SendFilesBox::preparePreview() { + generatePreviewFrom(0); +} + +void SendFilesBox::generatePreviewFrom(int fromBlock) { + Expects(fromBlock <= _blocks.size()); + using Type = Ui::PreparedFile::AlbumType; - _blocks.clear(); + _blocks.erase(_blocks.begin() + fromBlock, _blocks.end()); + + const auto fromItem = _blocks.empty() ? 0 : _blocks.back().tillIndex(); + Assert(fromItem <= _list.files.size()); + auto albumStart = -1; - const auto finishAlbum = [&](int till) { - if (albumStart < 0) { - return; - } - const auto count = (till - albumStart); - const auto preview = _inner->add(object_ptr( - this, - gsl::make_span(_list.files).subspan(albumStart, count), - _sendWay.current())); - - auto &block = _blocks.emplace_back(); - block.fromIndex = albumStart; - block.tillIndex = albumStart + count; - block.preview.reset(preview); - block.preview->show(); - - _sendWay.changes( - ) | rpl::start_with_next([=](SendFilesWay value) { - applyAlbumOrder(preview, albumStart); - preview->setSendWay(value); - }, preview->lifetime()); - - albumStart = -1; + const auto gifPaused = [controller = _controller] { + return controller->isGifPausedAtLeastFor( + Window::GifPauseReason::Layer); }; - const auto finishSingle = [&](int index) { - const auto &file = _list.files[index]; - const auto controller = _controller; - auto &block = _blocks.emplace_back(); - block.fromIndex = index; - block.tillIndex = index + 1; - const auto media = Ui::SingleMediaPreview::Create(this, [=] { - return controller->isGifPausedAtLeastFor( - Window::GifPauseReason::Layer); - }, file); - if (media) { - block.preview.reset( - _inner->add(object_ptr::fromRaw( - media))); - } else { - block.preview.reset( - _inner->add(object_ptr(this, file))); - } - block.preview->show(); + const auto pushBlock = [&](int from, int till) { + _blocks.emplace_back( + _inner.data(), + &_list.files, + from, + till, + gifPaused, + _sendWay.current()); + _inner->add(_blocks.back().takeWidget()); }; - for (auto i = 0, count = int(_list.files.size()); i != count; ++i) { + for (auto i = fromItem, till = int(_list.files.size()); i != till; ++i) { const auto type = _list.files[i].type; if (albumStart >= 0) { const auto albumCount = (i - albumStart); - if (type == Type::File || (albumCount == Ui::MaxAlbumItems())) { - finishAlbum(i); + if ((type == Type::File) + || (type == Type::None) + || (albumCount == Ui::MaxAlbumItems())) { + pushBlock(std::exchange(albumStart, -1), i); } else { continue; } } - if (type != Type::File) { + if (type != Type::File && type != Type::None) { if (albumStart < 0) { albumStart = i; } continue; } - finishSingle(i); + pushBlock(i, i + 1); } - finishAlbum(_list.files.size()); + if (albumStart >= 0) { + pushBlock(albumStart, _list.files.size()); + } + + _scroll->scrollToY(0); } void SendFilesBox::setupControls() { @@ -520,32 +564,6 @@ void SendFilesBox::updateSendWayControlsVisibility() { _groupFiles->setVisible(!onlyOne); } -void SendFilesBox::applyAlbumOrder( - not_null preview, - int from) { - const auto order = preview->takeOrder(); - const auto isDefault = [&] { - for (auto i = 0, count = int(order.size()); i != count; ++i) { - if (order[i] != i) { - return false; - } - } - return true; - }(); - if (isDefault) { - return; - } - - auto elements = std::vector(); - elements.reserve(order.size()); - for (const auto index : order) { - elements.push_back(std::move(_list.files[from + index])); - } - for (auto i = 0, count = int(order.size()); i != count; ++i) { - _list.files[from + i] = std::move(elements[i]); - } -} - void SendFilesBox::setupCaption() { _caption->setMaxLength( _controller->session().serverConfig().captionLengthMax); @@ -854,7 +872,9 @@ void SendFilesBox::send( Core::App().saveSettingsDelayed(); } - //applyAlbumOrder(); // #TODO files + for (auto &block : _blocks) { + block.applyAlbumOrder(); + } _confirmed = true; if (_confirmedCallback) { auto caption = (_caption && !_caption->isHidden()) diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index 00f0626e8a..b2df787527 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -84,10 +84,32 @@ protected: void resizeEvent(QResizeEvent *e) override; private: - struct Block { - base::unique_qptr preview; - int fromIndex = 0; - int tillIndex = 0; + class Block final { + public: + Block( + not_null parent, + not_null*> items, + int from, + int till, + Fn gifPaused, + Ui::SendFilesWay way); + Block(Block &&other) = default; + Block &operator=(Block &&other) = default; + + [[nodiscard]] int fromIndex() const; + [[nodiscard]] int tillIndex() const; + [[nodiscard]] object_ptr takeWidget(); + + void setSendWay(Ui::SendFilesWay way); + void applyAlbumOrder(); + + private: + base::unique_qptr _preview; + not_null*> _items; + int _from = 0; + int _till = 0; + bool _isAlbum = false; + }; void initSendWay(); void initPreview(); @@ -95,9 +117,7 @@ private: void setupControls(); void setupSendWayControls(); void setupCaption(); - void setupShadows( - not_null wrap, - not_null content); + void setupShadows(); void setupEmojiPanel(); void updateSendWayControlsVisibility(); @@ -105,7 +125,7 @@ private: void emojiFilterForGeometry(not_null event); void preparePreview(); - void applyAlbumOrder(not_null preview, int from); + void generatePreviewFrom(int fromBlock); void send(Api::SendOptions options, bool ctrlShiftEnter = false); void sendSilent(); diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.cpp b/Telegram/SourceFiles/storage/storage_media_prepare.cpp index aa9535964f..b0cc66abf4 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.cpp +++ b/Telegram/SourceFiles/storage/storage_media_prepare.cpp @@ -97,6 +97,8 @@ bool PrepareDetailsIsWaiting( Assert(!file.preview.isNull()); file.preview.setDevicePixelRatio(cRetinaFactor()); file.type = PreparedFile::AlbumType::Photo; + } else if (Core::IsMimeSticker(file.mime)) { + file.type = PreparedFile::AlbumType::None; } } else if (const auto video = std::get_if