Add jump-to-topic panel in View as Messages.
This commit is contained in:
parent
8281990bb8
commit
a4e4681835
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue