diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp
index ed3d79a58..e00198726 100644
--- a/Telegram/SourceFiles/settings/settings_chat.cpp
+++ b/Telegram/SourceFiles/settings/settings_chat.cpp
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "boxes/background_preview_box.h"
 #include "boxes/download_path_box.h"
 #include "boxes/local_storage_box.h"
+#include "boxes/edit_color_box.h"
 #include "ui/wrap/vertical_layout.h"
 #include "ui/wrap/slide_wrap.h"
 #include "ui/widgets/input_fields.h"
@@ -89,6 +90,7 @@ public:
 		QColor radiobuttonActive;
 		tr::phrase<> name;
 		QString path;
+		QColor accentColor;
 	};
 	DefaultTheme(Scheme scheme, bool checked);
 
@@ -801,7 +803,8 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
 			color("d7f0ff"),
 			color("ffffff"),
 			tr::lng_settings_theme_blue,
-			":/gui/day-blue.tdesktop-theme"
+			":/gui/day-blue.tdesktop-theme",
+			color("40a7e3")
 		},
 		Scheme{
 			Type::Default,
@@ -821,7 +824,8 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
 			color("6b808d"),
 			color("5ca7d4"),
 			tr::lng_settings_theme_midnight,
-			":/gui/night.tdesktop-theme"
+			":/gui/night.tdesktop-theme",
+			color("5288c1")
 		},
 		Scheme{
 			Type::NightGreen,
@@ -831,7 +835,8 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
 			color("6b808d"),
 			color("74bf93"),
 			tr::lng_settings_theme_matrix,
-			":/gui/night-green.tdesktop-theme"
+			":/gui/night-green.tdesktop-theme",
+			color("3fc1b0")
 		},
 	};
 	const auto chosen = [&] {
@@ -847,6 +852,47 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
 		return Type(-1);
 	};
 	const auto group = std::make_shared<Ui::RadioenumGroup<Type>>(chosen());
+
+	const auto apply = [=](
+			const Scheme &scheme,
+			const Window::Theme::Colorizer *colorizer = nullptr) {
+		const auto isNight = [](const Scheme &scheme) {
+			const auto type = scheme.type;
+			return (type != Type::DayBlue) && (type != Type::Default);
+		};
+		const auto currentlyIsCustom = (chosen() == Type(-1));
+		if (Window::Theme::IsNightMode() == isNight(scheme)) {
+			Window::Theme::ApplyDefaultWithPath(scheme.path, colorizer);
+		} else {
+			Window::Theme::ToggleNightMode(scheme.path, colorizer);
+		}
+		if (!currentlyIsCustom) {
+			Window::Theme::KeepApplied();
+		}
+	};
+	const auto applyWithColorize = [=](const Scheme &scheme) {
+		const auto box = Ui::show(Box<EditColorBox>(
+			"Choose accent color",
+			scheme.accentColor));
+		box->setSaveCallback([=](QColor result) {
+			auto colorizer = Window::Theme::Colorizer();
+			colorizer.hueThreshold = 10;
+			colorizer.saturationThreshold = 10;
+			colorizer.wasHue = scheme.accentColor.hue();
+			colorizer.nowHue = result.hue();
+			apply(scheme, &colorizer);
+		});
+	};
+	const auto schemeClicked = [=](
+			const Scheme &scheme,
+			Qt::KeyboardModifiers modifiers) {
+		if (scheme.accentColor.hue() && (modifiers & Qt::ControlModifier)) {
+			applyWithColorize(scheme);
+		} else {
+			apply(scheme);
+		}
+	};
+
 	auto buttons = ranges::view::all(
 		schemes
 	) | ranges::view::transform([&](const Scheme &scheme) {
@@ -859,34 +905,14 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
 			scheme.name(tr::now),
 			st::settingsTheme,
 			std::move(check));
+		result->addClickHandler([=] {
+			schemeClicked(scheme, result->clickModifiers());
+		});
 		weak->setUpdateCallback([=] { result->update(); });
 		return result;
 	}) | ranges::to_vector;
 
 	using Update = const Window::Theme::BackgroundUpdate;
