diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index f5c3c1499c..b6499165b8 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -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 diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 0698689800..bf1caf551f 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -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 }}; diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 2b1eb7085f..a7535d837d 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -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(_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( + 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 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, 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(); } diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index 3f37e872e8..ca9e1d64fb 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -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, - Api::SendOptions)>; + Api::SendOptions, + FullReplyTo)>; struct SendFilesBoxDescriptor { std::shared_ptr show; @@ -105,6 +111,7 @@ struct SendFilesBoxDescriptor { const style::ComposeControls *stOverride = nullptr; SendFilesConfirmed confirmed; Fn cancelled; + FullReplyTo replyTo; }; class SendFilesBox : public Ui::BoxContent { @@ -129,6 +136,7 @@ public: void setCancelledCallback(Fn callback) { _cancelledCallback = std::move(callback); } + void setReplyTo(FullReplyTo replyTo); [[nodiscard]] rpl::producer takeTextWithTagsRequests() const; @@ -164,6 +172,7 @@ private: [[nodiscard]] int fromIndex() const; [[nodiscard]] int tillIndex() const; + [[nodiscard]] bool isSingleFile() const; [[nodiscard]] object_ptr takeWidget(); [[nodiscard]] rpl::producer itemDeleteRequest() const; @@ -315,6 +324,10 @@ private: rpl::variable _footerHeight = 0; rpl::lifetime _dimensionsLifetime; + std::unique_ptr _replyHeader; + rpl::variable _replyHeaderHeight = 0; + FullReplyTo _replyTo; + object_ptr _scroll; QPointer _inner; std::deque _blocks; diff --git a/Telegram/SourceFiles/boxes/send_files_box_reply_header.cpp b/Telegram/SourceFiles/boxes/send_files_box_reply_header.cpp new file mode 100644 index 0000000000..881ca1fb7f --- /dev/null +++ b/Telegram/SourceFiles/boxes/send_files_box_reply_header.cpp @@ -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 show, + FullReplyTo replyTo) +: RpWidget(parent) +, _show(std::move(show)) +, _data(&_show->session().data()) +, _replyTo(std::move(replyTo)) +, _cancel(Ui::CreateChild(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 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([=] { + 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 diff --git a/Telegram/SourceFiles/boxes/send_files_box_reply_header.h b/Telegram/SourceFiles/boxes/send_files_box_reply_header.h new file mode 100644 index 0000000000..9515c896fd --- /dev/null +++ b/Telegram/SourceFiles/boxes/send_files_box_reply_header.h @@ -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 show, + FullReplyTo replyTo); + ~ReplyPillHeader(); + + [[nodiscard]] rpl::producer<> closeRequests() const; + [[nodiscard]] rpl::producer<> hideFinished() const; + [[nodiscard]] rpl::producer 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 _show; + const not_null _data; + const FullReplyTo _replyTo; + const not_null _cancel; + + HistoryItem *_shownMessage = nullptr; + Ui::Text::String _shownMessageName; + Ui::Text::String _shownMessageText; + std::unique_ptr _previewSpoiler; + bool _repaintScheduled = false; + + Ui::Animations::Simple _showAnimation; + rpl::variable _desiredHeight = 0; + rpl::event_stream<> _closeRequests; + rpl::variable _hideFinished = false; + bool _hiding = false; + bool _roundedShapeBelow = true; + +}; + +} // namespace SendFiles diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 4bc15a36ab..bffe23d89b 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -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; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index fe7a9944a6..0f3a21055b 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1368,9 +1368,14 @@ void HistoryWidget::sendTextAsFile( _peer, Api::SendType::Normal, sendMenuDetails()); + box->setReplyTo(replyTo()); box->setConfirmedCallback(crl::guard(this, [=]( std::shared_ptr 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 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, [=] { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index ff637d9966..e376e72623 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -3384,6 +3384,16 @@ void ComposeControls::fireSendTextAsFile( ? Api::SendType::ScheduledToUser : Api::SendType::Scheduled) : Api::SendType::Normal; + auto confirmed = [=, callback = _sendAsFileConfirmed]( + std::shared_ptr bundle, + Api::SendOptions options, + FullReplyTo replyTo) { + if (!replyTo.messageId + && replyingToMessage().messageId) { + cancelReplyMessage(); + } + callback(std::move(bundle), options); + }; _show->show(Box(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(), })); } diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp index 8d09db7458..138dd8f110 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp @@ -1192,10 +1192,16 @@ bool ChatWidget::confirmSendingFiles( _peer, Api::SendType::Normal, sendMenuDetails()); + box->setReplyTo(_composeControls->replyingToMessage()); box->setConfirmedCallback(crl::guard(this, [=]( std::shared_ptr 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( diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 904dddc0e6..cae8dc159e 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -575,7 +575,8 @@ bool ScheduledWidget::confirmSendingFiles( box->setConfirmedCallback(crl::guard(this, [=]( std::shared_ptr bundle, - Api::SendOptions options) { + Api::SendOptions options, + FullReplyTo) { sendingFilesConfirmed(std::move(bundle), options); })); box->setCancelledCallback(_composeControls->restoreTextCallback( diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index 1164fc3398..b745473553 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -668,8 +668,11 @@ bool ReplyArea::confirmSendingFiles( } const auto show = _controller->uiShow(); - auto confirmed = [=](auto &&...args) { - sendingFilesConfirmed(std::forward(args)...); + auto confirmed = [=]( + std::shared_ptr bundle, + Api::SendOptions options, + FullReplyTo) { + sendingFilesConfirmed(std::move(bundle), options); }; show->show(Box(SendFilesBoxDescriptor{ .show = show, diff --git a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp index 908bd3eee2..bfb96335f6 100644 --- a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp +++ b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp @@ -1344,7 +1344,8 @@ bool ShortcutMessages::confirmSendingFiles( box->setConfirmedCallback(crl::guard(this, [=]( std::shared_ptr bundle, - Api::SendOptions options) { + Api::SendOptions options, + FullReplyTo) { sendingFilesConfirmed(std::move(bundle), options); })); box->setCancelledCallback(_composeControls->restoreTextCallback( diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp index d312bbc458..5a08892251 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp @@ -175,8 +175,19 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) { } }); + auto hq = std::optional(); 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(), diff --git a/Telegram/SourceFiles/window/session/window_session_media.cpp b/Telegram/SourceFiles/window/session/window_session_media.cpp index 3e9f54c99a..dbb6cc43fb 100644 --- a/Telegram/SourceFiles/window/session/window_session_media.cpp +++ b/Telegram/SourceFiles/window/session/window_session_media.cpp @@ -100,11 +100,12 @@ void SessionController::showDrawToReplyFilesBox( .sendType = Api::SendType::Normal, .confirmed = crl::guard(this, [=]( std::shared_ptr bundle, - Api::SendOptions options) { + Api::SendOptions options, + FullReplyTo currentReplyTo) { if (const auto thread = weak.get()) { sendDrawToReplyFiles( thread, - replyTo, + currentReplyTo.messageId, std::move(bundle), options); }