From 9201cf24f1c59d9b6500be5c261c5746b11189bd Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Wed, 20 Dec 2023 23:02:54 -0400
Subject: [PATCH] Respect correct min-level for colors.

---
 Telegram/Resources/langs/lang.strings         | 13 +++++++
 Telegram/SourceFiles/api/api_peer_colors.cpp  | 15 ++++++++
 Telegram/SourceFiles/api/api_peer_colors.h    |  5 +++
 Telegram/SourceFiles/api/api_statistics.cpp   |  1 +
 .../boxes/peers/edit_peer_color_box.cpp       | 34 +++++++++++++------
 .../boxes/peers/edit_peer_info_box.cpp        |  3 ++
 Telegram/SourceFiles/data/data_channel.cpp    |  8 +++++
 Telegram/SourceFiles/data/data_channel.h      |  4 +++
 Telegram/SourceFiles/data/data_session.cpp    |  1 +
 Telegram/SourceFiles/ui/boxes/boost_box.cpp   | 23 +++++++++++--
 Telegram/SourceFiles/ui/boxes/boost_box.h     | 10 ++++++
 .../window/window_session_controller.cpp      |  2 ++
 12 files changed, 106 insertions(+), 13 deletions(-)

diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index bd6100058..ea98e618d 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -2133,6 +2133,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color.";
 "lng_boost_channel_needs_level_color#other" = "Your channel needs to reach **Level {count}** to change channel color.";
 
+"lng_boost_channel_title_wallpaper" = "Enable wallpapers";
+"lng_boost_channel_needs_level_wallpaper#one" = "Your channel needs to reach **Level {count}** to change channel wallpaper.";
+"lng_boost_channel_needs_level_wallpaper#other" = "Your channel needs to reach **Level {count}** to change channel wallpaper.";
+
+"lng_boost_channel_title_status" = "Enable emoji status";
+"lng_boost_channel_needs_level_status#one" = "Your channel needs to reach **Level {count}** to set emoji status.";
+"lng_boost_channel_needs_level_status#other" = "Your channel needs to reach **Level {count}** to set emoji status.";
+
 "lng_boost_channel_title_reactions" = "Custom reactions";
 "lng_boost_channel_needs_level_reactions#one" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as a reaction.";
 "lng_boost_channel_needs_level_reactions#other" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as reactions.";
@@ -2847,6 +2855,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_edit_sign_messages" = "Sign messages";
 "lng_edit_group" = "Edit group";
 "lng_edit_channel_color" = "Change name color";
+"lng_edit_channel_level_min" = "Level 1+";
+"lng_edit_channel_wallpaper" = "Channel wallpaper";
+"lng_edit_channel_wallpaper_about" = "Set a wallpaper that will be visible for everyone reading your channel.";
+"lng_edit_channel_status" = "Channel emoji status";
+"lng_edit_channel_status_about" = "Choose a status that will be shown next to the channel's name.";
 "lng_edit_self_title" = "Edit your name";
 "lng_confirm_contact_data" = "New Contact";
 "lng_add_contact" = "Create";
diff --git a/Telegram/SourceFiles/api/api_peer_colors.cpp b/Telegram/SourceFiles/api/api_peer_colors.cpp
index 85d60d814..50c2382fd 100644
--- a/Telegram/SourceFiles/api/api_peer_colors.cpp
+++ b/Telegram/SourceFiles/api/api_peer_colors.cpp
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "api/api_peer_colors.h"
 
 #include "apiwrap.h"
+#include "data/data_peer.h"
 #include "ui/chat/chat_style.h"
 
 namespace Api {
@@ -62,6 +63,16 @@ auto PeerColors::indicesValue() const
 	}));
 }
 
