Added reply header with preview to send files box.

This commit is contained in:
23rd
2026-04-13 11:06:47 +03:00
parent 91145dc868
commit 04aec11daa
15 changed files with 603 additions and 16 deletions
+2
View File
@@ -356,6 +356,8 @@ PRIVATE
boxes/send_gif_with_caption_box.h
boxes/send_files_box.cpp
boxes/send_files_box.h
boxes/send_files_box_reply_header.cpp
boxes/send_files_box_reply_header.h
boxes/share_box.cpp
boxes/share_box.h
boxes/star_gift_auction_box.cpp
+1
View File
@@ -59,6 +59,7 @@ boxPhotoTitlePosition: point(28px, 20px);
boxPhotoPadding: margins(28px, 28px, 28px, 18px);
boxPhotoCompressedSkip: 20px;
boxPhotoCaptionSkip: 8px;
boxPhotoCaptionReplyOverlap: 5px;
defaultChangeUserpicIcon: icon {{ "new_chat_photo", activeButtonFg }};
defaultUploadUserpicIcon: icon {{ "upload_chat_photo", msgDateImgFg }};
+68 -3
View File
@@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/premium_preview_box.h"
#include "boxes/send_gif_with_caption_box.h"
#include "boxes/send_credits_box.h"
#include "boxes/send_files_box_reply_header.h"
#include "ui/effects/scroll_content_shadow.h"
#include "ui/widgets/fields/number_input.h"
#include "ui/widgets/checkbox.h"
@@ -429,6 +430,10 @@ int SendFilesBox::Block::fromIndex() const {
return _from;
}
bool SendFilesBox::Block::isSingleFile() const {
return !_isAlbum && !_isSingleMedia;
}
int SendFilesBox::Block::tillIndex() const {
return _till;
}
@@ -646,9 +651,58 @@ SendFilesBox::SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor)
, _inner(
_scroll->setOwnedWidget(
object_ptr<Ui::VerticalLayout>(_scroll.data()))) {
setReplyTo(descriptor.replyTo);
enqueueNextPrepare();
}
void SendFilesBox::setReplyTo(FullReplyTo replyTo) {
if (_replyTo == replyTo) {
return;
} else if (!replyTo.messageId || !replyTo.messageId.peer) {
_replyTo = {};
if (_replyHeader) {
_replyHeader->hideAnimated();
}
return;
}
_replyTo = replyTo;
if (_replyHeader) {
_replyHeader = nullptr;
_replyHeaderHeight = 0;
}
_replyHeader = std::make_unique<SendFiles::ReplyPillHeader>(
this,
_show,
std::move(replyTo));
_replyHeader->setRoundedShapeBelow(
!_blocks.empty() && !_blocks.front().isSingleFile());
_replyHeader->show();
_replyHeader->desiredHeight(
) | rpl::on_next([=](int height) {
if (_replyHeaderHeight.current() != height) {
_replyHeaderHeight = height;
updateBoxSize();
updateControlsGeometry();
}
}, _replyHeader->lifetime());
_replyHeader->closeRequests(
) | rpl::on_next([=] {
_replyTo = {};
if (_replyHeader) {
_replyHeader->hideAnimated();
}
}, _replyHeader->lifetime());
_replyHeader->hideFinished(
) | rpl::on_next([=] {
InvokeQueued(this, [=] {
_replyHeader = nullptr;
_replyHeaderHeight = 0;
updateBoxSize();
updateControlsGeometry();
});
}, _replyHeader->lifetime());
}
Fn<SendMenu::Details()> SendFilesBox::prepareSendMenuDetails(
const SendFilesBoxDescriptor &descriptor) {
auto initial = descriptor.sendMenuDetails;
@@ -1219,6 +1273,10 @@ void SendFilesBox::generatePreviewFrom(int fromBlock) {
if (albumStart >= 0) {
pushBlock(albumStart, _list.files.size());
}
if (_replyHeader) {
_replyHeader->setRoundedShapeBelow(
!_blocks.empty() && !_blocks.front().isSingleFile());
}
}
void SendFilesBox::pushBlock(int from, int till) {
@@ -2083,6 +2141,7 @@ void SendFilesBox::updateBoxSize() {
if (!_caption->isHidden()) {
footerHeight += st::boxPhotoCaptionSkip + _caption->height();
}
footerHeight += _replyHeaderHeight.current();
const auto pairs = std::array<std::pair<RpWidget*, int>, 4>{ {
{ _groupFiles.data(), st::boxPhotoCompressedSkip },
{ _sendImagesAsPhotos.data(), st::boxPhotoCompressedSkip },
@@ -2170,8 +2229,14 @@ void SendFilesBox::updateControlsGeometry() {
bottom -= pair.second + pointer->heightNoMargins();
}
}
_scroll->resize(width(), bottom - _titleHeight.current());
_scroll->move(0, _titleHeight.current());
const auto replyH = _replyHeaderHeight.current();
const auto replyTopOverlap = std::min(st::boxPhotoCaptionSkip, replyH);
const auto replyTop = _titleHeight.current() - replyTopOverlap;
if (_replyHeader) {
_replyHeader->setGeometry(0, replyTop, width(), replyH);
}
_scroll->resize(width(), bottom - replyTop - replyH);
_scroll->move(0, replyTop + replyH);
}
void SendFilesBox::showFinished() {
@@ -2316,7 +2381,7 @@ void SendFilesBox::send(
}
}
_confirmedCallback(std::move(bundle), options);
_confirmedCallback(std::move(bundle), options, _replyTo);
}
closeBox();
}
+14 -1
View File
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "base/flags.h"
#include "data/data_msg_id.h"
#include "ui/layers/box_content.h"
#include "ui/chat/attach/attach_prepare.h"
#include "ui/chat/attach/attach_send_files_way.h"
@@ -62,6 +63,10 @@ class CharactersLimitLabel;
class ComposeAiButton;
} // namespace HistoryView::Controls
namespace SendFiles {
class ReplyPillHeader;
} // namespace SendFiles
enum class SendFilesAllow {
OnlyOne = (1 << 0),
Photos = (1 << 1),
@@ -91,7 +96,8 @@ using SendFilesCheck = Fn<bool(
using SendFilesConfirmed = Fn<void(
std::shared_ptr<Ui::PreparedBundle>,
Api::SendOptions)>;
Api::SendOptions,
FullReplyTo)>;
struct SendFilesBoxDescriptor {
std::shared_ptr<ChatHelpers::Show> show;
@@ -105,6 +111,7 @@ struct SendFilesBoxDescriptor {
const style::ComposeControls *stOverride = nullptr;
SendFilesConfirmed confirmed;
Fn<void()> cancelled;
FullReplyTo replyTo;
};
class SendFilesBox : public Ui::BoxContent {
@@ -129,6 +136,7 @@ public:
void setCancelledCallback(Fn<void()> callback) {
_cancelledCallback = std::move(callback);
}
void setReplyTo(FullReplyTo replyTo);
[[nodiscard]] rpl::producer<TextWithTags> takeTextWithTagsRequests() const;
@@ -164,6 +172,7 @@ private:
[[nodiscard]] int fromIndex() const;
[[nodiscard]] int tillIndex() const;
[[nodiscard]] bool isSingleFile() const;
[[nodiscard]] object_ptr<Ui::RpWidget> takeWidget();
[[nodiscard]] rpl::producer<int> itemDeleteRequest() const;
@@ -315,6 +324,10 @@ private:
rpl::variable<int> _footerHeight = 0;
rpl::lifetime _dimensionsLifetime;
std::unique_ptr<SendFiles::ReplyPillHeader> _replyHeader;
rpl::variable<int> _replyHeaderHeight = 0;
FullReplyTo _replyTo;
object_ptr<Ui::ScrollArea> _scroll;
QPointer<Ui::VerticalLayout> _inner;
std::deque<Block> _blocks;
@@ -0,0 +1,372 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/send_files_box_reply_header.h"
#include "chat_helpers/compose/compose_show.h"
#include "core/ui_integration.h"
#include "data/data_changes.h"
#include "data/data_media_types.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/view/history_view_reply.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/chat/chat_style.h"
#include "ui/effects/spoiler_mess.h"
#include "ui/image/image.h"
#include "ui/painter.h"
#include "ui/text/text_options.h"
#include "ui/power_saving.h"
#include "ui/widgets/buttons.h"
#include "window/window_session_controller.h"
#include "apiwrap.h"
#include "styles/style_boxes.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_dialogs.h"
namespace SendFiles {
namespace {
constexpr auto kAnimationDuration = crl::time(180);
} // namespace
ReplyPillHeader::ReplyPillHeader(
QWidget *parent,
std::shared_ptr<ChatHelpers::Show> show,
FullReplyTo replyTo)
: RpWidget(parent)
, _show(std::move(show))
, _data(&_show->session().data())
, _replyTo(std::move(replyTo))
, _cancel(Ui::CreateChild<Ui::IconButton>(this, st::sendFilesReplyCancel)) {
resize(
parent->width(),
st::boxPhotoCaptionSkip + st::historyReplyHeight);
_cancel->setAccessibleName(tr::lng_cancel(tr::now));
_cancel->setClickedCallback([=] {
hideAnimated();
});
setShownMessage(_data->message(_replyTo.messageId));
_data->session().changes().messageUpdates(
Data::MessageUpdate::Flag::Edited
| Data::MessageUpdate::Flag::Destroyed
) | rpl::filter([=](const Data::MessageUpdate &update) {
return (update.item == _shownMessage);
}) | rpl::on_next([=](const Data::MessageUpdate &update) {
if (update.flags & Data::MessageUpdate::Flag::Destroyed) {
_shownMessage = nullptr;
_shownMessageName.clear();
_shownMessageText.clear();
hideAnimated();
} else {
updateShownMessageText();
RpWidget::update();
}
}, lifetime());
animationCallback();
}
ReplyPillHeader::~ReplyPillHeader() = default;
rpl::producer<> ReplyPillHeader::closeRequests() const {
return _closeRequests.events();
}
rpl::producer<> ReplyPillHeader::hideFinished() const {
return _hideFinished.value()
| rpl::filter(rpl::mappers::_1)
| rpl::to_empty;
}
rpl::producer<int> ReplyPillHeader::desiredHeight() const {
return _desiredHeight.value();
}
void ReplyPillHeader::setRoundedShapeBelow(bool value) {
if (_roundedShapeBelow == value) {
return;
}
_roundedShapeBelow = value;
update();
}
void ReplyPillHeader::hideAnimated() {
if (_hiding) {
return;
}
_hiding = true;
_closeRequests.fire({});
_showAnimation.start(
[=] { animationCallback(); },
1.,
0.,
kAnimationDuration);
}
void ReplyPillHeader::animationCallback() {
const auto full = st::boxPhotoCaptionSkip + st::historyReplyHeight;
const auto value = _showAnimation.value(_hiding ? 0. : 1.);
_desiredHeight = int(base::SafeRound(full * value));
update();
if (_hiding && !_showAnimation.animating()) {
_hideFinished = true;
}
}
void ReplyPillHeader::resolveMessageData() {
const auto id = _replyTo.messageId;
if (!id || !id.peer) {
return;
}
const auto peer = _data->peer(id.peer);
const auto itemId = id.msg;
const auto callback = crl::guard(this, [=] {
if (!_shownMessage) {
if (const auto message = _data->message(peer, itemId)) {
setShownMessage(message);
} else {
hideAnimated();
}
}
});
_data->session().api().requestMessageData(peer, itemId, callback);
}
void ReplyPillHeader::setShownMessage(HistoryItem *item) {
_shownMessage = item;
if (item) {
updateShownMessageText();
const auto context = Core::TextContext({
.session = &item->history()->session(),
.customEmojiLoopLimit = 1,
});
_shownMessageName.setMarkedText(
st::fwdTextStyle,
HistoryView::Reply::ComposePreviewName(
item->history(),
item,
_replyTo),
Ui::NameTextOptions(),
context);
} else {
_shownMessageName.clear();
_shownMessageText.clear();
resolveMessageData();
}
update();
}
void ReplyPillHeader::updateShownMessageText() {
Expects(_shownMessage != nullptr);
const auto context = Core::TextContext({
.session = &_data->session(),
.repaint = [=] { customEmojiRepaint(); },
});
_shownMessageText.setMarkedText(
st::messageTextStyle,
(_replyTo.quote.empty()
? _shownMessage->inReplyText()
: _replyTo.quote),
Ui::DialogTextOptions(),
context);
}
void ReplyPillHeader::customEmojiRepaint() {
if (_repaintScheduled) {
return;
}
_repaintScheduled = true;
update();
}
void ReplyPillHeader::resizeEvent(QResizeEvent *e) {
_cancel->moveToRight(
st::boxPhotoPadding.right() + st::sendBoxAlbumGroupSkipRight,
(st::historyReplyHeight - _cancel->height()) / 2);
}
void ReplyPillHeader::paintEvent(QPaintEvent *e) {
_repaintScheduled = false;
Painter p(this);
p.setInactive(_show->paused(Window::GifPauseReason::Layer));
const auto left = st::boxPhotoPadding.left();
const auto right = st::boxPhotoPadding.right();
const auto bottomSkip = st::boxPhotoCaptionSkip;
const auto pillHeight = height() - bottomSkip;
if (pillHeight <= 0) {
return;
}
const auto pillRect = QRect(
left,
0,
width() - left - right,
pillHeight);
if (pillRect.isEmpty()) {
return;
}
{
auto hq = PainterHighQualityEnabler(p);
p.setPen(Qt::NoPen);
p.setBrush(st::windowBgOver);
const auto topRadius = st::bubbleRadiusLarge;
const auto bottomRadius = _roundedShapeBelow
? st::bubbleRadiusSmall
: st::bubbleRadiusLarge;
const auto rectF = QRectF(pillRect);
auto path = QPainterPath();
path.moveTo(rectF.left() + topRadius, rectF.top());
path.lineTo(rectF.right() - topRadius, rectF.top());
path.arcTo(
rectF.right() - 2 * topRadius,
rectF.top(),
2 * topRadius,
2 * topRadius,
90, -90);
path.lineTo(rectF.right(), rectF.bottom() - bottomRadius);
path.arcTo(
rectF.right() - 2 * bottomRadius,
rectF.bottom() - 2 * bottomRadius,
2 * bottomRadius,
2 * bottomRadius,
0, -90);
path.lineTo(rectF.left() + bottomRadius, rectF.bottom());
path.arcTo(
rectF.left(),
rectF.bottom() - 2 * bottomRadius,
2 * bottomRadius,
2 * bottomRadius,
270, -90);
path.lineTo(rectF.left(), rectF.top() + topRadius);
path.arcTo(
rectF.left(),
rectF.top(),
2 * topRadius,
2 * topRadius,
180, -90);
path.closeSubpath();
p.fillPath(path, st::windowBgOver);
}
const auto iconPos = st::sendFilesReplyIconPosition
+ QPoint(pillRect.left(), pillRect.top());
if (!_replyTo.quote.empty()) {
st::historyQuoteIcon.paint(p, iconPos, width());
} else {
st::historyReplyIcon.paint(p, iconPos, width());
// Remove 'settings' mini-icon.
p.fillRect(
QRect(
QPoint(style::ConvertScale(16), style::ConvertScale(5))
+ iconPos,
QSize(style::ConvertScale(11), style::ConvertScale(8))),
st::windowBgOver);
p.fillRect(
QRect(
QPoint(style::ConvertScale(22), style::ConvertScale(13))
+ iconPos,
QSize(style::ConvertScale(5), style::ConvertScale(2))),
st::windowBgOver);
}
const auto replySkip = st::historyReplySkip;
const auto textLeft = pillRect.left() + replySkip;
const auto availableWidth = _cancel->x() - textLeft;
if (availableWidth <= 0) {
return;
}
const auto pillCenterY = pillRect.top()
+ st::historyReplyHeight / 2;
if (!_shownMessage) {
p.setFont(st::msgDateFont);
p.setPen(st::historyComposeAreaFgService);
const auto top = pillCenterY - st::msgDateFont->height / 2;
p.drawText(
textLeft,
top + st::msgDateFont->ascent,
st::msgDateFont->elided(
tr::lng_profile_loading(tr::now),
availableWidth));
return;
}
const auto media = _shownMessage->media();
const auto hasPreview = media && media->hasReplyPreview();
const auto preview = hasPreview ? media->replyPreview() : nullptr;
const auto spoilered = media && media->hasSpoiler();
if (!spoilered) {
_previewSpoiler = nullptr;
} else if (!_previewSpoiler) {
_previewSpoiler = std::make_unique<Ui::SpoilerAnimation>([=] {
update();
});
}
const auto previewSkipValue = st::historyReplyPreview + st::msgReplyBarSkip;
const auto previewSkip = (hasPreview && preview) ? previewSkipValue : 0;
const auto contentLeft = textLeft + previewSkip;
const auto contentAvailable = availableWidth - previewSkip;
if (preview) {
const auto to = QRect(
textLeft,
pillCenterY - st::historyReplyPreview / 2,
st::historyReplyPreview,
st::historyReplyPreview);
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
preview->size() / style::DevicePixelRatio(),
{
.options = Images::Option::RoundSmall,
.outer = to.size(),
}));
if (_previewSpoiler) {
Ui::FillSpoilerRect(
p,
to,
Ui::DefaultImageSpoiler().frame(
_previewSpoiler->index(crl::now(), p.inactive())));
}
}
p.setPen(st::historyReplyNameFg);
p.setFont(st::msgServiceNameFont);
_shownMessageName.drawElided(
p,
contentLeft,
pillRect.top() + st::msgReplyPadding.top(),
contentAvailable);
p.setPen(st::historyComposeAreaFg);
_shownMessageText.draw(p, {
.position = QPoint(
contentLeft,
pillRect.top()
+ st::msgReplyPadding.top()
+ st::msgServiceNameFont->height),
.availableWidth = contentAvailable,
.palette = &st::historyComposeAreaPalette,
.spoiler = Ui::Text::DefaultSpoilerCache(),
.now = crl::now(),
.pausedEmoji = p.inactive() || On(PowerSaving::kEmojiChat),
.pausedSpoiler = p.inactive() || On(PowerSaving::kChatSpoiler),
.elisionLines = 1,
});
}
} // namespace SendFiles
@@ -0,0 +1,77 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/effects/animations.h"
#include "ui/rp_widget.h"
#include "ui/text/text.h"
class HistoryItem;
namespace ChatHelpers {
class Show;
} // namespace ChatHelpers
namespace Data {
class Session;
} // namespace Data
namespace Ui {
class IconButton;
class SpoilerAnimation;
} // namespace Ui
namespace SendFiles {
class ReplyPillHeader final : public Ui::RpWidget {
public:
ReplyPillHeader(
QWidget *parent,
std::shared_ptr<ChatHelpers::Show> show,
FullReplyTo replyTo);
~ReplyPillHeader();
[[nodiscard]] rpl::producer<> closeRequests() const;
[[nodiscard]] rpl::producer<> hideFinished() const;
[[nodiscard]] rpl::producer<int> desiredHeight() const;
void setRoundedShapeBelow(bool value);
void hideAnimated();
protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
private:
void resolveMessageData();
void setShownMessage(HistoryItem *item);
void updateShownMessageText();
void customEmojiRepaint();
void animationCallback();
const std::shared_ptr<ChatHelpers::Show> _show;
const not_null<Data::Session*> _data;
const FullReplyTo _replyTo;
const not_null<Ui::IconButton*> _cancel;
HistoryItem *_shownMessage = nullptr;
Ui::Text::String _shownMessageName;
Ui::Text::String _shownMessageText;
std::unique_ptr<Ui::SpoilerAnimation> _previewSpoiler;
bool _repaintScheduled = false;
Ui::Animations::Simple _showAnimation;
rpl::variable<int> _desiredHeight = 0;
rpl::event_stream<> _closeRequests;
rpl::variable<bool> _hideFinished = false;
bool _hiding = false;
bool _roundedShapeBelow = true;
};
} // namespace SendFiles
@@ -609,7 +609,7 @@ sendBoxAlbumSmallGroupSize: size(30px, 25px);
sendBoxAlbumSmallGroupCircleSize: 27px;
sendBoxFileGroupSkipTop: 2px;
sendBoxFileGroupSkipRight: 5px;
sendBoxFileGroupSkipRight: 1px;
sendBoxFileGroupEditInternalSkip: -1px;
sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
@@ -622,7 +622,7 @@ sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "send_media/send_media_cross", me
sendBoxAlbumButtonMediaMore: icon {{ "send_media/send_media_more", roundedFg }};
sendBoxAlbumGroupButtonMediaMore: icon {{ "send_media/send_media_more", roundedFg, point(4px, 1px) }};
sendBoxAlbumGroupButtonMediaDelete: icon {{ "send_media/send_media_cross", roundedFg, point(-2px, 1px) }};
sendBoxAlbumGroupButtonMediaDelete: icon {{ "send_media/send_media_cross", roundedFg }};
defaultComposeIcons: ComposeIcons {
settings: icon {{ "emoji/emoji_settings", emojiIconFg }};
@@ -1033,6 +1033,19 @@ historyPinnedShowAll: IconButton(historyReplyCancel) {
icon: icon {{ "pinned_show_all", historyReplyCancelFg }};
iconOver: icon {{ "pinned_show_all", historyReplyCancelFgOver }};
}
sendFilesReplyIconPosition: point(11px, 7px);
sendFilesReplyCancelSize: 24px;
sendFilesReplyCancel: IconButton(editMediaButton) {
width: sendFilesReplyCancelSize;
height: sendFilesReplyCancelSize;
icon: icon {{ "send_media/send_media_cross", historyReplyCancelFg }};
iconOver: icon {{ "send_media/send_media_cross", historyReplyCancelFgOver }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgRipple;
}
rippleAreaSize: sendFilesReplyCancelSize;
}
historyPinnedBotButton: RoundButton(defaultActiveButton) {
width: -34px;
height: 30px;
@@ -1368,9 +1368,14 @@ void HistoryWidget::sendTextAsFile(
_peer,
Api::SendType::Normal,
sendMenuDetails());
box->setReplyTo(replyTo());
box->setConfirmedCallback(crl::guard(this, [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options) {
Api::SendOptions options,
FullReplyTo currentReplyTo) {
if (!currentReplyTo.messageId && replyTo().messageId) {
cancelReply();
}
sendingFilesConfirmed(std::move(bundle), options);
}));
box->setCancelledCallback(crl::guard(this, [=] {
@@ -6782,10 +6787,15 @@ bool HistoryWidget::confirmSendingFiles(
_peer,
Api::SendType::Normal,
sendMenuDetails());
box->setReplyTo(replyTo());
_field->setTextWithTags({});
box->setConfirmedCallback(crl::guard(this, [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options) {
Api::SendOptions options,
FullReplyTo currentReplyTo) {
if (!currentReplyTo.messageId && replyTo().messageId) {
cancelReply();
}
sendingFilesConfirmed(std::move(bundle), options);
}));
box->setCancelledCallback(crl::guard(this, [=] {
@@ -3384,6 +3384,16 @@ void ComposeControls::fireSendTextAsFile(
? Api::SendType::ScheduledToUser
: Api::SendType::Scheduled)
: Api::SendType::Normal;
auto confirmed = [=, callback = _sendAsFileConfirmed](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options,
FullReplyTo replyTo) {
if (!replyTo.messageId
&& replyingToMessage().messageId) {
cancelReplyMessage();
}
callback(std::move(bundle), options);
};
_show->show(Box<SendFilesBox>(SendFilesBoxDescriptor{
.show = _show,
.list = Ui::PrepareTextAsFile(fileText),
@@ -3394,8 +3404,9 @@ void ComposeControls::fireSendTextAsFile(
.sendType = sendType,
.sendMenuDetails = _sendMenuDetails,
.stOverride = &_st,
.confirmed = _sendAsFileConfirmed,
.confirmed = std::move(confirmed),
.cancelled = std::move(restoreText),
.replyTo = replyingToMessage(),
}));
}
@@ -1192,10 +1192,16 @@ bool ChatWidget::confirmSendingFiles(
_peer,
Api::SendType::Normal,
sendMenuDetails());
box->setReplyTo(_composeControls->replyingToMessage());
box->setConfirmedCallback(crl::guard(this, [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options) {
Api::SendOptions options,
FullReplyTo currentReplyTo) {
if (!currentReplyTo.messageId
&& _composeControls->replyingToMessage().messageId) {
_composeControls->cancelReplyMessage();
}
sendingFilesConfirmed(std::move(bundle), options);
}));
box->setCancelledCallback(_composeControls->restoreTextCallback(
@@ -575,7 +575,8 @@ bool ScheduledWidget::confirmSendingFiles(
box->setConfirmedCallback(crl::guard(this, [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options) {
Api::SendOptions options,
FullReplyTo) {
sendingFilesConfirmed(std::move(bundle), options);
}));
box->setCancelledCallback(_composeControls->restoreTextCallback(
@@ -668,8 +668,11 @@ bool ReplyArea::confirmSendingFiles(
}
const auto show = _controller->uiShow();
auto confirmed = [=](auto &&...args) {
sendingFilesConfirmed(std::forward<decltype(args)>(args)...);
auto confirmed = [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options,
FullReplyTo) {
sendingFilesConfirmed(std::move(bundle), options);
};
show->show(Box<SendFilesBox>(SendFilesBoxDescriptor{
.show = show,
@@ -1344,7 +1344,8 @@ bool ShortcutMessages::confirmSendingFiles(
box->setConfirmedCallback(crl::guard(this, [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options) {
Api::SendOptions options,
FullReplyTo) {
sendingFilesConfirmed(std::move(bundle), options);
}));
box->setCancelledCallback(_composeControls->restoreTextCallback(
@@ -175,8 +175,19 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
}
});
auto hq = std::optional<PainterHighQualityEnabler>();
if (drawBackground()) {
const auto &padding = st::boxPhotoPadding;
const auto bgRect = QRect(
padding.left(),
0,
width() - padding.left() - padding.right(),
height());
const auto radius = st::bubbleRadiusSmall;
auto clipPath = QPainterPath();
clipPath.addRoundedRect(bgRect, radius, radius);
hq.emplace(p);
p.setClipPath(clipPath);
if (_previewLeft > padding.left()) {
p.fillRect(
padding.left(),
@@ -100,11 +100,12 @@ void SessionController::showDrawToReplyFilesBox(
.sendType = Api::SendType::Normal,
.confirmed = crl::guard(this, [=](
std::shared_ptr<Ui::PreparedBundle> bundle,
Api::SendOptions options) {
Api::SendOptions options,
FullReplyTo currentReplyTo) {
if (const auto thread = weak.get()) {
sendDrawToReplyFiles(
thread,
replyTo,
currentReplyTo.messageId,
std::move(bundle),
options);
}