From a41e9bf67e3a234716cc1fc820363fe80f160cc3 Mon Sep 17 00:00:00 2001
From: 23rd <23rd@vivaldi.net>
Date: Tue, 5 Nov 2024 14:10:43 +0300
Subject: [PATCH] Added preview of chats filters strip to filter link box.

---
 Telegram/SourceFiles/api/api_chat_filters.cpp |  2 +
 .../ui/controls/filter_link_header.cpp        | 91 ++++++++++++++++---
 .../ui/controls/filter_link_header.h          |  1 +
 .../ui/widgets/chat_filters_tabs_slider.cpp   |  4 +
 .../ui/widgets/chat_filters_tabs_slider.h     |  2 +
 5 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/Telegram/SourceFiles/api/api_chat_filters.cpp b/Telegram/SourceFiles/api/api_chat_filters.cpp
index ee6b97b58..2c8410b80 100644
--- a/Telegram/SourceFiles/api/api_chat_filters.cpp
+++ b/Telegram/SourceFiles/api/api_chat_filters.cpp
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "boxes/premium_limits_box.h"
 #include "boxes/filters/edit_filter_links.h" // FilterChatStatusText
 #include "core/application.h"
+#include "core/core_settings.h"
 #include "data/data_channel.h"
 #include "data/data_chat.h"
 #include "data/data_chat_filters.h"
@@ -152,6 +153,7 @@ void InitFilterLinkHeader(
 		.badge = (type == Ui::FilterLinkHeaderType::AddingChats
 			? std::move(count)
 			: rpl::single(0)),
+		.horizontalFilters = Core::App().settings().chatFiltersHorizontal(),
 	});
 	const auto widget = header.widget;
 	widget->resizeToWidth(st::boxWideWidth);
diff --git a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp
index 0d69c0efd..8228d3332 100644
--- a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp
+++ b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp
@@ -8,11 +8,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/controls/filter_link_header.h"
 
 #include "lang/lang_keys.h"
+#include "ui/image/image_prepare.h"
 #include "ui/painter.h"
 #include "ui/rp_widget.h"
-#include "ui/image/image_prepare.h"
+#include "ui/ui_utility.h"
 #include "ui/widgets/buttons.h"
+#include "ui/widgets/chat_filters_tabs_slider.h"
 #include "ui/widgets/labels.h"
+#include "styles/style_chat_helpers.h" // defaultEmojiSuggestions
+#include "styles/style_dialogs.h" // dialogsSearchTabs
 #include "styles/style_filter_icons.h"
 #include "styles/style_layers.h"
 #include "styles/style_settings.h"
@@ -68,6 +72,7 @@ private:
 
 	QString _folderTitle;
 	not_null<const style::icon*> _folderIcon;
+	bool _horizontalFilters = false;
 
 	int _maxHeight = 0;
 
@@ -75,6 +80,46 @@ private:
 
 };
 
