Provide unavailable reasons for messages.

This commit is contained in:
John Preston 2024-08-12 12:37:42 +02:00
parent 155f4ea252
commit 83f4c53766
8 changed files with 113 additions and 50 deletions

View file

@ -82,6 +82,50 @@ UnavailableReason UnavailableReason::Sensitive() {
return { u"sensitive"_q }; return { u"sensitive"_q };
} }
QString UnavailableReason::Compute(
not_null<Main::Session*> session,
const std::vector<UnavailableReason> &list) {
const auto &config = session->appConfig();
const auto skip = config.get<std::vector<QString>>(
"ignore_restriction_reasons",
std::vector<QString>());
auto &&filtered = ranges::views::all(
list
) | ranges::views::filter([&](const Data::UnavailableReason &reason) {
return !reason.sensitive()
&& !ranges::contains(skip, reason.reason);
});
const auto first = filtered.begin();
return (first != filtered.end()) ? first->text : QString();
}
// We should get a full restriction in "{full}: {reason}" format and we
// need to find an "-all" tag in {full}, otherwise ignore this restriction.
std::vector<UnavailableReason> UnavailableReason::Extract(
const MTPvector<MTPRestrictionReason> *list) {
if (!list) {
return {};
}
return ranges::views::all(
list->v
) | ranges::views::filter([](const MTPRestrictionReason &restriction) {
return restriction.match([&](const MTPDrestrictionReason &data) {
const auto platform = data.vplatform().v;
return false
#ifdef OS_MAC_STORE
|| (platform == "ios"_q)
#elif defined OS_WIN_STORE // OS_MAC_STORE
|| (platform == "ms"_q)
#endif // OS_MAC_STORE || OS_WIN_STORE
|| (platform == "all"_q);
});
}) | ranges::views::transform([](const MTPRestrictionReason &restriction) {
return restriction.match([&](const MTPDrestrictionReason &data) {
return UnavailableReason{ qs(data.vreason()), qs(data.vtext()) };
});
}) | ranges::to_vector;
}
bool ApplyBotMenuButton( bool ApplyBotMenuButton(
not_null<BotInfo*> info, not_null<BotInfo*> info,
const MTPBotMenuButton *button) { const MTPBotMenuButton *button) {
@ -505,19 +549,9 @@ auto PeerData::unavailableReasons() const
} }
QString PeerData::computeUnavailableReason() const { QString PeerData::computeUnavailableReason() const {
const auto &list = unavailableReasons(); return Data::UnavailableReason::Compute(
const auto &config = session().appConfig(); &session(),
const auto skip = config.get<std::vector<QString>>( unavailableReasons());
"ignore_restriction_reasons",
std::vector<QString>());
auto &&filtered = ranges::views::all(
list
) | ranges::views::filter([&](const Data::UnavailableReason &reason) {
return !reason.sensitive()
&& !ranges::contains(skip, reason.reason);
});
const auto first = filtered.begin();
return (first != filtered.end()) ? first->text : QString();
} }
bool PeerData::isUnavailableSensitive() const { bool PeerData::isUnavailableSensitive() const {

View file

@ -95,6 +95,13 @@ struct UnavailableReason {
[[nodiscard]] bool sensitive() const; [[nodiscard]] bool sensitive() const;
[[nodiscard]] static UnavailableReason Sensitive(); [[nodiscard]] static UnavailableReason Sensitive();
[[nodiscard]] static QString Compute(
not_null<Main::Session*> session,
const std::vector<UnavailableReason> &list);
[[nodiscard]] static std::vector<UnavailableReason> Extract(
const MTPvector<MTPRestrictionReason> *list);
}; };
bool ApplyBotMenuButton( bool ApplyBotMenuButton(

View file

@ -252,7 +252,8 @@ Image *PhotoData::getReplyPreview(
Image *PhotoData::getReplyPreview(not_null<HistoryItem*> item) { Image *PhotoData::getReplyPreview(not_null<HistoryItem*> item) {
const auto media = item->media(); const auto media = item->media();
const auto spoiler = media && media->hasSpoiler(); const auto spoiler = (media && media->hasSpoiler())
|| item->hasSensitiveSpoiler();
return getReplyPreview(item->fullId(), item->history()->peer, spoiler); return getReplyPreview(item->fullId(), item->history()->peer, spoiler);
} }

View file

@ -126,30 +126,6 @@ void CheckForSwitchInlineButton(not_null<HistoryItem*> 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.
std::vector<UnavailableReason> ExtractUnavailableReasons(
const QVector<MTPRestrictionReason> &restrictions) {
return ranges::views::all(
restrictions
) | ranges::views::filter([](const MTPRestrictionReason &restriction) {
return restriction.match([&](const auto &data) {
const auto platform = qs(data.vplatform());
return false
#ifdef OS_MAC_STORE
|| (platform == u"ios"_q)
#elif defined OS_WIN_STORE // OS_MAC_STORE
|| (platform == u"ms"_q)
#endif // OS_MAC_STORE || OS_WIN_STORE
|| (platform == u"all"_q);
});
}) | ranges::views::transform([](const MTPRestrictionReason &restriction) {
return restriction.match([&](const MTPDrestrictionReason &data) {
return UnavailableReason{ qs(data.vreason()), qs(data.vtext()) };
});
}) | ranges::to_vector;
}
[[nodiscard]] InlineImageLocation FindInlineThumbnail( [[nodiscard]] InlineImageLocation FindInlineThumbnail(
const QVector<MTPPhotoSize> &sizes) { const QVector<MTPPhotoSize> &sizes) {
const auto i = ranges::find( const auto i = ranges::find(
@ -606,12 +582,8 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
result->input = MTP_inputPeerUser(data.vid(), MTP_long(result->accessHash())); result->input = MTP_inputPeerUser(data.vid(), MTP_long(result->accessHash()));
result->inputUser = MTP_inputUser(data.vid(), MTP_long(result->accessHash())); result->inputUser = MTP_inputUser(data.vid(), MTP_long(result->accessHash()));
} }
if (const auto restriction = data.vrestriction_reason()) { result->setUnavailableReasons(Data::UnavailableReason::Extract(
result->setUnavailableReasons( data.vrestriction_reason()));
ExtractUnavailableReasons(restriction->v));
} else {
result->setUnavailableReasons({});
}
} }
if (data.is_deleted()) { if (data.is_deleted()) {
if (!result->phone().isEmpty()) { if (!result->phone().isEmpty()) {
@ -915,12 +887,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
channel->setAccessHash( channel->setAccessHash(
data.vaccess_hash().value_or(channel->access)); data.vaccess_hash().value_or(channel->access));
channel->date = data.vdate().v; channel->date = data.vdate().v;
if (const auto restriction = data.vrestriction_reason()) { channel->setUnavailableReasons(Data::UnavailableReason::Extract(
channel->setUnavailableReasons( data.vrestriction_reason()));
ExtractUnavailableReasons(restriction->v));
} else {
channel->setUnavailableReasons({});
}
} }
{ {

View file

@ -323,6 +323,9 @@ enum class MessageFlag : uint64 {
ShortcutMessage = (1ULL << 44), ShortcutMessage = (1ULL << 44),
EffectWatched = (1ULL << 45), EffectWatched = (1ULL << 45),
SensitiveContent = (1ULL << 46),
AllowSensitive = (1ULL << 47),
}; };
inline constexpr bool is_flag_type(MessageFlag) { return true; } inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags<MessageFlag>; using MessageFlags = base::flags<MessageFlag>;

View file

@ -190,6 +190,8 @@ struct HistoryItem::CreateConfig {
// For messages created from existing messages (forwarded). // For messages created from existing messages (forwarded).
const HistoryMessageReplyMarkup *inlineMarkup = nullptr; const HistoryMessageReplyMarkup *inlineMarkup = nullptr;
std::vector<Data::UnavailableReason> restrictions;
}; };
void HistoryItem::FillForwardedInfo( void HistoryItem::FillForwardedInfo(
@ -3279,6 +3281,24 @@ EffectId HistoryItem::effectId() const {
return _effectId; return _effectId;
} }
QString HistoryItem::computeUnavailableReason() const {
if (const auto restrictions = Get<HistoryMessageRestrictions>()) {
return Data::UnavailableReason::Compute(
&history()->session(),
restrictions->reasons);
}
return QString();
}
bool HistoryItem::hasSensitiveSpoiler() const {
return (_flags & MessageFlag::SensitiveContent)
&& !(_flags & MessageFlag::AllowSensitive);
}
void HistoryItem::allowSensitive() {
_flags |= MessageFlag::AllowSensitive;
}
bool HistoryItem::isEmpty() const { bool HistoryItem::isEmpty() const {
return _text.empty() return _text.empty()
&& !_media && !_media
@ -3487,6 +3507,12 @@ void HistoryItem::createComponents(CreateConfig &&config) {
if (_history->peer->isSelf()) { if (_history->peer->isSelf()) {
mask |= HistoryMessageSaved::Bit(); mask |= HistoryMessageSaved::Bit();
} }
if (!config.restrictions.empty()) {
if (config.restrictions.size() > 1
|| !config.restrictions.front().sensitive()) {
mask |= HistoryMessageRestrictions::Bit();
}
}
UpdateComponents(mask); UpdateComponents(mask);
@ -3559,6 +3585,19 @@ void HistoryItem::createComponents(CreateConfig &&config) {
} else { } else {
_flags &= ~MessageFlag::HasReplyMarkup; _flags &= ~MessageFlag::HasReplyMarkup;
} }
if (const auto restrictions = Get<HistoryMessageRestrictions>()) {
restrictions->reasons = std::move(config.restrictions);
const auto i = ranges::find(
restrictions->reasons,
true,
&Data::UnavailableReason::sensitive);
if (i != end(restrictions->reasons)) {
restrictions->reasons.erase(i);
_flags |= MessageFlag::SensitiveContent;
}
} else if (!config.restrictions.empty()) {
_flags |= MessageFlag::SensitiveContent;
}
if (out() && isSending()) { if (out() && isSending()) {
if (const auto channel = _history->peer->asMegagroup()) { if (const auto channel = _history->peer->asMegagroup()) {
@ -3874,6 +3913,8 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
config.markup = HistoryMessageMarkupData(data.vreply_markup()); config.markup = HistoryMessageMarkupData(data.vreply_markup());
config.editDate = data.vedit_date().value_or_empty(); config.editDate = data.vedit_date().value_or_empty();
config.postAuthor = qs(data.vpost_author().value_or_empty()); config.postAuthor = qs(data.vpost_author().value_or_empty());
config.restrictions = Data::UnavailableReason::Extract(
data.vrestriction_reason());
createComponents(std::move(config)); createComponents(std::move(config));
} }

View file

@ -516,6 +516,9 @@ public:
[[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEmpty() const;
[[nodiscard]] MessageGroupId groupId() const; [[nodiscard]] MessageGroupId groupId() const;
[[nodiscard]] EffectId effectId() const; [[nodiscard]] EffectId effectId() const;
[[nodiscard]] QString computeUnavailableReason() const;
[[nodiscard]] bool hasSensitiveSpoiler() const;
void allowSensitive();
[[nodiscard]] const HistoryMessageReplyMarkup *inlineReplyMarkup() const { [[nodiscard]] const HistoryMessageReplyMarkup *inlineReplyMarkup() const {
return const_cast<HistoryItem*>(this)->inlineReplyMarkup(); return const_cast<HistoryItem*>(this)->inlineReplyMarkup();

View file

@ -33,6 +33,7 @@ namespace Data {
class Session; class Session;
class Story; class Story;
class SavedSublist; class SavedSublist;
struct UnavailableReason;
} // namespace Data } // namespace Data
namespace Media::Player { namespace Media::Player {
@ -596,6 +597,11 @@ struct HistoryMessageFactcheck
bool requested = false; bool requested = false;
}; };
struct HistoryMessageRestrictions
: public RuntimeComponent<HistoryMessageRestrictions, HistoryItem> {
std::vector<Data::UnavailableReason> reasons;
};
struct HistoryServiceData struct HistoryServiceData
: public RuntimeComponent<HistoryServiceData, HistoryItem> { : public RuntimeComponent<HistoryServiceData, HistoryItem> {
std::vector<ClickHandlerPtr> textLinks; std::vector<ClickHandlerPtr> textLinks;