From d7fe2948ac48227bf7e721017f917b930b97a2c5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 19 Oct 2020 11:49:31 +0300 Subject: [PATCH] Add edit/remove buttons to Single[File|Media]Preview. --- Telegram/SourceFiles/boxes/boxes.style | 22 ++++--- Telegram/SourceFiles/boxes/send_files_box.cpp | 43 +++++++++---- Telegram/SourceFiles/boxes/send_files_box.h | 1 + .../ui/chat/attach/attach_album_thumbnail.cpp | 21 +++---- .../ui/chat/attach/attach_album_thumbnail.h | 4 +- .../attach/attach_single_file_preview.cpp | 38 +++++++++-- .../chat/attach/attach_single_file_preview.h | 13 +++- .../attach/attach_single_media_preview.cpp | 63 +++++++++++++++---- .../chat/attach/attach_single_media_preview.h | 22 ++++--- 9 files changed, 162 insertions(+), 65 deletions(-) diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 528cd1f703..6cd18ef631 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -508,29 +508,33 @@ editMediaButton: IconButton { // SendFilesBox -sendBoxAlbumGroupEditInternalSkip: 9px; +sendBoxAlbumGroupEditInternalSkip: 8px; sendBoxAlbumGroupSkipRight: 6px; sendBoxAlbumGroupSkipTop: 6px; -sendBoxAlbumGroupRadius: 12px; -sendBoxAlbumGroupHeight: 25px; +sendBoxAlbumGroupRadius: 13px; +sendBoxAlbumGroupHeight: 26px; sendBoxFileGroupSkipTop: 2px; sendBoxFileGroupSkipRight: 0px; sendBoxFileGroupEditInternalSkip: 4px; -sendBoxAlbumGroupEditButtonIcon: editMediaButtonIconPhoto; -sendBoxAlbumGroupEditButtonIconPosition: point(4px, -1px); - sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) { ripple: RippleAnimation(defaultRippleAnimation) { color: windowBgRipple; } } - -sendBoxAlbumGroupDeleteButtonIconPosition: point(-3px, 0px); -sendBoxAlbumGroupDeleteButtonIcon: icon {{ "history_file_cancel", msgServiceFg}}; +sendBoxAlbumGroupEditButtonIconFile: editMediaButtonIconFile; sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "history_file_cancel", menuIconFg, point(6px, 6px) }}; +sendBoxAlbumGroupButtonMediaEdit: icon {{ "settings_edit", msgServiceFg, point(3px, -2px) }}; +sendBoxAlbumGroupButtonMediaDelete: icon {{ "history_file_cancel", msgServiceFg, point(2px, 5px) }}; +sendBoxAlbumGroupButtonMedia: IconButton { + width: sendBoxAlbumGroupHeight; + height: sendBoxAlbumGroupHeight; + + icon: sendBoxAlbumGroupButtonMediaEdit; +} + // End of SendFilesBox calendarTitleHeight: boxTitleHeight; diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 1541aca0ca..bc1fcfdb91 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -132,6 +132,7 @@ SendFilesBox::Block::Block( gifPaused, first); if (media) { + _isSingleMedia = true; _preview.reset(media); } else { _preview.reset( @@ -154,19 +155,35 @@ object_ptr SendFilesBox::Block::takeWidget() { } rpl::producer SendFilesBox::Block::itemDeleteRequest() const { - if (!_isAlbum) { - return rpl::never(); + using namespace rpl::mappers; + + const auto preview = _preview.get(); + if (_isAlbum) { + const auto album = static_cast(_preview.get()); + return album->thumbDeleted() | rpl::map(_1 + _from); + } else if (_isSingleMedia) { + const auto media = static_cast(preview); + return media->deleteRequests() | rpl::map([=] { return _from; }); + } else { + const auto single = static_cast(preview); + return single->deleteRequests() | rpl::map([=] { return _from; }); } - const auto album = static_cast(_preview.get()); - return album->thumbDeleted(); } rpl::producer SendFilesBox::Block::itemReplaceRequest() const { - if (!_isAlbum) { - return rpl::never(); + using namespace rpl::mappers; + + const auto preview = _preview.get(); + if (_isAlbum) { + const auto album = static_cast(preview); + return album->thumbChanged() | rpl::map(_1 + _from); + } else if (_isSingleMedia) { + const auto media = static_cast(preview); + return media->editRequests() | rpl::map([=] { return _from; }); + } else { + const auto single = static_cast(preview); + return single->editRequests() | rpl::map([=] { return _from; }); } - const auto album = static_cast(_preview.get()); - return album->thumbChanged(); } void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) { @@ -512,7 +529,7 @@ void SendFilesBox::pushBlock(int from, int till) { ) | rpl::filter([=] { return !_removingIndex; }) | rpl::start_with_next([=](int index) { - _removingIndex = from + index; + _removingIndex = index; crl::on_main(this, [=] { const auto index = base::take(_removingIndex).value_or(-1); if (index < 0 || index >= _list.files.size()) { @@ -529,19 +546,19 @@ void SendFilesBox::pushBlock(int from, int till) { if (list.files.empty()) { return; } - _list.files[from + index] = std::move(list.files.front()); + _list.files[index] = std::move(list.files.front()); refreshAllAfterChanges(from); }; const auto checkResult = [=](const Ui::PreparedList &list) { if (_sendLimit != SendLimit::One) { return true; } - auto removing = std::move(_list.files[from + index]); - std::swap(_list.files[from + index], _list.files.back()); + auto removing = std::move(_list.files[index]); + std::swap(_list.files[index], _list.files.back()); _list.files.pop_back(); const auto result = _list.canBeSentInSlowmodeWith(list); _list.files.push_back(std::move(removing)); - std::swap(_list.files[from + index], _list.files.back()); + std::swap(_list.files[index], _list.files.back()); if (!result) { Ui::Toast::Show(tr::lng_slowmode_no_many(tr::now)); return false; diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index bde7ee2441..762f8c82a9 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -112,6 +112,7 @@ private: int _from = 0; int _till = 0; bool _isAlbum = false; + bool _isSingleMedia = false; }; void initSendWay(); diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp index 6f7d80381a..136a1db7ec 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp @@ -109,7 +109,7 @@ AlbumThumbnail::AlbumThumbnail( }); _deleteMedia->setClickedCallback(deleteCallback); - _editMedia->setIconOverride(&st::editMediaButtonIconFile); + _editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile); _deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile); updateFileRow(-1); @@ -520,19 +520,16 @@ QRect AlbumThumbnail::paintButtons( QRect groupRect(groupX, groupY, groupWidth, size); _buttonsRect.paint(p, groupRect); - const auto editP = st::sendBoxAlbumGroupEditButtonIconPosition; - const auto deleteP = st::sendBoxAlbumGroupDeleteButtonIconPosition; - - st::sendBoxAlbumGroupEditButtonIcon.paintInCenter( + st::sendBoxAlbumGroupButtonMediaEdit.paint( p, - QRect(groupX + editP.x(), groupY + editP.y(), size, size)); - st::sendBoxAlbumGroupDeleteButtonIcon.paintInCenter( + groupX, + groupY, + outerWidth); + st::sendBoxAlbumGroupButtonMediaDelete.paint( p, - QRect( - groupX + deleteLeft + deleteP.x(), - groupY + deleteP.y(), - size, - size)); + groupX + size + skipInternal, + groupY, + outerWidth); p.setOpacity(1); return groupRect; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h index c492d4eeb0..8341f4e8c3 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h @@ -89,8 +89,8 @@ private: QRect _lastRectOfButtons; - object_ptr _editMedia = nullptr; - object_ptr _deleteMedia = nullptr; + object_ptr _editMedia = { nullptr }; + object_ptr _deleteMedia = { nullptr }; }; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp index 1e837150e6..167a46960c 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp @@ -10,8 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/attach/attach_prepare.h" #include "ui/text/format_values.h" #include "ui/text/text_options.h" +#include "ui/widgets/buttons.h" #include "ui/image/image_prepare.h" -#include "ui/cached_round_corners.h" +#include "base/timer_rpl.h" #include "core/mime_type.h" #include "styles/style_chat.h" #include "styles/style_boxes.h" @@ -23,13 +24,30 @@ namespace Ui { SingleFilePreview::SingleFilePreview( QWidget *parent, const PreparedFile &file) -: RpWidget(parent) { +: RpWidget(parent) +, _editMedia(this, st::sendBoxAlbumGroupButtonFile) +, _deleteMedia(this, st::sendBoxAlbumGroupButtonFile) { preparePreview(file); + _editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile); + _deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile); + auto h = _fileThumb.isNull() ? (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom()) : (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom()); - resize(width(), st::boxPhotoPadding.top() + h + st::msgShadow); + resize(width(), h); +} + +SingleFilePreview::~SingleFilePreview() = default; + +rpl::producer<> SingleFilePreview::editRequests() const { + return _editMedia->clicks() | rpl::map([] { + return base::timer_once(st::historyAttach.ripple.hideDuration); + }) | rpl::flatten_latest(); +} + +rpl::producer<> SingleFilePreview::deleteRequests() const { + return _deleteMedia->clicks() | rpl::to_empty; } void SingleFilePreview::prepareThumb(const QImage &preview) { @@ -134,9 +152,7 @@ void SingleFilePreview::paintEvent(QPaintEvent *e) { linktop = st::msgFileThumbLinkTop; } auto namewidth = w - nameleft - (_fileThumb.isNull() ? st::msgFilePadding.left() : st::msgFileThumbPadding.left()); - int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); - - FillRoundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow); + int32 x = (width() - w) / 2, y = 0; if (_fileThumb.isNull()) { QRect inner(style::rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width())); @@ -168,4 +184,14 @@ void SingleFilePreview::paintEvent(QPaintEvent *e) { p.drawTextLeft(x + nameleft, y + statustop, width(), _statusText); } +void SingleFilePreview::resizeEvent(QResizeEvent *e) { + const auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); + const auto x = (width() - w) / 2; + const auto top = st::sendBoxFileGroupSkipTop; + auto right = st::sendBoxFileGroupSkipRight + x; + _deleteMedia->moveToRight(right, top); + right += st::sendBoxFileGroupEditInternalSkip + _deleteMedia->width(); + _editMedia->moveToRight(right, top); +} + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h index bb06249dd2..2be57bec8e 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h @@ -8,21 +8,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/rp_widget.h" +#include "base/object_ptr.h" namespace Ui { struct PreparedFile; +class IconButton; class SingleFilePreview final : public RpWidget { public: SingleFilePreview( QWidget *parent, const PreparedFile &file); + ~SingleFilePreview(); -protected: - void paintEvent(QPaintEvent *e) override; + [[nodiscard]] rpl::producer<> deleteRequests() const; + [[nodiscard]] rpl::producer<> editRequests() const; private: + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void preparePreview(const PreparedFile &file); void prepareThumb(const QImage &preview); @@ -33,6 +39,9 @@ private: QString _statusText; int _statusWidth = 0; + object_ptr _editMedia = { nullptr }; + object_ptr _deleteMedia = { nullptr }; + }; } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp index 3d88cbb350..f6fe54b10b 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp @@ -8,11 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/attach/attach_single_media_preview.h" #include "ui/chat/attach/attach_prepare.h" +#include "ui/widgets/buttons.h" #include "core/mime_type.h" #include "lottie/lottie_single_player.h" #include "styles/style_boxes.h" #include "styles/style_chat.h" #include "styles/style_layers.h" +#include "styles/palette.h" namespace Ui { namespace { @@ -64,20 +66,27 @@ SingleMediaPreview::SingleMediaPreview( : RpWidget(parent) , _gifPaused(std::move(gifPaused)) , _animated(animated) -, _sticker(sticker) { +, _sticker(sticker) +, _editMedia(this, st::sendBoxAlbumGroupButtonMedia) +, _deleteMedia(this, st::sendBoxAlbumGroupButtonMedia) +, _buttonsRect(st::sendBoxAlbumGroupRadius, st::callFingerprintBg) { Expects(!preview.isNull()); - _canSendAsPhoto = !_animated - && !_sticker - && ValidateThumbDimensions( - preview.width(), - preview.height()); + _deleteMedia->setIconOverride(&st::sendBoxAlbumGroupButtonMediaDelete); preparePreview(preview, animatedPreviewPath); } SingleMediaPreview::~SingleMediaPreview() = default; +rpl::producer<> SingleMediaPreview::deleteRequests() const { + return _deleteMedia->clicks() | rpl::to_empty; +} + +rpl::producer<> SingleMediaPreview::editRequests() const { + return _editMedia->clicks() | rpl::to_empty; +} + void SingleMediaPreview::preparePreview( QImage preview, const QString &animatedPreviewPath) { @@ -136,7 +145,20 @@ void SingleMediaPreview::preparePreview( prepareAnimatedPreview(animatedPreviewPath); - resize(width(), st::boxPhotoPadding.top() + _previewHeight); + resize(width(), _previewHeight); +} + +void SingleMediaPreview::resizeEvent(QResizeEvent *e) { + const auto skipInternal = st::sendBoxAlbumGroupEditInternalSkip; + const auto size = st::sendBoxAlbumGroupHeight; + const auto skipRight = st::sendBoxAlbumGroupSkipRight; + const auto skipTop = st::sendBoxAlbumGroupSkipTop; + const auto groupWidth = size * 2 + skipInternal; + + const auto left = _previewLeft + _previewWidth - groupWidth - skipRight; + const auto top = skipTop; + _editMedia->move(left, top); + _deleteMedia->move(left + size + skipInternal, top); } void SingleMediaPreview::prepareAnimatedPreview( @@ -190,33 +212,33 @@ void SingleMediaPreview::paintEvent(QPaintEvent *e) { if (!_sticker) { if (_previewLeft > st::boxPhotoPadding.left()) { - p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _previewLeft - st::boxPhotoPadding.left(), _previewHeight, st::confirmBg); + p.fillRect(st::boxPhotoPadding.left(), 0, _previewLeft - st::boxPhotoPadding.left(), _previewHeight, st::confirmBg); } if (_previewLeft + _previewWidth < width() - st::boxPhotoPadding.right()) { - p.fillRect(_previewLeft + _previewWidth, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _previewLeft - _previewWidth, _previewHeight, st::confirmBg); + p.fillRect(_previewLeft + _previewWidth, 0, width() - st::boxPhotoPadding.right() - _previewLeft - _previewWidth, _previewHeight, st::confirmBg); } } if (_gifPreview && _gifPreview->started()) { auto s = QSize(_previewWidth, _previewHeight); auto paused = _gifPaused(); auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : crl::now()); - p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), frame); + p.drawPixmap(_previewLeft, 0, frame); } else if (_lottiePreview && _lottiePreview->ready()) { const auto frame = _lottiePreview->frame(); const auto size = frame.size() / style::DevicePixelRatio(); p.drawImage( QRect( _previewLeft + (_previewWidth - size.width()) / 2, - st::boxPhotoPadding.top() + (_previewHeight - size.height()) / 2, + (_previewHeight - size.height()) / 2, size.width(), size.height()), frame); _lottiePreview->markFrameShown(); } else { - p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), _preview); + p.drawPixmap(_previewLeft, 0, _preview); } if (_animated && !_gifPreview && !_lottiePreview) { - auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); p.setPen(Qt::NoPen); p.setBrush(st::msgDateImgBg); @@ -228,6 +250,21 @@ void SingleMediaPreview::paintEvent(QPaintEvent *e) { auto icon = &st::historyFileInPlay; icon->paintInCenter(p, inner); } + paintButtonsBackground(p); +} + +void SingleMediaPreview::paintButtonsBackground(QPainter &p) { + const auto skipInternal = st::sendBoxAlbumGroupEditInternalSkip; + const auto size = st::sendBoxAlbumGroupHeight; + const auto skipRight = st::sendBoxAlbumGroupSkipRight; + const auto skipTop = st::sendBoxAlbumGroupSkipTop; + const auto groupWidth = size * 2 + skipInternal; + + const auto left = _previewLeft + _previewWidth - groupWidth - skipRight; + const auto top = skipTop; + + QRect groupRect(left, top, groupWidth, size); + _buttonsRect.paint(p, groupRect); } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.h index 8f61787d63..cd79c74cac 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.h @@ -8,7 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/rp_widget.h" +#include "ui/round_rect.h" #include "media/clip/media_clip_reader.h" +#include "base/object_ptr.h" namespace Lottie { class SinglePlayer; @@ -17,8 +19,9 @@ class SinglePlayer; namespace Ui { struct PreparedFile; +class IconButton; -class SingleMediaPreview : public RpWidget { +class SingleMediaPreview final : public RpWidget { public: static SingleMediaPreview *Create( QWidget *parent, @@ -34,24 +37,23 @@ public: const QString &animatedPreviewPath); ~SingleMediaPreview(); - bool canSendAsPhoto() const { - return _canSendAsPhoto; - } - -protected: - void paintEvent(QPaintEvent *e) override; + [[nodiscard]] rpl::producer<> deleteRequests() const; + [[nodiscard]] rpl::producer<> editRequests() const; private: + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void preparePreview( QImage preview, const QString &animatedPreviewPath); void prepareAnimatedPreview(const QString &animatedPreviewPath); + void paintButtonsBackground(QPainter &p); void clipCallback(Media::Clip::Notification notification); Fn _gifPaused; bool _animated = false; bool _sticker = false; - bool _canSendAsPhoto = false; QPixmap _preview; int _previewLeft = 0; int _previewWidth = 0; @@ -59,6 +61,10 @@ private: Media::Clip::ReaderPointer _gifPreview; std::unique_ptr _lottiePreview; + object_ptr _editMedia = { nullptr }; + object_ptr _deleteMedia = { nullptr }; + RoundRect _buttonsRect; + }; } // namespace Ui