diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 420d761e8b..eb2bf8bec3 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -501,6 +501,8 @@ PRIVATE data/components/factchecks.h data/components/location_pickers.cpp data/components/location_pickers.h + data/components/promo_suggestions.cpp + data/components/promo_suggestions.h data/components/recent_peers.cpp data/components/recent_peers.h data/components/scheduled_messages.cpp diff --git a/Telegram/SourceFiles/api/api_global_privacy.cpp b/Telegram/SourceFiles/api/api_global_privacy.cpp index 2a2def3c5a..0beb421833 100644 --- a/Telegram/SourceFiles/api/api_global_privacy.cpp +++ b/Telegram/SourceFiles/api/api_global_privacy.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_global_privacy.h" #include "apiwrap.h" +#include "data/components/promo_suggestions.h" #include "data/data_user.h" #include "main/main_session.h" #include "main/main_app_config.h" @@ -101,13 +102,11 @@ rpl::producer GlobalPrivacy::showArchiveAndMute() const { } rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const { - return _session->appConfig().suggestionRequested( - u"AUTOARCHIVE_POPULAR"_q); + return _session->promoSuggestions().requested(u"AUTOARCHIVE_POPULAR"_q); } void GlobalPrivacy::dismissArchiveAndMuteSuggestion() { - _session->appConfig().dismissSuggestion( - u"AUTOARCHIVE_POPULAR"_q); + _session->promoSuggestions().dismiss(u"AUTOARCHIVE_POPULAR"_q); } void GlobalPrivacy::updateHideReadTime(bool hide) { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index f79c7e455d..749c3722f9 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -91,8 +91,6 @@ namespace { // Save draft to the cloud with 1 sec extra delay. constexpr auto kSaveCloudDraftTimeout = 1000; -constexpr auto kTopPromotionInterval = TimeId(60 * 60); -constexpr auto kTopPromotionMinDelay = TimeId(10); constexpr auto kSmallDelayMs = 5; constexpr auto kReadFeaturedSetsTimeout = crl::time(1000); constexpr auto kFileLoaderQueueStopTimeout = crl::time(5000); @@ -163,7 +161,6 @@ ApiWrap::ApiWrap(not_null session) , _featuredSetsReadTimer([=] { readFeaturedSets(); }) , _dialogsLoadState(std::make_unique()) , _fileLoader(std::make_unique(kFileLoaderQueueStopTimeout)) -, _topPromotionTimer([=] { refreshTopPromotion(); }) , _updateNotifyTimer([=] { sendNotifySettingsUpdates(); }) , _statsSessionKillTimer([=] { checkStatsSessions(); }) , _authorizations(std::make_unique(this)) @@ -199,11 +196,6 @@ ApiWrap::ApiWrap(not_null session) }, _session->lifetime()); setupSupportMode(); - - Core::App().settings().proxy().connectionTypeValue( - ) | rpl::start_with_next([=] { - refreshTopPromotion(); - }, _session->lifetime()); }); } @@ -243,77 +235,6 @@ void ApiWrap::requestChangelog( //).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 { - 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( const QString &path, Fn callback) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 0817560b7f..529114b0a1 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -200,7 +200,6 @@ public: void requestChangelog( const QString &sinceVersion, Fn callback); - void refreshTopPromotion(); void requestDeepLinkInfo( const QString &path, Fn callback); @@ -569,9 +568,6 @@ private: not_null album, Fn done = nullptr); - void getTopPromotionDelayed(TimeId now, TimeId next); - void topPromotionDone(const MTPhelp_PromoData &proxy); - void sendNotifySettingsUpdates(); template @@ -709,11 +705,6 @@ private: std::unique_ptr _fileLoader; base::flat_map> _sendingAlbums; - mtpRequestId _topPromotionRequestId = 0; - std::pair _topPromotionKey; - TimeId _topPromotionNextRequestTime = TimeId(0); - base::Timer _topPromotionTimer; - base::flat_set> _updateNotifyTopics; base::flat_set> _updateNotifyPeers; base::flat_set _updateNotifyDefaults; diff --git a/Telegram/SourceFiles/data/components/promo_suggestions.cpp b/Telegram/SourceFiles/data/components/promo_suggestions.cpp new file mode 100644 index 0000000000..f6ccf5981d --- /dev/null +++ b/Telegram/SourceFiles/data/components/promo_suggestions.cpp @@ -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 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 { + 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 diff --git a/Telegram/SourceFiles/data/components/promo_suggestions.h b/Telegram/SourceFiles/data/components/promo_suggestions.h new file mode 100644 index 0000000000..b25e263b9f --- /dev/null +++ b/Telegram/SourceFiles/data/components/promo_suggestions.h @@ -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 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 _session; + base::flat_set _dismissedSuggestions; + std::vector _pendingSuggestions; + + History *_topPromoted = nullptr; + + mtpRequestId _topPromotionRequestId = 0; + std::pair _topPromotionKey; + TimeId _topPromotionNextRequestTime = TimeId(0); + base::Timer _topPromotionTimer; + + rpl::event_stream<> _refreshed; + + rpl::lifetime _lifetime; + +}; + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 039903f2a3..915ead6baf 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -4807,36 +4807,6 @@ MessageIdsList Session::takeMimeForwardIds() { 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) { return data.match([&](const MTPDaccount_wallPapers &data) { setWallpapers(data.vwallpapers().v, data.vhash().v); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 8ba4f0924b..6e94e6ed2d 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -801,11 +801,6 @@ public: void setMimeForwardIds(MessageIdsList &&list); MessageIdsList takeMimeForwardIds(); - void setTopPromoted( - History *promoted, - const QString &type, - const QString &message); - bool updateWallpapers(const MTPaccount_WallPapers &data); void removeWallpaper(const WallPaper &paper); const std::vector &wallpapers() const; @@ -1129,8 +1124,6 @@ private: ReactionId, base::flat_set>> _viewsByTag; - History *_topPromoted = nullptr; - std::unordered_map> _peers; MessageIdsList _mimeForwardIds; diff --git a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp index 3d13095640..4780dad469 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp @@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_group_call_bar.h" #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" -#include "main/main_app_config.h" +#include "data/components/promo_suggestions.h" #include "main/main_session.h" #include "settings/settings_credits_graphics.h" #include "settings/settings_premium.h" @@ -120,9 +120,9 @@ rpl::producer*> TopBarSuggestionValue( const auto content = state->content; const auto wrap = state->wrap; using RightIcon = TopBarSuggestionContent::RightIcon; - const auto config = &session->appConfig(); + const auto promo = &session->promoSuggestions(); if (session->premiumCanBuy() - && config->suggestionCurrent(kSugPremiumGrace.utf8())) { + && promo->current(kSugPremiumGrace.utf8())) { content->setRightIcon(RightIcon::Close); content->setClickedCallback([=] { const auto controller = FindSessionController(parent); @@ -133,7 +133,7 @@ rpl::producer*> TopBarSuggestionValue( })); }); content->setHideCallback([=] { - config->dismissSuggestion(kSugPremiumGrace.utf8()); + promo->dismiss(kSugPremiumGrace.utf8()); repeat(repeat); }); content->setContent( @@ -147,7 +147,7 @@ rpl::producer*> TopBarSuggestionValue( Toggle{ true, anim::type::normal }); return; } else if (session->premiumCanBuy() - && config->suggestionCurrent(kSugLowCreditsSubs.utf8())) { + && promo->current(kSugLowCreditsSubs.utf8())) { state->creditsHistory = std::make_unique( session->user(), false, @@ -165,13 +165,12 @@ rpl::producer*> TopBarSuggestionValue( needed, Settings::SmallBalanceSubscription{ peers }, [=] { - config->dismissSuggestion( - kSugLowCreditsSubs.utf8()); + promo->dismiss(kSugLowCreditsSubs.utf8()); repeat(repeat); })); }); content->setHideCallback([=] { - config->dismissSuggestion(kSugLowCreditsSubs.utf8()); + promo->dismiss(kSugLowCreditsSubs.utf8()); repeat(repeat); }); content->setContent( @@ -219,7 +218,7 @@ rpl::producer*> TopBarSuggestionValue( return; } else if (session->premiumCanBuy() - && config->suggestionCurrent(kSugBirthdayContacts.utf8())) { + && promo->current(kSugBirthdayContacts.utf8())) { session->data().contactBirthdays( ) | rpl::start_with_next(crl::guard(content, [=] { const auto users = session->data() @@ -242,8 +241,7 @@ rpl::producer*> TopBarSuggestionValue( } }); content->setHideCallback([=] { - config->dismissSuggestion( - kSugBirthdayContacts.utf8()); + promo->dismiss(kSugBirthdayContacts.utf8()); controller->showToast( tr::lng_dialogs_suggestions_birthday_contact_dismiss( tr::now)); @@ -351,7 +349,7 @@ rpl::producer*> TopBarSuggestionValue( Toggle{ true, anim::type::normal }); }), state->giftsLifetime); return; - } else if (config->suggestionCurrent(kSugSetBirthday.utf8()) + } else if (promo->current(kSugSetBirthday.utf8()) && !Data::IsBirthdayToday(session->user()->birthday())) { content->setRightIcon(RightIcon::Close); content->setClickedCallback([=] { @@ -373,7 +371,7 @@ rpl::producer*> TopBarSuggestionValue( }); }); content->setHideCallback([=] { - config->dismissSuggestion(kSugSetBirthday.utf8()); + promo->dismiss(kSugSetBirthday.utf8()); repeat(repeat); }); content->setContent( @@ -387,13 +385,13 @@ rpl::producer*> TopBarSuggestionValue( Toggle{ true, anim::type::normal }); return; } else if (session->premiumPossible() && !session->premium()) { - const auto isPremiumAnnual = config->suggestionCurrent( + const auto isPremiumAnnual = promo->current( kSugPremiumAnnual.utf8()); const auto isPremiumRestore = !isPremiumAnnual - && config->suggestionCurrent(kSugPremiumRestore.utf8()); + && promo->current(kSugPremiumRestore.utf8()); const auto isPremiumUpgrade = !isPremiumAnnual && !isPremiumRestore - && config->suggestionCurrent(kSugPremiumUpgrade.utf8()); + && promo->current(kSugPremiumUpgrade.utf8()); const auto set = [=](QString discount) { constexpr auto kMinus = QChar(0x2212); const auto &title = isPremiumAnnual @@ -416,7 +414,7 @@ rpl::producer*> TopBarSuggestionValue( content->setClickedCallback([=] { const auto controller = FindSessionController(parent); Settings::ShowPremium(controller, "dialogs_hint"); - config->dismissSuggestion(isPremiumAnnual + promo->dismiss(isPremiumAnnual ? kSugPremiumAnnual.utf8() : isPremiumRestore ? kSugPremiumRestore.utf8() @@ -442,7 +440,7 @@ rpl::producer*> TopBarSuggestionValue( return; } } - if (config->suggestionCurrent(kSugSetUserpic.utf8()) + if (promo->current(kSugSetUserpic.utf8()) && !session->user()->userpicPhotoId()) { const auto controller = FindSessionController(parent); content->setRightIcon(RightIcon::Close); @@ -484,7 +482,7 @@ rpl::producer*> TopBarSuggestionValue( }); content->setHideCallback([=] { - config->dismissSuggestion(kSugSetUserpic.utf8()); + promo->dismiss(kSugSetUserpic.utf8()); repeat(repeat); }); @@ -541,7 +539,7 @@ rpl::producer*> TopBarSuggestionValue( (was == now) ? toggle.type : anim::type::instant); }, lifetime); - session->appConfig().value() | rpl::start_with_next([=] { + session->promoSuggestions().value() | rpl::start_with_next([=] { const auto was = state->wrap; processCurrentSuggestion(processCurrentSuggestion); if (was != state->wrap) { diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index 62a2fd6b36..f5ace98778 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -170,15 +170,6 @@ void AppConfig::refresh(bool force) { } updateIgnoredRestrictionReasons(std::move(was)); - { - const auto dismissedSuggestions = get>( - u"dismissed_suggestions"_q, - std::vector()); - for (const auto &suggestion : dismissedSuggestions) { - _dismissedSuggestions.emplace(suggestion); - } - } - DEBUG_LOG(("getAppConfig result handled.")); _refreshed.fire({}); }, [](const MTPDhelp_appConfigNotModified &) {}); @@ -331,47 +322,6 @@ std::vector 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>( - u"pending_suggestions"_q, - std::vector()), - 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 { return get( u"new_noncontact_peers_require_premium_without_ownpremium"_q, diff --git a/Telegram/SourceFiles/main/main_app_config.h b/Telegram/SourceFiles/main/main_app_config.h index d536557758..dbf26522cf 100644 --- a/Telegram/SourceFiles/main/main_app_config.h +++ b/Telegram/SourceFiles/main/main_app_config.h @@ -48,11 +48,6 @@ public: [[nodiscard]] rpl::producer<> refreshed() 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]] auto ignoredRestrictionReasons() const @@ -125,7 +120,6 @@ private: bool _pendingRefresh = false; base::flat_map _data; rpl::event_stream<> _refreshed; - base::flat_set _dismissedSuggestions; std::vector _ignoreRestrictionReasons; rpl::event_stream> _ignoreRestrictionChanges; diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 77609c60ea..0df874fb2f 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/components/credits.h" #include "data/components/factchecks.h" #include "data/components/location_pickers.h" +#include "data/components/promo_suggestions.h" #include "data/components/recent_peers.h" #include "data/components/scheduled_messages.h" #include "data/components/sponsored_messages.h" @@ -117,6 +118,7 @@ Session::Session( , _factchecks(std::make_unique(this)) , _locationPickers(std::make_unique()) , _credits(std::make_unique(this)) +, _promoSuggestions(std::make_unique(this)) , _cachedReactionIconFactory(std::make_unique()) , _supportHelper(Support::Helper::Create(this)) , _fastButtonsBots(std::make_unique(this)) diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 65543d0969..6d5eaf38f7 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -39,6 +39,7 @@ class TopPeers; class Factchecks; class LocationPickers; class Credits; +class PromoSuggestions; } // namespace Data namespace HistoryView::Reactions { @@ -189,6 +190,9 @@ public: [[nodiscard]] InlineBots::AttachWebView &attachWebView() const { return *_attachWebView; } + [[nodiscard]] Data::PromoSuggestions &promoSuggestions() const { + return *_promoSuggestions; + } [[nodiscard]] auto cachedReactionIconFactory() const -> HistoryView::Reactions::CachedIconFactory & { return *_cachedReactionIconFactory; @@ -290,6 +294,7 @@ private: const std::unique_ptr _factchecks; const std::unique_ptr _locationPickers; const std::unique_ptr _credits; + const std::unique_ptr _promoSuggestions; using ReactionIconFactory = HistoryView::Reactions::CachedIconFactory; const std::unique_ptr _cachedReactionIconFactory;