Moved out top promo from api and suggestions from config to single file.

This commit is contained in:
23rd 2025-05-06 11:11:45 +03:00
parent dc1459438c
commit c2e887a86e
13 changed files with 288 additions and 205 deletions

View file

@ -501,6 +501,8 @@ PRIVATE
data/components/factchecks.h data/components/factchecks.h
data/components/location_pickers.cpp data/components/location_pickers.cpp
data/components/location_pickers.h data/components/location_pickers.h
data/components/promo_suggestions.cpp
data/components/promo_suggestions.h
data/components/recent_peers.cpp data/components/recent_peers.cpp
data/components/recent_peers.h data/components/recent_peers.h
data/components/scheduled_messages.cpp data/components/scheduled_messages.cpp

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_global_privacy.h" #include "api/api_global_privacy.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "data/components/promo_suggestions.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_app_config.h" #include "main/main_app_config.h"
@ -101,13 +102,11 @@ rpl::producer<bool> GlobalPrivacy::showArchiveAndMute() const {
} }
rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const { rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const {
return _session->appConfig().suggestionRequested( return _session->promoSuggestions().requested(u"AUTOARCHIVE_POPULAR"_q);
u"AUTOARCHIVE_POPULAR"_q);
} }
void GlobalPrivacy::dismissArchiveAndMuteSuggestion() { void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
_session->appConfig().dismissSuggestion( _session->promoSuggestions().dismiss(u"AUTOARCHIVE_POPULAR"_q);
u"AUTOARCHIVE_POPULAR"_q);
} }
void GlobalPrivacy::updateHideReadTime(bool hide) { void GlobalPrivacy::updateHideReadTime(bool hide) {

View file

@ -91,8 +91,6 @@ namespace {
// Save draft to the cloud with 1 sec extra delay. // Save draft to the cloud with 1 sec extra delay.
constexpr auto kSaveCloudDraftTimeout = 1000; constexpr auto kSaveCloudDraftTimeout = 1000;
constexpr auto kTopPromotionInterval = TimeId(60 * 60);
constexpr auto kTopPromotionMinDelay = TimeId(10);
constexpr auto kSmallDelayMs = 5; constexpr auto kSmallDelayMs = 5;
constexpr auto kReadFeaturedSetsTimeout = crl::time(1000); constexpr auto kReadFeaturedSetsTimeout = crl::time(1000);
constexpr auto kFileLoaderQueueStopTimeout = crl::time(5000); constexpr auto kFileLoaderQueueStopTimeout = crl::time(5000);
@ -163,7 +161,6 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
, _featuredSetsReadTimer([=] { readFeaturedSets(); }) , _featuredSetsReadTimer([=] { readFeaturedSets(); })
, _dialogsLoadState(std::make_unique<DialogsLoadState>()) , _dialogsLoadState(std::make_unique<DialogsLoadState>())
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout)) , _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
, _topPromotionTimer([=] { refreshTopPromotion(); })
, _updateNotifyTimer([=] { sendNotifySettingsUpdates(); }) , _updateNotifyTimer([=] { sendNotifySettingsUpdates(); })
, _statsSessionKillTimer([=] { checkStatsSessions(); }) , _statsSessionKillTimer([=] { checkStatsSessions(); })
, _authorizations(std::make_unique<Api::Authorizations>(this)) , _authorizations(std::make_unique<Api::Authorizations>(this))
@ -199,11 +196,6 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
}, _session->lifetime()); }, _session->lifetime());
setupSupportMode(); setupSupportMode();
Core::App().settings().proxy().connectionTypeValue(
) | rpl::start_with_next([=] {
refreshTopPromotion();
}, _session->lifetime());
}); });
} }
@ -243,77 +235,6 @@ void ApiWrap::requestChangelog(
//).send(); //).send();
} }
void ApiWrap::refreshTopPromotion() {
const auto now = base::unixtime::now();
const auto next = (_topPromotionNextRequestTime != 0)
? _topPromotionNextRequestTime
: now;
if (_topPromotionRequestId) {
getTopPromotionDelayed(now, next);
return;
}
const auto key = [&]() -> std::pair<QString, uint32> {
if (!Core::App().settings().proxy().isEnabled()) {
return {};
}
const auto &proxy = Core::App().settings().proxy().selected();
if (proxy.type != MTP::ProxyData::Type::Mtproto) {
return {};
}
return { proxy.host, proxy.port };
}();
if (_topPromotionKey == key && now < next) {
getTopPromotionDelayed(now, next);
return;
}
_topPromotionKey = key;
_topPromotionRequestId = request(MTPhelp_GetPromoData(
)).done([=](const MTPhelp_PromoData &result) {
_topPromotionRequestId = 0;
topPromotionDone(result);
}).fail([=] {
_topPromotionRequestId = 0;
const auto now = base::unixtime::now();
const auto next = _topPromotionNextRequestTime = now
+ kTopPromotionInterval;
if (!_topPromotionTimer.isActive()) {
getTopPromotionDelayed(now, next);
}
}).send();
}
void ApiWrap::getTopPromotionDelayed(TimeId now, TimeId next) {
_topPromotionTimer.callOnce(std::min(
std::max(next - now, kTopPromotionMinDelay),
kTopPromotionInterval) * crl::time(1000));
};
void ApiWrap::topPromotionDone(const MTPhelp_PromoData &proxy) {
_topPromotionNextRequestTime = proxy.match([&](const auto &data) {
return data.vexpires().v;
});
getTopPromotionDelayed(
base::unixtime::now(),
_topPromotionNextRequestTime);
proxy.match([&](const MTPDhelp_promoDataEmpty &data) {
_session->data().setTopPromoted(nullptr, QString(), QString());
}, [&](const MTPDhelp_promoData &data) {
_session->data().processChats(data.vchats());
_session->data().processUsers(data.vusers());
if (const auto peer = data.vpeer()) {
const auto peerId = peerFromMTP(*peer);
const auto history = _session->data().history(peerId);
_session->data().setTopPromoted(
history,
data.vpsa_type().value_or_empty(),
data.vpsa_message().value_or_empty());
} else {
_session->data().setTopPromoted(nullptr, QString(), QString());
}
});
}
void ApiWrap::requestDeepLinkInfo( void ApiWrap::requestDeepLinkInfo(
const QString &path, const QString &path,
Fn<void(TextWithEntities message, bool updateRequired)> callback) { Fn<void(TextWithEntities message, bool updateRequired)> callback) {

View file

@ -200,7 +200,6 @@ public:
void requestChangelog( void requestChangelog(
const QString &sinceVersion, const QString &sinceVersion,
Fn<void(const MTPUpdates &result)> callback); Fn<void(const MTPUpdates &result)> callback);
void refreshTopPromotion();
void requestDeepLinkInfo( void requestDeepLinkInfo(
const QString &path, const QString &path,
Fn<void(TextWithEntities message, bool updateRequired)> callback); Fn<void(TextWithEntities message, bool updateRequired)> callback);
@ -569,9 +568,6 @@ private:
not_null<SendingAlbum*> album, not_null<SendingAlbum*> album,
Fn<void(bool)> done = nullptr); Fn<void(bool)> done = nullptr);
void getTopPromotionDelayed(TimeId now, TimeId next);
void topPromotionDone(const MTPhelp_PromoData &proxy);
void sendNotifySettingsUpdates(); void sendNotifySettingsUpdates();
template <typename Request> template <typename Request>
@ -709,11 +705,6 @@ private:
std::unique_ptr<TaskQueue> _fileLoader; std::unique_ptr<TaskQueue> _fileLoader;
base::flat_map<uint64, std::shared_ptr<SendingAlbum>> _sendingAlbums; base::flat_map<uint64, std::shared_ptr<SendingAlbum>> _sendingAlbums;
mtpRequestId _topPromotionRequestId = 0;
std::pair<QString, uint32> _topPromotionKey;
TimeId _topPromotionNextRequestTime = TimeId(0);
base::Timer _topPromotionTimer;
base::flat_set<not_null<const Data::ForumTopic*>> _updateNotifyTopics; base::flat_set<not_null<const Data::ForumTopic*>> _updateNotifyTopics;
base::flat_set<not_null<const PeerData*>> _updateNotifyPeers; base::flat_set<not_null<const PeerData*>> _updateNotifyPeers;
base::flat_set<Data::DefaultNotify> _updateNotifyDefaults; base::flat_set<Data::DefaultNotify> _updateNotifyDefaults;