+int PeerColors::requiredLevelFor(PeerId channel, uint8 index) const {
+	if (Data::DecideColorIndex(channel) == index) {
+		return 0;
+	} else if (const auto i = _requiredLevels.find(index)
+		; i != end(_requiredLevels)) {
+		return i->second;
+	}
+	return 1;
+}
+
 void PeerColors::apply(const MTPDhelp_peerColors &data) {
 	auto suggested = std::vector<uint8>();
 	auto colors = std::make_shared<
@@ -89,6 +100,7 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
 	};
 
 	const auto &list = data.vcolors().v;
+	_requiredLevels.clear();
 	suggested.reserve(list.size());
 	for (const auto &color : list) {
 		const auto &data = color.data();
@@ -98,6 +110,9 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
 			continue;
 		}
 		const auto colorIndex = uint8(colorIndexBare);
+		if (const auto min = data.vchannel_min_level()) {
+			_requiredLevels[colorIndex] = min->v;
+		}
 		if (!data.is_hidden()) {
 			suggested.push_back(colorIndex);
 		}
diff --git a/Telegram/SourceFiles/api/api_peer_colors.h b/Telegram/SourceFiles/api/api_peer_colors.h
index de06d4221..0ad1a63c7 100644
--- a/Telegram/SourceFiles/api/api_peer_colors.h
+++ b/Telegram/SourceFiles/api/api_peer_colors.h
@@ -28,6 +28,10 @@ public:
 	[[nodiscard]] auto indicesValue() const
 		-> rpl::producer<Ui::ColorIndicesCompressed>;
 
+	[[nodiscard]] int requiredLevelFor(
+		PeerId channel,
+		uint8 index) const;
+
 private:
 	void request();
 	void apply(const MTPDhelp_peerColors &data);
@@ -38,6 +42,7 @@ private:
 	mtpRequestId _requestId = 0;
 	base::Timer _timer;
 	rpl::variable<std::vector<uint8>> _suggested;
+	base::flat_map<uint8, int> _requiredLevels;
 	rpl::event_stream<> _colorIndicesChanged;
 	std::unique_ptr<Ui::ColorIndicesCompressed> _colorIndicesCurrent;
 
diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp
index 16d27b34d..f24e156d0 100644
--- a/Telegram/SourceFiles/api/api_statistics.cpp
+++ b/Telegram/SourceFiles/api/api_statistics.cpp
@@ -612,6 +612,7 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
 			_peer->input
 		)).done([=](const MTPpremium_BoostsStatus &result) {
 			const auto &data = result.data();
+			channel->updateLevelHint(data.vlevel().v);
 			const auto hasPremium = !!data.vpremium_audience();
 			const auto premiumMemberCount = hasPremium
 				? std::max(0, int(data.vpremium_audience()->data().vpart().v))
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp
index fd3458c1d..f686c06cf 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp
@@ -452,8 +452,11 @@ void Set(
 			: tr::lng_settings_color_changed_channel(tr::now));
 	};
 	const auto fail = [=](const MTP::Error &error) {
-		setLocal(wasIndex, wasEmojiId);
-		show->showToast(error.type());
+		const auto type = error.type();
+		if (type != u"CHAT_NOT_MODIFIED"_q) {
+			setLocal(wasIndex, wasEmojiId);
+			show->showToast(type);
+		}
 	};
 	const auto send = [&](auto &&request) {
 		peer->session().api().request(
@@ -469,7 +472,7 @@ void Set(
 	} else if (const auto channel = peer->asChannel()) {
 		using Flag = MTPchannels_UpdateColor::Flag;
 		send(MTPchannels_UpdateColor(
-			MTP_flags(Flag::f_background_emoji_id),
+			MTP_flags(Flag::f_color | Flag::f_background_emoji_id),
 			channel->inputChannel,
 			MTP_int(colorIndex),
 			MTP_long(backgroundEmojiId)));
@@ -509,9 +512,19 @@ void Apply(
 			peer->input
 		)).done([=](const MTPpremium_BoostsStatus &result) {
 			const auto &data = result.data();
-			const auto required = session->account().appConfig().get<int>(
-				"channel_color_level_min",
-				5);
+			if (const auto channel = peer->asChannel()) {
+				channel->updateLevelHint(data.vlevel().v);
+			}
+			const auto peerColors = &peer->session().api().peerColors();
+			const auto colorRequired = peerColors->requiredLevelFor(
+				peer->id,
+				colorIndex);
+			const auto iconRequired = backgroundEmojiId
+				? session->account().appConfig().get<int>(
+					"channel_bg_icon_level_min",
+					5)
+				: 0;
+			const auto required = std::max(colorRequired, iconRequired);
 			if (data.vlevel().v >= required) {
 				Set(show, peer, colorIndex, backgroundEmojiId);
 				close();
@@ -842,11 +855,12 @@ void AddPeerColorButton(
 		not_null<Ui::VerticalLayout*> container,
 		std::shared_ptr<ChatHelpers::Show> show,
 		not_null<PeerData*> peer) {
+	auto label = peer->isSelf()
+		? tr::lng_settings_theme_name_color()
+		: tr::lng_edit_channel_color();
 	const auto button = AddButtonWithIcon(
 		container,
-		(peer->isSelf()
-			? tr::lng_settings_theme_name_color()
-			: tr::lng_edit_channel_color()),
+		rpl::duplicate(label),
 		st::settingsColorButton,
 		{ &st::menuIconChangeColors });
 
@@ -873,7 +887,7 @@ void AddPeerColorButton(
 
 	rpl::combine(
 		button->widthValue(),
-		tr::lng_settings_theme_name_color(),
+		rpl::duplicate(label),
 		rpl::duplicate(colorIndexValue)
 	) | rpl::start_with_next([=](
 			int width,
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
index 7b1010272..fba0c7303 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
@@ -1294,6 +1294,9 @@ void Controller::editReactions() {
 		_peer->input
 	)).done([=](const MTPpremium_BoostsStatus &result) {
 		_controls.levelRequested = false;
+		if (const auto channel = _peer->asChannel()) {
+			channel->updateLevelHint(result.data().vlevel().v);
+		}
 		const auto link = qs(result.data().vboost_url());
 		const auto weak = base::make_weak(_navigation->parentController());
 		auto counters = ParseBoostCounters(result);
diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp
index ca1bd81b2..fecbe6287 100644
--- a/Telegram/SourceFiles/data/data_channel.cpp
+++ b/Telegram/SourceFiles/data/data_channel.cpp
@@ -949,6 +949,14 @@ void ChannelData::processTopics(const MTPVector<MTPForumTopic> &topics) {
 	}
 }
 
+int ChannelData::levelHint() const {
+	return _levelHint;
+}
+
+void ChannelData::updateLevelHint(int levelHint) {
+	_levelHint = levelHint;
+}
+
 namespace Data {
 
 void ApplyMigration(
diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h
index 0d1faf269..d55e8a4e6 100644
--- a/Telegram/SourceFiles/data/data_channel.h
+++ b/Telegram/SourceFiles/data/data_channel.h
@@ -463,6 +463,9 @@ public:
 
 	void processTopics(const MTPVector<MTPForumTopic> &topics);
 
+	[[nodiscard]] int levelHint() const;
+	void updateLevelHint(int levelHint);
+
 	// Still public data members.
 	uint64 access = 0;
 
@@ -497,6 +500,7 @@ private:
 	int _restrictedCount = 0;
 	int _kickedCount = 0;
 	int _pendingRequestsCount = 0;
+	int _levelHint = 0;
 	std::vector<UserId> _recentRequesters;
 	MsgId _availableMinId = 0;
 
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index eaea5ba61..c385a8c3d 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -845,6 +845,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
 
 		const auto wasCallNotEmpty = Data::ChannelHasActiveCall(channel);
 
+		channel->updateLevelHint(data.vlevel().value_or_empty());
 		if (const auto count = data.vparticipants_count()) {
 			channel->setMembersCount(count->v);
 		}
diff --git a/Telegram/SourceFiles/ui/boxes/boost_box.cpp b/Telegram/SourceFiles/ui/boxes/boost_box.cpp
index 592436a13..5a226eea4 100644
--- a/Telegram/SourceFiles/ui/boxes/boost_box.cpp
+++ b/Telegram/SourceFiles/ui/boxes/boost_box.cpp
@@ -467,15 +467,32 @@ void AskBoostBox(
 
 	box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
 
-	auto title = v::is<AskBoostChannelColor>(data.reason.data)
-		? tr::lng_boost_channel_title_color()
-		: tr::lng_boost_channel_title_reactions();
+	auto title = v::match(data.reason.data, [&](
+			AskBoostChannelColor data) {
+		return tr::lng_boost_channel_title_color();
+	}, [&](AskBoostWallpaper data) {
+		return tr::lng_boost_channel_title_wallpaper();
+	}, [&](AskBoostEmojiStatus data) {
+		return tr::lng_boost_channel_title_status();
+	}, [&](AskBoostCustomReactions data) {
+		return tr::lng_boost_channel_title_reactions();
+	});
 	auto reasonText = v::match(data.reason.data, [&](
 			AskBoostChannelColor data) {
 		return tr::lng_boost_channel_needs_level_color(
 			lt_count,
 			rpl::single(float64(data.requiredLevel)),
 			Ui::Text::RichLangValue);
+	}, [&](AskBoostWallpaper data) {
+		return tr::lng_boost_channel_needs_level_wallpaper(
+			lt_count,
+			rpl::single(float64(data.requiredLevel)),
+			Ui::Text::RichLangValue);
+	}, [&](AskBoostEmojiStatus data) {
+		return tr::lng_boost_channel_needs_level_status(
+			lt_count,
+			rpl::single(float64(data.requiredLevel)),
+			Ui::Text::RichLangValue);
 	}, [&](AskBoostCustomReactions data) {
 		return tr::lng_boost_channel_needs_level_reactions(
 			lt_count,
diff --git a/Telegram/SourceFiles/ui/boxes/boost_box.h b/Telegram/SourceFiles/ui/boxes/boost_box.h
index 84d0b65b3..68ff1d771 100644
--- a/Telegram/SourceFiles/ui/boxes/boost_box.h
+++ b/Telegram/SourceFiles/ui/boxes/boost_box.h
@@ -54,6 +54,14 @@ struct AskBoostChannelColor {
 	int requiredLevel = 0;
 };
 
+struct AskBoostWallpaper {
+	int requiredLevel = 0;
+};
+
+struct AskBoostEmojiStatus {
+	int requiredLevel = 0;
+};
+
 struct AskBoostCustomReactions {
 	int count = 0;
 };
@@ -61,6 +69,8 @@ struct AskBoostCustomReactions {
 struct AskBoostReason {
 	std::variant<
 		AskBoostChannelColor,
+		AskBoostWallpaper,
+		AskBoostEmojiStatus,
 		AskBoostCustomReactions> data;
 };
 
diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp
index 7e12d1945..3a348ade3 100644
--- a/Telegram/SourceFiles/window/window_session_controller.cpp
+++ b/Telegram/SourceFiles/window/window_session_controller.cpp
@@ -623,6 +623,7 @@ void SessionNavigation::resolveBoostState(not_null<ChannelData*> channel) {
 		channel->input
 	)).done([=](const MTPpremium_BoostsStatus &result) {
 		_boostStateResolving = nullptr;
+		channel->updateLevelHint(result.data().vlevel().v);
 		const auto submit = [=](Fn<void(Ui::BoostCounters)> done) {
 			applyBoost(channel, done);
 		};
@@ -730,6 +731,7 @@ void SessionNavigation::applyBoostsChecked(
 		_api.request(MTPpremium_GetBoostsStatus(
 			channel->input
 		)).done([=](const MTPpremium_BoostsStatus &result) {
+			channel->updateLevelHint(result.data().vlevel().v);
 			done(ParseBoostCounters(result));
 		}).fail([=](const MTP::Error &error) {
 			showToast(u"Error: "_q + error.type());