From 67290eed586a0429195f86c9ff4c0de662ec6ecc Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 10 Oct 2020 15:04:28 +0300 Subject: [PATCH] Use new message bar for pinned message. --- Telegram/CMakeLists.txt | 2 + .../SourceFiles/history/history_widget.cpp | 386 ++++++++---------- Telegram/SourceFiles/history/history_widget.h | 22 +- .../history/view/history_view_pinned_bar.cpp | 229 +++++++++++ .../history/view/history_view_pinned_bar.h | 59 +++ Telegram/SourceFiles/ui/chat/message_bar.cpp | 13 +- 6 files changed, 473 insertions(+), 238 deletions(-) create mode 100644 Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp create mode 100644 Telegram/SourceFiles/history/view/history_view_pinned_bar.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index abc87d05b3..5a0a439a9e 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -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 diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 7474dc637f..ff32dd3e1f 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -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 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 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(_history); - _pinnedTracker->shownMessageId( - ) | rpl::start_with_next([=](MsgId messageId) { - showPinnedMessage({ peerToChannel(_peer->id), messageId }); - }, _list->lifetime()); -} + _pinnedBar = std::make_unique( + 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()) { + _pinnedBar->closeClicks( + ) | rpl::start_with_next([=] { + hidePinnedMessage(); + }, _pinnedBar->lifetime()); + + _pinnedBarHeight = 0; + _pinnedBar->heightValue( + ) | rpl::start_with_next([=](int height) { + _topDelta = (height - _pinnedBarHeight); + _pinnedBarHeight = height; updateHistoryGeometry(); - updateControlsVisibility(); updateControlsGeometry(); - this->update(); + _topDelta = 0; + }, _pinnedBar->lifetime()); + orderWidgets(); + if (_a_show.animating()) { + _pinnedBar->hide(); } } - -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(pinnedId.msg, this); - if (_a_show.animating()) { - _pinnedBar->cancel->hide(); - _pinnedBar->shadow->hide(); - } else { - _pinnedBar->cancel->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; - _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); - } - updateControlsGeometry(); - } - 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(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 document, Api::SendOptions options) { @@ -5622,25 +5574,25 @@ void HistoryWidget::UnpinMessage(not_null 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 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() diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index e23a4de00c..db6ed145b9 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -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 cancel; - object_ptr shadow; - }; enum ScrollChangeType { ScrollChangeNone, @@ -492,10 +484,6 @@ private: void updateReplyEditTexts(bool force = false); void updateReplyEditText(not_null 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 _fieldBarCancel; - FullMsgId _pinnedId; - std::unique_ptr _pinnedBar; std::unique_ptr _pinnedTracker; + std::unique_ptr _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; diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp new file mode 100644 index 0000000000..82aaafc42d --- /dev/null +++ b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp @@ -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 ContentByItem( + not_null 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 ContentByItemId( + not_null 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([=](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 parent, + not_null session, + rpl::producer itemId, + bool withClose) +: _wrap(parent, object_ptr(parent)) +, _close(withClose + ? std::make_unique( + _wrap.entity(), + st::historyReplyCancel) + : nullptr) +, _shadow(std::make_unique(_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( + _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 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 \ No newline at end of file diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_bar.h b/Telegram/SourceFiles/history/view/history_view_pinned_bar.h new file mode 100644 index 0000000000..e6e61e9314 --- /dev/null +++ b/Telegram/SourceFiles/history/view/history_view_pinned_bar.h @@ -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 parent, + not_null session, + rpl::producer 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 heightValue() const; + [[nodiscard]] rpl::producer<> closeClicks() const; + + [[nodiscard]] rpl::lifetime &lifetime() { + return _wrap.lifetime(); + } + +private: + void createControls(); + + Ui::SlideWrap<> _wrap; + std::unique_ptr _bar; + std::unique_ptr _close; + std::unique_ptr _shadow; + rpl::event_stream _content; + bool _shouldBeShown = false; + bool _forceHidden = false; + +}; + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/ui/chat/message_bar.cpp b/Telegram/SourceFiles/ui/chat/message_bar.cpp index cf4a27c602..05a02f16cf 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bar.cpp @@ -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.); } }