diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index ab7450ff4..e4c35a957 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -598,6 +598,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_blocked_list_already_blocked" = "blocked already";
 "lng_blocked_list_about" = "Blocked users can't send you messages or add you to groups. They will not see your profile pictures, online and last seen status.";
 "lng_blocked_list_not_found" = "No users found.";
+"lng_blocked_list_confirm_title" = "Block {name}";
+"lng_blocked_list_confirm_text" = "Do you want to block {name} from messaging and calling you on Telegram?";
+"lng_blocked_list_confirm_clear" = "Delete this chat";
+"lng_blocked_list_confirm_ok" = "Block";
 
 "lng_edit_privacy_everyone" = "Everybody";
 "lng_edit_privacy_contacts" = "My contacts";
@@ -1411,7 +1415,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_contact_phone" = "Phone Number";
 "lng_enter_contact_data" = "New Contact";
 "lng_contact_mobile_hidden" = "Mobile hidden";
-"lng_contact_phone_after" = "Phone number will be visible once {user} adds you as a contact. Your phone number will become visible to {name}.";
+"lng_contact_phone_after" = "Phone number will be visible once {user} adds you as a contact. Your phone number will become {visible} to {name}.";
+"lng_contact_phone_visible" = "visible";
 "lng_contact_phone_show" = "When you click {button}, your phone number will become visible to {user}.";
 "lng_edit_contact_title" = "Edit contact name";
 "lng_edit_channel_title" = "Edit channel";
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index 2d98862e2..b39ed0c41 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -90,6 +90,8 @@ boxLayerTitleAdditionalSkip: 9px;
 boxLayerTitleAdditionalFont: normalFont;
 boxLayerScroll: defaultSolidScroll;
 
