diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp
index dee46fee4..bd06d725f 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.cpp
+++ b/Telegram/SourceFiles/history/history_inner_widget.cpp
@@ -432,6 +432,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 				}
 				if (item->mentionsMe() && item->isMediaUnread()) {
 					readMentions.insert(item);
+					_widget->enqueueMessageHighlight(item);
 				}
 
 				int32 h = item->height();
@@ -482,6 +483,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 					}
 					if (item->mentionsMe() && item->isMediaUnread()) {
 						readMentions.insert(item);
+						_widget->enqueueMessageHighlight(item);
 					}
 				}
 				p.translate(0, h);
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index de972840d..6b345ce0d 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -600,9 +600,14 @@ TextSelection shiftSelection(TextSelection selection, uint16 byLength) {
 
 } // namespace internal
 
-HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElement()
-, id(msgId)
-, date(msgDate)
+HistoryItem::HistoryItem(
+	not_null<History*> history,
+	MsgId id,
+	MTPDmessage::Flags flags,
+	QDateTime date,
+	UserId from) : HistoryElement()
+, id(id)
+, date(date)
 , _history(history)
 , _from(from ? App::user(from) : history->peer)
 , _flags(flags | MTPDmessage_ClientFlag::f_pending_init_dimensions | MTPDmessage_ClientFlag::f_pending_resize)
diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h
index d34ed37e8..8d9bc3464 100644
--- a/Telegram/SourceFiles/history/history_item.h
+++ b/Telegram/SourceFiles/history/history_item.h
@@ -526,7 +526,7 @@ public:
 	}
 	void addLogEntryOriginal(WebPageId localId, const QString &label, const TextWithEntities &content);
 
-	History *history() const {
+	not_null<History*> history() const {
 		return _history;
 	}
 	PeerData *from() const {
@@ -921,7 +921,12 @@ public:
 	~HistoryItem();
 
 protected:
-	HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from);
+	HistoryItem(
+		not_null<History*> history,
+		MsgId id,
+		MTPDmessage::Flags flags,
+		QDateTime date,
+		UserId from);
 
 	// To completely create history item we need to call
 	// a virtual method, it can not be done from constructor.
@@ -938,7 +943,7 @@ protected:
 	void finishEdition(int oldKeyboardTop);
 	void finishEditionToEmpty();
 
-	not_null<History*> _history;
+	const not_null<History*> _history;
 	not_null<PeerData*> _from;
 	HistoryBlock *_block = nullptr;
 	int _indexInBlock = -1;
diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp
index 98ee11fef..3cfec00f7 100644
--- a/Telegram/SourceFiles/history/history_message.cpp
+++ b/Telegram/SourceFiles/history/history_message.cpp
@@ -1613,12 +1613,10 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
 		}
 	}
 
