Use new message bar for pinned message.

This commit is contained in:
John Preston 2020-10-10 15:04:28 +03:00
parent ae298818a8
commit 67290eed58
6 changed files with 473 additions and 238 deletions

View file

@ -561,6 +561,8 @@ PRIVATE
history/view/history_view_message.cpp
history/view/history_view_message.h
history/view/history_view_object.h
history/view/history_view_pinned_bar.cpp
history/view/history_view_pinned_bar.h
history/view/history_view_pinned_tracker.cpp
history/view/history_view_pinned_tracker.h
history/view/history_view_replies_section.cpp

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h"
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
#include "ui/text/format_values.h"
#include "ui/chat/message_bar.h"
#include "ui/image/image.h"
#include "ui/special_buttons.h"
#include "inline_bots/inline_bot_result.h"
@ -62,6 +63,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_scheduled_section.h"
#include "history/view/history_view_schedule_box.h"
#include "history/view/history_view_webpage_preview.h"
#include "history/view/history_view_top_bar_widget.h"
#include "history/view/history_view_contact_status.h"
#include "history/view/history_view_pinned_tracker.h"
#include "history/view/history_view_pinned_bar.h"
#include "history/view/media/history_view_media.h"
#include "profile/profile_block_group_members.h"
#include "info/info_memento.h"
@ -86,9 +91,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/player/media_player_instance.h"
#include "core/application.h"
#include "apiwrap.h"
#include "history/view/history_view_top_bar_widget.h"
#include "history/view/history_view_contact_status.h"
#include "history/view/history_view_pinned_tracker.h"
#include "base/qthelp_regex.h"
#include "ui/widgets/popup_menu.h"
#include "ui/item_text_options.h"
@ -552,7 +554,6 @@ HistoryWidget::HistoryWidget(
UpdateFlag::Rights
| UpdateFlag::Migration
| UpdateFlag::UnavailableReason
| UpdateFlag::PinnedMessage
| UpdateFlag::IsBlocked
| UpdateFlag::Admins
| UpdateFlag::Members
@ -590,14 +591,6 @@ HistoryWidget::HistoryWidget(
updateControlsVisibility();
updateControlsGeometry();
}
if (flags & UpdateFlag::PinnedMessage) {
if (pinnedMsgVisibilityUpdated()) {
updateHistoryGeometry();
updateControlsVisibility();
updateControlsGeometry();
this->update();
}
}
if (flags & UpdateFlag::Slowmode) {
updateSendButtonType();
}
@ -1142,7 +1135,7 @@ void HistoryWidget::orderWidgets() {
_contactStatus->raise();
}
if (_pinnedBar) {
_pinnedBar->shadow->raise();
_pinnedBar->raise();
}
_topShadow->raise();
if (_membersDropdown) {
@ -1698,7 +1691,7 @@ void HistoryWidget::showHistory(
_history->showAtMsgId = _showAtMsgId;
destroyUnreadBarOnClose();
showPinnedMessage(FullMsgId());
_pinnedBar = nullptr;
_pinnedTracker = nullptr;
_membersDropdown.destroy();
_scrollToAnimation.stop();
@ -1814,7 +1807,6 @@ void HistoryWidget::showHistory(
_updateHistoryItems.stop();
setupPinnedTracker();
pinnedMsgVisibilityUpdated();
if (_history->scrollTopItem
|| (_migrated && _migrated->scrollTopItem)
|| _history->isReadyFor(_showAtMsgId)) {
@ -2026,13 +2018,15 @@ void HistoryWidget::updateControlsVisibility() {
if (_tabbedPanel) {
_tabbedPanel->hideFast();
}
if (_pinnedBar) {
_pinnedBar->hide();
}
hideChildren();
return;
}
if (_pinnedBar) {
_pinnedBar->cancel->show();
_pinnedBar->shadow->show();
_pinnedBar->show();
}
if (_firstLoadRequest && !_scroll->isHidden()) {
_scroll->hide();
@ -2242,7 +2236,7 @@ void HistoryWidget::showAboutTopPromotion() {
}
void HistoryWidget::updateMouseTracking() {
bool trackMouse = !_fieldBarCancel->isHidden() || _pinnedBar;
const auto trackMouse = !_fieldBarCancel->isHidden();
setMouseTracking(trackMouse);
}
@ -3180,6 +3174,9 @@ void HistoryWidget::showAnimated(
if (_tabbedPanel) {
_tabbedPanel->hideFast();
}
if (_pinnedBar) {
_pinnedBar->hide();
}
hideChildren();
if (params.withTopBarShadow) _topShadow->show();
@ -3336,14 +3333,12 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
void HistoryWidget::updateOverStates(QPoint pos) {
auto inField = pos.y() >= (_scroll->y() + _scroll->height()) && pos.y() < height() && pos.x() >= 0 && pos.x() < width();
auto inReplyEditForward = QRect(st::historyReplySkip, _field->y() - st::historySendPadding - st::historyReplyHeight, width() - st::historyReplySkip - _fieldBarCancel->width(), st::historyReplyHeight).contains(pos) && (_editMsgId || replyToId() || readyToForward());
auto inPinnedMsg = QRect(0, _topBar->bottomNoMargins(), width(), st::historyReplyHeight).contains(pos) && _pinnedBar;
auto inClickable = inReplyEditForward || inPinnedMsg;
auto inClickable = inReplyEditForward;
if (inField != _inField && _recording) {
_inField = inField;
_send->setRecordActive(_inField);
}
_inReplyEditForward = inReplyEditForward;
_inPinnedMsg = inPinnedMsg;
if (inClickable != _inClickable) {
_inClickable = inClickable;
setCursor(_inClickable ? style::cur_pointer : style::cur_default);
@ -4442,10 +4437,10 @@ void HistoryWidget::updateControlsGeometry() {
const auto pinnedBarTop = _topBar->bottomNoMargins();
if (_pinnedBar) {
_pinnedBar->cancel->moveToLeft(width() - _pinnedBar->cancel->width(), pinnedBarTop);
_pinnedBar->shadow->setGeometryToLeft(0, pinnedBarTop + st::historyReplyHeight, width(), st::lineWidth);
_pinnedBar->move(0, pinnedBarTop);
_pinnedBar->resizeToWidth(width());
}
const auto contactStatusTop = pinnedBarTop + (_pinnedBar ? st::historyReplyHeight : 0);
const auto contactStatusTop = pinnedBarTop + (_pinnedBar ? _pinnedBar->height() : 0);
if (_contactStatus) {
_contactStatus->move(0, contactStatusTop);
}
@ -4487,9 +4482,6 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) {
while (item == _replyReturn) {
calcNextReplyReturn();
}
if (_pinnedBar && item->id == _pinnedBar->msgId) {
pinnedMsgVisibilityUpdated();
}
if (_kbReplyTo && item == _kbReplyTo) {
toggleKeyboard();
_kbReplyTo = nullptr;
@ -4509,9 +4501,6 @@ void HistoryWidget::itemEdited(not_null<HistoryItem*> item) {
if (item.get() == _replyEditMsg) {
updateReplyEditTexts(true);
}
if (_pinnedBar && item->id == _pinnedBar->msgId) {
updatePinnedBar(true);
}
}
void HistoryWidget::updateScrollColors() {
@ -4612,7 +4601,7 @@ void HistoryWidget::updateHistoryGeometry(
auto newScrollHeight = height() - _topBar->height();
if (_pinnedBar) {
newScrollHeight -= st::historyReplyHeight;
newScrollHeight -= _pinnedBar->height();
}
if (_contactStatus) {
newScrollHeight -= _contactStatus->height();
@ -4848,7 +4837,7 @@ int HistoryWidget::computeMaxFieldHeight() const {
const auto available = height()
- _topBar->height()
- (_contactStatus ? _contactStatus->height() : 0)
- (_pinnedBar ? st::historyReplyHeight : 0)
- (_pinnedBar ? _pinnedBar->height() : 0)
- ((_editMsgId
|| replyToId()
|| readyToForward()
@ -4980,9 +4969,9 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
} else {
Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId());
}
} else if (_inPinnedMsg) {
Assert(_pinnedBar != nullptr);
Ui::showPeerHistory(_peer, _pinnedBar->msgId);
//} else if (_inPinnedMsg) { // #TODO pinned
// Assert(_pinnedBar != nullptr);
// Ui::showPeerHistory(_peer, _pinnedBar->msgId);
}
}
@ -5189,48 +5178,6 @@ void HistoryWidget::sendInlineResult(
_field->setFocus();
}
HistoryWidget::PinnedBar::PinnedBar(MsgId msgId, HistoryWidget *parent)
: msgId(msgId)
, cancel(parent, st::historyReplyCancel)
, shadow(parent) {
}
HistoryWidget::PinnedBar::~PinnedBar() {
cancel.destroyDelayed();
shadow.destroyDelayed();
}
void HistoryWidget::updatePinnedBar(bool force) {
update();
if (!_pinnedBar) {
return;
}
const auto messageId = _pinnedBar->msgId;
if (!force) {
if (_pinnedBar->msg) {
return;
}
}
Assert(_history != nullptr);
if (!_pinnedBar->msg) {
_pinnedBar->msg = session().data().message(
_history->channelId(),
messageId);
}
if (_pinnedBar->msg) {
_pinnedBar->text.setText(
st::messageTextStyle,
_pinnedBar->msg->inReplyText(),
Ui::DialogTextOptions());
update();
} else if (force) {
destroyPinnedBar();
_history->peer->removePinnedMessage(messageId);
updateControlsGeometry();
}
}
void HistoryWidget::updatePinnedViewer() {
if (_firstLoadRequest
|| _delayedShowAtRequest
@ -5264,80 +5211,90 @@ void HistoryWidget::setupPinnedTracker() {
Expects(_history != nullptr);
_pinnedTracker = std::make_unique<HistoryView::PinnedTracker>(_history);
_pinnedTracker->shownMessageId(
) | rpl::start_with_next([=](MsgId messageId) {
showPinnedMessage({ peerToChannel(_peer->id), messageId });
}, _list->lifetime());
}
_pinnedBar = std::make_unique<HistoryView::PinnedBar>(
this,
&session(),
_pinnedTracker->shownMessageId() | rpl::map([=](MsgId messageId) {
return FullMsgId{ peerToChannel(_peer->id), messageId };
}),
true);
void HistoryWidget::showPinnedMessage(FullMsgId id) {
if (_pinnedId == id) {
return;
}
_pinnedId = id;
if (pinnedMsgVisibilityUpdated()) {
updateHistoryGeometry();
updateControlsVisibility();
updateControlsGeometry();
this->update();
}
}
bool HistoryWidget::pinnedMsgVisibilityUpdated() {
auto result = false;
auto pinnedId = _pinnedId;
if (pinnedId && !_peer->canPinMessages()) {
const auto hiddenId = session().settings().hiddenPinnedMessageId(
_peer->id);
if (hiddenId == pinnedId.msg) {
pinnedId = FullMsgId();
} else if (hiddenId) {
session().settings().setHiddenPinnedMessageId(_peer->id, 0);
session().saveSettings();
}
}
if (pinnedId) {
if (!_pinnedBar) {
_pinnedBar = std::make_unique<PinnedBar>(pinnedId.msg, this);
if (_a_show.animating()) {
_pinnedBar->cancel->hide();
_pinnedBar->shadow->hide();
} else {
_pinnedBar->cancel->show();
_pinnedBar->shadow->show();
}
_pinnedBar->cancel->addClickHandler([=] {
_pinnedBar->closeClicks(
) | rpl::start_with_next([=] {
hidePinnedMessage();
});
orderWidgets();
}, _pinnedBar->lifetime());
updatePinnedBar();
result = true;
const auto barTop = unreadBarTop();
if (!barTop || _scroll->scrollTop() != *barTop) {
synteticScrollToY(_scroll->scrollTop() + st::historyReplyHeight);
}
} else if (_pinnedBar->msgId != pinnedId.msg) {
_pinnedBar->msgId = pinnedId.msg;
_pinnedBar->msg = nullptr;
_pinnedBar->text.clear();
updatePinnedBar();
}
if (!_pinnedBar->msg) {
requestMessageData(_pinnedBar->msgId);
}
} else if (_pinnedBar) {
destroyPinnedBar();
result = true;
const auto barTop = unreadBarTop();
if (!barTop || _scroll->scrollTop() != *barTop) {
synteticScrollToY(_scroll->scrollTop() - st::historyReplyHeight);
}
_pinnedBarHeight = 0;
_pinnedBar->heightValue(
) | rpl::start_with_next([=](int height) {
_topDelta = (height - _pinnedBarHeight);
_pinnedBarHeight = height;
updateHistoryGeometry();
updateControlsGeometry();
_topDelta = 0;
}, _pinnedBar->lifetime());
orderWidgets();
if (_a_show.animating()) {
_pinnedBar->hide();
}
return result;
}
//
//bool HistoryWidget::pinnedMsgVisibilityUpdated() {
// auto result = false;
// auto pinnedId = _pinnedId;
// if (pinnedId && !_peer->canPinMessages()) {
// const auto hiddenId = session().settings().hiddenPinnedMessageId(
// _peer->id);
// if (hiddenId == pinnedId.msg) {
// pinnedId = FullMsgId();
// } else if (hiddenId) {
// session().settings().setHiddenPinnedMessageId(_peer->id, 0);
// session().saveSettings();
// }
// }
// if (pinnedId) {
// if (!_pinnedBar) {
// _pinnedBar = std::make_unique<PinnedBar>(pinnedId.msg, this);
// if (_a_show.animating()) {
// _pinnedBar->cancel->hide();
// _pinnedBar->bar->widget()->hide();
// _pinnedBar->shadow->hide();
// } else {
// _pinnedBar->cancel->show();
// _pinnedBar->bar->widget()->show();
// _pinnedBar->shadow->show();
// }
// _pinnedBar->cancel->addClickHandler([=] {
// hidePinnedMessage();
// });
// orderWidgets();
//
// updatePinnedBar();
// result = true;
//
// const auto barTop = unreadBarTop();
// if (!barTop || _scroll->scrollTop() != *barTop) {
// synteticScrollToY(_scroll->scrollTop() + st::historyReplyHeight);
// }
// } else if (_pinnedBar->msgId != pinnedId.msg) {
// _pinnedBar->msgId = pinnedId.msg;
// _pinnedBar->msg = nullptr;
// updatePinnedBar();
// }
// if (!_pinnedBar->msg) {
// requestMessageData(_pinnedBar->msgId);
// }
// } else if (_pinnedBar) {
// destroyPinnedBar();
// result = true;
// const auto barTop = unreadBarTop();
// if (!barTop || _scroll->scrollTop() != *barTop) {
// synteticScrollToY(_scroll->scrollTop() - st::historyReplyHeight);
// }
// updateControlsGeometry();
// }
// return result;
//}
void HistoryWidget::requestMessageData(MsgId msgId) {
const auto callback = [=](ChannelData *channel, MsgId msgId) {
@ -5349,11 +5306,6 @@ void HistoryWidget::requestMessageData(MsgId msgId) {
crl::guard(this, callback));
}
void HistoryWidget::destroyPinnedBar() {
_pinnedBar.reset();
_inPinnedMsg = false;
}
bool HistoryWidget::sendExistingDocument(
not_null<DocumentData*> document,
Api::SendOptions options) {
@ -5622,25 +5574,25 @@ void HistoryWidget::UnpinMessage(not_null<PeerData*> peer, MsgId msgId) {
}
void HistoryWidget::hidePinnedMessage() {
const auto pinnedId = _pinnedId;
if (!pinnedId) {
if (pinnedMsgVisibilityUpdated()) {
updateControlsGeometry();
update();
}
return;
}
//const auto pinnedId = _pinnedId; // #TODO pinned
//if (!pinnedId) {
// if (pinnedMsgVisibilityUpdated()) {
// updateControlsGeometry();
// update();
// }
// return;
//}
if (_peer->canPinMessages()) {
unpinMessage(pinnedId);
} else {
session().settings().setHiddenPinnedMessageId(_peer->id, pinnedId.msg);
session().saveSettings();
if (pinnedMsgVisibilityUpdated()) {
updateControlsGeometry();
update();
}
}
//if (_peer->canPinMessages()) {
// unpinMessage(pinnedId);
//} else {
// session().settings().setHiddenPinnedMessageId(_peer->id, pinnedId.msg);
// session().saveSettings();
// if (pinnedMsgVisibilityUpdated()) {
// updateControlsGeometry();
// update();
// }
//}
}
bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const {
@ -6080,13 +6032,12 @@ void HistoryWidget::updateTopBarSelection() {
}
void HistoryWidget::messageDataReceived(ChannelData *channel, MsgId msgId) {
if (!_peer || _peer->asChannel() != channel || !msgId) return;
if (!_peer || _peer->asChannel() != channel || !msgId) {
return;
}
if (_editMsgId == msgId || _replyToId == msgId) {
updateReplyEditTexts(true);
}
if (_pinnedBar && _pinnedBar->msgId == msgId) {
updatePinnedBar(true);
}
}
void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
@ -6420,49 +6371,49 @@ void HistoryWidget::drawRecording(Painter &p, float64 recordActive) {
p.setPen(anim::pen(st::historyRecordCancel, st::historyRecordCancelActive, 1. - recordActive));
p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, tr::lng_record_cancel(tr::now));
}
void HistoryWidget::drawPinnedBar(Painter &p) {
Expects(_pinnedBar != nullptr);
auto top = _topBar->bottomNoMargins();
p.fillRect(myrtlrect(0, top, width(), st::historyReplyHeight), st::historyPinnedBg);
top += st::msgReplyPadding.top();
QRect rbar(myrtlrect(st::msgReplyBarSkip + st::msgReplyBarPos.x(), top + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height()));
p.fillRect(rbar, st::msgInReplyBarColor);
int32 left = st::msgReplyBarSkip + st::msgReplyBarSkip;
if (_pinnedBar->msg) {
const auto media = _pinnedBar->msg->media();
if (media && media->hasReplyPreview()) {
if (const auto image = media->replyPreview()) {
QRect to(left, top, st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
p.drawPixmap(to.x(), to.y(), image->pixSingle(image->width() / cIntRetinaFactor(), image->height() / cIntRetinaFactor(), to.width(), to.height(), ImageRoundRadius::Small));
}
left += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
}
p.setPen(st::historyReplyNameFg);
p.setFont(st::msgServiceNameFont);
const auto poll = media ? media->poll() : nullptr;
const auto pinnedHeader = (_pinnedBar->msgId < _peer->topPinnedMessageId())
? tr::lng_pinned_previous(tr::now)
: !poll
? tr::lng_pinned_message(tr::now)
: poll->quiz()
? tr::lng_pinned_quiz(tr::now)
: tr::lng_pinned_poll(tr::now);
p.drawText(left, top + st::msgServiceNameFont->ascent, pinnedHeader);
p.setPen(st::historyComposeAreaFg);
p.setTextPalette(st::historyComposeAreaPalette);
_pinnedBar->text.drawElided(p, left, top + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right());
p.restoreTextPalette();
} else {
p.setFont(st::msgDateFont);
p.setPen(st::historyComposeAreaFgService);
p.drawText(left, top + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right()));
}
}
//
//void HistoryWidget::drawPinnedBar(Painter &p) {
// Expects(_pinnedBar != nullptr);
//
// auto top = _topBar->bottomNoMargins();
// p.fillRect(myrtlrect(0, top, width(), st::historyReplyHeight), st::historyPinnedBg);
//
// top += st::msgReplyPadding.top();
// QRect rbar(myrtlrect(st::msgReplyBarSkip + st::msgReplyBarPos.x(), top + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height()));
// p.fillRect(rbar, st::msgInReplyBarColor);
//
// //int32 left = st::msgReplyBarSkip + st::msgReplyBarSkip;
// //if (_pinnedBar->msg) {
// // const auto media = _pinnedBar->msg->media();
// // if (media && media->hasReplyPreview()) {
// // if (const auto image = media->replyPreview()) {
// // QRect to(left, top, st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
// // p.drawPixmap(to.x(), to.y(), image->pixSingle(image->width() / cIntRetinaFactor(), image->height() / cIntRetinaFactor(), to.width(), to.height(), ImageRoundRadius::Small));
// // }
// // left += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
// // }
// // p.setPen(st::historyReplyNameFg);
// // p.setFont(st::msgServiceNameFont);
// // const auto poll = media ? media->poll() : nullptr;
// // const auto pinnedHeader = (_pinnedBar->msgId < _peer->topPinnedMessageId())
// // ? tr::lng_pinned_previous(tr::now)
// // : !poll
// // ? tr::lng_pinned_message(tr::now)
// // : poll->quiz()
// // ? tr::lng_pinned_quiz(tr::now)
// // : tr::lng_pinned_poll(tr::now);
// // p.drawText(left, top + st::msgServiceNameFont->ascent, pinnedHeader);
//
// // p.setPen(st::historyComposeAreaFg);
// // p.setTextPalette(st::historyComposeAreaPalette);
// // _pinnedBar->text.drawElided(p, left, top + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right());
// // p.restoreTextPalette();
// //} else {
// // p.setFont(st::msgDateFont);
// // p.setPen(st::historyComposeAreaFgService);
// // p.drawText(left, top + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right()));
// //}
//}
bool HistoryWidget::paintShowAnimationFrame() {
auto progress = _a_show.value(1.);
@ -6513,9 +6464,6 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
} else if (const auto error = writeRestriction()) {
drawRestrictedWrite(p, *error);
}
if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {
drawPinnedBar(p);
}
} else {
const auto w = st::msgServiceFont->width(tr::lng_willbe_history(tr::now))
+ st::msgPadding.left()

View file

@ -66,6 +66,7 @@ class SilentToggle;
class FlatButton;
class LinkButton;
class RoundButton;
class MessageBar;
namespace Toast {
class Instance;
} // namespace Toast
@ -94,6 +95,7 @@ class TopBarWidget;
class ContactStatus;
class Element;
class PinnedTracker;
class PinnedBar;
} // namespace HistoryView
class DragArea;
@ -326,16 +328,6 @@ private slots:
private:
using TabbedPanel = ChatHelpers::TabbedPanel;
using TabbedSelector = ChatHelpers::TabbedSelector;
struct PinnedBar {
PinnedBar(MsgId msgId, HistoryWidget *parent);
~PinnedBar();
MsgId msgId = 0;
HistoryItem *msg = nullptr;
Ui::Text::String text;
object_ptr<Ui::IconButton> cancel;
object_ptr<Ui::PlainShadow> shadow;
};
enum ScrollChangeType {
ScrollChangeNone,
@ -492,10 +484,6 @@ private:
void updateReplyEditTexts(bool force = false);
void updateReplyEditText(not_null<HistoryItem*> item);
void showPinnedMessage(FullMsgId id);
void updatePinnedBar(bool force = false);
bool pinnedMsgVisibilityUpdated();
void destroyPinnedBar();
void updatePinnedViewer();
void setupPinnedTracker();
@ -511,7 +499,6 @@ private:
int left,
int top) const;
void drawRecording(Painter &p, float64 recordActive);
void drawPinnedBar(Painter &p);
void drawRestrictedWrite(Painter &p, const QString &error);
bool paintShowAnimationFrame();
@ -614,9 +601,9 @@ private:
object_ptr<Ui::IconButton> _fieldBarCancel;
FullMsgId _pinnedId;
std::unique_ptr<PinnedBar> _pinnedBar;
std::unique_ptr<HistoryView::PinnedTracker> _pinnedTracker;
std::unique_ptr<HistoryView::PinnedBar> _pinnedBar;
int _pinnedBarHeight = 0;
mtpRequestId _saveEditMsgRequestId = 0;
@ -705,7 +692,6 @@ private:
bool _recording = false;
bool _inField = false;
bool _inReplyEditForward = false;
bool _inPinnedMsg = false;
bool _inClickable = false;
int _recordingSamples = 0;
int _recordCancelWidth;

View file

@ -0,0 +1,229 @@
/*
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 "history/view/history_view_pinned_bar.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_changes.h"
#include "data/data_poll.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h"
#include "history/history_item.h"
#include "history/history.h"
#include "apiwrap.h"
#include "styles/style_chat.h"
namespace HistoryView {
namespace {
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem(
not_null<HistoryItem*> item) {
return item->history()->session().changes().messageFlagsValue(
item,
Data::MessageUpdate::Flag::Edited
) | rpl::map([=] {
const auto media = item->media();
const auto poll = media ? media->poll() : nullptr;
return Ui::MessageBarContent{
.id = item->id,
.title = ((item->id < item->history()->peer->topPinnedMessageId())
? tr::lng_pinned_previous(tr::now)
: !poll
? tr::lng_pinned_message(tr::now)
: poll->quiz()
? tr::lng_pinned_quiz(tr::now)
: tr::lng_pinned_poll(tr::now)),
.text = item->inReplyText(),
};
});
}
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId(
not_null<Main::Session*> session,
FullMsgId id,
bool alreadyLoaded = false) {
if (!id) {
return rpl::single(Ui::MessageBarContent());
} else if (const auto item = session->data().message(id)) {
return ContentByItem(item);
} else if (alreadyLoaded) {
return rpl::single(Ui::MessageBarContent()); // Deleted message?..
}
auto load = rpl::make_producer<Ui::MessageBarContent>([=](auto consumer) {
consumer.put_next(Ui::MessageBarContent{
.text = tr::lng_contacts_loading(tr::now),
});
const auto channel = id.channel
? session->data().channel(id.channel).get()
: nullptr;
const auto callback = [=](ChannelData *channel, MsgId id) {
consumer.put_done();
};
session->api().requestMessageData(channel, id.msg, callback);
return rpl::lifetime();
});
return std::move(
load
) | rpl::then(rpl::deferred([=] {
return ContentByItemId(session, id, true);
}));
}
} // namespace
PinnedBar::PinnedBar(
not_null<QWidget*> parent,
not_null<Main::Session*> session,
rpl::producer<FullMsgId> itemId,
bool withClose)
: _wrap(parent, object_ptr<Ui::RpWidget>(parent))
, _close(withClose
? std::make_unique<Ui::IconButton>(
_wrap.entity(),
st::historyReplyCancel)
: nullptr)
, _shadow(std::make_unique<Ui::PlainShadow>(_wrap.parentWidget())) {
_wrap.hide(anim::type::instant);
_shadow->hide();
_wrap.entity()->paintRequest(
) | rpl::start_with_next([=](QRect clip) {
QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
}, lifetime());
_wrap.setAttribute(Qt::WA_OpaquePaintEvent);
rpl::duplicate(
itemId
) | rpl::distinct_until_changed(
) | rpl::map([=](FullMsgId id) {
return ContentByItemId(session, id);
}) | rpl::flatten_latest(
) | rpl::filter([=](const Ui::MessageBarContent &content) {
return !content.title.isEmpty() || !content.text.text.isEmpty();
}) | rpl::start_with_next([=](Ui::MessageBarContent &&content) {
const auto creating = !_bar;
if (creating) {
createControls();
}
_bar->set(std::move(content));
if (creating) {
_bar->finishAnimating();
}
}, lifetime());
std::move(
itemId
) | rpl::map([=](FullMsgId id) {
return !id;
}) | rpl::start_with_next([=](bool hidden) {
_shouldBeShown = !hidden;
if (!_forceHidden) {
_wrap.toggle(_shouldBeShown, anim::type::normal);
} else if (!_shouldBeShown) {
_bar = nullptr;
}
}, lifetime());
}
void PinnedBar::createControls() {
Expects(!_bar);
_bar = std::make_unique<Ui::MessageBar>(
_wrap.entity(),
st::defaultMessageBar);
if (_close) {
_close->raise();
}
_bar->widget()->move(0, 0);
_bar->widget()->show();
_wrap.entity()->resize(_wrap.entity()->width(), _bar->widget()->height());
_wrap.geometryValue(
) | rpl::start_with_next([=](QRect rect) {
_shadow->setGeometry(
rect.x(),
rect.y() + rect.height(),
rect.width(),
st::lineWidth);
_bar->widget()->resizeToWidth(
rect.width() - (_close ? _close->width() : 0));
const auto hidden = _wrap.isHidden() || !rect.height();
if (_shadow->isHidden() != hidden) {
_shadow->setVisible(!hidden);
}
if (_close) {
_close->moveToRight(0, 0);
}
}, _bar->widget()->lifetime());
_wrap.shownValue(
) | rpl::skip(
1
) | rpl::filter([=](bool shown) {
return !shown && !_forceHidden;
}) | rpl::start_with_next([=] {
_bar = nullptr;
}, _bar->widget()->lifetime());
Ensures(_bar != nullptr);
}
void PinnedBar::show() {
if (!_forceHidden) {
return;
}
_forceHidden = false;
if (_shouldBeShown) {
_wrap.show(anim::type::instant);
_shadow->show();
}
}
void PinnedBar::hide() {
if (_forceHidden) {
return;
}
_forceHidden = true;
_wrap.hide(anim::type::instant);
_shadow->hide();
}
void PinnedBar::raise() {
_wrap.raise();
_shadow->raise();
}
void PinnedBar::move(int x, int y) {
_wrap.move(x, y);
}
void PinnedBar::resizeToWidth(int width) {
_wrap.entity()->resizeToWidth(width);
}
int PinnedBar::height() const {
return !_forceHidden
? _wrap.height()
: _shouldBeShown
? st::historyReplyHeight
: 0;
}
rpl::producer<int> PinnedBar::heightValue() const {
return _wrap.heightValue();
}
rpl::producer<> PinnedBar::closeClicks() const {
return !_close
? (rpl::never<>() | rpl::type_erased())
: (_close->clicks() | rpl::map([] { return rpl::empty_value(); }));
}
} // namespace HistoryView

View file

@ -0,0 +1,59 @@
/*
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/wrap/slide_wrap.h"
#include "ui/chat/message_bar.h"
namespace Main {
class Session;
} // namespace Main
namespace Ui {
class IconButton;
class PlainShadow;
} // namespace Ui
namespace HistoryView {
class PinnedBar final {
public:
PinnedBar(
not_null<QWidget*> parent,
not_null<Main::Session*> session,
rpl::producer<FullMsgId> itemId,
bool withClose = false);
void show();
void hide();
void raise();
void move(int x, int y);
void resizeToWidth(int width);
[[nodiscard]] int height() const;
[[nodiscard]] rpl::producer<int> heightValue() const;
[[nodiscard]] rpl::producer<> closeClicks() const;
[[nodiscard]] rpl::lifetime &lifetime() {
return _wrap.lifetime();
}
private:
void createControls();
Ui::SlideWrap<> _wrap;
std::unique_ptr<Ui::MessageBar> _bar;
std::unique_ptr<Ui::IconButton> _close;
std::unique_ptr<Ui::PlainShadow> _shadow;
rpl::event_stream<Ui::MessageBarContent> _content;
bool _shouldBeShown = false;
bool _forceHidden = false;
};
} // namespace HistoryView

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_options.h"
#include "styles/style_chat.h"
#include "styles/palette.h"
namespace Ui {
@ -205,7 +206,7 @@ void MessageBar::paint(Painter &p) {
const auto imageShown = _animation
? _animation->imageShown.value(imageFinal)
: imageFinal;
if (progress == 1. && imageShown == 1. && _animation) {
if (progress == 1. && imageShown == imageFinal && _animation) {
_animation = nullptr;
}
const auto body = [&] {
@ -237,6 +238,13 @@ void MessageBar::paint(Painter &p) {
? (shiftTo - shiftFull)
: (shiftTo + shiftFull);
const auto bar = QRect(
st::msgReplyBarSkip + st::msgReplyBarPos.x(),
st::msgReplyPadding.top() + st::msgReplyBarPos.y(),
st::msgReplyBarSize.width(),
st::msgReplyBarSize.height());
p.fillRect(bar, st::msgInReplyBarColor);
if (!_animation) {
if (!_image.isNull()) {
p.drawPixmap(image, _image);
@ -261,6 +269,7 @@ void MessageBar::paint(Painter &p) {
_animation->imageFrom);
p.setOpacity(progress);
p.drawPixmap(rect.translated(0, shiftTo), _animation->imageTo);
p.setOpacity(1.);
} else {
p.drawPixmap(rect, _image);
}
@ -277,6 +286,7 @@ void MessageBar::paint(Painter &p) {
_animation->bodyOrTextFrom);
p.setOpacity(progress);
p.drawPixmap(body.x(), text.y() + shiftTo, _animation->bodyOrTextTo);
p.setOpacity(1.);
}
if (!_animation || _animation->bodyAnimation != BodyAnimation::Full) {
p.setPen(_st.titleFg);
@ -289,6 +299,7 @@ void MessageBar::paint(Painter &p) {
_animation->bodyOrTextFrom);
p.setOpacity(progress);
p.drawPixmap(body.x(), body.y() + shiftTo, _animation->bodyOrTextTo);
p.setOpacity(1.);
}
}