Add edit/remove buttons to Single[File|Media]Preview.

This commit is contained in:
John Preston 2020-10-19 11:49:31 +03:00
parent 5589f51369
commit d7fe2948ac
9 changed files with 162 additions and 65 deletions

View file

@ -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;

View file

@ -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<Ui::RpWidget> SendFilesBox::Block::takeWidget() {
}
rpl::producer<int> SendFilesBox::Block::itemDeleteRequest() const {
if (!_isAlbum) {
return rpl::never<int>();
using namespace rpl::mappers;
const auto preview = _preview.get();
if (_isAlbum) {
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
return album->thumbDeleted() | rpl::map(_1 + _from);
} else if (_isSingleMedia) {
const auto media = static_cast<Ui::SingleMediaPreview*>(preview);
return media->deleteRequests() | rpl::map([=] { return _from; });
} else {
const auto single = static_cast<Ui::SingleFilePreview*>(preview);
return single->deleteRequests() | rpl::map([=] { return _from; });
}
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
return album->thumbDeleted();
}
rpl::producer<int> SendFilesBox::Block::itemReplaceRequest() const {
if (!_isAlbum) {
return rpl::never<int>();
using namespace rpl::mappers;
const auto preview = _preview.get();
if (_isAlbum) {
const auto album = static_cast<Ui::AlbumPreview*>(preview);
return album->thumbChanged() | rpl::map(_1 + _from);
} else if (_isSingleMedia) {
const auto media = static_cast<Ui::SingleMediaPreview*>(preview);
return media->editRequests() | rpl::map([=] { return _from; });
} else {
const auto single = static_cast<Ui::SingleFilePreview*>(preview);
return single->editRequests() | rpl::map([=] { return _from; });
}
const auto album = static_cast<Ui::AlbumPreview*>(_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;

View file

@ -112,6 +112,7 @@ private:
int _from = 0;
int _till = 0;
bool _isAlbum = false;
bool _isSingleMedia = false;
};
void initSendWay();

View file

@ -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;

View file

@ -89,8 +89,8 @@ private:
QRect _lastRectOfButtons;
object_ptr<IconButton> _editMedia = nullptr;
object_ptr<IconButton> _deleteMedia = nullptr;
object_ptr<IconButton> _editMedia = { nullptr };
object_ptr<IconButton> _deleteMedia = { nullptr };
};

View file

@ -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

View file

@ -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<IconButton> _editMedia = { nullptr };
object_ptr<IconButton> _deleteMedia = { nullptr };
};
} // namespace Ui

View file

@ -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

View file

@ -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<bool()> _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<Lottie::SinglePlayer> _lottiePreview;
object_ptr<IconButton> _editMedia = { nullptr };
object_ptr<IconButton> _deleteMedia = { nullptr };
RoundRect _buttonsRect;
};
} // namespace Ui