diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 959923c05..16fcdae1a 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -641,6 +641,43 @@ void ApiWrap::requestDialogEntry(
 	}).send();
 }
 
+void ApiWrap::requestDialogEntries(
+		std::vector<not_null<History*>> histories) {
+	const auto already = [&](not_null<History*> history) {
+		const auto [i, ok] = _dialogRequests.try_emplace(history);
+		return !ok;
+	};
+	histories.erase(ranges::remove_if(histories, already), end(histories));
+	if (histories.empty()) {
+		return;
+	}
+	auto peers = QVector<MTPInputDialogPeer>();
+	peers.reserve(histories.size());
+	for (const auto history : histories) {
+		peers.push_back(MTP_inputDialogPeer(history->peer->input));
+	}
+	const auto finalize = [=](std::vector<not_null<History*>> histories) {
+		for (const auto history : histories) {
+			if (const auto callbacks = _dialogRequests.take(history)) {
+				for (const auto callback : *callbacks) {
+					callback();
+				}
+			}
+		}
+	};
+	request(MTPmessages_GetPeerDialogs(
+		MTP_vector(std::move(peers))
+	)).done([=](const MTPmessages_PeerDialogs &result) {
+		applyPeerDialogs(result);
+		for (const auto history : histories) {
+			historyDialogEntryApplied(history);
+		}
+		finalize(histories);
+	}).fail([=](const RPCError &error) {
+		finalize(histories);
+	}).send();
+}
+
 void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
 	Expects(dialogs.type() == mtpc_messages_peerDialogs);
 
diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h
index abbd8a811..c1d331d6e 100644
--- a/Telegram/SourceFiles/apiwrap.h
+++ b/Telegram/SourceFiles/apiwrap.h
@@ -87,6 +87,7 @@ public:
 	void requestDialogEntry(
 		not_null<History*> history,
 		Fn<void()> callback = nullptr);
+	void requestDialogEntries(std::vector<not_null<History*>> histories);
 	//void applyFeedSources(const MTPDchannels_feedSources &data); // #feed
 	//void setFeedChannels(
 	//	not_null<Data::Feed*> feed,
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index 908c235e8..f9b8d0565 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -451,9 +451,12 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
 			}
 		}
 
+		const auto showUnreadInSearchResults = uniqueSearchResults();
 		if (!_waitingForSearch || !_searchResults.empty()) {
 			const auto text = _searchResults.empty()
 				? lang(lng_search_no_results)
+				: showUnreadInSearchResults
+				? qsl("Search results")
 				: lng_search_found_results(
 					lt_count,
 					_searchedMigratedCount + _searchedCount);
@@ -489,7 +492,8 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
 						active,
 						selected,
 						paintingOther,
-						ms);
+						ms,
+						showUnreadInSearchResults);
 					p.translate(0, st::dialogsRowHeight);
 				}
 			}
@@ -674,7 +678,6 @@ void DialogsInner::paintSearchInFeed(
 	paintSearchInFilter(p, paintUserpic, top, fullWidth, icon, text);
 }
 
-
 void DialogsInner::activate() {
 }
 
@@ -1840,28 +1843,53 @@ void DialogsInner::addAllSavedPeers() {
 	addSavedPeersAfter(QDateTime());
 }
 