-	auto fullAnimMs = App::main() ? App::main()->animActiveTimeStart(this) : 0LL;
+	auto fullAnimMs = App::main() ? App::main()->highlightStartTime(this) : 0LL;
 	if (fullAnimMs > 0 && fullAnimMs <= ms) {
-		int animms = ms - fullAnimMs;
-		if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) {
-			App::main()->stopAnimActive();
-		} else {
+		auto animms = ms - fullAnimMs;
+		if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
 			auto top = marginTop();
 			auto bottom = marginBottom();
 			auto fill = qMin(top, bottom);
diff --git a/Telegram/SourceFiles/history/history_service_layout.cpp b/Telegram/SourceFiles/history/history_service_layout.cpp
index 4a43b0f0f..7b7b28f5f 100644
--- a/Telegram/SourceFiles/history/history_service_layout.cpp
+++ b/Telegram/SourceFiles/history/history_service_layout.cpp
@@ -188,16 +188,18 @@ int WideChatWidth() {
 	return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left();
 }
 
-void ServiceMessagePainter::paint(Painter &p, const HistoryService *message, const PaintContext &context, int height) {
+void ServiceMessagePainter::paint(
+		Painter &p,
+		not_null<const HistoryService*> message,
+		const PaintContext &context,
+		int height) {
 	auto g = message->countGeometry();
 	if (g.width() < 1) return;
 
-	auto fullAnimMs = App::main() ? App::main()->animActiveTimeStart(message) : 0LL;
+	auto fullAnimMs = App::main() ? App::main()->highlightStartTime(message) : 0LL;
 	if (fullAnimMs > 0 && fullAnimMs <= context.ms) {
-		int animms = context.ms - fullAnimMs;
-		if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) {
-			App::main()->stopAnimActive();
-		} else {
+		auto animms = context.ms - fullAnimMs;
+		if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
 			auto top = st::msgServiceMargin.top();
 			auto bottom = st::msgServiceMargin.bottom();
 			auto fill = qMin(top, bottom);
diff --git a/Telegram/SourceFiles/history/history_service_layout.h b/Telegram/SourceFiles/history/history_service_layout.h
index 55b3bbf2a..67f3ff74f 100644
--- a/Telegram/SourceFiles/history/history_service_layout.h
+++ b/Telegram/SourceFiles/history/history_service_layout.h
@@ -39,7 +39,11 @@ struct PaintContext {
 
 class ServiceMessagePainter {
 public:
-	static void paint(Painter &p, const HistoryService *message, const PaintContext &context, int height);
+	static void paint(
+		Painter &p,
+		not_null<const HistoryService*> message,
+		const PaintContext &context,
+		int height);
 
 	static void paintDate(Painter &p, const QDateTime &date, int y, int w);
 	static void paintDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w);
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 0eba2e2c2..b753fc021 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -680,8 +680,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
 
 	_sendActionStopTimer.setSingleShot(true);
 
-	_animActiveTimer.setSingleShot(false);
-	connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep()));
+	_highlightTimer.setCallback([this] { updateHighlightedMessage(); });
 
 	_membersDropdownShowTimer.setSingleShot(true);
 	connect(&_membersDropdownShowTimer, SIGNAL(timeout()), this, SLOT(onMembersDropdownShow()));
@@ -948,24 +947,108 @@ void HistoryWidget::scrollToAnimationCallback(FullMsgId attachToId) {
 	}
 }
 
-void HistoryWidget::highlightMessage(HistoryItem *context) {
-	Expects(_list != nullptr);
+void HistoryWidget::enqueueMessageHighlight(not_null<HistoryItem*> item) {
+	auto enqueueMessageId = [this](MsgId universalId) {
+		if (_highlightQueue.empty() && !_highlightTimer.isActive()) {
+			highlightMessage(universalId);
+		} else if (_highlightedMessageId != universalId
+			&& !base::contains(_highlightQueue, universalId)) {
+			_highlightQueue.push_back(universalId);
+			checkNextHighlight();
+		}
+	};
+	if (item->history() == _history) {
+		enqueueMessageId(item->id);
+	} else if (item->history() == _migrated) {
+		enqueueMessageId(-item->id);
+	}
+}
 
-	_animActiveStart = getms();
-	_animActiveTimer.start(AnimationTimerDelta);
-	_activeAnimMsgId = _showAtMsgId;
-	if (context
-		&& context->history() == _history
-		&& context->isGroupMigrate()
+void HistoryWidget::highlightMessage(MsgId universalMessageId) {
+	_highlightStart = getms();
+	_highlightedMessageId = universalMessageId;
+	_highlightTimer.callEach(AnimationTimerDelta);
+
+	adjustHighlightedMessageToMigrated();
+}
+
+void HistoryWidget::adjustHighlightedMessageToMigrated() {
+	if (_history
+		&& _highlightTimer.isActive()
+		&& _highlightedMessageId > 0
 		&& _migrated
 		&& !_migrated->isEmpty()
 		&& _migrated->loadedAtBottom()
 		&& _migrated->blocks.back()->items.back()->isGroupMigrate()
 		&& _list->historyTop() != _list->historyDrawTop()) {
-		_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id;
+		auto highlighted = App::histItemById(
+			_history->channelId(),
+			_highlightedMessageId);
+		if (highlighted && highlighted->isGroupMigrate()) {
+			_highlightedMessageId = -_migrated->blocks.back()->items.back()->id;
+		}
 	}
 }
 
+void HistoryWidget::checkNextHighlight() {
+	if (_highlightTimer.isActive()) {
+		return;
+	}
+	auto nextHighlight = [this] {
+		while (!_highlightQueue.empty()) {
+			auto msgId = _highlightQueue.front();
+			_highlightQueue.pop_front();
+			auto item = getItemFromHistoryOrMigrated(msgId);
+			if (item && !item->detached()) {
+				return msgId;
+			}
+		}
+		return 0;
+	}();
+	if (!nextHighlight) {
+		return;
+	}
+	highlightMessage(nextHighlight);
+}
+
+void HistoryWidget::updateHighlightedMessage() {
+	auto item = getItemFromHistoryOrMigrated(_highlightedMessageId);
+	if (!item || item->detached()) {
+		return stopMessageHighlight();
+	}
+	auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
+	if (getms() - _highlightStart > duration) {
+		return stopMessageHighlight();
+	}
+
+	Ui::repaintHistoryItem(item);
+}
+
+TimeMs HistoryWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
+	auto isHighlighted = [this](not_null<const HistoryItem*> item) {
+		if (item->id == _highlightedMessageId) {
+			return (item->history() == _history);
+		} else if (item->id == -_highlightedMessageId) {
+			return (item->history() == _migrated);
+		}
+		return false;
+	};
+	return (isHighlighted(item) && _highlightTimer.isActive())
+		? _highlightStart
+		: 0;
+}
+
+void HistoryWidget::stopMessageHighlight() {
+	_highlightTimer.cancel();
+	_highlightedMessageId = 0;
+	checkNextHighlight();
+}
+
+void HistoryWidget::clearHighlightMessages() {
+	_highlightQueue.clear();
+	stopMessageHighlight();
+}
+
 int HistoryWidget::itemTopForHighlight(not_null<HistoryItem*> item) const {
 	auto itemTop = _list->itemTop(item);
 	Assert(itemTop >= 0);
@@ -1644,6 +1727,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
 		showAtMsgId = ShowAtTheEndMsgId;
 	}
 
+	clearHighlightMessages();
 	if (_history) {
 		if (_peer->id == peerId && !reload) {
 			updateForwarding();
@@ -1676,7 +1760,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
 
 					auto item = getItemFromHistoryOrMigrated(_showAtMsgId);
 					animatedScrollToY(countInitialScrollTop(), item);
-					highlightMessage(item);
 				} else {
 					historyLoaded();
 				}
@@ -4808,7 +4891,7 @@ int HistoryWidget::countInitialScrollTop() {
 			return countInitialScrollTop();
 		} else {
 			result = itemTopForHighlight(item);
-			highlightMessage(item);
+			enqueueMessageHighlight(item);
 		}
 	} else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) {
 		result = unreadBarTop();
@@ -4974,12 +5057,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage>
 	_list->messagesReceived(peer, messages);
 	if (!_firstLoadRequest) {
 		updateHistoryGeometry();
-		if (_animActiveTimer.isActive() && _activeAnimMsgId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop() && _history) {
-			auto animActiveItem = App::histItemById(_history->channelId(), _activeAnimMsgId);
-			if (animActiveItem && animActiveItem->isGroupMigrate()) {
-				_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id;
-			}
-		}
+		adjustHighlightedMessageToMigrated();
 		updateBotKeyboard();
 	}
 }
@@ -6147,36 +6225,6 @@ HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) con
 	return App::histItemById(_channel, genericMsgId);
 }
 
