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 };
}
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(
not_null<BotInfo*> info,
const MTPBotMenuButton *button) {
@ -505,19 +549,9 @@ auto PeerData::unavailableReasons() const
}
QString PeerData::computeUnavailableReason() const {
const auto &list = unavailableReasons();
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();
return Data::UnavailableReason::Compute(
&session(),
unavailableReasons());
}
bool PeerData::isUnavailableSensitive() const {

View file

@ -95,6 +95,13 @@ struct UnavailableReason {
[[nodiscard]] bool sensitive() const;
[[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(

View file

@ -252,7 +252,8 @@ Image *PhotoData::getReplyPreview(
Image *PhotoData::getReplyPreview(not_null<HistoryItem*> item) {
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);
}

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(
const QVector<MTPPhotoSize> &sizes) {
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->inputUser = MTP_inputUser(data.vid(), MTP_long(result->accessHash()));
}
if (const auto restriction = data.vrestriction_reason()) {
result->setUnavailableReasons(
ExtractUnavailableReasons(restriction->v));
} else {
result->setUnavailableReasons({});
}
result->setUnavailableReasons(Data::UnavailableReason::Extract(
data.vrestriction_reason()));
}
if (data.is_deleted()) {
if (!result->phone().isEmpty()) {
@ -915,12 +887,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
channel->setAccessHash(
data.vaccess_hash().value_or(channel->access));
channel->date = data.vdate().v;
if (const auto restriction = data.vrestriction_reason()) {
channel->setUnavailableReasons(
ExtractUnavailableReasons(restriction->v));
} else {
channel->setUnavailableReasons({});
}
channel->setUnavailableReasons(Data::UnavailableReason::Extract(
data.vrestriction_reason()));
}
{

View file

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

View file

@ -190,6 +190,8 @@ struct HistoryItem::CreateConfig {
// For messages created from existing messages (forwarded).
const HistoryMessageReplyMarkup *inlineMarkup = nullptr;
std::vector<Data::UnavailableReason> restrictions;
};
void HistoryItem::FillForwardedInfo(
@ -3279,6 +3281,24 @@ EffectId HistoryItem::effectId() const {
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 {
return _text.empty()
&& !_media
@ -3487,6 +3507,12 @@ void HistoryItem::createComponents(CreateConfig &&config) {
if (_history->peer->isSelf()) {
mask |= HistoryMessageSaved::Bit();
}
if (!config.restrictions.empty()) {
if (config.restrictions.size() > 1
|| !config.restrictions.front().sensitive()) {
mask |= HistoryMessageRestrictions::Bit();
}
}
UpdateComponents(mask);
@ -3559,6 +3585,19 @@ void HistoryItem::createComponents(CreateConfig &&config) {
} else {
_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 (const auto channel = _history->peer->asMegagroup()) {
@ -3874,6 +3913,8 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
config.markup = HistoryMessageMarkupData(data.vreply_markup());
config.editDate = data.vedit_date().value_or_empty();
config.postAuthor = qs(data.vpost_author().value_or_empty());
config.restrictions = Data::UnavailableReason::Extract(
data.vrestriction_reason());
createComponents(std::move(config));
}

View file

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

View file

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