+bool DialogsInner::uniqueSearchResults() const {
+	return Auth().supportMode()
+		&& _filter.startsWith('#')
+		&& !_searchInChat;
+}
+
+bool DialogsInner::hasHistoryInSearchResults(not_null<History*> history) const {
+	using Result = std::unique_ptr<Dialogs::FakeRow>;
+	return ranges::find(
+		_searchResults,
+		history,
+		[](const Result &result) { return result->item()->history(); }
+	) != end(_searchResults);
+}
+
 bool DialogsInner::searchReceived(
 		const QVector<MTPMessage> &messages,
 		DialogsSearchRequestType type,
 		int fullCount) {
+	const auto uniquePeers = uniqueSearchResults();
 	if (type == DialogsSearchFromStart || type == DialogsSearchPeerFromStart) {
 		clearSearchResults(false);
 	}
 	auto isGlobalSearch = (type == DialogsSearchFromStart || type == DialogsSearchFromOffset);
 	auto isMigratedSearch = (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset);
 
+	auto unknownUnreadCounts = std::vector<not_null<History*>>();
 	TimeId lastDateFound = 0;
 	for_const (auto message, messages) {
 		auto msgId = idFromMessage(message);
 		auto peerId = peerFromMessage(message);
 		auto lastDate = dateFromMessage(message);
-		if (auto peer = App::peerLoaded(peerId)) {
+		if (const auto peer = App::peerLoaded(peerId)) {
 			if (lastDate) {
-				auto item = App::histories().addNewMessage(message, NewMessageExisting);
-				_searchResults.push_back(
-					std::make_unique<Dialogs::FakeRow>(
-						_searchInChat,
-						item));
+				const auto item = App::histories().addNewMessage(
+					message,
+					NewMessageExisting);
+				const auto history = item->history();
+				if (!uniquePeers || !hasHistoryInSearchResults(history)) {
+					_searchResults.push_back(
+						std::make_unique<Dialogs::FakeRow>(
+							_searchInChat,
+							item));
+					if (uniquePeers && !history->unreadCountKnown()) {
+						unknownUnreadCounts.push_back(history);
+					}
+				}
 				lastDateFound = lastDate;
 				if (isGlobalSearch) {
 					_lastSearchDate = lastDateFound;
@@ -1891,7 +1919,12 @@ bool DialogsInner::searchReceived(
 			|| type == DialogsSearchMigratedFromOffset)) {
 		_waitingForSearch = false;
 	}
+
 	refresh();
+
+	if (!unknownUnreadCounts.empty()) {
+		Auth().api().requestDialogEntries(std::move(unknownUnreadCounts));
+	}
 	return lastDateFound != 0;
 }
 
@@ -2476,7 +2509,9 @@ bool DialogsInner::chooseRow() {
 		if (const auto history = chosen.key.history()) {
 			App::main()->choosePeer(
 				history->peer->id,
-				chosen.message.fullId.msg);
+				(uniqueSearchResults()
+					? ShowAtUnreadMsgId
+					: chosen.message.fullId.msg));
 		} else if (const auto feed = chosen.key.feed()) {
 			_controller->showSection(
 				HistoryFeed::Memento(feed, chosen.message),
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h
index bb615bd43..48dcdd9bb 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h
@@ -189,6 +189,8 @@ private:
 	void handlePeerNameChange(
 		not_null<PeerData*> peer,
 		const base::flat_set<QChar> &oldLetters);
+	bool uniqueSearchResults() const;
+	bool hasHistoryInSearchResults(not_null<History*> history) const;
 
 	void applyDialog(const MTPDdialog &dialog);
 //	void applyFeedDialog(const MTPDdialogFeed &dialog); // #feed
diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
index da2815157..e89768168 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
@@ -52,6 +52,102 @@ void paintRowDate(Painter &p, QDateTime date, QRect &rectForName, bool active, b
 	paintRowTopRight(p, dt, rectForName, active, selected);
 }
 
+void PaintNarrowCounter(
+		Painter &p,
+		bool displayUnreadCounter,
+		bool displayUnreadMark,
+		bool displayMentionBadge,
+		int unreadCount,
+		bool active,
+		bool unreadMuted) {
+	auto skipBeforeMention = 0;
+	if (displayUnreadCounter || displayUnreadMark) {
+		auto counter = (unreadCount > 0)
+			? QString::number(unreadCount)
+			: QString();
+		const auto allowDigits = displayMentionBadge ? 1 : 3;
+		if (counter.size() > allowDigits + 1) {
+			counter = qsl("..") + counter.mid(counter.size() - allowDigits);
+		}
+		auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize;
+		auto unreadTop = st::dialogsPadding.y() + st::dialogsPhotoSize - st::dialogsUnreadHeight;
+		auto unreadWidth = 0;
+
+		UnreadBadgeStyle st;
+		st.active = active;
+		st.muted = unreadMuted;
+		paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
+		skipBeforeMention += unreadWidth + st.padding;
+	}
+	if (displayMentionBadge) {
+		auto counter = qsl("@");
+		auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize - skipBeforeMention;
+		auto unreadTop = st::dialogsPadding.y() + st::dialogsPhotoSize - st::dialogsUnreadHeight;
+		auto unreadWidth = 0;
+
+		UnreadBadgeStyle st;
+		st.active = active;
+		st.muted = false;
+		st.padding = 0;
+		st.textTop = 0;
+		paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
+	}
+}
+
+int PaintWideCounter(
+		Painter &p,
+		int texttop,
+		int availableWidth,
+		int fullWidth,
+		bool displayUnreadCounter,
+		bool displayUnreadMark,
+		bool displayMentionBadge,
+		bool displayPinnedIcon,
+		int unreadCount,
+		bool active,
+		bool selected,
+		bool unreadMuted) {
+	const auto initial = availableWidth;
+	auto hadOneBadge = false;
+	if (displayUnreadCounter || displayUnreadMark) {
+		auto counter = (unreadCount > 0)
+			? QString::number(unreadCount)
+			: QString();
+		auto unreadRight = fullWidth - st::dialogsPadding.x();
+		auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
+		auto unreadWidth = 0;
+
+		UnreadBadgeStyle st;
+		st.active = active;
+		st.muted = unreadMuted;
+		paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
+		availableWidth -= unreadWidth + st.padding;
+
+		hadOneBadge = true;
+	} else if (displayPinnedIcon) {
+		auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon));
+		icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth);
+		availableWidth -= icon.width() + st::dialogsUnreadPadding;
+
+		hadOneBadge = true;
+	}
+	if (displayMentionBadge) {
+		auto counter = qsl("@");
+		auto unreadRight = fullWidth - st::dialogsPadding.x() - (initial - availableWidth);
+		auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
+		auto unreadWidth = 0;
+
+		UnreadBadgeStyle st;
+		st.active = active;
+		st.muted = false;
+		st.padding = 0;
+		st.textTop = 0;
+		paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
+		availableWidth -= unreadWidth + st.padding + (hadOneBadge ? st::dialogsUnreadPadding : 0);
+	}
+	return availableWidth;
+}
+
 enum class Flag {
 	Active           = 0x01,
 	Selected         = 0x02,
@@ -370,7 +466,13 @@ UnreadBadgeStyle::UnreadBadgeStyle()
 , font(st::dialogsUnreadFont) {
 }
 
-void paintUnreadCount(Painter &p, const QString &text, int x, int y, const UnreadBadgeStyle &st, int *outUnreadWidth) {
+void paintUnreadCount(
+		Painter &p,
+		const QString &text,
+		int x,
+		int y,
+		const UnreadBadgeStyle &st,
+		int *outUnreadWidth) {
 	int unreadWidth = st.font->width(text);
 	int unreadRectWidth = unreadWidth + 2 * st.padding;
 	int unreadRectHeight = st.size;
@@ -464,45 +566,22 @@ void RowPainter::paint(
 		| (onlyBackground ? Flag::OnlyBackground : Flag(0))
 		| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0));
 	const auto paintItemCallback = [&](int nameleft, int namewidth) {
-		auto availableWidth = namewidth;
-		auto texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
-		auto hadOneBadge = false;
-		if (displayUnreadCounter || displayUnreadMark) {
-			auto counter = (unreadCount > 0)
-				? QString::number(unreadCount)
-				: QString();
-			auto unreadRight = fullWidth - st::dialogsPadding.x();
-			auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
-			auto unreadWidth = 0;
-
-			UnreadBadgeStyle st;
-			st.active = active;
-			st.muted = unreadMuted;
-			paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
-			availableWidth -= unreadWidth + st.padding;
-
-			hadOneBadge = true;
-		} else if (displayPinnedIcon) {
-			auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon));
-			icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth);
-			availableWidth -= icon.width() + st::dialogsUnreadPadding;
-
-			hadOneBadge = true;
-		}
-		if (displayMentionBadge) {
-			auto counter = qsl("@");
-			auto unreadRight = fullWidth - st::dialogsPadding.x() - (namewidth - availableWidth);
-			auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
-			auto unreadWidth = 0;
-
-			UnreadBadgeStyle st;
-			st.active = active;
-			st.muted = false;
-			st.padding = 0;
-			st.textTop = 0;
-			paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
-			availableWidth -= unreadWidth + st.padding + (hadOneBadge ? st::dialogsUnreadPadding : 0);
-		}
+		const auto texttop = st::dialogsPadding.y()
+			+ st::msgNameFont->height
+			+ st::dialogsSkip;
+		const auto availableWidth = PaintWideCounter(
+			p,
+			texttop,
+			namewidth,
+			fullWidth,
+			displayUnreadCounter,
+			displayUnreadMark,
+			displayMentionBadge,
+			displayPinnedIcon,
+			unreadCount,
+			active,
+			selected,
+			unreadMuted);
 		const auto &color = active
 			? st::dialogsTextFgServiceActive
 			: (selected
@@ -517,7 +596,7 @@ void RowPainter::paint(
 			color,
 			ms) : false;
 		if (!actionWasPainted) {
-			auto itemRect = QRect(
+			const auto itemRect = QRect(
 				nameleft,
 				texttop,
 				availableWidth,
@@ -533,39 +612,14 @@ void RowPainter::paint(
 		}
 	};
 	const auto paintCounterCallback = [&] {
-		auto hadOneBadge = false;
-		auto skipBeforeMention = 0;
-		if (displayUnreadCounter || displayUnreadMark) {
-			auto counter = (unreadCount > 0)
-				? QString::number(unreadCount)
-				: QString();
-			const auto allowDigits = displayMentionBadge ? 1 : 3;
-			if (counter.size() > allowDigits + 1) {
-				counter = qsl("..") + counter.mid(counter.size() - allowDigits);
-			}
-			auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize;
-			auto unreadTop = st::dialogsPadding.y() + st::dialogsPhotoSize - st::dialogsUnreadHeight;
-			auto unreadWidth = 0;
-
-			UnreadBadgeStyle st;
-			st.active = active;
-			st.muted = unreadMuted;
-			paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
-			skipBeforeMention += unreadWidth + st.padding;
-		}
-		if (displayMentionBadge) {
-			auto counter = qsl("@");
-			auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize - skipBeforeMention;
-			auto unreadTop = st::dialogsPadding.y() + st::dialogsPhotoSize - st::dialogsUnreadHeight;
-			auto unreadWidth = 0;
-
-			UnreadBadgeStyle st;
-			st.active = active;
-			st.muted = false;
-			st.padding = 0;
-			st.textTop = 0;
-			paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
-		}
+		PaintNarrowCounter(
+			p,
+			displayUnreadCounter,
+			displayUnreadMark,
+			displayMentionBadge,
+			unreadCount,
+			active,
+			unreadMuted);
 	};
 	paintRow(
 		p,
@@ -590,7 +644,8 @@ void RowPainter::paint(
 		bool active,
 		bool selected,
 		bool onlyBackground,
-		TimeMs ms) {
+		TimeMs ms,
+		bool displayUnreadInfo) {
 	auto item = row->item();
 	auto history = item->history();
 	auto cloudDraft = nullptr;
@@ -618,19 +673,63 @@ void RowPainter::paint(
 		}
 		return HistoryItem::DrawInDialog::Normal;
 	}();
+
+	const auto unreadCount = displayUnreadInfo
+		? history->chatListUnreadCount()
+		: 0;
+	const auto unreadMark = displayUnreadInfo
+		&& history->chatListUnreadMark();
+	const auto unreadMuted = history->chatListMutedBadge();
+	const auto displayMentionBadge = displayUnreadInfo
+		&& history->hasUnreadMentions();
+	const auto displayUnreadCounter = (unreadCount > 0);
+	const auto displayUnreadMark = !displayUnreadCounter
+		&& !displayMentionBadge
+		&& unreadMark;
+	const auto displayPinnedIcon = false;
+
 	const auto paintItemCallback = [&](int nameleft, int namewidth) {
-		auto lastWidth = namewidth;
-		auto texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
+		const auto texttop = st::dialogsPadding.y()
+			+ st::msgNameFont->height
+			+ st::dialogsSkip;
+		const auto availableWidth = PaintWideCounter(
+			p,
+			texttop,
+			namewidth,
+			fullWidth,
+			displayUnreadCounter,
+			displayUnreadMark,
+			displayMentionBadge,
+			displayPinnedIcon,
+			unreadCount,
+			active,
+			selected,
+			unreadMuted);
+
+		const auto itemRect = QRect(
+			nameleft,
+			texttop,
+			availableWidth,
+			st::dialogsTextFont->height);
 		item->drawInDialog(
 			p,
-			QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height),
+			itemRect,
 			active,
 			selected,
 			drawInDialogWay,
 			row->_cacheFor,
 			row->_cache);
 	};
-	const auto paintCounterCallback = [] {};
+	const auto paintCounterCallback = [&] {
+		PaintNarrowCounter(
+			p,
+			displayUnreadCounter,
+			displayUnreadMark,
+			displayMentionBadge,
+			unreadCount,
+			active,
+			unreadMuted);
+	};
 	const auto showSavedMessages = history->peer->isSelf()
 		&& !row->searchInChat();
 	const auto flags = (active ? Flag::Active : Flag(0))
diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.h b/Telegram/SourceFiles/dialogs/dialogs_layout.h
index dc67d6d73..b75b22d55 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_layout.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_layout.h
@@ -44,7 +44,8 @@ public:
 		bool active,
 		bool selected,
 		bool onlyBackground,
-		TimeMs ms);
+		TimeMs ms,
+		bool displayUnreadInfo);
 	static QRect sendActionAnimationRect(
 		int animationWidth,
 		int animationHeight,