+boxRowPadding: margins(23px, 0px, 23px, 0px);
+
 boxTopMargin: 6px;
 
 boxTitleClose: IconButton(defaultIconButton) {
@@ -980,3 +982,6 @@ linkedChatAboutPadding: margins(20px, 20px, 20px, 20px);
 
 addContactFieldMargin: margins(19px, 0px, 19px, 10px);
 addContactWarningMargin: margins(19px, 10px, 19px, 5px);
+blockUserConfirmation: FlatLabel(boxLabel) {
+	minWidth: 240px;
+}
diff --git a/Telegram/SourceFiles/boxes/generic_box.cpp b/Telegram/SourceFiles/boxes/generic_box.cpp
new file mode 100644
index 000000000..0e49abcbb
--- /dev/null
+++ b/Telegram/SourceFiles/boxes/generic_box.cpp
@@ -0,0 +1,25 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "boxes/generic_box.h"
+
+#include "ui/wrap/vertical_layout.h"
+#include "ui/wrap/padding_wrap.h"
+#include "ui/wrap/wrap.h"
+#include "styles/style_boxes.h"
+
+void GenericBox::prepare() {
+	_init(this);
+
+	auto wrap = object_ptr<Ui::OverrideMargins>(this, std::move(_content));
+	setDimensionsToContent(_width ? _width : st::boxWidth, wrap.data());
+	setInnerWidget(std::move(wrap));
+}
+
+void GenericBox::addSkip(int height) {
+	addRow(object_ptr<Ui::FixedHeightWidget>(this, height));
+}
diff --git a/Telegram/SourceFiles/boxes/generic_box.h b/Telegram/SourceFiles/boxes/generic_box.h
new file mode 100644
index 000000000..317bc4908
--- /dev/null
+++ b/Telegram/SourceFiles/boxes/generic_box.h
@@ -0,0 +1,140 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+#include "boxes/abstract_box.h"
+#include "ui/wrap/vertical_layout.h"
+
+#include <tuple>
+
+namespace st {
+extern const style::margins &boxRowPadding;
+} // namespace st
+
+class GenericBox : public BoxContent {
+public:
+	// InitMethod::operator()(not_null<GenericBox*> box, InitArgs...)
+	// init(box, args...)
+	template <
+		typename InitMethod,
+		typename ...InitArgs,
+		typename = decltype(std::declval<std::decay_t<InitMethod>>()(
+			std::declval<not_null<GenericBox*>>(),
+			std::declval<std::decay_t<InitArgs>>()...))>
+	GenericBox(
+		QWidget*,
+		InitMethod &&init,
+		InitArgs &&...args);
+
+	void setWidth(int width) {
+		_width = width;
+	}
+
+	int rowsCount() const {
+		return _content->count();
+	}
+
+	template <
+		typename Widget,
+		typename = std::enable_if_t<
+		std::is_base_of_v<RpWidget, Widget>>>
+	Widget *insertRow(
+			int atPosition,
+			object_ptr<Widget> &&child,
+			const style::margins &margin = st::boxRowPadding) {
+		return _content->insert(
+			atPosition,
+			std::move(child),
+			margin);
+	}
+
+	template <
+		typename Widget,
+		typename = std::enable_if_t<
+		std::is_base_of_v<RpWidget, Widget>>>
+	Widget *addRow(
+			object_ptr<Widget> &&child,
+			const style::margins &margin = st::boxRowPadding) {
+		return _content->add(std::move(child), margin);
+	}
+
+	void addSkip(int height);
+
+protected:
+	void prepare() override;
+
+private:
+	template <typename InitMethod, typename ...InitArgs>
+	struct Initer {
+		template <typename OtherMethod, typename ...OtherArgs>
+		Initer(OtherMethod &&method, OtherArgs &&...args);
+
+		void operator()(not_null<GenericBox*> box);
+
+		template <std::size_t... I>
+		void call(
+			not_null<GenericBox*> box,
+			std::index_sequence<I...>);
+
+		InitMethod method;
+		std::tuple<InitArgs...> args;
+	};
+
+	template <typename InitMethod, typename ...InitArgs>
+	auto MakeIniter(InitMethod &&method, InitArgs &&...args)
+		-> Initer<std::decay_t<InitMethod>, std::decay_t<InitArgs>...>;
+
+	FnMut<void(not_null<GenericBox*>)> _init;
+	object_ptr<Ui::VerticalLayout> _content;
+	int _width = 0;
+
+};
+
+template <typename InitMethod, typename ...InitArgs>
+template <typename OtherMethod, typename ...OtherArgs>
+GenericBox::Initer<InitMethod, InitArgs...>::Initer(
+	OtherMethod &&method,
+	OtherArgs &&...args)
+: method(std::forward<OtherMethod>(method))
+, args(std::forward<OtherArgs>(args)...) {
+}
+
+template <typename InitMethod, typename ...InitArgs>
+inline void GenericBox::Initer<InitMethod, InitArgs...>::operator()(
+		not_null<GenericBox*> box) {
+	call(box, std::make_index_sequence<sizeof...(InitArgs)>());
+}
+
+template <typename InitMethod, typename ...InitArgs>
+template <std::size_t... I>
+inline void GenericBox::Initer<InitMethod, InitArgs...>::call(
+		not_null<GenericBox*> box,
+		std::index_sequence<I...>) {
+	std::invoke(method, box, std::get<I>(args)...);
+}
+
+template <typename InitMethod, typename ...InitArgs>
+inline auto GenericBox::MakeIniter(InitMethod &&method, InitArgs &&...args)
+-> Initer<std::decay_t<InitMethod>, std::decay_t<InitArgs>...> {
+	return {
+		std::forward<InitMethod>(method),
+		std::forward<InitArgs>(args)...
+	};
+}
+
+template <typename InitMethod, typename ...InitArgs, typename>
+inline GenericBox::GenericBox(
+	QWidget*,
+	InitMethod &&init,
+	InitArgs &&...args)
+: _init(
+	MakeIniter(
+		std::forward<InitMethod>(init),
+		std::forward<InitArgs>(args)...))
+, _content(this) {
+}
diff --git a/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp b/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp
index b216c1e09..b040454ea 100644
--- a/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp
@@ -173,10 +173,15 @@ void AddToContactsBox::setupWarning(
 	const auto name = _user->firstName.isEmpty()
 		? _user->lastName
 		: _user->firstName;
+	const auto nameWithEntities = TextWithEntities{ name };
 	const auto text = _phone.isEmpty()
-		? TextWithEntities{
-			lng_contact_phone_after(lt_user, name, lt_name, name)
-		}
+		? lng_contact_phone_after__generic<TextWithEntities>(
+			lt_user,
+			nameWithEntities,
+			lt_visible,
+			BoldText(lang(lng_contact_phone_visible)),
+			lt_name,
+			nameWithEntities)
 		: lng_contact_phone_show__generic<TextWithEntities>(
 			lt_button,
 			BoldText(lang(lng_box_done).toUpper()),
diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp
index dcf9e122a..65a82b598 100644
--- a/Telegram/SourceFiles/data/data_user.cpp
+++ b/Telegram/SourceFiles/data/data_user.cpp
@@ -235,6 +235,11 @@ void UserData::setIsBlocked(bool is) {
 		: BlockStatus::NotBlocked;
 	if (_blockStatus != status) {
 		_blockStatus = status;
+		if (is) {
+			_fullFlags.add(MTPDuserFull::Flag::f_blocked);
+		} else {
+			_fullFlags.remove(MTPDuserFull::Flag::f_blocked);
+		}
 		Notify::peerUpdatedDelayed(this, UpdateFlag::UserIsBlocked);
 	}
 }
diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp
index 7bb8ce97e..2c040d9c4 100644
--- a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp
@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "lang/lang_keys.h"
 #include "ui/widgets/buttons.h"
+#include "ui/widgets/checkbox.h"
+#include "ui/widgets/labels.h"
 #include "data/data_peer.h"
 #include "data/data_user.h"
 #include "data/data_chat.h"
@@ -19,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "apiwrap.h"
 #include "auth_session.h"
 #include "boxes/confirm_box.h"
+#include "boxes/generic_box.h"
 #include "styles/style_history.h"
 #include "styles/style_boxes.h"
 
@@ -41,7 +44,9 @@ bool BarCurrentlyHidden(not_null<PeerData*> peer) {
 	}
 	using Setting = MTPDpeerSettings::Flag;
 	if (const auto user = peer->asUser()) {
-		if (user->isContact()
+		if (user->isBlocked()) {
+			return true;
+		} else if (user->isContact()
 			&& !((*settings) & Setting::f_share_contact)) {
 			return true;
 		}
@@ -55,6 +60,82 @@ auto MapToEmpty() {
 	return rpl::map([] { return rpl::empty_value(); });
 }
 
+TextWithEntities BoldText(const QString &text) {
+	auto result = TextWithEntities{ text };
+	result.entities.push_back({ EntityType::Bold, 0, text.size() });
+	return result;
+}
+
+void BlockUserBox(
+		not_null<GenericBox*> box,
+		not_null<UserData*> user,
+		not_null<Window::Controller*> window) {
+	using Flag = MTPDpeerSettings::Flag;
+	const auto settings = user->settings().value_or(Flag(0));
+
+	const auto name = user->firstName.isEmpty()
+		? user->lastName
+		: user->firstName;
+
+	box->addRow(object_ptr<Ui::FlatLabel>(
+		box,
+		rpl::single(
+			lng_blocked_list_confirm_text__generic<TextWithEntities>(
+				lt_name,
+				BoldText(name))),
+		st::blockUserConfirmation));
+
+	box->addSkip(st::boxMediumSkip);
+
+	const auto report = (settings & Flag::f_report_spam)
+		? box->addRow(object_ptr<Ui::Checkbox>(
+			box,
+			lang(lng_report_spam),
+			true,
+			st::defaultBoxCheckbox))
+		: nullptr;
+
+	if (report) {
+		box->addSkip(st::boxMediumSkip);
+	}
+
+	const auto clear = box->addRow(object_ptr<Ui::Checkbox>(
+		box,
+		lang(lng_blocked_list_confirm_clear),
+		true,
+		st::defaultBoxCheckbox));
+
+	box->addSkip(st::boxLittleSkip);
+
+	box->setTitle([=] {
+		return lng_blocked_list_confirm_title(lt_name, name);
+	});
+
+	box->addButton(langFactory(lng_blocked_list_confirm_ok), [=] {
+		const auto reportChecked = report && report->checked();
+		const auto clearChecked = clear->checked();
+
+		box->closeBox();
+
+		user->session().api().blockUser(user);
+		if (reportChecked) {
+			user->session().api().request(MTPmessages_ReportSpam(
+				user->input
+			)).send();
+		}
+		if (clearChecked) {
+			crl::on_main(&user->session(), [=] {
+				user->session().api().deleteConversation(user, false);
+			});
+			window->sessionController()->showBackFromStack();
+		}
+	}, st::attentionBoxButton);
+
+	box->addButton(langFactory(lng_cancel), [=] {
+		box->closeBox();
+	});
+}
+
 } // namespace
 
 ContactStatus::Bar::Bar(QWidget *parent, const QString &name)
@@ -215,23 +296,31 @@ void ContactStatus::setupWidgets(not_null<Ui::RpWidget*> parent) {
 auto ContactStatus::PeerState(not_null<PeerData*> peer)
 -> rpl::producer<State> {
 	using SettingsChange = PeerData::Settings::Change;
-	using Settings = MTPDpeerSettings::Flags;
 	using Setting = MTPDpeerSettings::Flag;
 	if (const auto user = peer->asUser()) {
 		using FlagsChange = UserData::Flags::Change;
-		using Flags = MTPDuser::Flags;
+		using FullFlagsChange = UserData::FullFlags::Change;
 		using Flag = MTPDuser::Flag;
+		using FullFlag = MTPDuserFull::Flag;
 
 		auto isContactChanges = user->flagsValue(
 		) | rpl::filter([](FlagsChange flags) {
 			return flags.diff
 				& (Flag::f_contact | Flag::f_mutual_contact);
 		});
+		auto isBlockedChanges = user->fullFlagsValue(
+		) | rpl::filter([](FullFlagsChange full) {
+			return full.diff & FullFlag::f_blocked;
+		});
 		return rpl::combine(
 			std::move(isContactChanges),
+			std::move(isBlockedChanges),
 			user->settingsValue()
-		) | rpl::map([=](FlagsChange flags, SettingsChange settings) {
-			if (!settings.value) {
+		) | rpl::map([=](
+				FlagsChange flags,
+				FullFlagsChange full,
+				SettingsChange settings) {
+			if (!settings.value || (full.value & FullFlag::f_blocked)) {
 				return State::None;
 			} else if (user->isContact()) {
 				if (settings.value & Setting::f_share_contact) {
@@ -283,26 +372,28 @@ void ContactStatus::setupHandlers(not_null<PeerData*> peer) {
 	setupCloseHandler(peer);
 }
 
-void ContactStatus::setupAddHandler(not_null<UserData*> peer) {
+void ContactStatus::setupAddHandler(not_null<UserData*> user) {
 	_bar.entity()->addClicks(
 	) | rpl::start_with_next([=] {
-		Expects(peer->isUser());
-
-		Window::PeerMenuAddContact(peer->asUser());
+		Window::PeerMenuAddContact(user);
 	}, _bar.lifetime());
 }
 
-void ContactStatus::setupBlockHandler(not_null<UserData*> peer) {
+void ContactStatus::setupBlockHandler(not_null<UserData*> user) {
+	_bar.entity()->blockClicks(
+	) | rpl::start_with_next([=] {
+		_window->show(Box<GenericBox>(BlockUserBox, user, _window));
+	}, _bar.lifetime());
 }
 
-void ContactStatus::setupShareHandler(not_null<UserData*> peer) {
+void ContactStatus::setupShareHandler(not_null<UserData*> user) {
 	_bar.entity()->shareClicks(
 	) | rpl::start_with_next([=] {
-		peer->setSettings(0);
-		peer->session().api().request(MTPcontacts_AcceptContact(
-			peer->inputUser
+		user->setSettings(0);
+		user->session().api().request(MTPcontacts_AcceptContact(
+			user->inputUser
 		)).done([=](const MTPUpdates &result) {
-			peer->session().api().applyUpdates(result);
+			user->session().api().applyUpdates(result);
 		}).send();
 	}, _bar.lifetime());
 }
diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.h b/Telegram/SourceFiles/history/view/history_view_contact_status.h
index 63f679769..e75198d8d 100644
--- a/Telegram/SourceFiles/history/view/history_view_contact_status.h
+++ b/Telegram/SourceFiles/history/view/history_view_contact_status.h
@@ -79,9 +79,9 @@ private:
 	void setupWidgets(not_null<Ui::RpWidget*> parent);
 	void setupState(not_null<PeerData*> peer);
 	void setupHandlers(not_null<PeerData*> peer);
-	void setupAddHandler(not_null<UserData*> peer);
-	void setupBlockHandler(not_null<UserData*> peer);
-	void setupShareHandler(not_null<UserData*> peer);
+	void setupAddHandler(not_null<UserData*> user);
+	void setupBlockHandler(not_null<UserData*> user);
+	void setupShareHandler(not_null<UserData*> user);
 	void setupReportHandler(not_null<PeerData*> peer);
 	void setupCloseHandler(not_null<PeerData*> peer);
 
diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt
index 49e608bf6..c4c5a53a4 100644
--- a/Telegram/gyp/telegram_sources.txt
+++ b/Telegram/gyp/telegram_sources.txt
@@ -50,6 +50,8 @@
 <(src_loc)/boxes/edit_color_box.h
 <(src_loc)/boxes/edit_privacy_box.cpp
 <(src_loc)/boxes/edit_privacy_box.h
+<(src_loc)/boxes/generic_box.cpp
+<(src_loc)/boxes/generic_box.h
 <(src_loc)/boxes/language_box.cpp
 <(src_loc)/boxes/language_box.h
 <(src_loc)/boxes/local_storage_box.cpp