-void HistoryWidget::onAnimActiveStep() {
-	if (!_history || !_activeAnimMsgId || (_activeAnimMsgId < 0 && (!_migrated || -_activeAnimMsgId >= ServerMaxMsgId))) {
-		return _animActiveTimer.stop();
-	}
-
-	auto item = getItemFromHistoryOrMigrated(_activeAnimMsgId);
-	if (!item || item->detached()) {
-		return _animActiveTimer.stop();
-	}
-
-	if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) {
-		stopAnimActive();
-	} else {
-		Ui::repaintHistoryItem(item);
-	}
-}
-
-uint64 HistoryWidget::animActiveTimeStart(const HistoryItem *msg) const {
-	if (!msg) return 0;
-	if ((msg->history() == _history && msg->id == _activeAnimMsgId) || (_migrated && msg->history() == _migrated && msg->id == -_activeAnimMsgId)) {
-		return _animActiveTimer.isActive() ? _animActiveStart : 0;
-	}
-	return 0;
-}
-
-void HistoryWidget::stopAnimActive() {
-	_animActiveTimer.stop();
-	_activeAnimMsgId = 0;
-}
-
 SelectedItemSet HistoryWidget::getSelectedItems() const {
 	return _list ? _list->getSelectedItems() : SelectedItemSet();
 }
diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h
index 8664ae88b..c97a49a7f 100644
--- a/Telegram/SourceFiles/history/history_widget.h
+++ b/Telegram/SourceFiles/history/history_widget.h
@@ -262,8 +262,8 @@ public:
 
 	bool touchScroll(const QPoint &delta);
 
-	uint64 animActiveTimeStart(const HistoryItem *msg) const;
-	void stopAnimActive();
+	void enqueueMessageHighlight(not_null<HistoryItem*> item);
+	TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;
 
 	SelectedItemSet getSelectedItems() const;
 	void itemEdited(HistoryItem *item);
@@ -445,8 +445,6 @@ public slots:
 	void onForwardSelected();
 	void onClearSelected();
 
-	void onAnimActiveStep();
-
 	void onDraftSaveDelayed();
 	void onDraftSave(bool delayed = false);
 	void onCloudDraftSave();
@@ -492,6 +490,13 @@ private:
 	void showNextUnreadMention();
 	void handlePeerUpdate();
 
+	void highlightMessage(MsgId universalMessageId);
+	void adjustHighlightedMessageToMigrated();
+	void checkNextHighlight();
+	void updateHighlightedMessage();
+	void clearHighlightMessages();
+	void stopMessageHighlight();
+
 	void animationCallback();
 	void updateOverStates(QPoint pos);
 	void recordStartCallback();
@@ -701,7 +706,7 @@ private:
 	HistoryItem *getItemFromHistoryOrMigrated(MsgId genericMsgId) const;
 	void animatedScrollToItem(MsgId msgId);
 	void animatedScrollToY(int scrollTo, HistoryItem *attachTo = nullptr);
-	void highlightMessage(HistoryItem *context);
+
 	void updateDragAreas();
 
 	// when scroll position or scroll area size changed this method
@@ -729,8 +734,6 @@ private:
 	MsgId _delayedShowAtMsgId = -1; // wtf?
 	mtpRequestId _delayedShowAtRequest = 0;
 
-	MsgId _activeAnimMsgId = 0;
-
 	object_ptr<Ui::AbstractButton> _backAnimationButton = { nullptr };
 	object_ptr<Window::TopBarWidget> _topBar;
 	object_ptr<Ui::ScrollArea> _scroll;
@@ -846,8 +849,10 @@ private:
 	QTimer _scrollTimer;
 	int32 _scrollDelta = 0;
 
-	QTimer _animActiveTimer;
-	float64 _animActiveStart = 0;
+	MsgId _highlightedMessageId = 0;
+	std::deque<MsgId> _highlightQueue;
+	base::Timer _highlightTimer;
+	TimeMs _highlightStart = 0;
 
 	QMap<QPair<History*, SendAction::Type>, mtpRequestId> _sendActionRequests;
 	QTimer _sendActionStopTimer;
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 09ae9be1f..076f3d2cd 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -1529,12 +1529,8 @@ void MainWidget::unreadCountChanged(History *history) {
 	_history->unreadCountChanged(history);
 }
 
-TimeMs MainWidget::animActiveTimeStart(const HistoryItem *msg) const {
-	return _history->animActiveTimeStart(msg);
-}
-
-void MainWidget::stopAnimActive() {
-	_history->stopAnimActive();
+TimeMs MainWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
+	return _history->highlightStartTime(item);
 }
 
 void MainWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) {
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 4c56f6196..e8578466e 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -309,8 +309,7 @@ public:
     void readServerHistory(History *history, ReadServerHistoryChecks checks = ReadServerHistoryChecks::OnlyIfUnread);
 	void unreadCountChanged(History *history);
 
-	TimeMs animActiveTimeStart(const HistoryItem *msg) const;
-	void stopAnimActive();
+	TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;
 
 	void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
 	void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp
index 6b8701927..f530946ff 100644
--- a/Telegram/SourceFiles/mediaview.cpp
+++ b/Telegram/SourceFiles/mediaview.cpp
@@ -1026,7 +1026,7 @@ void MediaView::onCopy() {
 }
 
 void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
-	_history = context ? context->history() : nullptr;
+	_history = context ? context->history().get() : nullptr;
 	_migrated = nullptr;
 	if (_history) {
 		if (_history->peer->migrateFrom()) {
@@ -1144,7 +1144,7 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) {
 
 void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
 	_photo = 0;
-	_history = context ? context->history() : nullptr;
+	_history = context ? context->history().get() : nullptr;
 	_migrated = nullptr;
 	if (_history) {
 		if (_history->peer->migrateFrom()) {