diff --git a/Telegram/SourceFiles/api/api_sensitive_content.cpp b/Telegram/SourceFiles/api/api_sensitive_content.cpp index 0a5c4f739c..7ff3dd6103 100644 --- a/Telegram/SourceFiles/api/api_sensitive_content.cpp +++ b/Telegram/SourceFiles/api/api_sensitive_content.cpp @@ -8,11 +8,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_sensitive_content.h" #include "apiwrap.h" +#include "main/main_session.h" +#include "main/main_account.h" +#include "main/main_app_config.h" namespace Api { +namespace { + +constexpr auto kRefreshAppConfigTimeout = 3 * crl::time(1000); + +} // namespace SensitiveContent::SensitiveContent(not_null api) -: _api(api->instance()) { +: _session(&api->session()) +, _api(api->instance()) +, _appConfigReloadTimer([=] { _session->account().appConfig().refresh(); }) { } void SensitiveContent::reload() { @@ -57,6 +67,8 @@ void SensitiveContent::update(bool enabled) { _requestId = 0; }).send(); _enabled = enabled; + + _appConfigReloadTimer.callOnce(kRefreshAppConfigTimeout); } } // namespace Api diff --git a/Telegram/SourceFiles/api/api_sensitive_content.h b/Telegram/SourceFiles/api/api_sensitive_content.h index 7c9e9d85c5..0a61f9da73 100644 --- a/Telegram/SourceFiles/api/api_sensitive_content.h +++ b/Telegram/SourceFiles/api/api_sensitive_content.h @@ -8,9 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "mtproto/sender.h" +#include "base/timer.h" class ApiWrap; +namespace Main { +class Session; +} // namespace Main + namespace Api { class SensitiveContent final { @@ -25,10 +30,12 @@ public: [[nodiscard]] rpl::producer canChange() const; private: + const not_null _session; MTP::Sender _api; mtpRequestId _requestId = 0; rpl::variable _enabled = false; rpl::variable _canChange = false; + base::Timer _appConfigReloadTimer; }; diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 2435a16312..a7eefdbd35 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -339,13 +339,14 @@ bool ChannelData::isGroupAdmin(not_null user) const { return false; } -QString ChannelData::unavailableReason() const { - return _unavailableReason; +auto ChannelData::unavailableReasons() const +-> const std::vector & { + return _unavailableReasons; } -void ChannelData::setUnavailableReason(const QString &text) { - if (_unavailableReason != text) { - _unavailableReason = text; +void ChannelData::setUnavailableReasons(std::vector &&reasons) { + if (_unavailableReasons != reasons) { + _unavailableReasons = std::move(reasons); Notify::peerUpdatedDelayed( this, Notify::PeerUpdate::Flag::UnavailableReasonChanged); diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index df8adf4e79..df583c2862 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -368,8 +368,8 @@ public: return _ptsWaiter.waitingForShortPoll(); } - [[nodiscard]] QString unavailableReason() const override; - void setUnavailableReason(const QString &reason); + void setUnavailableReasons( + std::vector &&reason); [[nodiscard]] MsgId availableMinId() const { return _availableMinId; @@ -412,6 +412,8 @@ public: TimeId inviteDate = 0; private: + auto unavailableReasons() const + -> const std::vector & override; bool canEditLastAdmin(not_null user) const; Flags _flags = Flags(MTPDchannel_ClientFlag::f_forbidden | 0); @@ -431,7 +433,7 @@ private: RestrictionFlags _restrictions; TimeId _restrictedUntil; - QString _unavailableReason; + std::vector _unavailableReasons; QString _inviteLink; ChannelData *_linkedChat = nullptr; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index cfb91084e1..9431b625d0 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "boxes/confirm_box.h" #include "main/main_session.h" +#include "main/main_account.h" +#include "main/main_app_config.h" #include "core/application.h" #include "mainwindow.h" #include "window/window_session_controller.h" @@ -376,6 +378,27 @@ void PeerData::setUserpicChecked( } } +auto PeerData::unavailableReasons() const +-> const std::vector & { + static const auto result = std::vector(); + return result; +} + +QString PeerData::computeUnavailableReason() const { + const auto &list = unavailableReasons(); + const auto &config = session().account().appConfig(); + const auto skip = config.get>( + "ignore_restriction_reasons", + std::vector()); + auto &&filtered = ranges::view::all( + list + ) | ranges::view::filter([&](const Data::UnavailableReason &reason) { + return ranges::find(skip, reason.reason) == end(skip); + }); + const auto first = filtered.begin(); + return (first != filtered.end()) ? first->text : QString(); +} + bool PeerData::canPinMessages() const { if (const auto user = asUser()) { return user->fullFlags() & MTPDuserFull::Flag::f_can_pin_message; diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 9d5716bb16..fcb82c2c47 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -84,6 +84,18 @@ private: }; +struct UnavailableReason { + QString reason; + QString text; + + bool operator==(const UnavailableReason &other) const { + return (reason == other.reason) && (text == other.text); + } + bool operator!=(const UnavailableReason &other) const { + return !(*this == other); + } +}; + } // namespace Data class PeerClickHandler : public ClickHandler { @@ -271,9 +283,7 @@ public: // If this string is not empty we must not allow to open the // conversation and we must show this string instead. - [[nodiscard]] virtual QString unavailableReason() const { - return QString(); - } + [[nodiscard]] QString computeUnavailableReason() const; [[nodiscard]] ClickHandlerPtr createOpenLink(); [[nodiscard]] const ClickHandlerPtr &openLink() { @@ -346,6 +356,8 @@ private: void fillNames(); std::unique_ptr createEmptyUserpic() const; void refreshEmptyUserpic() const; + [[nodiscard]] virtual auto unavailableReasons() const + -> const std::vector &; void setUserpicChecked( PhotoId photoId, diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 5409793315..e794f48fa3 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -101,30 +101,26 @@ void CheckForSwitchInlineButton(not_null item) { // We should get a full restriction in "{full}: {reason}" format and we // need to find an "-all" tag in {full}, otherwise ignore this restriction. -QString ExtractUnavailableReason( +std::vector ExtractUnavailableReasons( const QVector &restrictions) { - auto &&texts = ranges::view::all( + return ranges::view::all( restrictions - ) | ranges::view::transform([](const MTPRestrictionReason &restriction) { + ) | ranges::view::filter([](const MTPRestrictionReason &restriction) { return restriction.match([&](const MTPDrestrictionReason &data) { const auto platform = qs(data.vplatform()); - return (false + return false #ifdef OS_MAC_STORE || (platform == qstr("ios")) #elif defined OS_WIN_STORE // OS_MAC_STORE || (platform == qstr("ms")) #endif // OS_MAC_STORE || OS_WIN_STORE - || (platform == qstr("all"))) - ? std::make_optional(qs(data.vtext())) - : std::nullopt; + || (platform == qstr("all")); }); - }) | ranges::view::filter([](const std::optional &value) { - return value.has_value(); - }) | ranges::view::transform([](const std::optional &value) { - return *value; - }); - const auto begin = texts.begin(); - return (begin != texts.end()) ? *begin : nullptr; + }) | ranges::view::transform([](const MTPRestrictionReason &restriction) { + return restriction.match([&](const MTPDrestrictionReason &data) { + return UnavailableReason{ qs(data.vreason()), qs(data.vtext()) }; + }); + }) | ranges::to_vector; } MTPPhotoSize FindDocumentInlineThumbnail(const MTPDdocument &data) { @@ -365,10 +361,10 @@ not_null Session::processUser(const MTPUser &data) { result->inputUser = MTP_inputUser(data.vid(), MTP_long(result->accessHash())); } if (const auto restriction = data.vrestriction_reason()) { - result->setUnavailableReason( - ExtractUnavailableReason(restriction->v)); + result->setUnavailableReasons( + ExtractUnavailableReasons(restriction->v)); } else { - result->setUnavailableReason(QString()); + result->setUnavailableReasons({}); } } if (data.is_deleted()) { @@ -636,10 +632,10 @@ not_null Session::processChat(const MTPChat &data) { channel->setVersion(data.vversion().v); } if (const auto restriction = data.vrestriction_reason()) { - channel->setUnavailableReason( - ExtractUnavailableReason(restriction->v)); + channel->setUnavailableReasons( + ExtractUnavailableReasons(restriction->v)); } else { - channel->setUnavailableReason(QString()); + channel->setUnavailableReasons({}); } channel->setFlags(data.vflags().v); //if (const auto feedId = data.vfeed_id()) { // #feed diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index d861551b59..fbb4e78f24 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -81,13 +81,15 @@ void UserData::setPhoto(const MTPUserProfilePhoto &photo) { } } -QString UserData::unavailableReason() const { - return _unavailableReason; +auto UserData::unavailableReasons() const +-> const std::vector & { + return _unavailableReasons; } -void UserData::setUnavailableReason(const QString &text) { - if (_unavailableReason != text) { - _unavailableReason = text; +void UserData::setUnavailableReasons( + std::vector &&reasons) { + if (_unavailableReasons != reasons) { + _unavailableReasons = std::move(reasons); Notify::peerUpdatedDelayed( this, Notify::PeerUpdate::Flag::UnavailableReasonChanged); diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 5a6df93d1f..d583652846 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -207,8 +207,8 @@ public: std::unique_ptr botInfo; - QString unavailableReason() const override; - void setUnavailableReason(const QString &reason); + void setUnavailableReasons( + std::vector &&reasons); int commonChatsCount() const { return _commonChatsCount; @@ -216,10 +216,13 @@ public: void setCommonChatsCount(int count); private: + auto unavailableReasons() const + -> const std::vector & override; + Flags _flags; FullFlags _fullFlags; - QString _unavailableReason; + std::vector _unavailableReasons; QString _phone; ContactStatus _contactStatus = ContactStatus::Unknown; BlockStatus _blockStatus = BlockStatus::Unknown; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 4996804fa0..12e7d64627 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -562,7 +562,7 @@ HistoryWidget::HistoryWidget( updateNotifyControls(); } if (update.flags & UpdateFlag::UnavailableReasonChanged) { - const auto unavailable = _peer->unavailableReason(); + const auto unavailable = _peer->computeUnavailableReason(); if (!unavailable.isEmpty()) { controller->showBackFromStack(); Ui::show(Box(unavailable)); diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index bf88207252..0f09e2ea05 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -41,6 +41,7 @@ void AppConfig::refresh() { _requestId = 0; refreshDelayed(); if (result.type() == mtpc_jsonObject) { + _data.clear(); for (const auto &element : result.c_jsonObject().vvalue().v) { element.match([&](const MTPDjsonObjectValue &data) { _data.emplace_or_assign(qs(data.vkey()), data.vvalue()); @@ -94,4 +95,23 @@ QString AppConfig::getString( }); } +std::vector AppConfig::getStringArray( + const QString &key, + std::vector &&fallback) const { + return getValue(key, [&](const MTPJSONValue &value) { + return value.match([&](const MTPDjsonArray &data) { + auto result = std::vector(); + for (const auto &entry : data.vvalue().v) { + if (entry.type() != mtpc_jsonString) { + return std::move(fallback); + } + result.push_back(qs(entry.c_jsonString().vvalue())); + } + return result; + }, [&](const auto &data) { + return std::move(fallback); + }); + }); +} + } // namespace Main diff --git a/Telegram/SourceFiles/main/main_app_config.h b/Telegram/SourceFiles/main/main_app_config.h index 3eb8b43156..54afb170e9 100644 --- a/Telegram/SourceFiles/main/main_app_config.h +++ b/Telegram/SourceFiles/main/main_app_config.h @@ -23,13 +23,16 @@ public: return getDouble(key, fallback); } else if constexpr (std::is_same_v) { return getString(key, fallback); + } else if constexpr (std::is_same_v>) { + return getStringArray(key, std::move(fallback)); } } [[nodiscard]] rpl::producer<> refreshed() const; -private: void refresh(); + +private: void refreshDelayed(); template @@ -43,6 +46,9 @@ private: [[nodiscard]] QString getString( const QString &key, const QString &fallback) const; + [[nodiscard]] std::vector getStringArray( + const QString &key, + std::vector &&fallback) const; const not_null _account; std::optional _api; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 3209c76ee0..7222f06c7d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1593,7 +1593,7 @@ void MainWidget::ui_showPeerHistory( peerId = peer->id; if (showAtMsgId > 0) showAtMsgId = -showAtMsgId; } - const auto unavailable = peer->unavailableReason(); + const auto unavailable = peer->computeUnavailableReason(); if (!unavailable.isEmpty()) { if (params.activation != anim::activation::background) { Ui::show(Box(unavailable));