Add jump-to-topic panel in View as Messages.

This commit is contained in:
John Preston 2022-12-02 18:19:56 +04:00
parent 8281990bb8
commit a4e4681835
25 changed files with 470 additions and 150 deletions

View File

@ -2213,7 +2213,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
history->requestChatListMessage(); history->requestChatListMessage();
if (!history->folderKnown() if (!history->folderKnown()
|| (!history->unreadCountKnown() || (!history->unreadCountKnown()
&& !history->peer->isForum())) { && !history->isForum())) {
history->owner().histories().requestDialogEntry(history); history->owner().histories().requestDialogEntry(history);
} }
if (!channel->amCreator()) { if (!channel->amCreator()) {

View File

@ -86,8 +86,7 @@ forumDialogRow: DialogRow(defaultDialogRow) {
forumDialogJumpArrow: icon{{ "dialogs/dialogs_topic_arrow", dialogsTextFg }}; forumDialogJumpArrow: icon{{ "dialogs/dialogs_topic_arrow", dialogsTextFg }};
forumDialogJumpArrowOver: icon{{ "dialogs/dialogs_topic_arrow", dialogsTextFgOver }}; forumDialogJumpArrowOver: icon{{ "dialogs/dialogs_topic_arrow", dialogsTextFgOver }};
forumDialogJumpArrowSkip: 8px; forumDialogJumpArrowSkip: 8px;
forumDialogJumpArrowLeft: 3px; forumDialogJumpArrowPosition: point(3px, 3px);
forumDialogJumpArrowTop: 3px;
forumDialogJumpPadding: margins(8px, 3px, 8px, 3px); forumDialogJumpPadding: margins(8px, 3px, 8px, 3px);
forumDialogJumpRadius: 11px; forumDialogJumpRadius: 11px;

View File

@ -571,8 +571,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
bool mayBeActive) { bool mayBeActive) {
const auto key = row->key(); const auto key = row->key();
const auto active = mayBeActive && (activeEntry.key == key); const auto active = mayBeActive && (activeEntry.key == key);
const auto forum = key.history() const auto forum = key.history() && key.history()->isForum();
&& key.history()->peer->isForum();
if (forum && !_topicJumpCache) { if (forum && !_topicJumpCache) {
_topicJumpCache = std::make_unique<Ui::TopicJumpCache>(); _topicJumpCache = std::make_unique<Ui::TopicJumpCache>();
} }

View File

@ -264,7 +264,7 @@ Row::Row(Key key, int index, int top) : _id(key), _top(top), _index(index) {
void Row::recountHeight(float64 narrowRatio) { void Row::recountHeight(float64 narrowRatio) {
if (const auto history = _id.history()) { if (const auto history = _id.history()) {
_height = history->peer->isForum() _height = history->isForum()
? anim::interpolate( ? anim::interpolate(
st::forumDialogRow.height, st::forumDialogRow.height,
st::defaultDialogRow.height, st::defaultDialogRow.height,

View File

@ -455,7 +455,7 @@ void Widget::chosenRow(const ChosenRow &row) {
topic, topic,
row.message.fullId.msg, row.message.fullId.msg,
Window::SectionShow::Way::ClearStack); Window::SectionShow::Way::ClearStack);
} else if (history && history->peer->isForum() && !row.message.fullId) { } else if (history && history->isForum() && !row.message.fullId) {
const auto forum = history->peer->forum(); const auto forum = history->peer->forum();
if (controller()->shownForum().current() == forum) { if (controller()->shownForum().current() == forum) {
controller()->closeForum(); controller()->closeForum();
@ -1916,7 +1916,7 @@ void Widget::dropEvent(QDropEvent *e) {
controller()->content()->filesOrForwardDrop( controller()->content()->filesOrForwardDrop(
thread, thread,
e->mimeData()); e->mimeData());
if (!thread->owningHistory()->peer->isForum()) { if (!thread->owningHistory()->isForum()) {
hideChildList(); hideChildList();
} }
controller()->widget()->raise(); controller()->widget()->raise();

View File

@ -56,7 +56,7 @@ const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
} else if (const auto user = history->peer->asUser()) { } else if (const auto user = history->peer->asUser()) {
return (user->onlineTill > 0); return (user->onlineTill > 0);
} }
return !history->peer->isForum(); return !history->isForum();
} }
void PaintRowTopRight( void PaintRowTopRight(

View File

@ -326,14 +326,11 @@ void MessageView::paint(
rect.setLeft(rect.x() + _textCache.maxWidth()); rect.setLeft(rect.x() + _textCache.maxWidth());
} }
if (jump1) { if (jump1) {
const auto x = (rect.width() > 0) const auto position = st::forumDialogJumpArrowPosition
? rect.x() + QPoint((rect.width() > 0) ? rect.x() : finalRight, rect.y());
: finalRight;
const auto add = st::forumDialogJumpArrowLeft;
const auto y = rect.y() + st::forumDialogJumpArrowTop;
(context.selected (context.selected
? st::forumDialogJumpArrowOver ? st::forumDialogJumpArrowOver
: st::forumDialogJumpArrow).paint(p, x + add, y, context.width); : st::forumDialogJumpArrow).paint(p, position, context.width);
} }
} }

View File

@ -1271,7 +1271,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
if (item->unread(this)) { if (item->unread(this)) {
if (unreadCountKnown()) { if (unreadCountKnown()) {
setUnreadCount(unreadCount() + 1); setUnreadCount(unreadCount() + 1);
} else if (!peer->isForum()) { } else if (!isForum()) {
owner().histories().requestDialogEntry(this); owner().histories().requestDialogEntry(this);
} }
} else { } else {
@ -1800,7 +1800,7 @@ void History::setUnreadCount(int newUnreadCount) {
if (_unreadCount == newUnreadCount) { if (_unreadCount == newUnreadCount) {
return; return;
} }
const auto notifier = unreadStateChangeNotifier(!peer->isForum()); const auto notifier = unreadStateChangeNotifier(!isForum());
_unreadCount = newUnreadCount; _unreadCount = newUnreadCount;
const auto lastOutgoing = [&] { const auto lastOutgoing = [&] {
@ -1839,7 +1839,7 @@ void History::setUnreadMark(bool unread) {
return; return;
} }
const auto notifier = unreadStateChangeNotifier( const auto notifier = unreadStateChangeNotifier(
!unreadCount() && !peer->isForum()); !unreadCount() && !isForum());
Thread::setUnreadMarkFlag(unread); Thread::setUnreadMarkFlag(unread);
} }
@ -1871,7 +1871,7 @@ void History::setMuted(bool muted) {
if (this->muted() == muted) { if (this->muted() == muted) {
return; return;
} else { } else {
const auto state = peer->isForum() const auto state = isForum()
? Dialogs::BadgesState() ? Dialogs::BadgesState()
: computeBadgesState(); : computeBadgesState();
const auto notify = (state.unread || state.reaction); const auto notify = (state.unread || state.reaction);
@ -1984,7 +1984,7 @@ int History::chatListNameVersion() const {
} }
void History::hasUnreadMentionChanged(bool has) { void History::hasUnreadMentionChanged(bool has) {
if (peer->isForum()) { if (isForum()) {
return; return;
} }
auto was = chatListUnreadState(); auto was = chatListUnreadState();
@ -1997,7 +1997,7 @@ void History::hasUnreadMentionChanged(bool has) {
} }
void History::hasUnreadReactionChanged(bool has) { void History::hasUnreadReactionChanged(bool has) {
if (peer->isForum()) { if (isForum()) {
return; return;
} }
auto was = chatListUnreadState(); auto was = chatListUnreadState();
@ -2966,18 +2966,22 @@ HistoryItem *History::lastEditableMessage() const {
} }
void History::resizeToWidth(int newWidth) { void History::resizeToWidth(int newWidth) {
const auto resizeAllItems = (_width != newWidth); using Request = HistoryBlock::ResizeRequest;
const auto request = (_flags & Flag::PendingAllItemsResize)
if (!resizeAllItems && !hasPendingResizedItems()) { ? Request::ReinitAll
: (_width != newWidth)
? Request::ResizeAll
: Request::ResizePending;
if (request == Request::ResizePending && !hasPendingResizedItems()) {
return; return;
} }
_flags &= ~(Flag::HasPendingResizedItems); _flags &= ~(Flag::HasPendingResizedItems | Flag::PendingAllItemsResize);
_width = newWidth; _width = newWidth;
int y = 0; int y = 0;
for (const auto &block : blocks) { for (const auto &block : blocks) {
block->setY(y); block->setY(y);
y += block->resizeGetHeight(newWidth, resizeAllItems); y += block->resizeGetHeight(newWidth, request);
} }
_height = y; _height = y;
} }
@ -3024,6 +3028,11 @@ void History::forumChanged(Data::Forum *old) {
if (cloudDraft(MsgId(0))) { if (cloudDraft(MsgId(0))) {
updateChatListSortPosition(); updateChatListSortPosition();
} }
_flags |= Flag::PendingAllItemsResize;
}
bool History::isForum() const {
return (_flags & Flag::IsForum);
} }
not_null<History*> History::migrateToOrMe() const { not_null<History*> History::migrateToOrMe() const {
@ -3441,14 +3450,25 @@ HistoryBlock::HistoryBlock(not_null<History*> history)
: _history(history) { : _history(history) {
} }
int HistoryBlock::resizeGetHeight(int newWidth, bool resizeAllItems) { int HistoryBlock::resizeGetHeight(int newWidth, ResizeRequest request) {
auto y = 0; auto y = 0;
for (const auto &message : messages) { if (request == ResizeRequest::ReinitAll) {
message->setY(y); for (const auto &message : messages) {
if (resizeAllItems || message->pendingResize()) { message->setY(y);
message->initDimensions();
y += message->resizeGetHeight(newWidth); y += message->resizeGetHeight(newWidth);
} else { }
y += message->height(); } else if (request == ResizeRequest::ResizeAll) {
for (const auto &message : messages) {
message->setY(y);
y += message->resizeGetHeight(newWidth);
}
} else {
for (const auto &message : messages) {
message->setY(y);
y += message->pendingResize()
? message->resizeGetHeight(newWidth)
: message->height();
} }
} }
_height = y; _height = y;

View File

@ -94,6 +94,7 @@ public:
} }
void forumChanged(Data::Forum *old); void forumChanged(Data::Forum *old);
[[nodiscard]] bool isForum() const;
not_null<History*> migrateToOrMe() const; not_null<History*> migrateToOrMe() const;
History *migrateFrom() const; History *migrateFrom() const;
@ -462,10 +463,11 @@ private:
enum class Flag : uchar { enum class Flag : uchar {
HasPendingResizedItems = (1 << 0), HasPendingResizedItems = (1 << 0),
IsTopPromoted = (1 << 1), PendingAllItemsResize = (1 << 1),
IsForum = (1 << 2), IsTopPromoted = (1 << 2),
FakeUnreadWhileOpened = (1 << 3), IsForum = (1 << 3),
HasPinnedMessages = (1 << 4), FakeUnreadWhileOpened = (1 << 4),
HasPinnedMessages = (1 << 5),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { friend inline constexpr auto is_flag_type(Flag) {
@ -636,12 +638,18 @@ private:
HistoryView::SendActionPainter _sendActionPainter; HistoryView::SendActionPainter _sendActionPainter;
}; };
class HistoryBlock { class HistoryBlock {
public: public:
using Element = HistoryView::Element; using Element = HistoryView::Element;
enum class ResizeRequest {
ReinitAll = 0,
ResizeAll = 1,
ResizePending = 2,
};
HistoryBlock(not_null<History*> history); HistoryBlock(not_null<History*> history);
HistoryBlock(const HistoryBlock &) = delete; HistoryBlock(const HistoryBlock &) = delete;
HistoryBlock &operator=(const HistoryBlock &) = delete; HistoryBlock &operator=(const HistoryBlock &) = delete;
@ -652,7 +660,7 @@ public:
void remove(not_null<Element*> view); void remove(not_null<Element*> view);
void refreshView(not_null<Element*> view); void refreshView(not_null<Element*> view);
int resizeGetHeight(int newWidth, bool resizeAllItems); int resizeGetHeight(int newWidth, ResizeRequest request);
int y() const { int y() const {
return _y; return _y;
} }

View File

@ -227,7 +227,7 @@ public:
return _widget ? _widget->elementAnimationsPaused() : false; return _widget ? _widget->elementAnimationsPaused() : false;
} }
bool elementHideReply(not_null<const Element*> view) override { bool elementHideReply(not_null<const Element*> view) override {
return false; return view->isTopicRootReply();
} }
bool elementShownUnread(not_null<const Element*> view) override { bool elementShownUnread(not_null<const Element*> view) override {
return view->data()->unread(view->data()->history()); return view->data()->unread(view->data()->history());
@ -2096,7 +2096,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
const auto repliesCount = item->repliesCount(); const auto repliesCount = item->repliesCount();
const auto withReplies = (repliesCount > 0); const auto withReplies = (repliesCount > 0);
const auto topicRootId = item->history()->peer->isForum() const auto topicRootId = item->history()->isForum()
? item->topicRootId() ? item->topicRootId()
: 0; : 0;
if (topicRootId if (topicRootId

View File

@ -775,7 +775,7 @@ void HistoryItem::setRealId(MsgId newId) {
} }
_history->owner().notifyItemDataChange(this); _history->owner().notifyItemDataChange(this);
_history->owner().requestItemRepaint(this); _history->owner().requestItemResize(this);
} }
bool HistoryItem::canPin() const { bool HistoryItem::canPin() const {

View File

@ -2971,7 +2971,7 @@ void HistoryWidget::unreadCountUpdated() {
} }
}); });
} else { } else {
_cornerButtons.updateJumpDownVisibility(_history->peer->isForum() _cornerButtons.updateJumpDownVisibility(_history->isForum()
? 0 ? 0
: _history->chatListBadgesState().unreadCounter); : _history->chatListBadgesState().unreadCounter);
} }
@ -5991,7 +5991,7 @@ void HistoryWidget::handlePeerMigration() {
} }
bool HistoryWidget::replyToPreviousMessage() { bool HistoryWidget::replyToPreviousMessage() {
if (!_history || _editMsgId || _history->peer->isForum()) { if (!_history || _editMsgId || _history->isForum()) {
return false; return false;
} }
const auto fullId = FullMsgId(_history->peer->id, _replyToId); const auto fullId = FullMsgId(_history->peer->id, _replyToId);
@ -6014,7 +6014,7 @@ bool HistoryWidget::replyToPreviousMessage() {
} }
bool HistoryWidget::replyToNextMessage() { bool HistoryWidget::replyToNextMessage() {
if (!_history || _editMsgId || _history->peer->isForum()) { if (!_history || _editMsgId || _history->isForum()) {
return false; return false;
} }
const auto fullId = FullMsgId(_history->peer->id, _replyToId); const auto fullId = FullMsgId(_history->peer->id, _replyToId);

View File

@ -617,7 +617,7 @@ bool AddViewRepliesAction(
|| (context != Context::History && context != Context::Pinned)) { || (context != Context::History && context != Context::Pinned)) {
return false; return false;
} }
const auto topicRootId = item->history()->peer->isForum() const auto topicRootId = item->history()->isForum()
? item->topicRootId() ? item->topicRootId()
: 0; : 0;
const auto repliesCount = item->repliesCount(); const auto repliesCount = item->repliesCount();

View File

@ -566,6 +566,10 @@ bool Element::isBubbleAttachedToNext() const {
return _flags & Flag::BubbleAttachedToNext; return _flags & Flag::BubbleAttachedToNext;
} }
bool Element::isTopicRootReply() const {
return _flags & Flag::TopicRootReply;
}
int Element::skipBlockWidth() const { int Element::skipBlockWidth() const {
return st::msgDateSpace + infoWidth() - st::msgDateDelta.x(); return st::msgDateSpace + infoWidth() - st::msgDateDelta.x();
} }
@ -905,7 +909,8 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
< kAttachMessageToPreviousSecondsDelta) < kAttachMessageToPreviousSecondsDelta)
&& mayBeAttached(this) && mayBeAttached(this)
&& mayBeAttached(previous) && mayBeAttached(previous)
&& (!previousMarkup || previousMarkup->hiddenBy(prev->media())); && (!previousMarkup || previousMarkup->hiddenBy(prev->media()))
&& (item->topicRootId() == prev->topicRootId());
if (possible) { if (possible) {
const auto forwarded = item->Get<HistoryMessageForwarded>(); const auto forwarded = item->Get<HistoryMessageForwarded>();
const auto prevForwarded = prev->Get<HistoryMessageForwarded>(); const auto prevForwarded = prev->Get<HistoryMessageForwarded>();
@ -1068,17 +1073,35 @@ void Element::recountDisplayDateInBlocks() {
} }
QSize Element::countOptimalSize() { QSize Element::countOptimalSize() {
_flags &= ~Flag::NeedsResize;
return performCountOptimalSize(); return performCountOptimalSize();
} }
QSize Element::countCurrentSize(int newWidth) { QSize Element::countCurrentSize(int newWidth) {
if (_flags & Flag::NeedsResize) { if (_flags & Flag::NeedsResize) {
_flags &= ~Flag::NeedsResize;
initDimensions(); initDimensions();
} }
return performCountCurrentSize(newWidth); return performCountCurrentSize(newWidth);
} }
void Element::refreshIsTopicRootReply() {
const auto topicRootReply = countIsTopicRootReply();
if (topicRootReply) {
_flags |= Flag::TopicRootReply;
} else {
_flags &= ~Flag::TopicRootReply;
}
}
bool Element::countIsTopicRootReply() const {
const auto item = data();
if (!item->history()->isForum()) {
return false;
}
const auto replyTo = item->replyToId();
return !replyTo || (item->topicRootId() == replyTo);
}
void Element::setDisplayDate(bool displayDate) { void Element::setDisplayDate(bool displayDate) {
const auto item = data(); const auto item = data();
if (displayDate && !Has<DateBadge>()) { if (displayDate && !Has<DateBadge>()) {
@ -1156,6 +1179,10 @@ bool Element::displayFromName() const {
return false; return false;
} }
bool Element::displayTopicButton() const {
return false;
}
bool Element::displayForwardedFrom() const { bool Element::displayForwardedFrom() const {
return false; return false;
} }

View File

@ -254,6 +254,7 @@ public:
SpecialOnlyEmoji = 0x0080, SpecialOnlyEmoji = 0x0080,
CustomEmojiRepainting = 0x0100, CustomEmojiRepainting = 0x0100,
ScheduledUntilOnline = 0x0200, ScheduledUntilOnline = 0x0200,
TopicRootReply = 0x0400,
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }
@ -290,6 +291,8 @@ public:
[[nodiscard]] bool isBubbleAttachedToPrevious() const; [[nodiscard]] bool isBubbleAttachedToPrevious() const;
[[nodiscard]] bool isBubbleAttachedToNext() const; [[nodiscard]] bool isBubbleAttachedToNext() const;
[[nodiscard]] bool isTopicRootReply() const;
[[nodiscard]] int skipBlockWidth() const; [[nodiscard]] int skipBlockWidth() const;
[[nodiscard]] int skipBlockHeight() const; [[nodiscard]] int skipBlockHeight() const;
[[nodiscard]] virtual int infoWidth() const; [[nodiscard]] virtual int infoWidth() const;
@ -373,6 +376,7 @@ public:
[[nodiscard]] virtual bool displayFromPhoto() const; [[nodiscard]] virtual bool displayFromPhoto() const;
[[nodiscard]] virtual bool hasFromName() const; [[nodiscard]] virtual bool hasFromName() const;
[[nodiscard]] virtual bool displayFromName() const; [[nodiscard]] virtual bool displayFromName() const;
[[nodiscard]] virtual bool displayTopicButton() const;
[[nodiscard]] virtual bool displayForwardedFrom() const; [[nodiscard]] virtual bool displayForwardedFrom() const;
[[nodiscard]] virtual bool hasOutLayout() const; [[nodiscard]] virtual bool hasOutLayout() const;
[[nodiscard]] virtual bool drawBubble() const; [[nodiscard]] virtual bool drawBubble() const;
@ -497,6 +501,7 @@ protected:
void clearSpecialOnlyEmoji(); void clearSpecialOnlyEmoji();
void checkSpecialOnlyEmoji(); void checkSpecialOnlyEmoji();
void refreshIsTopicRootReply();
private: private:
// This should be called only from previousInBlocksChanged() // This should be called only from previousInBlocksChanged()
@ -510,6 +515,8 @@ private:
// HistoryView::Element::Flag::AttachedToPrevious. // HistoryView::Element::Flag::AttachedToPrevious.
void recountAttachToPreviousInBlocks(); void recountAttachToPreviousInBlocks();
[[nodiscard]] bool countIsTopicRootReply() const;
QSize countOptimalSize() final override; QSize countOptimalSize() final override;
QSize countCurrentSize(int newWidth) final override; QSize countCurrentSize(int newWidth) final override;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_message.h" #include "history/view/history_view_message.h"
#include "core/click_handler_types.h" // ClickHandlerContext #include "core/click_handler_types.h" // ClickHandlerContext
#include "core/ui_integration.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "history/history_message.h" #include "history/history_message.h"
@ -225,6 +226,23 @@ QString FastReplyText() {
return tr::lng_fast_reply(tr::now); return tr::lng_fast_reply(tr::now);
} }
[[nodiscard]] ClickHandlerPtr MakeTopicButtonLink(
not_null<Data::ForumTopic*> topic,
MsgId messageId) {
const auto weak = base::make_weak(topic);
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
if (const auto strong = weak.get()) {
controller->showTopic(
strong,
messageId,
Window::SectionShow::Way::Forward);
}
}
});
}
} // namespace } // namespace
style::color FromNameFg( style::color FromNameFg(
@ -260,11 +278,19 @@ style::color FromNameFg(
struct Message::CommentsButton { struct Message::CommentsButton {
std::unique_ptr<Ui::RippleAnimation> ripple; std::unique_ptr<Ui::RippleAnimation> ripple;
int rippleShift = 0;
std::vector<UserpicInRow> userpics; std::vector<UserpicInRow> userpics;
QImage cachedUserpics; QImage cachedUserpics;
ClickHandlerPtr link; ClickHandlerPtr link;
QPoint lastPoint; QPoint lastPoint;
int rippleShift = 0;
};
struct Message::TopicButton {
std::unique_ptr<Ui::RippleAnimation> ripple;
ClickHandlerPtr link;
Ui::Text::String name;
QPoint lastPoint;
int nameVersion = 0;
}; };
struct Message::FromNameStatus { struct Message::FromNameStatus {
@ -488,9 +514,11 @@ auto Message::takeReactionAnimations()
QSize Message::performCountOptimalSize() { QSize Message::performCountOptimalSize() {
const auto item = message(); const auto item = message();
const auto markup = item->inlineReplyMarkup(); const auto markup = item->inlineReplyMarkup();
refreshIsTopicRootReply();
validateText(); validateText();
validateInlineKeyboard(markup); validateInlineKeyboard(markup);
updateViewButtonExistence(); updateViewButtonExistence();
refreshTopicButton();
updateMediaInBubbleState(); updateMediaInBubbleState();
refreshRightBadge(); refreshRightBadge();
refreshInfoSkipBlock(); refreshInfoSkipBlock();
@ -614,6 +642,15 @@ QSize Message::performCountOptimalSize() {
} else if (via && !displayForwardedFrom()) { } else if (via && !displayForwardedFrom()) {
accumulate_max(maxWidth, st::msgPadding.left() + via->maxWidth + st::msgPadding.right()); accumulate_max(maxWidth, st::msgPadding.left() + via->maxWidth + st::msgPadding.right());
} }
if (displayTopicButton()) {
const auto padding = st::msgPadding + st::topicButtonPadding;
accumulate_max(
maxWidth,
(padding.left()
+ _topicButton->name.maxWidth()
+ st::topicButtonArrowSkip
+ padding.right()));
}
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
const auto skip1 = forwarded->psaType.isEmpty() const auto skip1 = forwarded->psaType.isEmpty()
? 0 ? 0
@ -653,6 +690,34 @@ QSize Message::performCountOptimalSize() {
return QSize(maxWidth, minHeight); return QSize(maxWidth, minHeight);
} }
void Message::refreshTopicButton() {
const auto item = message();
if (isAttachedToPrevious() || context() != Context::History) {
_topicButton = nullptr;
} else if (const auto topic = item->topic()) {
if (!_topicButton) {
_topicButton = std::make_unique<TopicButton>();
}
const auto jumpToId = IsServerMsgId(item->id) ? item->id : MsgId();
_topicButton->link = MakeTopicButtonLink(topic, jumpToId);
if (_topicButton->nameVersion != topic->titleVersion()) {
_topicButton->nameVersion = topic->titleVersion();
const auto context = Core::MarkedTextContext{
.session = &history()->session(),
.customEmojiRepaint = [=] { customEmojiRepaint(); },
.customEmojiLoopLimit = 1,
};
_topicButton->name.setMarkedText(
st::fwdTextStyle,
topic->titleWithIcon(),
kMarkupTextOptions,
context);
}
} else {
_topicButton = nullptr;
}
}
int Message::marginTop() const { int Message::marginTop() const {
auto result = 0; auto result = 0;
if (!isHidden()) { if (!isHidden()) {
@ -869,6 +934,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
trect.setY(trect.y() - st::msgPadding.top()); trect.setY(trect.y() - st::msgPadding.top());
} else { } else {
paintFromName(p, trect, context); paintFromName(p, trect, context);
paintTopicButton(p, trect, context);
paintForwardedInfo(p, trect, context); paintForwardedInfo(p, trect, context);
paintReplyInfo(p, trect, context); paintReplyInfo(p, trect, context);
paintViaBotIdInfo(p, trect, context); paintViaBotIdInfo(p, trect, context);
@ -1233,6 +1299,71 @@ void Message::paintFromName(
trect.setY(trect.y() + st::msgNameFont->height); trect.setY(trect.y() + st::msgNameFont->height);
} }
void Message::paintTopicButton(
Painter &p,
QRect &trect,
const PaintContext &context) const {
if (!displayTopicButton()) {
return;
}
trect.setTop(trect.top() + st::topicButtonSkip);
const auto padding = st::topicButtonPadding;
const auto availableWidth = trect.width();
const auto height = padding.top()
+ st::msgNameFont->height
+ padding.bottom();
const auto width = std::max(
std::min(
availableWidth,
(padding.left()
+ _topicButton->name.maxWidth()
+ st::topicButtonArrowSkip
+ padding.right())),
height);
const auto rect = QRect(trect.x(), trect.y(), width, height);
const auto st = context.st;
const auto stm = context.messageStyle();
const auto skip = padding.right() + st::topicButtonArrowSkip;
auto color = stm->msgServiceFg->c;
color.setAlpha(color.alpha() / 8);
p.setPen(Qt::NoPen);
p.setBrush(color);
{
auto hq = PainterHighQualityEnabler(p);
p.drawRoundedRect(rect, height / 2, height / 2);
}
if (_topicButton->ripple) {
_topicButton->ripple->paint(
p,
rect.x(),
rect.y(),
this->width(),
&color);
if (_topicButton->ripple->empty()) {
_topicButton->ripple.reset();
}
}
clearCustomEmojiRepaint();
p.setPen(stm->msgServiceFg);
p.setTextPalette(stm->fwdTextPalette);
_topicButton->name.drawElided(
p,
trect.x() + padding.left(),
trect.y() + padding.top(),
width - padding.left() - skip);
const auto &icon = st::topicButtonArrow;
icon.paint(
p,
rect.x() + rect.width() - skip + st::topicButtonArrowPosition.x(),
rect.y() + padding.top() + st::topicButtonArrowPosition.y(),
this->width(),
stm->msgServiceFg->c);
trect.setY(trect.y() + height + st::topicButtonSkip);
}
void Message::paintForwardedInfo( void Message::paintForwardedInfo(
Painter &p, Painter &p,
QRect &trect, QRect &trect,
@ -1388,6 +1519,7 @@ PointState Message::pointState(QPoint point) const {
// trect.setY(trect.y() - st::msgPadding.top()); // trect.setY(trect.y() - st::msgPadding.top());
//} else { //} else {
// if (getStateFromName(point, trect, &result)) return result; // if (getStateFromName(point, trect, &result)) return result;
// if (getStateTopicButton(point, trect, &result)) return result;
// if (getStateForwardedInfo(point, trect, &result, request)) return result; // if (getStateForwardedInfo(point, trect, &result, request)) return result;
// if (getStateReplyInfo(point, trect, &result)) return result; // if (getStateReplyInfo(point, trect, &result)) return result;
// if (getStateViaBotIdInfo(point, trect, &result)) return result; // if (getStateViaBotIdInfo(point, trect, &result)) return result;
@ -1432,6 +1564,8 @@ void Message::clickHandlerPressedChanged(
return; return;
} else if (_comments && (handler == _comments->link)) { } else if (_comments && (handler == _comments->link)) {
toggleCommentsButtonRipple(pressed); toggleCommentsButtonRipple(pressed);
} else if (_topicButton && (handler == _topicButton->link)) {
toggleTopicButtonRipple(pressed);
} else if (_viewButton) { } else if (_viewButton) {
_viewButton->checkLink(handler, pressed); _viewButton->checkLink(handler, pressed);
} }
@ -1444,7 +1578,7 @@ void Message::toggleCommentsButtonRipple(bool pressed) {
return; return;
} else if (pressed) { } else if (pressed) {
if (!_comments->ripple) { if (!_comments->ripple) {
createCommentsRipple(); createCommentsButtonRipple();
} }
_comments->ripple->add(_comments->lastPoint _comments->ripple->add(_comments->lastPoint
+ QPoint(_comments->rippleShift, 0)); + QPoint(_comments->rippleShift, 0));
@ -1522,7 +1656,7 @@ BottomRippleMask Message::bottomRippleMask(int buttonHeight) const {
}; };
} }
void Message::createCommentsRipple() { void Message::createCommentsButtonRipple() {
auto mask = bottomRippleMask(st::historyCommentsButtonHeight); auto mask = bottomRippleMask(st::historyCommentsButtonHeight);
_comments->ripple = std::make_unique<Ui::RippleAnimation>( _comments->ripple = std::make_unique<Ui::RippleAnimation>(
st::defaultRippleAnimation, st::defaultRippleAnimation,
@ -1531,6 +1665,45 @@ void Message::createCommentsRipple() {
_comments->rippleShift = mask.shift; _comments->rippleShift = mask.shift;
} }
void Message::toggleTopicButtonRipple(bool pressed) {
Expects(_topicButton != nullptr);
if (!drawBubble()) {
return;
} else if (pressed) {
if (!_topicButton->ripple) {
createTopicButtonRipple();
}
_topicButton->ripple->add(_topicButton->lastPoint);
} else if (_topicButton->ripple) {
_topicButton->ripple->lastStop();
}
}
void Message::createTopicButtonRipple() {
const auto geometry = countGeometry().marginsRemoved(st::msgPadding);
const auto availableWidth = geometry.width();
const auto padding = st::topicButtonPadding;
const auto height = padding.top()
+ st::msgNameFont->height
+ padding.bottom();
const auto width = std::max(
std::min(
availableWidth,
(padding.left()
+ _topicButton->name.maxWidth()
+ st::topicButtonArrowSkip
+ padding.right())),
height);
auto mask = Ui::RippleAnimation::RoundRectMask(
{ width, height },
height / 2);
_topicButton->ripple = std::make_unique<Ui::RippleAnimation>(
st::defaultRippleAnimation,
std::move(mask),
[=] { repaint(); });
}
bool Message::hasHeavyPart() const { bool Message::hasHeavyPart() const {
return _comments return _comments
|| (_fromNameStatus && _fromNameStatus->custom) || (_fromNameStatus && _fromNameStatus->custom)
@ -1692,6 +1865,9 @@ TextState Message::textState(
if (getStateFromName(point, trect, &result)) { if (getStateFromName(point, trect, &result)) {
return result; return result;
} }
if (getStateTopicButton(point, trect, &result)) {
return result;
}
if (getStateForwardedInfo(point, trect, &result, request)) { if (getStateForwardedInfo(point, trect, &result, request)) {
return result; return result;
} }
@ -1847,57 +2023,89 @@ bool Message::getStateFromName(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<TextState*> outResult) const { not_null<TextState*> outResult) const {
const auto item = message(); if (!displayFromName()) {
if (displayFromName()) { return false;
const auto replyWidth = [&] { }
if (isUnderCursor() && displayFastReply()) { const auto replyWidth = [&] {
return st::msgFont->width(FastReplyText()); if (isUnderCursor() && displayFastReply()) {
return st::msgFont->width(FastReplyText());
}
return 0;
}();
if (replyWidth
&& point.x() >= trect.left() + trect.width() - replyWidth
&& point.x() < trect.left() + trect.width() + st::msgPadding.right()
&& point.y() >= trect.top() - st::msgPadding.top()
&& point.y() < trect.top() + st::msgServiceFont->height) {
outResult->link = fastReplyLink();
return true;
}
if (point.y() >= trect.top() && point.y() < trect.top() + st::msgNameFont->height) {
auto availableLeft = trect.left();
auto availableWidth = trect.width();
if (replyWidth) {
availableWidth -= st::msgPadding.right() + replyWidth;
}
const auto item = message();
const auto from = item->displayFrom();
const auto nameText = [&]() -> const Ui::Text::String * {
if (from) {
validateFromNameText(from);
return &_fromName;
} else if (const auto info = item->hiddenSenderInfo()) {
return &info->nameText();
} else {
Unexpected("Corrupt forwarded information in message.");
} }
return 0;
}(); }();
if (replyWidth if (point.x() >= availableLeft
&& point.x() >= trect.left() + trect.width() - replyWidth && point.x() < availableLeft + availableWidth
&& point.x() < trect.left() + trect.width() + st::msgPadding.right() && point.x() < availableLeft + nameText->maxWidth()) {
&& point.y() >= trect.top() - st::msgPadding.top() outResult->link = fromLink();
&& point.y() < trect.top() + st::msgServiceFont->height) {
outResult->link = fastReplyLink();
return true; return true;
} }
if (point.y() >= trect.top() && point.y() < trect.top() + st::msgNameFont->height) { auto via = item->Get<HistoryMessageVia>();
auto availableLeft = trect.left(); if (via
auto availableWidth = trect.width(); && !displayForwardedFrom()
if (replyWidth) { && point.x() >= availableLeft + nameText->maxWidth() + st::msgServiceFont->spacew
availableWidth -= st::msgPadding.right() + replyWidth; && point.x() < availableLeft + availableWidth
} && point.x() < availableLeft + nameText->maxWidth() + st::msgServiceFont->spacew + via->width) {
const auto from = item->displayFrom(); outResult->link = via->link;
const auto nameText = [&]() -> const Ui::Text::String * { return true;
if (from) {
validateFromNameText(from);
return &_fromName;
} else if (const auto info = item->hiddenSenderInfo()) {
return &info->nameText();
} else {
Unexpected("Corrupt forwarded information in message.");
}
}();
if (point.x() >= availableLeft
&& point.x() < availableLeft + availableWidth
&& point.x() < availableLeft + nameText->maxWidth()) {
outResult->link = fromLink();
return true;
}
auto via = item->Get<HistoryMessageVia>();
if (via
&& !displayForwardedFrom()
&& point.x() >= availableLeft + nameText->maxWidth() + st::msgServiceFont->spacew
&& point.x() < availableLeft + availableWidth
&& point.x() < availableLeft + nameText->maxWidth() + st::msgServiceFont->spacew + via->width) {
outResult->link = via->link;
return true;
}
} }
trect.setTop(trect.top() + st::msgNameFont->height);
} }
trect.setTop(trect.top() + st::msgNameFont->height);
return false;
}
bool Message::getStateTopicButton(
QPoint point,
QRect &trect,
not_null<TextState*> outResult) const {
if (!displayTopicButton()) {
return false;
}
trect.setTop(trect.top() + st::topicButtonSkip);
const auto padding = st::topicButtonPadding;
const auto availableWidth = trect.width();
const auto height = padding.top()
+ st::msgNameFont->height
+ padding.bottom();
const auto width = std::max(
std::min(
availableWidth,
(padding.left()
+ _topicButton->name.maxWidth()
+ st::topicButtonArrowSkip
+ padding.right())),
height);
const auto rect = QRect(trect.x(), trect.y(), width, height);
if (rect.contains(point)) {
outResult->link = _topicButton->link;
_topicButton->lastPoint = point - rect.topLeft();
return true;
}
trect.setY(trect.y() + height + st::topicButtonSkip);
return false; return false;
} }
@ -1906,56 +2114,57 @@ bool Message::getStateForwardedInfo(
QRect &trect, QRect &trect,
not_null<TextState*> outResult, not_null<TextState*> outResult,
StateRequest request) const { StateRequest request) const {
if (displayForwardedFrom()) { if (!displayForwardedFrom()) {
const auto item = message(); return false;
const auto forwarded = item->Get<HistoryMessageForwarded>(); }
const auto skip1 = forwarded->psaType.isEmpty() const auto item = message();
? 0 const auto forwarded = item->Get<HistoryMessageForwarded>();
: st::historyPsaIconSkip1; const auto skip1 = forwarded->psaType.isEmpty()
const auto skip2 = forwarded->psaType.isEmpty() ? 0
? 0 : st::historyPsaIconSkip1;
: st::historyPsaIconSkip2; const auto skip2 = forwarded->psaType.isEmpty()
const auto fits = (forwarded->text.maxWidth() <= (trect.width() - skip1)); ? 0
const auto fwdheight = (fits ? 1 : 2) * st::semiboldFont->height; : st::historyPsaIconSkip2;
if (point.y() >= trect.top() && point.y() < trect.top() + fwdheight) { const auto fits = (forwarded->text.maxWidth() <= (trect.width() - skip1));
if (skip1) { const auto fwdheight = (fits ? 1 : 2) * st::semiboldFont->height;
const auto &icon = st::historyPsaIconIn; if (point.y() >= trect.top() && point.y() < trect.top() + fwdheight) {
const auto position = fits if (skip1) {
? st::historyPsaIconPosition1 const auto &icon = st::historyPsaIconIn;
: st::historyPsaIconPosition2; const auto position = fits
const auto iconRect = QRect( ? st::historyPsaIconPosition1
trect.x() + trect.width() - position.x() - icon.width(), : st::historyPsaIconPosition2;
trect.y() + position.y(), const auto iconRect = QRect(
icon.width(), trect.x() + trect.width() - position.x() - icon.width(),
icon.height()); trect.y() + position.y(),
if (iconRect.contains(point)) { icon.width(),
if (const auto link = psaTooltipLink()) { icon.height());
outResult->link = link; if (iconRect.contains(point)) {
return true; if (const auto link = psaTooltipLink()) {
} outResult->link = link;
return true;
} }
} }
const auto useWidth = trect.width() - (fits ? skip1 : skip2);
const auto breakEverywhere = (forwarded->text.countHeight(useWidth) > 2 * st::semiboldFont->height);
auto textRequest = request.forText();
if (breakEverywhere) {
textRequest.flags |= Ui::Text::StateRequest::Flag::BreakEverywhere;
}
*outResult = TextState(item, forwarded->text.getState(
point - trect.topLeft(),
useWidth,
textRequest));
outResult->symbol = 0;
outResult->afterSymbol = false;
if (breakEverywhere) {
outResult->cursor = CursorState::Forwarded;
} else {
outResult->cursor = CursorState::None;
}
return true;
} }
trect.setTop(trect.top() + fwdheight); const auto useWidth = trect.width() - (fits ? skip1 : skip2);
const auto breakEverywhere = (forwarded->text.countHeight(useWidth) > 2 * st::semiboldFont->height);
auto textRequest = request.forText();
if (breakEverywhere) {
textRequest.flags |= Ui::Text::StateRequest::Flag::BreakEverywhere;
}
*outResult = TextState(item, forwarded->text.getState(
point - trect.topLeft(),
useWidth,
textRequest));
outResult->symbol = 0;
outResult->afterSymbol = false;
if (breakEverywhere) {
outResult->cursor = CursorState::Forwarded;
} else {
outResult->cursor = CursorState::None;
}
return true;
} }
trect.setTop(trect.top() + fwdheight);
return false; return false;
} }
@ -2076,6 +2285,14 @@ void Message::updatePressed(QPoint point) {
if (displayFromName()) { if (displayFromName()) {
trect.setTop(trect.top() + st::msgNameFont->height); trect.setTop(trect.top() + st::msgNameFont->height);
} }
if (displayTopicButton()) {
trect.setTop(trect.top()
+ st::topicButtonSkip
+ st::topicButtonPadding.top()
+ st::msgNameFont->height
+ st::topicButtonPadding.bottom()
+ st::topicButtonSkip);
}
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
auto forwarded = item->Get<HistoryMessageForwarded>(); auto forwarded = item->Get<HistoryMessageForwarded>();
auto fwdheight = ((forwarded->text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; auto fwdheight = ((forwarded->text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height;
@ -2652,6 +2869,10 @@ bool Message::hasBubble() const {
return drawBubble(); return drawBubble();
} }
bool Message::displayTopicButton() const {
return _topicButton != nullptr;
}
bool Message::unwrapped() const { bool Message::unwrapped() const {
const auto item = message(); const auto item = message();
if (isHidden()) { if (isHidden()) {
@ -2946,6 +3167,7 @@ void Message::updateMediaInBubbleState() {
auto mediaHasSomethingAbove = false; auto mediaHasSomethingAbove = false;
auto getMediaHasSomethingAbove = [&] { auto getMediaHasSomethingAbove = [&] {
return displayFromName() return displayFromName()
|| displayTopicButton()
|| displayForwardedFrom() || displayForwardedFrom()
|| displayedReply() || displayedReply()
|| item->Has<HistoryMessageVia>(); || item->Has<HistoryMessageVia>();
@ -3064,6 +3286,13 @@ QRect Message::innerGeometry() const {
// See paintFromName(). // See paintFromName().
result.translate(0, st::msgNameFont->height); result.translate(0, st::msgNameFont->height);
} }
if (displayTopicButton()) {
result.translate(0, st::topicButtonSkip
+ st::topicButtonPadding.top()
+ st::msgNameFont->height
+ st::topicButtonPadding.bottom()
+ st::topicButtonSkip);
}
// Skip displayForwardedFrom() until there are no animations for it. // Skip displayForwardedFrom() until there are no animations for it.
if (displayedReply()) { if (displayedReply()) {
// See paintReplyInfo(). // See paintReplyInfo().
@ -3284,6 +3513,14 @@ int Message::resizeContentGetHeight(int newWidth) {
newHeight += st::msgNameFont->height; newHeight += st::msgNameFont->height;
} }
if (displayTopicButton()) {
newHeight += st::topicButtonSkip
+ st::topicButtonPadding.top()
+ st::msgNameFont->height
+ st::topicButtonPadding.bottom()
+ st::topicButtonSkip;
}
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
const auto forwarded = item->Get<HistoryMessageForwarded>(); const auto forwarded = item->Get<HistoryMessageForwarded>();
const auto skip1 = forwarded->psaType.isEmpty() const auto skip1 = forwarded->psaType.isEmpty()

View File

@ -123,6 +123,7 @@ public:
bool hasOutLayout() const override; bool hasOutLayout() const override;
bool drawBubble() const override; bool drawBubble() const override;
bool hasBubble() const override; bool hasBubble() const override;
bool displayTopicButton() const override;
bool unwrapped() const override; bool unwrapped() const override;
int minWidthForMedia() const override; int minWidthForMedia() const override;
bool hasFastReply() const override; bool hasFastReply() const override;
@ -167,6 +168,7 @@ protected:
private: private:
struct CommentsButton; struct CommentsButton;
struct FromNameStatus; struct FromNameStatus;
struct TopicButton;
void initLogEntryOriginal(); void initLogEntryOriginal();
void initPsa(); void initPsa();
@ -180,7 +182,10 @@ private:
TextSelection selection) const; TextSelection selection) const;
void toggleCommentsButtonRipple(bool pressed); void toggleCommentsButtonRipple(bool pressed);
void createCommentsRipple(); void createCommentsButtonRipple();
void toggleTopicButtonRipple(bool pressed);
void createTopicButtonRipple();
void paintCommentsButton( void paintCommentsButton(
Painter &p, Painter &p,
@ -190,6 +195,10 @@ private:
Painter &p, Painter &p,
QRect &trect, QRect &trect,
const PaintContext &context) const; const PaintContext &context) const;
void paintTopicButton(
Painter &p,
QRect &trect,
const PaintContext &context) const;
void paintForwardedInfo( void paintForwardedInfo(
Painter &p, Painter &p,
QRect &trect, QRect &trect,
@ -217,6 +226,10 @@ private:
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<TextState*> outResult) const; not_null<TextState*> outResult) const;
bool getStateTopicButton(
QPoint point,
QRect &trect,
not_null<TextState*> outResult) const;
bool getStateForwardedInfo( bool getStateForwardedInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
@ -257,6 +270,7 @@ private:
[[nodiscard]] bool displayGoToOriginal() const; [[nodiscard]] bool displayGoToOriginal() const;
[[nodiscard]] ClickHandlerPtr fastReplyLink() const; [[nodiscard]] ClickHandlerPtr fastReplyLink() const;
void refreshTopicButton();
void refreshInfoSkipBlock(); void refreshInfoSkipBlock();
[[nodiscard]] int plainMaxWidth() const; [[nodiscard]] int plainMaxWidth() const;
[[nodiscard]] int monospaceMaxWidth() const; [[nodiscard]] int monospaceMaxWidth() const;
@ -279,6 +293,7 @@ private:
mutable ClickHandlerPtr _fastReplyLink; mutable ClickHandlerPtr _fastReplyLink;
mutable std::unique_ptr<ViewButton> _viewButton; mutable std::unique_ptr<ViewButton> _viewButton;
std::unique_ptr<Reactions::InlineList> _reactions; std::unique_ptr<Reactions::InlineList> _reactions;
std::unique_ptr<TopicButton> _topicButton;
mutable std::unique_ptr<CommentsButton> _comments; mutable std::unique_ptr<CommentsButton> _comments;
mutable Ui::Text::String _fromName; mutable Ui::Text::String _fromName;

View File

@ -703,7 +703,7 @@ void TopBarWidget::backClicked() {
_controller->closeFolder(); _controller->closeFolder();
} else if (_activeChat.section == Section::ChatsList } else if (_activeChat.section == Section::ChatsList
&& _activeChat.key.history() && _activeChat.key.history()
&& _activeChat.key.history()->peer->isForum()) { && _activeChat.key.history()->isForum()) {
_controller->closeForum(); _controller->closeForum();
} else { } else {
_controller->showBackFromStack(); _controller->showBackFromStack();

View File

@ -430,7 +430,8 @@ bool ExtendedPreview::needsBubble() const {
|| item->viaBot() || item->viaBot()
|| _parent->displayedReply() || _parent->displayedReply()
|| _parent->displayForwardedFrom() || _parent->displayForwardedFrom()
|| _parent->displayFromName()); || _parent->displayFromName()
|| _parent->displayTopicButton());
} }
QPoint ExtendedPreview::resolveCustomInfoRightBottom() const { QPoint ExtendedPreview::resolveCustomInfoRightBottom() const {

View File

@ -1308,7 +1308,8 @@ bool Gif::needsBubble() const {
|| item->viaBot() || item->viaBot()
|| _parent->displayedReply() || _parent->displayedReply()
|| _parent->displayForwardedFrom() || _parent->displayForwardedFrom()
|| _parent->displayFromName(); || _parent->displayFromName()
|| _parent->displayTopicButton();
return false; return false;
} }

View File

@ -377,7 +377,8 @@ bool Location::needsBubble() const {
|| item->viaBot() || item->viaBot()
|| _parent->displayedReply() || _parent->displayedReply()
|| _parent->displayForwardedFrom() || _parent->displayForwardedFrom()
|| _parent->displayFromName(); || _parent->displayFromName()
|| _parent->displayTopicButton();
} }
QPoint Location::resolveCustomInfoRightBottom() const { QPoint Location::resolveCustomInfoRightBottom() const {

View File

@ -775,6 +775,7 @@ bool GroupedMedia::computeNeedBubble() const {
|| _parent->displayedReply() || _parent->displayedReply()
|| _parent->displayForwardedFrom() || _parent->displayForwardedFrom()
|| _parent->displayFromName() || _parent->displayFromName()
|| _parent->displayTopicButton()
) { ) {
return true; return true;
} }

View File

@ -412,7 +412,7 @@ void Photo::paintUserpicFrame(
auto request = ::Media::Streaming::FrameRequest(); auto request = ::Media::Streaming::FrameRequest();
request.outer = size * cIntRetinaFactor(); request.outer = size * cIntRetinaFactor();
request.resize = size * cIntRetinaFactor(); request.resize = size * cIntRetinaFactor();
const auto forum = _parent->data()->history()->peer->isForum(); const auto forum = _parent->data()->history()->isForum();
if (forum) { if (forum) {
request.rounding = Images::CornersMaskRef( request.rounding = Images::CornersMaskRef(
Images::CornersMask(ImageRoundRadius::Large)); Images::CornersMask(ImageRoundRadius::Large));
@ -439,7 +439,7 @@ void Photo::paintUserpicFrame(
return; return;
} }
const auto pix = [&] { const auto pix = [&] {
const auto forum = _parent->data()->history()->peer->isForum(); const auto forum = _parent->data()->history()->isForum();
const auto args = Images::PrepareArgs{ const auto args = Images::PrepareArgs{
.options = (forum .options = (forum
? Images::Option::RoundLarge ? Images::Option::RoundLarge
@ -885,7 +885,8 @@ bool Photo::needsBubble() const {
|| item->viaBot() || item->viaBot()
|| _parent->displayedReply() || _parent->displayedReply()
|| _parent->displayForwardedFrom() || _parent->displayForwardedFrom()
|| _parent->displayFromName()); || _parent->displayFromName()
|| _parent->displayTopicButton());
} }
QPoint Photo::resolveCustomInfoRightBottom() const { QPoint Photo::resolveCustomInfoRightBottom() const {

View File

@ -261,7 +261,7 @@ void Uploader::sendProgressUpdate(
if (history->peer->isMegagroup()) { if (history->peer->isMegagroup()) {
manager.update(history, replyTo, type, progress); manager.update(history, replyTo, type, progress);
} }
} else if (history->peer->isForum()) { } else if (history->isForum()) {
manager.update(history, item->topicRootId(), type, progress); manager.update(history, item->topicRootId(), type, progress);
} }
_api->session().data().requestItemRepaint(item); _api->session().data().requestItemRepaint(item);

View File

@ -649,6 +649,12 @@ historyPinnedBotButton: RoundButton(defaultActiveButton) {
} }
historyPinnedBotButtonMaxWidth: 150px; historyPinnedBotButtonMaxWidth: 150px;
topicButtonSkip: 3px;
topicButtonPadding: margins(6px, 3px, 8px, 3px);
topicButtonArrowSkip: 8px;
topicButtonArrowPosition: point(3px, 3px);
topicButtonArrow: icon{{ "dialogs/dialogs_topic_arrow", historyReplyIconFg }};
msgBotKbDuration: 200; msgBotKbDuration: 200;
msgBotKbFont: semiboldFont; msgBotKbFont: semiboldFont;
msgBotKbIconPadding: 4px; msgBotKbIconPadding: 4px;