+[[nodiscard]] QImage GeneratePreview(
+		not_null<Ui::RpWidget*> parent,
+		const QString &title,
+		int badge) {
+	using Tabs = Ui::ChatsFiltersTabs;
+	auto owned = parent->lifetime().make_state<base::unique_qptr<Tabs>>(
+		base::make_unique_q<Tabs>(parent, st::dialogsSearchTabs));
+	const auto raw = owned->get();
+	raw->setSections({
+		tr::lng_filters_name_people(tr::now),
+		title,
+		tr::lng_filters_name_unread(tr::now),
+	});
+	raw->fitWidthToSections();
+	raw->setActiveSectionFast(1);
+	raw->stopAnimation();
+
+	auto result = QImage(
+		raw->size() * style::DevicePixelRatio(),
+		QImage::Format_ARGB32_Premultiplied);
+	result.setDevicePixelRatio(style::DevicePixelRatio());
+	result.fill(st::windowBg->c);
+	{
+		auto p = QPainter(&result);
+		Ui::RenderWidget(p, raw, QPoint(), raw->rect());
+
+		const auto &r = st::defaultEmojiSuggestions.fadeRight;
+		const auto &l = st::defaultEmojiSuggestions.fadeLeft;
+		const auto padding = st::filterLinkSubsectionTitlePadding.top();
+		const auto w = raw->width();
+		const auto h = raw->height();
+		r.fill(p, QRect(w - r.width() - padding, 0, r.width(), h));
+		l.fill(p, QRect(padding, 0, l.width(), h));
+		p.fillRect(0, 0, padding, h, st::windowBg);
+		p.fillRect(w - padding, 0, padding, raw->height(), st::windowBg);
+	}
+	owned->reset();
+	return result;
+}
+
 [[nodiscard]] QImage GeneratePreview(
 		const QString &title,
 		not_null<const style::icon*> icon,
@@ -199,17 +244,18 @@ Widget::Widget(
 , _titleFont(st::boxTitle.style.font)
 , _titlePadding(st::filterLinkTitlePadding)
 , _folderTitle(descriptor.folderTitle)
-, _folderIcon(descriptor.folderIcon) {
+, _folderIcon(descriptor.folderIcon)
+, _horizontalFilters(descriptor.horizontalFilters) {
 	setMinimumHeight(st::boxTitleHeight);
 	refreshTitleText();
 	setTitlePosition(st::boxTitlePosition.x(), st::boxTitlePosition.y());
 
 	style::PaletteChanged(
-	) | rpl::start_with_next([=] {
+	) | rpl::start_with_next([this] {
 		_preview = QImage();
 	}, lifetime());
 
-	_badge.changes() | rpl::start_with_next([=] {
+	_badge.changes() | rpl::start_with_next([this] {
 		_preview = QImage();
 		update();
 	}, lifetime());
@@ -242,7 +288,9 @@ void Widget::resizeEvent(QResizeEvent *e) {
 	_about->resizeToWidth(availableWidth);
 
 	const auto minHeight = minimumHeight();
-	const auto maxHeight = st::filterLinkAboutTop
+	const auto maxHeight = (_horizontalFilters
+			? (st::filterLinkAboutTop * 0.8)
+			: st::filterLinkAboutTop)
 		+ _about->height()
 		+ st::filterLinkAboutBottom;
 	if (maxHeight <= minHeight) {
@@ -283,12 +331,22 @@ void Widget::resizeEvent(QResizeEvent *e) {
 QRectF Widget::previewRect(
 		float64 topProgress,
 		float64 sizeProgress) const {
-	const auto size = st::filterLinkPreview * sizeProgress;
-	return QRectF(
-		(width() - size) / 2.,
-		st::filterLinkPreviewTop * topProgress,
-		size,
-		size);
+	if (_horizontalFilters) {
+		const auto size = (_preview.size() / style::DevicePixelRatio())
+			* sizeProgress;
+		return QRectF(
+			(width() - size.width()) / 2.,
+			st::filterLinkPreviewTop * 1.5 * topProgress,
+			size.width(),
+			size.height());
+	} else {
+		const auto size = st::filterLinkPreview * sizeProgress;
+		return QRectF(
+			(width() - size) / 2.,
+			st::filterLinkPreviewTop * topProgress,
+			size,
+			size);
+	}
 };
 
 void Widget::paintEvent(QPaintEvent *e) {
@@ -298,10 +356,13 @@ void Widget::paintEvent(QPaintEvent *e) {
 	if (_progress.top) {
 		auto hq = PainterHighQualityEnabler(p);
 		if (_preview.isNull()) {
-			_preview = GeneratePreview(
-				_folderTitle,
-				_folderIcon,
-				_badge.current());
+			const auto badge = _badge.current();
+			if (_horizontalFilters) {
+				_preview = GeneratePreview(this, _folderTitle, badge);
+				Widget::resizeEvent(nullptr);
+			} else {
+				_preview = GeneratePreview(_folderTitle, _folderIcon, badge);
+			}
 		}
 		p.drawImage(_previewRect, _preview);
 	}
diff --git a/Telegram/SourceFiles/ui/controls/filter_link_header.h b/Telegram/SourceFiles/ui/controls/filter_link_header.h
index 8769bf069..c55e20846 100644
--- a/Telegram/SourceFiles/ui/controls/filter_link_header.h
+++ b/Telegram/SourceFiles/ui/controls/filter_link_header.h
@@ -29,6 +29,7 @@ struct FilterLinkHeaderDescriptor {
 	base::required<QString> folderTitle;
 	not_null<const style::icon*> folderIcon;
 	rpl::producer<int> badge;
+	bool horizontalFilters = false;
 };
 
 struct FilterLinkHeader {
diff --git a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp
index c93b61453..2e43aa53d 100644
--- a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp
+++ b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp
@@ -411,4 +411,8 @@ int ChatsFiltersTabs::reordering() const {
 	return _reordering;
 }
 
+void ChatsFiltersTabs::stopAnimation() {
+	Ui::DiscreteSlider::stopAnimation();
+}
+
 } // namespace Ui
diff --git a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h
index 3a027d278..652ee2759 100644
--- a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h
+++ b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h
@@ -43,6 +43,8 @@ public:
 	void setReordering(int value);
 	[[nodiscard]] int reordering() const;
 
+	void stopAnimation();
+
 protected:
 	struct ShiftedSection {
 		not_null<Ui::DiscreteSlider::Section*> section;