Improve reply preview above the field.
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 759 B |
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/chat/input_link_settings.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
Telegram/Resources/icons/chat/input_link_settings@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/chat/input_link_settings@3x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 593 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_quote.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
Telegram/Resources/icons/chat/input_reply_quote@2x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_quote@3x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_settings.png
Normal file
After Width: | Height: | Size: 711 B |
BIN
Telegram/Resources/icons/chat/input_reply_settings@2x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_settings@3x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
|
@ -2714,6 +2714,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_forwarding_from_two" = "{user} and {second_user}";
|
"lng_forwarding_from_two" = "{user} and {second_user}";
|
||||||
"lng_inline_switch_choose" = "Choose conversation...";
|
"lng_inline_switch_choose" = "Choose conversation...";
|
||||||
"lng_inline_switch_cant" = "Sorry, no way to write here :(";
|
"lng_inline_switch_cant" = "Sorry, no way to write here :(";
|
||||||
|
"lng_preview_reply_to" = "Reply to {name}";
|
||||||
|
"lng_preview_reply_to_quote" = "Reply to quote by {name}";
|
||||||
|
|
||||||
"lng_reply_in_another_title" = "Reply in...";
|
"lng_reply_in_another_title" = "Reply in...";
|
||||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||||
|
|
|
@ -827,11 +827,13 @@ historyEmojiStatusInfoLabel: FlatLabel(historyContactStatusLabel) {
|
||||||
}
|
}
|
||||||
historyContactStatusMinSkip: 16px;
|
historyContactStatusMinSkip: 16px;
|
||||||
|
|
||||||
historyReplySkip: 51px;
|
historyReplySkip: 53px;
|
||||||
historyReplyNameFg: windowActiveTextFg;
|
historyReplyNameFg: windowActiveTextFg;
|
||||||
historyReplyHeight: 49px;
|
historyReplyHeight: 49px;
|
||||||
historyReplyIconPosition: point(5px, 5px);
|
historyReplyIconPosition: point(7px, 7px);
|
||||||
historyReplyIcon: icon {{ "chat/input_reply", historyReplyIconFg }};
|
historyReplyIcon: icon {{ "chat/input_reply_settings", historyReplyIconFg }};
|
||||||
|
historyLinkIcon: icon {{ "chat/input_link_settings", historyReplyIconFg }};
|
||||||
|
historyQuoteIcon: icon {{ "chat/input_reply_quote", historyReplyIconFg }};
|
||||||
historyForwardIcon: icon {{ "chat/input_forward", historyReplyIconFg }};
|
historyForwardIcon: icon {{ "chat/input_forward", historyReplyIconFg }};
|
||||||
historyEditIcon: icon {{ "chat/input_edit", historyReplyIconFg }};
|
historyEditIcon: icon {{ "chat/input_edit", historyReplyIconFg }};
|
||||||
historyReplyCancel: IconButton {
|
historyReplyCancel: IconButton {
|
||||||
|
|
|
@ -101,6 +101,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/history_view_pinned_bar.h"
|
#include "history/view/history_view_pinned_bar.h"
|
||||||
#include "history/view/history_view_group_call_bar.h"
|
#include "history/view/history_view_group_call_bar.h"
|
||||||
#include "history/view/history_view_item_preview.h"
|
#include "history/view/history_view_item_preview.h"
|
||||||
|
#include "history/view/history_view_reply.h"
|
||||||
#include "history/view/history_view_requests_bar.h"
|
#include "history/view/history_view_requests_bar.h"
|
||||||
#include "history/view/history_view_sticker_toast.h"
|
#include "history/view/history_view_sticker_toast.h"
|
||||||
#include "history/view/history_view_translate_bar.h"
|
#include "history/view/history_view_translate_bar.h"
|
||||||
|
@ -4374,11 +4375,10 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
void HistoryWidget::updateOverStates(QPoint pos) {
|
void HistoryWidget::updateOverStates(QPoint pos) {
|
||||||
const auto isReadyToForward = readyToForward();
|
const auto isReadyToForward = readyToForward();
|
||||||
const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
|
|
||||||
const auto detailsRect = QRect(
|
const auto detailsRect = QRect(
|
||||||
skip,
|
0,
|
||||||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
||||||
width() - skip - _fieldBarCancel->width(),
|
width() - _fieldBarCancel->width(),
|
||||||
st::historyReplyHeight);
|
st::historyReplyHeight);
|
||||||
const auto hasWebPage = !!_previewDrawPreview;
|
const auto hasWebPage = !!_previewDrawPreview;
|
||||||
const auto inDetails = detailsRect.contains(pos)
|
const auto inDetails = detailsRect.contains(pos)
|
||||||
|
@ -4418,10 +4418,6 @@ void HistoryWidget::leaveToChildEvent(QEvent *e, QWidget *child) { // e -- from
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (_replyForwardPressed) {
|
|
||||||
_replyForwardPressed = false;
|
|
||||||
update(0, _field->y() - st::historySendPadding - st::historyReplyHeight, width(), st::historyReplyHeight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
||||||
|
@ -6243,20 +6239,7 @@ bool HistoryWidget::cornerButtonsHas(HistoryView::CornerButtonType type) {
|
||||||
|
|
||||||
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
const auto isReadyToForward = readyToForward();
|
const auto isReadyToForward = readyToForward();
|
||||||
const auto hasSecondLayer = (_editMsgId
|
if (_inPhotoEdit && _photoEditMedia) {
|
||||||
|| _replyTo
|
|
||||||
|| isReadyToForward
|
|
||||||
|| _kbReplyTo);
|
|
||||||
_replyForwardPressed = hasSecondLayer && QRect(
|
|
||||||
0,
|
|
||||||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
|
||||||
st::historyReplySkip,
|
|
||||||
st::historyReplyHeight).contains(e->pos());
|
|
||||||
if (_replyForwardPressed
|
|
||||||
&& !_fieldBarCancel->isHidden()
|
|
||||||
&& !isReadyToForward) {
|
|
||||||
updateField();
|
|
||||||
} else if (_inPhotoEdit && _photoEditMedia) {
|
|
||||||
EditCaptionBox::StartPhotoEdit(
|
EditCaptionBox::StartPhotoEdit(
|
||||||
controller(),
|
controller(),
|
||||||
_photoEditMedia,
|
_photoEditMedia,
|
||||||
|
@ -7486,7 +7469,6 @@ void HistoryWidget::cancelEdit() {
|
||||||
|
|
||||||
void HistoryWidget::cancelFieldAreaState() {
|
void HistoryWidget::cancelFieldAreaState() {
|
||||||
controller()->hideLayer();
|
controller()->hideLayer();
|
||||||
_replyForwardPressed = false;
|
|
||||||
if (_previewDrawPreview) {
|
if (_previewDrawPreview) {
|
||||||
_preview->apply({ .removed = true });
|
_preview->apply({ .removed = true });
|
||||||
} else if (_editMsgId) {
|
} else if (_editMsgId) {
|
||||||
|
@ -7818,25 +7800,23 @@ void HistoryWidget::updateForwarding() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateReplyToName() {
|
void HistoryWidget::updateReplyToName() {
|
||||||
if (_editMsgId) {
|
if (!_history || _editMsgId) {
|
||||||
return;
|
return;
|
||||||
} else if (!_replyEditMsg && (_replyTo || !_kbReplyTo)) {
|
} else if (!_replyEditMsg && (_replyTo || !_kbReplyTo)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto from = [&] {
|
const auto context = Core::MarkedTextContext{
|
||||||
const auto item = _replyEditMsg ? _replyEditMsg : _kbReplyTo;
|
.session = &_history->session(),
|
||||||
if (const auto from = item->displayFrom()) {
|
.customEmojiRepaint = [] {},
|
||||||
return from;
|
.customEmojiLoopLimit = 1,
|
||||||
}
|
};
|
||||||
return item->author().get();
|
const auto to = _replyEditMsg ? _replyEditMsg : _kbReplyTo;
|
||||||
}();
|
const auto replyToQuote = _replyTo && !_replyTo.quote.empty();
|
||||||
_replyToName.setText(
|
_replyToName.setMarkedText(
|
||||||
st::msgNameStyle,
|
st::fwdTextStyle,
|
||||||
from->name(),
|
HistoryView::Reply::ComposePreviewName(_history, to, replyToQuote),
|
||||||
Ui::NameTextOptions());
|
Ui::NameTextOptions(),
|
||||||
_replyToNameVersion = (_replyEditMsg
|
context);
|
||||||
? _replyEditMsg
|
|
||||||
: _kbReplyTo)->author()->nameVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateField() {
|
void HistoryWidget::updateField() {
|
||||||
|
@ -7856,12 +7836,6 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
auto hasForward = readyToForward();
|
auto hasForward = readyToForward();
|
||||||
auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
|
auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
|
||||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||||
if (!_editMsgId
|
|
||||||
&& drawMsgText
|
|
||||||
&& (_replyToNameVersion
|
|
||||||
< drawMsgText->author()->nameVersion())) {
|
|
||||||
updateReplyToName();
|
|
||||||
}
|
|
||||||
backy -= st::historyReplyHeight;
|
backy -= st::historyReplyHeight;
|
||||||
backh += st::historyReplyHeight;
|
backh += st::historyReplyHeight;
|
||||||
} else if (hasForward) {
|
} else if (hasForward) {
|
||||||
|
@ -7871,12 +7845,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
backy -= st::historyReplyHeight;
|
backy -= st::historyReplyHeight;
|
||||||
backh += st::historyReplyHeight;
|
backh += st::historyReplyHeight;
|
||||||
}
|
}
|
||||||
auto drawWebPagePreview = _previewDrawPreview && !_replyForwardPressed;
|
|
||||||
p.setInactive(
|
p.setInactive(
|
||||||
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
|
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
|
||||||
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
|
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
|
||||||
|
|
||||||
const auto media = (!drawWebPagePreview && drawMsgText)
|
const auto media = (!_previewDrawPreview && drawMsgText)
|
||||||
? drawMsgText->media()
|
? drawMsgText->media()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto hasPreview = media && media->hasReplyPreview();
|
const auto hasPreview = media && media->hasReplyPreview();
|
||||||
|
@ -7890,86 +7863,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
if (_previewDrawPreview) {
|
||||||
const auto now = crl::now();
|
st::historyLinkIcon.paint(
|
||||||
const auto paused = p.inactive();
|
p,
|
||||||
const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
|
st::historyReplyIconPosition + QPoint(0, backy),
|
||||||
auto replyLeft = st::historyReplySkip;
|
width());
|
||||||
(_editMsgId ? st::historyEditIcon : st::historyReplyIcon).paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
|
||||||
if (!drawWebPagePreview) {
|
|
||||||
if (drawMsgText) {
|
|
||||||
if (hasPreview) {
|
|
||||||
if (preview) {
|
|
||||||
const auto overEdit = _photoEditMedia
|
|
||||||
? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
|
|
||||||
: 0.;
|
|
||||||
auto to = QRect(
|
|
||||||
replyLeft,
|
|
||||||
backy + (st::historyReplyHeight - 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 (_replySpoiler) {
|
|
||||||
if (overEdit > 0.) {
|
|
||||||
p.setOpacity(1. - overEdit);
|
|
||||||
}
|
|
||||||
Ui::FillSpoilerRect(
|
|
||||||
p,
|
|
||||||
to,
|
|
||||||
Ui::DefaultImageSpoiler().frame(
|
|
||||||
_replySpoiler->index(now, pausedSpoiler)));
|
|
||||||
}
|
|
||||||
if (overEdit > 0.) {
|
|
||||||
p.setOpacity(overEdit);
|
|
||||||
p.fillRect(to, st::historyEditMediaBg);
|
|
||||||
st::historyEditMedia.paintInCenter(p, to);
|
|
||||||
p.setOpacity(1.);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
replyLeft += st::historyReplyPreview + st::msgReplyBarSkip;
|
|
||||||
}
|
|
||||||
p.setPen(st::historyReplyNameFg);
|
|
||||||
if (_editMsgId) {
|
|
||||||
paintEditHeader(p, rect, replyLeft, backy);
|
|
||||||
} else {
|
|
||||||
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
|
||||||
}
|
|
||||||
p.setPen(st::historyComposeAreaFg);
|
|
||||||
_replyEditMsgText.draw(p, {
|
|
||||||
.position = QPoint(
|
|
||||||
replyLeft,
|
|
||||||
backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
|
|
||||||
.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
|
|
||||||
.palette = &st::historyComposeAreaPalette,
|
|
||||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
|
||||||
.now = now,
|
|
||||||
.pausedEmoji = paused || On(PowerSaving::kEmojiChat),
|
|
||||||
.pausedSpoiler = pausedSpoiler,
|
|
||||||
.elisionLines = 1,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
p.setFont(st::msgDateFont);
|
|
||||||
p.setPen(st::historyComposeAreaFgService);
|
|
||||||
p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (hasForward) {
|
|
||||||
st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
|
||||||
if (!drawWebPagePreview) {
|
|
||||||
const auto x = st::historyReplySkip;
|
|
||||||
const auto available = width()
|
|
||||||
- x
|
|
||||||
- _fieldBarCancel->width()
|
|
||||||
- st::msgReplyPadding.right();
|
|
||||||
_forwardPanel->paint(p, x, backy, available, width());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (drawWebPagePreview) {
|
|
||||||
const auto textTop = backy + st::msgReplyPadding.top();
|
const auto textTop = backy + st::msgReplyPadding.top();
|
||||||
auto previewLeft = st::historyReplySkip;
|
auto previewLeft = st::historyReplySkip;
|
||||||
|
|
||||||
|
@ -7998,6 +7896,87 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
previewLeft,
|
previewLeft,
|
||||||
textTop + st::msgServiceNameFont->height,
|
textTop + st::msgServiceNameFont->height,
|
||||||
elidedWidth);
|
elidedWidth);
|
||||||
|
} else if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||||
|
const auto now = crl::now();
|
||||||
|
const auto paused = p.inactive();
|
||||||
|
const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
|
||||||
|
auto replyLeft = st::historyReplySkip;
|
||||||
|
(_editMsgId
|
||||||
|
? st::historyEditIcon
|
||||||
|
: (_replyTo && !_replyTo.quote.empty())
|
||||||
|
? st::historyQuoteIcon
|
||||||
|
: st::historyReplyIcon).paint(
|
||||||
|
p,
|
||||||
|
st::historyReplyIconPosition + QPoint(0, backy),
|
||||||
|
width());
|
||||||
|
if (drawMsgText) {
|
||||||
|
if (hasPreview) {
|
||||||
|
if (preview) {
|
||||||
|
const auto overEdit = _photoEditMedia
|
||||||
|
? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
|
||||||
|
: 0.;
|
||||||
|
auto to = QRect(
|
||||||
|
replyLeft,
|
||||||
|
backy + (st::historyReplyHeight - 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 (_replySpoiler) {
|
||||||
|
if (overEdit > 0.) {
|
||||||
|
p.setOpacity(1. - overEdit);
|
||||||
|
}
|
||||||
|
Ui::FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
to,
|
||||||
|
Ui::DefaultImageSpoiler().frame(
|
||||||
|
_replySpoiler->index(now, pausedSpoiler)));
|
||||||
|
}
|
||||||
|
if (overEdit > 0.) {
|
||||||
|
p.setOpacity(overEdit);
|
||||||
|
p.fillRect(to, st::historyEditMediaBg);
|
||||||
|
st::historyEditMedia.paintInCenter(p, to);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replyLeft += st::historyReplyPreview + st::msgReplyBarSkip;
|
||||||
|
}
|
||||||
|
p.setPen(st::historyReplyNameFg);
|
||||||
|
if (_editMsgId) {
|
||||||
|
paintEditHeader(p, rect, replyLeft, backy);
|
||||||
|
} else {
|
||||||
|
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
||||||
|
}
|
||||||
|
p.setPen(st::historyComposeAreaFg);
|
||||||
|
_replyEditMsgText.draw(p, {
|
||||||
|
.position = QPoint(
|
||||||
|
replyLeft,
|
||||||
|
backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
|
||||||
|
.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
|
||||||
|
.palette = &st::historyComposeAreaPalette,
|
||||||
|
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||||
|
.now = now,
|
||||||
|
.pausedEmoji = paused || On(PowerSaving::kEmojiChat),
|
||||||
|
.pausedSpoiler = pausedSpoiler,
|
||||||
|
.elisionLines = 1,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
p.setFont(st::msgDateFont);
|
||||||
|
p.setPen(st::historyComposeAreaFgService);
|
||||||
|
p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()));
|
||||||
|
}
|
||||||
|
} else if (hasForward) {
|
||||||
|
st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
||||||
|
const auto x = st::historyReplySkip;
|
||||||
|
const auto available = width()
|
||||||
|
- x
|
||||||
|
- _fieldBarCancel->width()
|
||||||
|
- st::msgReplyPadding.right();
|
||||||
|
_forwardPanel->paint(p, x, backy, available, width());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -647,7 +647,6 @@ private:
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
FullReplyTo _replyTo;
|
FullReplyTo _replyTo;
|
||||||
Ui::Text::String _replyToName;
|
Ui::Text::String _replyToName;
|
||||||
int _replyToNameVersion = 0;
|
|
||||||
|
|
||||||
FullReplyTo _processingReplyTo;
|
FullReplyTo _processingReplyTo;
|
||||||
HistoryItem *_processingReplyItem = nullptr;
|
HistoryItem *_processingReplyItem = nullptr;
|
||||||
|
@ -688,8 +687,6 @@ private:
|
||||||
Ui::Text::String _previewTitle;
|
Ui::Text::String _previewTitle;
|
||||||
Ui::Text::String _previewDescription;
|
Ui::Text::String _previewDescription;
|
||||||
|
|
||||||
bool _replyForwardPressed = false;
|
|
||||||
|
|
||||||
PeerData *_peer = nullptr;
|
PeerData *_peer = nullptr;
|
||||||
|
|
||||||
bool _canSendMessages = false;
|
bool _canSendMessages = false;
|
||||||
|
|
|
@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/controls/history_view_voice_record_bar.h"
|
#include "history/view/controls/history_view_voice_record_bar.h"
|
||||||
#include "history/view/controls/history_view_ttl_button.h"
|
#include "history/view/controls/history_view_ttl_button.h"
|
||||||
#include "history/view/controls/history_view_webpage_processor.h"
|
#include "history/view/controls/history_view_webpage_processor.h"
|
||||||
|
#include "history/view/history_view_reply.h"
|
||||||
#include "history/view/history_view_webpage_preview.h"
|
#include "history/view/history_view_webpage_preview.h"
|
||||||
#include "inline_bots/bot_attach_web_view.h"
|
#include "inline_bots/bot_attach_web_view.h"
|
||||||
#include "inline_bots/inline_results_widget.h"
|
#include "inline_bots/inline_results_widget.h"
|
||||||
|
@ -192,7 +193,6 @@ private:
|
||||||
Ui::Text::String _shownMessageText;
|
Ui::Text::String _shownMessageText;
|
||||||
std::unique_ptr<Ui::SpoilerAnimation> _shownPreviewSpoiler;
|
std::unique_ptr<Ui::SpoilerAnimation> _shownPreviewSpoiler;
|
||||||
Ui::Animations::Simple _inPhotoEditOver;
|
Ui::Animations::Simple _inPhotoEditOver;
|
||||||
int _shownMessageNameVersion = -1;
|
|
||||||
bool _shownMessageHasPreview : 1 = false;
|
bool _shownMessageHasPreview : 1 = false;
|
||||||
bool _inPhotoEdit : 1 = false;
|
bool _inPhotoEdit : 1 = false;
|
||||||
bool _photoEditAllowed : 1 = false;
|
bool _photoEditAllowed : 1 = false;
|
||||||
|
@ -245,7 +245,6 @@ void FieldHeader::init() {
|
||||||
updateVisible();
|
updateVisible();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
const auto leftIconPressed = lifetime().make_state<bool>(false);
|
|
||||||
paintRequest(
|
paintRequest(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
@ -253,21 +252,29 @@ void FieldHeader::init() {
|
||||||
p.fillRect(rect(), st::historyComposeAreaBg);
|
p.fillRect(rect(), st::historyComposeAreaBg);
|
||||||
|
|
||||||
const auto position = st::historyReplyIconPosition;
|
const auto position = st::historyReplyIconPosition;
|
||||||
if (isEditingMessage()) {
|
if (_preview.parsed) {
|
||||||
|
st::historyLinkIcon.paint(p, position, width());
|
||||||
|
} else if (isEditingMessage()) {
|
||||||
st::historyEditIcon.paint(p, position, width());
|
st::historyEditIcon.paint(p, position, width());
|
||||||
} else if (readyToForward()) {
|
} else if (readyToForward()) {
|
||||||
st::historyForwardIcon.paint(p, position, width());
|
st::historyForwardIcon.paint(p, position, width());
|
||||||
} else if (replyingToMessage()) {
|
} else if (const auto reply = replyingToMessage()) {
|
||||||
st::historyReplyIcon.paint(p, position, width());
|
if (!reply.quote.empty()) {
|
||||||
|
st::historyQuoteIcon.paint(p, position, width());
|
||||||
|
} else {
|
||||||
|
st::historyReplyIcon.paint(p, position, width());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(_preview.parsed && !*leftIconPressed)
|
if (_preview.parsed) {
|
||||||
? paintWebPage(
|
paintWebPage(
|
||||||
p,
|
p,
|
||||||
_history ? _history->peer : _data->session().user())
|
_history ? _history->peer : _data->session().user());
|
||||||
: (isEditingMessage() || !readyToForward())
|
} else if (isEditingMessage() || !readyToForward()) {
|
||||||
? paintEditOrReplyToMessage(p)
|
paintEditOrReplyToMessage(p);
|
||||||
: paintForwardInfo(p);
|
} else {
|
||||||
|
paintForwardInfo(p);
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_editMsgId.value(
|
_editMsgId.value(
|
||||||
|
@ -359,13 +366,9 @@ void FieldHeader::init() {
|
||||||
updateOver(inPreviewRect, inPhotoEdit);
|
updateOver(inPreviewRect, inPhotoEdit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto isLeftIcon = (pos.x() < st::historyReplySkip);
|
|
||||||
const auto isLeftButton = (e->button() == Qt::LeftButton);
|
const auto isLeftButton = (e->button() == Qt::LeftButton);
|
||||||
if (type == QEvent::MouseButtonPress) {
|
if (type == QEvent::MouseButtonPress) {
|
||||||
if (isLeftButton && isLeftIcon && !inPreviewRect) {
|
if (isLeftButton && inPhotoEdit) {
|
||||||
*leftIconPressed = true;
|
|
||||||
update();
|
|
||||||
} else if (isLeftButton && inPhotoEdit) {
|
|
||||||
_editPhotoRequests.fire({});
|
_editPhotoRequests.fire({});
|
||||||
} else if (isLeftButton && inPreviewRect) {
|
} else if (isLeftButton && inPreviewRect) {
|
||||||
const auto reply = replyingToMessage();
|
const auto reply = replyingToMessage();
|
||||||
|
@ -384,11 +387,6 @@ void FieldHeader::init() {
|
||||||
_editOptionsRequests.fire({});
|
_editOptionsRequests.fire({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type == QEvent::MouseButtonRelease) {
|
|
||||||
if (isLeftButton && *leftIconPressed) {
|
|
||||||
*leftIconPressed = false;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
@ -431,9 +429,21 @@ void FieldHeader::setShownMessage(HistoryItem *item) {
|
||||||
st::msgNameStyle,
|
st::msgNameStyle,
|
||||||
tr::lng_edit_message(tr::now),
|
tr::lng_edit_message(tr::now),
|
||||||
Ui::NameTextOptions());
|
Ui::NameTextOptions());
|
||||||
|
} else if (item) {
|
||||||
|
const auto context = Core::MarkedTextContext{
|
||||||
|
.session = &_history->session(),
|
||||||
|
.customEmojiRepaint = [] {},
|
||||||
|
.customEmojiLoopLimit = 1,
|
||||||
|
};
|
||||||
|
const auto replyTo = _replyTo.current();
|
||||||
|
const auto quote = replyTo && !replyTo.quote.empty();
|
||||||
|
_shownMessageName.setMarkedText(
|
||||||
|
st::fwdTextStyle,
|
||||||
|
HistoryView::Reply::ComposePreviewName(_history, item, quote),
|
||||||
|
Ui::NameTextOptions(),
|
||||||
|
context);
|
||||||
} else {
|
} else {
|
||||||
_shownMessageName.clear();
|
_shownMessageName.clear();
|
||||||
_shownMessageNameVersion = -1;
|
|
||||||
}
|
}
|
||||||
updateVisible();
|
updateVisible();
|
||||||
update();
|
update();
|
||||||
|
@ -545,19 +555,6 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEditingMessage()) {
|
|
||||||
const auto user = _shownMessage->displayFrom()
|
|
||||||
? _shownMessage->displayFrom()
|
|
||||||
: _shownMessage->author().get();
|
|
||||||
if (_shownMessageNameVersion < user->nameVersion()) {
|
|
||||||
_shownMessageName.setText(
|
|
||||||
st::msgNameStyle,
|
|
||||||
user->name(),
|
|
||||||
Ui::NameTextOptions());
|
|
||||||
_shownMessageNameVersion = user->nameVersion();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto media = _shownMessage->media();
|
const auto media = _shownMessage->media();
|
||||||
_shownMessageHasPreview = media && media->hasReplyPreview();
|
_shownMessageHasPreview = media && media->hasReplyPreview();
|
||||||
const auto preview = _shownMessageHasPreview
|
const auto preview = _shownMessageHasPreview
|
||||||
|
@ -692,12 +689,11 @@ FullReplyTo FieldHeader::getDraftReply() const {
|
||||||
|
|
||||||
void FieldHeader::updateControlsGeometry(QSize size) {
|
void FieldHeader::updateControlsGeometry(QSize size) {
|
||||||
const auto isReadyToForward = readyToForward();
|
const auto isReadyToForward = readyToForward();
|
||||||
const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
|
|
||||||
_cancel->moveToRight(0, 0);
|
_cancel->moveToRight(0, 0);
|
||||||
_clickableRect = QRect(
|
_clickableRect = QRect(
|
||||||
skip,
|
|
||||||
0,
|
0,
|
||||||
width() - skip - _cancel->width(),
|
0,
|
||||||
|
width() - _cancel->width(),
|
||||||
height());
|
height());
|
||||||
_shownMessagePreviewRect = QRect(
|
_shownMessagePreviewRect = QRect(
|
||||||
st::historyReplySkip,
|
st::historyReplySkip,
|
||||||
|
|
|
@ -642,6 +642,8 @@ void DraftOptionsBox(
|
||||||
if (const auto current = state->quote.current()) {
|
if (const auto current = state->quote.current()) {
|
||||||
result.messageId = current.item->fullId();
|
result.messageId = current.item->fullId();
|
||||||
result.quote = current.text;
|
result.quote = current.text;
|
||||||
|
} else {
|
||||||
|
result.quote = {};
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -394,10 +394,11 @@ void Reply::updateName(
|
||||||
viaBotUsername = bot->username();
|
viaBotUsername = bot->username();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto history = view->history();
|
||||||
const auto &fields = data->fields();
|
const auto &fields = data->fields();
|
||||||
const auto sender = resolvedSender.value_or(this->sender(view, data));
|
const auto sender = resolvedSender.value_or(this->sender(view, data));
|
||||||
const auto externalPeer = fields.externalPeerId
|
const auto externalPeer = fields.externalPeerId
|
||||||
? view->history()->owner().peer(fields.externalPeerId).get()
|
? history->owner().peer(fields.externalPeerId).get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto displayAsExternal = data->displayAsExternal(view->data());
|
const auto displayAsExternal = data->displayAsExternal(view->data());
|
||||||
const auto groupNameAdded = displayAsExternal
|
const auto groupNameAdded = displayAsExternal
|
||||||
|
@ -415,38 +416,20 @@ void Reply::updateName(
|
||||||
+ st::historyReplyPreviewMargin.right()
|
+ st::historyReplyPreviewMargin.right()
|
||||||
- st::historyReplyPadding.left())
|
- st::historyReplyPadding.left())
|
||||||
: 0;
|
: 0;
|
||||||
const auto peerIcon = [](PeerData *peer) {
|
|
||||||
using namespace std;
|
|
||||||
return !peer
|
|
||||||
? pair(&st::historyReplyUser, st::historyReplyUserPadding)
|
|
||||||
: peer->isBroadcast()
|
|
||||||
? pair(&st::historyReplyChannel, st::historyReplyChannelPadding)
|
|
||||||
: (peer->isChannel() || peer->isChat())
|
|
||||||
? pair(&st::historyReplyGroup, st::historyReplyGroupPadding)
|
|
||||||
: pair(&st::historyReplyUser, st::historyReplyUserPadding);
|
|
||||||
};
|
|
||||||
const auto peerEmoji = [&](PeerData *peer) {
|
|
||||||
const auto owner = &view->history()->owner();
|
|
||||||
const auto icon = peerIcon(peer);
|
|
||||||
return Ui::Text::SingleCustomEmoji(
|
|
||||||
owner->customEmojiManager().registerInternalEmoji(
|
|
||||||
*icon.first,
|
|
||||||
icon.second));
|
|
||||||
};
|
|
||||||
auto nameFull = TextWithEntities();
|
auto nameFull = TextWithEntities();
|
||||||
if (displayAsExternal && !groupNameAdded && !fields.storyId) {
|
if (displayAsExternal && !groupNameAdded && !fields.storyId) {
|
||||||
nameFull.append(peerEmoji(sender));
|
nameFull.append(PeerEmoji(history, sender));
|
||||||
}
|
}
|
||||||
nameFull.append(name);
|
nameFull.append(name);
|
||||||
if (groupNameAdded) {
|
if (groupNameAdded) {
|
||||||
nameFull.append(' ').append(peerEmoji(externalPeer));
|
nameFull.append(' ').append(PeerEmoji(history, externalPeer));
|
||||||
nameFull.append(externalPeer->name());
|
nameFull.append(externalPeer->name());
|
||||||
}
|
}
|
||||||
if (!viaBotUsername.isEmpty()) {
|
if (!viaBotUsername.isEmpty()) {
|
||||||
nameFull.append(u" @"_q).append(viaBotUsername);
|
nameFull.append(u" @"_q).append(viaBotUsername);
|
||||||
}
|
}
|
||||||
const auto context = Core::MarkedTextContext{
|
const auto context = Core::MarkedTextContext{
|
||||||
.session = &view->history()->session(),
|
.session = &history->session(),
|
||||||
.customEmojiRepaint = [] {},
|
.customEmojiRepaint = [] {},
|
||||||
.customEmojiLoopLimit = 1,
|
.customEmojiLoopLimit = 1,
|
||||||
};
|
};
|
||||||
|
@ -813,6 +796,61 @@ void Reply::stopLastRipple() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities Reply::PeerEmoji(
|
||||||
|
not_null<History*> history,
|
||||||
|
PeerData *peer) {
|
||||||
|
using namespace std;
|
||||||
|
const auto icon = !peer
|
||||||
|
? pair(&st::historyReplyUser, st::historyReplyUserPadding)
|
||||||
|
: peer->isBroadcast()
|
||||||
|
? pair(&st::historyReplyChannel, st::historyReplyChannelPadding)
|
||||||
|
: (peer->isChannel() || peer->isChat())
|
||||||
|
? pair(&st::historyReplyGroup, st::historyReplyGroupPadding)
|
||||||
|
: pair(&st::historyReplyUser, st::historyReplyUserPadding);
|
||||||
|
const auto owner = &history->owner();
|
||||||
|
return Ui::Text::SingleCustomEmoji(
|
||||||
|
owner->customEmojiManager().registerInternalEmoji(
|
||||||
|
*icon.first,
|
||||||
|
icon.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities Reply::ComposePreviewName(
|
||||||
|
not_null<History*> history,
|
||||||
|
not_null<HistoryItem*> to,
|
||||||
|
bool quote) {
|
||||||
|
const auto sender = [&] {
|
||||||
|
if (const auto from = to->displayFrom()) {
|
||||||
|
return not_null(from);
|
||||||
|
}
|
||||||
|
return to->author();
|
||||||
|
}();
|
||||||
|
const auto toPeer = to->history()->peer;
|
||||||
|
const auto displayAsExternal = (to->history() != history);
|
||||||
|
const auto groupNameAdded = displayAsExternal
|
||||||
|
&& (toPeer != sender)
|
||||||
|
&& (toPeer->isChat() || toPeer->isMegagroup());
|
||||||
|
const auto shorten = groupNameAdded || quote;
|
||||||
|
|
||||||
|
auto nameFull = TextWithEntities();
|
||||||
|
using namespace HistoryView;
|
||||||
|
if (displayAsExternal && !groupNameAdded) {
|
||||||
|
nameFull.append(Reply::PeerEmoji(history, sender));
|
||||||
|
}
|
||||||
|
nameFull.append(shorten ? sender->shortName() : sender->name());
|
||||||
|
if (groupNameAdded) {
|
||||||
|
nameFull.append(' ').append(Reply::PeerEmoji(history, toPeer));
|
||||||
|
nameFull.append(toPeer->name());
|
||||||
|
}
|
||||||
|
return (quote
|
||||||
|
? tr::lng_preview_reply_to_quote
|
||||||
|
: tr::lng_preview_reply_to)(
|
||||||
|
tr::now,
|
||||||
|
lt_name,
|
||||||
|
nameFull,
|
||||||
|
Ui::Text::WithEntities);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Reply::unloadPersistentAnimation() {
|
void Reply::unloadPersistentAnimation() {
|
||||||
_text.unloadPersistentAnimation();
|
_text.unloadPersistentAnimation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,14 @@ public:
|
||||||
return _link;
|
return _link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static TextWithEntities PeerEmoji(
|
||||||
|
not_null<History*> history,
|
||||||
|
PeerData *peer);
|
||||||
|
[[nodiscard]] static TextWithEntities ComposePreviewName(
|
||||||
|
not_null<History*> history,
|
||||||
|
not_null<HistoryItem*> to,
|
||||||
|
bool quote);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] Ui::Text::GeometryDescriptor textGeometry(
|
[[nodiscard]] Ui::Text::GeometryDescriptor textGeometry(
|
||||||
int available,
|
int available,
|
||||||
|
|