diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp
index 89c53f604..0107b2fbc 100644
--- a/Telegram/SourceFiles/boxes/star_gift_box.cpp
+++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp
@@ -108,6 +108,7 @@ constexpr auto kSentToastDuration = 3 * crl::time(1000);
 constexpr auto kSwitchUpgradeCoverInterval = 3 * crl::time(1000);
 constexpr auto kCrossfadeDuration = crl::time(400);
 constexpr auto kUpgradeDoneToastDuration = 4 * crl::time(1000);
+constexpr auto kGiftsPreloadTimeout = 3 * crl::time(1000);
 
 using namespace HistoryView;
 using namespace Info::PeerGifts;
@@ -2193,7 +2194,66 @@ void ChooseStarGiftRecipient(
 void ShowStarGiftBox(
 		not_null<Window::SessionController*> controller,
 		not_null<PeerData*> peer) {
-	controller->show(Box(GiftBox, controller, peer));
+	struct Session {
+		PeerData *peer = nullptr;
+		bool premiumGiftsReady = false;
+		bool starsGiftsReady = false;
+		rpl::lifetime lifetime;
+	};
+	static auto Map = base::flat_map<not_null<Main::Session*>, Session>();
+
+	const auto session = &controller->session();
+	auto i = Map.find(session);
+	if (i == end(Map)) {
+		i = Map.emplace(session).first;
+		session->lifetime().add([=] { Map.remove(session); });
+	} else if (i->second.peer == peer) {
+		return;
+	}
+	i->second = Session{ .peer = peer };
+
+	const auto weak = base::make_weak(controller);
+	const auto show = [=] {
+		Map[session] = Session();
+		if (const auto strong = weak.get()) {
+			strong->show(Box(GiftBox, strong, peer));
+		}
+	};
+
+	base::timer_once(
+		kGiftsPreloadTimeout
+	) | rpl::start_with_next(show, i->second.lifetime);
+
+	const auto user = peer->asUser();
+	if (user && !user->isSelf()) {
+		GiftsPremium(
+			session,
+			peer
+		) | rpl::start_with_next([=](PremiumGiftsDescriptor &&gifts) {
+			if (!gifts.list.empty()) {
+				auto &entry = Map[session];
+				entry.premiumGiftsReady = true;
+				if (entry.starsGiftsReady) {
+					show();
+				}
+			}
+		}, i->second.lifetime);
+	} else {
+		i->second.premiumGiftsReady = true;
+	}
+
+	GiftsStars(
+		session,
+		peer
+	) | rpl::start_with_next([=](std::vector<GiftTypeStars> &&gifts) {
+		if (!gifts.empty()) {
+			auto &entry = Map[session];
+			entry.starsGiftsReady = true;
+			if (entry.premiumGiftsReady) {
+				show();
+			}
+		}
+	}, i->second.lifetime);
 }
 
 void AddUniqueGiftCover(
diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp
index 376b95c07..63106347d 100644
--- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp
+++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp
@@ -199,6 +199,8 @@ void InnerWidget::subscribeToUpdates() {
 		} else if (update.action == Action::Save
 			|| update.action == Action::Unsave) {
 			i->gift.hidden = (update.action == Action::Unsave);
+
+			const auto unpin = i->gift.hidden && i->gift.pinned;
 			v::match(i->descriptor, [](GiftTypePremium &) {
 			}, [&](GiftTypeStars &data) {
 				data.hidden = i->gift.hidden;
@@ -209,6 +211,9 @@ void InnerWidget::subscribeToUpdates() {
 					view.manageId = {};
 				}
 			}
+			if (unpin) {
+				markUnpinned(i);
+			}
 		} else if (update.action == Action::Pin
 			|| update.action == Action::Unpin) {
 			if (update.action == Action::Pin) {