View file

@ -0,0 +1,197 @@
/*
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 "data/components/promo_suggestions.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "data/data_changes.h"
#include "data/data_histories.h"
#include "data/data_session.h"
#include "history/history.h"
#include "main/main_session.h"
namespace Data {
namespace {
constexpr auto kTopPromotionInterval = TimeId(60 * 60);
constexpr auto kTopPromotionMinDelay = TimeId(10);
} // namespace
PromoSuggestions::PromoSuggestions(not_null<Main::Session*> session)
: _session(session)
, _topPromotionTimer([=] { refreshTopPromotion(); }) {
Core::App().settings().proxy().connectionTypeValue(
) | rpl::start_with_next([=] {
refreshTopPromotion();
}, _lifetime);
}
PromoSuggestions::~PromoSuggestions() = default;
void PromoSuggestions::refreshTopPromotion() {
const auto now = base::unixtime::now();
const auto next = (_topPromotionNextRequestTime != 0)
? _topPromotionNextRequestTime
: now;
if (_topPromotionRequestId) {
getTopPromotionDelayed(now, next);
return;
}
const auto key = [&]() -> std::pair<QString, uint32> {
if (!Core::App().settings().proxy().isEnabled()) {
return {};
}
const auto &proxy = Core::App().settings().proxy().selected();
if (proxy.type != MTP::ProxyData::Type::Mtproto) {
return {};
}
return { proxy.host, proxy.port };
}();
if (_topPromotionKey == key && now < next) {
getTopPromotionDelayed(now, next);
return;
}
_topPromotionKey = key;
_topPromotionRequestId = _session->api().request(MTPhelp_GetPromoData(
)).done([=](const MTPhelp_PromoData &result) {
_topPromotionRequestId = 0;
topPromotionDone(result);
}).fail([=] {
_topPromotionRequestId = 0;
const auto now = base::unixtime::now();
const auto next = _topPromotionNextRequestTime = now
+ kTopPromotionInterval;
if (!_topPromotionTimer.isActive()) {
getTopPromotionDelayed(now, next);
}
}).send();
}
void PromoSuggestions::getTopPromotionDelayed(TimeId now, TimeId next) {
_topPromotionTimer.callOnce(std::min(
std::max(next - now, kTopPromotionMinDelay),
kTopPromotionInterval) * crl::time(1000));
};
void PromoSuggestions::topPromotionDone(const MTPhelp_PromoData &proxy) {
_topPromotionNextRequestTime = proxy.match([&](const auto &data) {
return data.vexpires().v;
});
getTopPromotionDelayed(
base::unixtime::now(),
_topPromotionNextRequestTime);
proxy.match([&](const MTPDhelp_promoDataEmpty &data) {
setTopPromoted(nullptr, QString(), QString());
}, [&](const MTPDhelp_promoData &data) {
_session->data().processChats(data.vchats());
_session->data().processUsers(data.vusers());
auto changedPendingSuggestions = false;
auto pendingSuggestions = ranges::views::all(
data.vpending_suggestions().v
) | ranges::views::transform([](const auto &suggestion) {
return qs(suggestion);
}) | ranges::to_vector;
if (!ranges::equal(_pendingSuggestions, pendingSuggestions)) {
_pendingSuggestions = std::move(pendingSuggestions);
changedPendingSuggestions = true;
}
auto changedDismissedSuggestions = false;
for (const auto &suggestion : data.vdismissed_suggestions().v) {
changedDismissedSuggestions
|= _dismissedSuggestions.emplace(qs(suggestion)).second;
}
if (changedPendingSuggestions || changedDismissedSuggestions) {
_refreshed.fire({});
}
if (const auto peer = data.vpeer()) {
const auto peerId = peerFromMTP(*peer);
const auto history = _session->data().history(peerId);
setTopPromoted(
history,
data.vpsa_type().value_or_empty(),
data.vpsa_message().value_or_empty());
} else {
setTopPromoted(nullptr, QString(), QString());
}
});
}
rpl::producer<> PromoSuggestions::value() const {
return _refreshed.events_starting_with({});
}
void PromoSuggestions::setTopPromoted(
History *promoted,
const QString &type,
const QString &message) {
const auto changed = (_topPromoted != promoted);
if (!changed
&& (!promoted || promoted->topPromotionMessage() == message)) {
return;
}
if (changed) {
if (_topPromoted) {
_topPromoted->cacheTopPromotion(false, QString(), QString());
}
}
const auto old = std::exchange(_topPromoted, promoted);
if (_topPromoted) {
_session->data().histories().requestDialogEntry(_topPromoted);
_topPromoted->cacheTopPromotion(true, type, message);
_topPromoted->requestChatListMessage();
_session->changes().historyUpdated(
_topPromoted,
HistoryUpdate::Flag::TopPromoted);
}
if (changed && old) {
_session->changes().historyUpdated(
old,
HistoryUpdate::Flag::TopPromoted);
}
}
bool PromoSuggestions::current(const QString &key) const {
if (key == u"BIRTHDAY_CONTACTS_TODAY"_q) {
if (_dismissedSuggestions.contains(key)) {
return false;
} else {
const auto known
= _session->data().knownBirthdaysToday();
if (!known) {
return true;
}
return !known->empty();
}
}
return !_dismissedSuggestions.contains(key)
&& ranges::contains(_pendingSuggestions, key);
}
rpl::producer<> PromoSuggestions::requested(const QString &key) const {
return value() | rpl::filter([=] { return current(key); });
}
void PromoSuggestions::dismiss(const QString &key) {
if (!_dismissedSuggestions.emplace(key).second) {
return;
}
_session->api().request(MTPhelp_DismissSuggestion(
MTP_inputPeerEmpty(),
MTP_string(key)
)).send();
}
} // namespace Data

View file

@ -0,0 +1,61 @@
/*
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 "base/timer.h"
class History;
namespace Main {
class Session;
} // namespace Main
namespace Data {
class PromoSuggestions final {
public:
explicit PromoSuggestions(not_null<Main::Session*> session);
~PromoSuggestions();
[[nodiscard]] bool current(const QString &key) const;
[[nodiscard]] rpl::producer<> requested(
const QString &key) const;
void dismiss(const QString &key);
void refreshTopPromotion();
rpl::producer<> value() const;
// Create rpl::producer<> refreshed() const; on memand.
private:
void setTopPromoted(
History *promoted,
const QString &type,
const QString &message);
void getTopPromotionDelayed(TimeId now, TimeId next);
void topPromotionDone(const MTPhelp_PromoData &proxy);
const not_null<Main::Session*> _session;
base::flat_set<QString> _dismissedSuggestions;
std::vector<QString> _pendingSuggestions;
History *_topPromoted = nullptr;
mtpRequestId _topPromotionRequestId = 0;
std::pair<QString, uint32> _topPromotionKey;
TimeId _topPromotionNextRequestTime = TimeId(0);
base::Timer _topPromotionTimer;
rpl::event_stream<> _refreshed;
rpl::lifetime _lifetime;
};
} // namespace Data

View file

@ -4807,36 +4807,6 @@ MessageIdsList Session::takeMimeForwardIds() {
return std::move(_mimeForwardIds); return std::move(_mimeForwardIds);
} }
void Session::setTopPromoted(
History *promoted,
const QString &type,
const QString &message) {
const auto changed = (_topPromoted != promoted);
if (!changed
&& (!promoted || promoted->topPromotionMessage() == message)) {
return;
}
if (changed) {
if (_topPromoted) {
_topPromoted->cacheTopPromotion(false, QString(), QString());
}
}
const auto old = std::exchange(_topPromoted, promoted);
if (_topPromoted) {
histories().requestDialogEntry(_topPromoted);
_topPromoted->cacheTopPromotion(true, type, message);
_topPromoted->requestChatListMessage();
session().changes().historyUpdated(
_topPromoted,
HistoryUpdate::Flag::TopPromoted);
}
if (changed && old) {
session().changes().historyUpdated(
old,
HistoryUpdate::Flag::TopPromoted);
}
}
bool Session::updateWallpapers(const MTPaccount_WallPapers &data) { bool Session::updateWallpapers(const MTPaccount_WallPapers &data) {
return data.match([&](const MTPDaccount_wallPapers &data) { return data.match([&](const MTPDaccount_wallPapers &data) {
setWallpapers(data.vwallpapers().v, data.vhash().v); setWallpapers(data.vwallpapers().v, data.vhash().v);

View file

@ -801,11 +801,6 @@ public:
void setMimeForwardIds(MessageIdsList &&list); void setMimeForwardIds(MessageIdsList &&list);
MessageIdsList takeMimeForwardIds(); MessageIdsList takeMimeForwardIds();
void setTopPromoted(
History *promoted,
const QString &type,
const QString &message);
bool updateWallpapers(const MTPaccount_WallPapers &data); bool updateWallpapers(const MTPaccount_WallPapers &data);
void removeWallpaper(const WallPaper &paper); void removeWallpaper(const WallPaper &paper);
const std::vector<WallPaper> &wallpapers() const; const std::vector<WallPaper> &wallpapers() const;
@ -1129,8 +1124,6 @@ private:
ReactionId, ReactionId,
base::flat_set<not_null<ViewElement*>>> _viewsByTag; base::flat_set<not_null<ViewElement*>>> _viewsByTag;
History *_topPromoted = nullptr;
std::unordered_map<PeerId, std::unique_ptr<PeerData>> _peers; std::unordered_map<PeerId, std::unique_ptr<PeerData>> _peers;
MessageIdsList _mimeForwardIds; MessageIdsList _mimeForwardIds;

View file

@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_group_call_bar.h" #include "history/view/history_view_group_call_bar.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_app_config.h" #include "data/components/promo_suggestions.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "settings/settings_credits_graphics.h" #include "settings/settings_credits_graphics.h"
#include "settings/settings_premium.h" #include "settings/settings_premium.h"
@ -120,9 +120,9 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
const auto content = state->content; const auto content = state->content;
const auto wrap = state->wrap; const auto wrap = state->wrap;
using RightIcon = TopBarSuggestionContent::RightIcon; using RightIcon = TopBarSuggestionContent::RightIcon;
const auto config = &session->appConfig(); const auto promo = &session->promoSuggestions();
if (session->premiumCanBuy() if (session->premiumCanBuy()
&& config->suggestionCurrent(kSugPremiumGrace.utf8())) { && promo->current(kSugPremiumGrace.utf8())) {
content->setRightIcon(RightIcon::Close); content->setRightIcon(RightIcon::Close);
content->setClickedCallback([=] { content->setClickedCallback([=] {
const auto controller = FindSessionController(parent); const auto controller = FindSessionController(parent);
@ -133,7 +133,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
})); }));
}); });
content->setHideCallback([=] { content->setHideCallback([=] {
config->dismissSuggestion(kSugPremiumGrace.utf8()); promo->dismiss(kSugPremiumGrace.utf8());
repeat(repeat); repeat(repeat);
}); });
content->setContent( content->setContent(
@ -147,7 +147,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
Toggle{ true, anim::type::normal }); Toggle{ true, anim::type::normal });
return; return;
} else if (session->premiumCanBuy() } else if (session->premiumCanBuy()
&& config->suggestionCurrent(kSugLowCreditsSubs.utf8())) { && promo->current(kSugLowCreditsSubs.utf8())) {
state->creditsHistory = std::make_unique<Api::CreditsHistory>( state->creditsHistory = std::make_unique<Api::CreditsHistory>(
session->user(), session->user(),
false, false,
@ -165,13 +165,12 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
needed, needed,
Settings::SmallBalanceSubscription{ peers }, Settings::SmallBalanceSubscription{ peers },
[=] { [=] {
config->dismissSuggestion( promo->dismiss(kSugLowCreditsSubs.utf8());
kSugLowCreditsSubs.utf8());
repeat(repeat); repeat(repeat);
})); }));
}); });
content->setHideCallback([=] { content->setHideCallback([=] {
config->dismissSuggestion(kSugLowCreditsSubs.utf8()); promo->dismiss(kSugLowCreditsSubs.utf8());
repeat(repeat); repeat(repeat);
}); });
content->setContent( content->setContent(
@ -219,7 +218,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
return; return;
} else if (session->premiumCanBuy() } else if (session->premiumCanBuy()
&& config->suggestionCurrent(kSugBirthdayContacts.utf8())) { && promo->current(kSugBirthdayContacts.utf8())) {
session->data().contactBirthdays( session->data().contactBirthdays(
) | rpl::start_with_next(crl::guard(content, [=] { ) | rpl::start_with_next(crl::guard(content, [=] {
const auto users = session->data() const auto users = session->data()
@ -242,8 +241,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
} }
}); });
content->setHideCallback([=] { content->setHideCallback([=] {
config->dismissSuggestion( promo->dismiss(kSugBirthdayContacts.utf8());
kSugBirthdayContacts.utf8());
controller->showToast( controller->showToast(
tr::lng_dialogs_suggestions_birthday_contact_dismiss( tr::lng_dialogs_suggestions_birthday_contact_dismiss(
tr::now)); tr::now));
@ -351,7 +349,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
Toggle{ true, anim::type::normal }); Toggle{ true, anim::type::normal });
}), state->giftsLifetime); }), state->giftsLifetime);
return; return;
} else if (config->suggestionCurrent(kSugSetBirthday.utf8()) } else if (promo->current(kSugSetBirthday.utf8())
&& !Data::IsBirthdayToday(session->user()->birthday())) { && !Data::IsBirthdayToday(session->user()->birthday())) {
content->setRightIcon(RightIcon::Close); content->setRightIcon(RightIcon::Close);
content->setClickedCallback([=] { content->setClickedCallback([=] {
@ -373,7 +371,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
}); });
}); });
content->setHideCallback([=] { content->setHideCallback([=] {
config->dismissSuggestion(kSugSetBirthday.utf8()); promo->dismiss(kSugSetBirthday.utf8());
repeat(repeat); repeat(repeat);
}); });
content->setContent( content->setContent(
@ -387,13 +385,13 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
Toggle{ true, anim::type::normal }); Toggle{ true, anim::type::normal });
return; return;
} else if (session->premiumPossible() && !session->premium()) { } else if (session->premiumPossible() && !session->premium()) {
const auto isPremiumAnnual = config->suggestionCurrent( const auto isPremiumAnnual = promo->current(
kSugPremiumAnnual.utf8()); kSugPremiumAnnual.utf8());
const auto isPremiumRestore = !isPremiumAnnual const auto isPremiumRestore = !isPremiumAnnual
&& config->suggestionCurrent(kSugPremiumRestore.utf8()); && promo->current(kSugPremiumRestore.utf8());
const auto isPremiumUpgrade = !isPremiumAnnual const auto isPremiumUpgrade = !isPremiumAnnual
&& !isPremiumRestore && !isPremiumRestore
&& config->suggestionCurrent(kSugPremiumUpgrade.utf8()); && promo->current(kSugPremiumUpgrade.utf8());
const auto set = [=](QString discount) { const auto set = [=](QString discount) {
constexpr auto kMinus = QChar(0x2212); constexpr auto kMinus = QChar(0x2212);
const auto &title = isPremiumAnnual const auto &title = isPremiumAnnual
@ -416,7 +414,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
content->setClickedCallback([=] { content->setClickedCallback([=] {
const auto controller = FindSessionController(parent); const auto controller = FindSessionController(parent);
Settings::ShowPremium(controller, "dialogs_hint"); Settings::ShowPremium(controller, "dialogs_hint");
config->dismissSuggestion(isPremiumAnnual promo->dismiss(isPremiumAnnual
? kSugPremiumAnnual.utf8() ? kSugPremiumAnnual.utf8()
: isPremiumRestore : isPremiumRestore
? kSugPremiumRestore.utf8() ? kSugPremiumRestore.utf8()
@ -442,7 +440,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
return; return;
} }
} }
if (config->suggestionCurrent(kSugSetUserpic.utf8()) if (promo->current(kSugSetUserpic.utf8())
&& !session->user()->userpicPhotoId()) { && !session->user()->userpicPhotoId()) {
const auto controller = FindSessionController(parent); const auto controller = FindSessionController(parent);
content->setRightIcon(RightIcon::Close); content->setRightIcon(RightIcon::Close);
@ -484,7 +482,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
}); });
content->setHideCallback([=] { content->setHideCallback([=] {
config->dismissSuggestion(kSugSetUserpic.utf8()); promo->dismiss(kSugSetUserpic.utf8());
repeat(repeat); repeat(repeat);
}); });
@ -541,7 +539,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
(was == now) ? toggle.type : anim::type::instant); (was == now) ? toggle.type : anim::type::instant);
}, lifetime); }, lifetime);
session->appConfig().value() | rpl::start_with_next([=] { session->promoSuggestions().value() | rpl::start_with_next([=] {
const auto was = state->wrap; const auto was = state->wrap;
processCurrentSuggestion(processCurrentSuggestion); processCurrentSuggestion(processCurrentSuggestion);
if (was != state->wrap) { if (was != state->wrap) {

View file

@ -170,15 +170,6 @@ void AppConfig::refresh(bool force) {
} }
updateIgnoredRestrictionReasons(std::move(was)); updateIgnoredRestrictionReasons(std::move(was));
{
const auto dismissedSuggestions = get<std::vector<QString>>(
u"dismissed_suggestions"_q,
std::vector<QString>());
for (const auto &suggestion : dismissedSuggestions) {
_dismissedSuggestions.emplace(suggestion);
}
}
DEBUG_LOG(("getAppConfig result handled.")); DEBUG_LOG(("getAppConfig result handled."));
_refreshed.fire({}); _refreshed.fire({});
}, [](const MTPDhelp_appConfigNotModified &) {}); }, [](const MTPDhelp_appConfigNotModified &) {});
@ -331,47 +322,6 @@ std::vector<int> AppConfig::getIntArray(
}); });
} }
bool AppConfig::suggestionCurrent(const QString &key) const {
if (key == u"BIRTHDAY_CONTACTS_TODAY"_q) {
if (_dismissedSuggestions.contains(key)
|| !_account->sessionExists()) {
return false;
} else {
const auto known
= _account->session().data().knownBirthdaysToday();
if (!known) {
return true;
}
return !known->empty();
}
}
return !_dismissedSuggestions.contains(key)
&& ranges::contains(
get<std::vector<QString>>(
u"pending_suggestions"_q,
std::vector<QString>()),
key);
}
rpl::producer<> AppConfig::suggestionRequested(const QString &key) const {
return value(
) | rpl::filter([=] {
return suggestionCurrent(key);
});
}
void AppConfig::dismissSuggestion(const QString &key) {
Expects(_api.has_value());
if (!_dismissedSuggestions.emplace(key).second) {
return;
}
_api->request(MTPhelp_DismissSuggestion(
MTP_inputPeerEmpty(),
MTP_string(key)
)).send();
}
bool AppConfig::newRequirePremiumFree() const { bool AppConfig::newRequirePremiumFree() const {
return get<bool>( return get<bool>(
u"new_noncontact_peers_require_premium_without_ownpremium"_q, u"new_noncontact_peers_require_premium_without_ownpremium"_q,

View file

@ -48,11 +48,6 @@ public:
[[nodiscard]] rpl::producer<> refreshed() const; [[nodiscard]] rpl::producer<> refreshed() const;
[[nodiscard]] rpl::producer<> value() const; [[nodiscard]] rpl::producer<> value() const;
[[nodiscard]] bool suggestionCurrent(const QString &key) const;
[[nodiscard]] rpl::producer<> suggestionRequested(
const QString &key) const;
void dismissSuggestion(const QString &key);
[[nodiscard]] bool newRequirePremiumFree() const; [[nodiscard]] bool newRequirePremiumFree() const;
[[nodiscard]] auto ignoredRestrictionReasons() const [[nodiscard]] auto ignoredRestrictionReasons() const
@ -125,7 +120,6 @@ private:
bool _pendingRefresh = false; bool _pendingRefresh = false;
base::flat_map<QString, MTPJSONValue> _data; base::flat_map<QString, MTPJSONValue> _data;
rpl::event_stream<> _refreshed; rpl::event_stream<> _refreshed;
base::flat_set<QString> _dismissedSuggestions;
std::vector<QString> _ignoreRestrictionReasons; std::vector<QString> _ignoreRestrictionReasons;
rpl::event_stream<std::vector<QString>> _ignoreRestrictionChanges; rpl::event_stream<std::vector<QString>> _ignoreRestrictionChanges;

View file

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/components/credits.h" #include "data/components/credits.h"
#include "data/components/factchecks.h" #include "data/components/factchecks.h"
#include "data/components/location_pickers.h" #include "data/components/location_pickers.h"
#include "data/components/promo_suggestions.h"
#include "data/components/recent_peers.h" #include "data/components/recent_peers.h"
#include "data/components/scheduled_messages.h" #include "data/components/scheduled_messages.h"
#include "data/components/sponsored_messages.h" #include "data/components/sponsored_messages.h"
@ -117,6 +118,7 @@ Session::Session(
, _factchecks(std::make_unique<Data::Factchecks>(this)) , _factchecks(std::make_unique<Data::Factchecks>(this))
, _locationPickers(std::make_unique<Data::LocationPickers>()) , _locationPickers(std::make_unique<Data::LocationPickers>())
, _credits(std::make_unique<Data::Credits>(this)) , _credits(std::make_unique<Data::Credits>(this))
, _promoSuggestions(std::make_unique<Data::PromoSuggestions>(this))
, _cachedReactionIconFactory(std::make_unique<ReactionIconFactory>()) , _cachedReactionIconFactory(std::make_unique<ReactionIconFactory>())
, _supportHelper(Support::Helper::Create(this)) , _supportHelper(Support::Helper::Create(this))
, _fastButtonsBots(std::make_unique<Support::FastButtonsBots>(this)) , _fastButtonsBots(std::make_unique<Support::FastButtonsBots>(this))

View file

@ -39,6 +39,7 @@ class TopPeers;
class Factchecks; class Factchecks;
class LocationPickers; class LocationPickers;
class Credits; class Credits;
class PromoSuggestions;
} // namespace Data } // namespace Data
namespace HistoryView::Reactions { namespace HistoryView::Reactions {
@ -189,6 +190,9 @@ public:
[[nodiscard]] InlineBots::AttachWebView &attachWebView() const { [[nodiscard]] InlineBots::AttachWebView &attachWebView() const {
return *_attachWebView; return *_attachWebView;
} }
[[nodiscard]] Data::PromoSuggestions &promoSuggestions() const {
return *_promoSuggestions;
}
[[nodiscard]] auto cachedReactionIconFactory() const [[nodiscard]] auto cachedReactionIconFactory() const
-> HistoryView::Reactions::CachedIconFactory & { -> HistoryView::Reactions::CachedIconFactory & {
return *_cachedReactionIconFactory; return *_cachedReactionIconFactory;
@ -290,6 +294,7 @@ private:
const std::unique_ptr<Data::Factchecks> _factchecks; const std::unique_ptr<Data::Factchecks> _factchecks;
const std::unique_ptr<Data::LocationPickers> _locationPickers; const std::unique_ptr<Data::LocationPickers> _locationPickers;
const std::unique_ptr<Data::Credits> _credits; const std::unique_ptr<Data::Credits> _credits;
const std::unique_ptr<Data::PromoSuggestions> _promoSuggestions;
using ReactionIconFactory = HistoryView::Reactions::CachedIconFactory; using ReactionIconFactory = HistoryView::Reactions::CachedIconFactory;
const std::unique_ptr<ReactionIconFactory> _cachedReactionIconFactory; const std::unique_ptr<ReactionIconFactory> _cachedReactionIconFactory;