-	const auto apply = [=](const Scheme &scheme) {
-		const auto isNight = [](const Scheme &scheme) {
-			const auto type = scheme.type;
-			return (type != Type::DayBlue) && (type != Type::Default);
-		};
-		const auto currentlyIsCustom = (chosen() == Type(-1));
-		if (Window::Theme::IsNightMode() == isNight(scheme)) {
-			Window::Theme::ApplyDefaultWithPath(scheme.path);
-		} else {
-			Window::Theme::ToggleNightMode(scheme.path);
-		}
-		if (!currentlyIsCustom) {
-			Window::Theme::KeepApplied();
-		}
-	};
-	group->setChangedCallback([=](Type type) {
-		const auto i = ranges::find_if(schemes, [&](const Scheme &scheme) {
-			return (type == scheme.type && type != chosen());
-		});
-		if (i != end(schemes)) {
-			apply(*i);
-		}
-	});
 	base::ObservableViewer(
 		*Window::Theme::Background()
 	) | rpl::filter([](const Update &update) {
diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp
index daf581689..36bf523b6 100644
--- a/Telegram/SourceFiles/window/themes/window_theme.cpp
+++ b/Telegram/SourceFiles/window/themes/window_theme.cpp
@@ -143,12 +143,44 @@ bool readNameAndValue(const char *&from, const char *end, QLatin1String *outName
 	return true;
 }
 
+void Colorize(
+		uchar &r,
+		uchar &g,
+		uchar &b,
+		not_null<const Colorizer*> colorizer) {
+	auto color = QColor(int(r), int(g), int(b));
+	auto hue = 0;
+	auto saturation = 0;
+	auto value = 0;
+	color.getHsv(&hue, &saturation, &value);
+	if ((saturation < colorizer->saturationThreshold)
+		|| (std::abs(hue - colorizer->wasHue) > colorizer->hueThreshold)) {
+		return;
+	}
+	const auto changed = hue + (colorizer->nowHue - colorizer->wasHue);
+	auto nowR = 0;
+	auto nowG = 0;
+	auto nowB = 0;
+	QColor::fromHsv(
+		(changed + 360) % 360,
+		saturation,
+		value
+	).getRgb(&nowR, &nowG, &nowB);
+	r = uchar(nowR);
+	g = uchar(nowG);
+	b = uchar(nowB);
+}
+
 enum class SetResult {
 	Ok,
 	Bad,
 	NotFound,
 };
-SetResult setColorSchemeValue(QLatin1String name, QLatin1String value, Instance *out) {
+SetResult setColorSchemeValue(
+		QLatin1String name,
+		QLatin1String value,
+		Instance *out,
+		const Colorizer *colorizer) {
 	auto result = style::palette::SetResult::Ok;
 	auto size = value.size();
 	auto data = value.data();
@@ -158,6 +190,9 @@ SetResult setColorSchemeValue(QLatin1String name, QLatin1String value, Instance
 		auto g = readHexUchar(data[3], data[4], error);
 		auto b = readHexUchar(data[5], data[6], error);
 		auto a = (size == 9) ? readHexUchar(data[7], data[8], error) : uchar(255);
+		if (colorizer) {
+			Colorize(r, g, b, colorizer);
+		}
 		if (error) {
 			LOG(("Theme Warning: Skipping value '%1: %2' (expected a color value in #rrggbb or #rrggbbaa or a previously defined key in the color scheme)").arg(name).arg(value));
 			return SetResult::Ok;
@@ -189,13 +224,16 @@ SetResult setColorSchemeValue(QLatin1String name, QLatin1String value, Instance
 	return SetResult::Bad;
 }
 
-bool loadColorScheme(const QByteArray &content, Instance *out) {
+bool loadColorScheme(
+		const QByteArray &content,
+		Instance *out,
+		const Colorizer *colorizer = nullptr) {
 	auto unsupported = QMap<QLatin1String, QLatin1String>();
-	return ReadPaletteValues(content, [&unsupported, out](QLatin1String name, QLatin1String value) {
+	return ReadPaletteValues(content, [&](QLatin1String name, QLatin1String value) {
 		// Find the named value in the already read unsupported list.
 		value = unsupported.value(value, value);
 
-		auto result = setColorSchemeValue(name, value, out);
+		auto result = setColorSchemeValue(name, value, out, colorizer);
 		if (result == SetResult::Bad) {
 			return false;
 		} else if (result == SetResult::NotFound) {
@@ -279,7 +317,11 @@ bool loadBackground(zlib::FileToRead &file, QByteArray *outBackground, bool *out
 	return true;
 }
 
-bool loadTheme(const QByteArray &content, Cached &cache, Instance *out = nullptr) {
+bool loadTheme(
+		const QByteArray &content,
+		Cached &cache,
+		Instance *out = nullptr,
+		const Colorizer *colorizer = nullptr) {
 	cache = Cached();
 	zlib::FileToRead file(content);
 
@@ -295,7 +337,7 @@ bool loadTheme(const QByteArray &content, Cached &cache, Instance *out = nullptr
 			LOG(("Theme Error: could not read 'colors.tdesktop-theme' or 'colors.tdesktop-palette' in the theme file."));
 			return false;
 		}
-		if (!loadColorScheme(schemeContent, out)) {
+		if (!loadColorScheme(schemeContent, out, colorizer)) {
 			return false;
 		}
 		Background()->saveAdjustableColors();
@@ -331,7 +373,7 @@ bool loadTheme(const QByteArray &content, Cached &cache, Instance *out = nullptr
 		}
 	} else {
 		// Looks like it is not a .zip theme.
-		if (!loadColorScheme(content, out)) {
+		if (!loadColorScheme(content, out, colorizer)) {
 			return false;
 		}
 		Background()->saveAdjustableColors();
@@ -893,7 +935,9 @@ bool ChatBackground::nightMode() const {
 	return _nightMode;
 }
 
-void ChatBackground::toggleNightMode(std::optional<QString> themePath) {
+void ChatBackground::toggleNightMode(
+		std::optional<QString> themePath,
+		const Colorizer *colorizer) {
 	const auto settingDefault = themePath.has_value();
 	const auto oldNightMode = _nightMode;
 	const auto newNightMode = !_nightMode;
@@ -926,7 +970,7 @@ void ChatBackground::toggleNightMode(std::optional<QString> themePath) {
 		path = themePath
 			? *themePath
 			: (newNightMode ? NightThemePath() : QString());
-		ApplyDefaultWithPath(path);
+		ApplyDefaultWithPath(path, colorizer);
 	}
 
 	// Theme editor could have already reverted the testing of this toggle.
@@ -1005,9 +1049,11 @@ bool Apply(std::unique_ptr<Preview> preview) {
 	return true;
 }
 
-void ApplyDefaultWithPath(const QString &themePath) {
+void ApplyDefaultWithPath(
+		const QString &themePath,
+		const Colorizer *colorizer) {
 	if (!themePath.isEmpty()) {
-		if (auto preview = PreviewFromFile(themePath)) {
+		if (auto preview = PreviewFromFile(themePath, colorizer)) {
 			Apply(std::move(preview));
 		}
 	} else {
@@ -1094,21 +1140,27 @@ void SetNightModeValue(bool nightMode) {
 }
 
 void ToggleNightMode() {
-	Background()->toggleNightMode(std::nullopt);
+	Background()->toggleNightMode(std::nullopt, nullptr);
 }
 
-void ToggleNightMode(const QString &path) {
-	Background()->toggleNightMode(path);
+void ToggleNightMode(
+		const QString &path,
+		const Colorizer *colorizer) {
+	Background()->toggleNightMode(path, colorizer);
 }
 
-bool LoadFromFile(const QString &path, Instance *out, QByteArray *outContent) {
+bool LoadFromFile(
+		const QString &path,
+		Instance *out,
+		QByteArray *outContent,
+		const Colorizer *colorizer) {
 	*outContent = readThemeContent(path);
 	if (outContent->size() < 4) {
 		LOG(("Theme Error: Could not load theme from %1").arg(path));
 		return false;
 	}
 
-	return loadTheme(*outContent,  out->cached, out);
+	return loadTheme(*outContent,  out->cached, out, colorizer);
 }
 
 bool IsPaletteTestingPath(const QString &path) {
diff --git a/Telegram/SourceFiles/window/themes/window_theme.h b/Telegram/SourceFiles/window/themes/window_theme.h
index 323c93189..61a6e662c 100644
--- a/Telegram/SourceFiles/window/themes/window_theme.h
+++ b/Telegram/SourceFiles/window/themes/window_theme.h
@@ -49,20 +49,35 @@ struct Preview {
 	QImage preview;
 };
 
+struct Colorizer {
+	int wasHue = 0;
+	int nowHue = 0;
+	int hueThreshold = 0;
+	int saturationThreshold = 0;
+};
+
 bool Apply(const QString &filepath);
 bool Apply(std::unique_ptr<Preview> preview);
-void ApplyDefaultWithPath(const QString &themePath);
+void ApplyDefaultWithPath(
+	const QString &themePath,
+	const Colorizer *colorizer = nullptr);
 bool ApplyEditedPalette(const QString &path, const QByteArray &content);
 void KeepApplied();
 QString NightThemePath();
 [[nodiscard]] bool IsNightMode();
 void SetNightModeValue(bool nightMode);
 void ToggleNightMode();
-void ToggleNightMode(const QString &themePath);
+void ToggleNightMode(
+	const QString &themePath,
+	const Colorizer *colorizer = nullptr);
 [[nodiscard]] bool IsNonDefaultBackground();
 void Revert();
 
-bool LoadFromFile(const QString &file, Instance *out, QByteArray *outContent);
+bool LoadFromFile(
+	const QString &file,
+	Instance *out,
+	QByteArray *outContent,
+	const Colorizer *colorizer = nullptr);
 bool IsPaletteTestingPath(const QString &path);
 QColor CountAverageColor(const QImage &image);
 QColor AdjustedColor(QColor original, QColor background);
@@ -152,7 +167,9 @@ private:
 
 	void setNightModeValue(bool nightMode);
 	[[nodiscard]] bool nightMode() const;
-	void toggleNightMode(std::optional<QString> themePath);
+	void toggleNightMode(
+		std::optional<QString> themePath,
+		const Colorizer *colorizer);
 	void keepApplied(const QString &path, bool write);
 	[[nodiscard]] bool isNonDefaultThemeOrBackground();
 	[[nodiscard]] bool isNonDefaultBackground();
@@ -162,7 +179,9 @@ private:
 	friend bool IsNightMode();
 	friend void SetNightModeValue(bool nightMode);
 	friend void ToggleNightMode();
-	friend void ToggleNightMode(const QString &themePath);
+	friend void ToggleNightMode(
+		const QString &themePath,
+		const Colorizer *colorizer);
 	friend void KeepApplied();
 	friend bool IsNonDefaultBackground();
 
diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp
index 7e473fc39..e75c09719 100644
--- a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp
+++ b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp
@@ -908,7 +908,9 @@ void Generator::restoreTextPalette() {
 
 } // namespace
 
-std::unique_ptr<Preview> PreviewFromFile(const QString &filepath) {
+std::unique_ptr<Preview> PreviewFromFile(
+		const QString &filepath,
+		const Colorizer *colorizer) {
 	auto result = std::make_unique<Preview>();
 	result->pathRelative = filepath.isEmpty()
 		? QString()
@@ -916,7 +918,11 @@ std::unique_ptr<Preview> PreviewFromFile(const QString &filepath) {
 	result->pathAbsolute = filepath.isEmpty()
 		? QString()
 		: QFileInfo(filepath).absoluteFilePath();
-	if (!LoadFromFile(filepath, &result->instance, &result->content)) {
+	if (!LoadFromFile(
+			filepath,
+			&result->instance,
+			&result->content,
+			colorizer)) {
 		return nullptr;
 	}
 	return result;
diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.h b/Telegram/SourceFiles/window/themes/window_theme_preview.h
index adde5109a..067b075db 100644
--- a/Telegram/SourceFiles/window/themes/window_theme_preview.h
+++ b/Telegram/SourceFiles/window/themes/window_theme_preview.h
@@ -18,7 +18,9 @@ struct CurrentData {
 	bool backgroundTiled = false;
 };
 
-std::unique_ptr<Preview> PreviewFromFile(const QString &filepath);
+std::unique_ptr<Preview> PreviewFromFile(
+	const QString &filepath,
+	const Colorizer *colorizer = nullptr);
 std::unique_ptr<Preview> GeneratePreview(
 	const QString &filepath,
 	CurrentData &&data);