Filter out allowed gift types.

This commit is contained in:
John Preston 2025-03-17 13:27:24 +04:00
parent b656e14453
commit c0fed4d2c3
5 changed files with 141 additions and 40 deletions

View file

@ -1321,6 +1321,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_privacy_gifts_types_about" = "Choose the types of gifts that you accept.";
"lng_edit_privacy_gifts_show_icon" = "Show Gift Icon in Chats";
"lng_edit_privacy_gifts_show_icon_about" = "Display the {emoji}Gift icon in the message input field for both participants in all chats.";
"lng_edit_privacy_gifts_restricted" = "This user doesn't accept gifts.";
"lng_edit_privacy_calls_title" = "Calls";
"lng_edit_privacy_calls_header" = "Who can call me";

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "api/api_credits.h"
#include "api/api_global_privacy.h"
#include "api/api_premium.h"
#include "base/event_filter.h"
#include "base/random.h"
@ -686,6 +687,24 @@ void PreviewWrap::paintEvent(QPaintEvent *e) {
};
}
[[nodiscard]] bool AllowedToSend(
const GiftTypeStars &gift,
not_null<PeerData*> peer) {
using Type = Api::DisallowedGiftType;
const auto user = peer->asUser();
if (!user || user->isSelf()) {
return true;
}
const auto disallowedTypes = user ? user->disallowedGiftTypes() : Type();
const auto allowLimited = !(disallowedTypes & Type::Limited);
const auto allowUnlimited = !(disallowedTypes & Type::Unlimited);
const auto allowUnique = !(disallowedTypes & Type::Unique);
if (!gift.info.limitedCount) {
return allowUnlimited;
}
return allowLimited || (gift.info.starsToUpgrade && allowUnique);
}
[[nodiscard]] rpl::producer<std::vector<GiftTypeStars>> GiftsStars(
not_null<Main::Session*> session,
not_null<PeerData*> peer) {
@ -694,6 +713,12 @@ void PreviewWrap::paintEvent(QPaintEvent *e) {
};
static auto Map = base::flat_map<not_null<Main::Session*>, Session>();
const auto filtered = [=](std::vector<GiftTypeStars> list) {
list.erase(ranges::remove_if(list, [&](const GiftTypeStars &gift) {
return !AllowedToSend(gift, peer);
}), end(list));
return list;
};
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
@ -703,7 +728,7 @@ void PreviewWrap::paintEvent(QPaintEvent *e) {
session->lifetime().add([=] { Map.remove(session); });
}
if (!i->second.last.empty()) {
consumer.put_next_copy(i->second.last);
consumer.put_next(filtered(i->second.last));
}
using namespace Api;
@ -725,7 +750,7 @@ void PreviewWrap::paintEvent(QPaintEvent *e) {
auto &map = Map[session];
if (map.last != list) {
map.last = list;
consumer.put_next_copy(list);
consumer.put_next(filtered(std::move(list)));
}
}, lifetime);
@ -1897,6 +1922,7 @@ void AddBlock(
? IsSoldOut(gift.info)
: (price && gift.info.stars != price);
}), end(gifts));
return GiftsDescriptor{
gifts | ranges::to<std::vector<GiftDescriptor>>(),
};
@ -1924,6 +1950,24 @@ void GiftBox(
AddSkip(content, st::defaultVerticalListSkip * 5);
// Check disallowed gift types
const auto user = peer->asUser();
using Type = Api::DisallowedGiftType;
const auto disallowedTypes = user
? user->disallowedGiftTypes()
: Type::Premium;
const auto premiumDisallowed = peer->isSelf()
|| (disallowedTypes & Type::Premium);
const auto limitedDisallowed = !peer->isSelf()
&& (disallowedTypes & Type::Limited);
const auto unlimitedDisallowed = !peer->isSelf()
&& (disallowedTypes & Type::Unlimited);
const auto uniqueDisallowed = !peer->isSelf()
&& (disallowedTypes & Type::Unique);
const auto allStarsDisallowed = limitedDisallowed
&& unlimitedDisallowed
&& uniqueDisallowed;
content->add(
object_ptr<CenterWrap<>>(
content,
@ -1945,11 +1989,12 @@ void GiftBox(
window->showSettings(Settings::CreditsId());
return false;
};
if (peer->isUser() && !peer->isSelf()) {
if (peer->isUser() && !peer->isSelf() && !premiumDisallowed) {
const auto premiumClickHandlerFilter = [=](const auto &...) {
Settings::ShowPremium(window, u"gift_send"_q);
return false;
};
AddBlock(content, window, {
.subtitle = tr::lng_gift_premium_subtitle(),
.about = tr::lng_gift_premium_about(
@ -1962,28 +2007,32 @@ void GiftBox(
.content = MakePremiumGifts(window, peer),
});
}
AddBlock(content, window, {
.subtitle = (peer->isSelf()
? tr::lng_gift_self_title()
: peer->isBroadcast()
? tr::lng_gift_channel_title()
: tr::lng_gift_stars_subtitle()),
.about = (peer->isSelf()
? tr::lng_gift_self_about(Text::WithEntities)
: peer->isBroadcast()
? tr::lng_gift_channel_about(
lt_name,
rpl::single(Text::Bold(peer->name())),
Text::WithEntities)
: tr::lng_gift_stars_about(
lt_name,
rpl::single(Text::Bold(peer->shortName())),
lt_link,
tr::lng_gift_stars_link() | Text::ToLink(),
Text::WithEntities)),
.aboutFilter = starsClickHandlerFilter,
.content = MakeStarsGifts(window, peer),
});
// Only add star gifts if at least one type is allowed
if (!allStarsDisallowed) {
AddBlock(content, window, {
.subtitle = (peer->isSelf()
? tr::lng_gift_self_title()
: peer->isBroadcast()
? tr::lng_gift_channel_title()
: tr::lng_gift_stars_subtitle()),
.about = (peer->isSelf()
? tr::lng_gift_self_about(Text::WithEntities)
: peer->isBroadcast()
? tr::lng_gift_channel_about(
lt_name,
rpl::single(Text::Bold(peer->name())),
Text::WithEntities)
: tr::lng_gift_stars_about(
lt_name,
rpl::single(Text::Bold(peer->shortName())),
lt_link,
tr::lng_gift_stars_link() | Text::ToLink(),
Text::WithEntities)),
.aboutFilter = starsClickHandlerFilter,
.content = MakeStarsGifts(window, peer),
});
}
}
struct SelfOption {
@ -2195,6 +2244,19 @@ void ShowStarGiftBox(
const auto show = [=] {
Map[session] = Session();
if (const auto strong = weak.get()) {
if (const auto user = peer->asUser()) {
using Type = Api::DisallowedGiftType;
const auto disallowedTypes = user->disallowedGiftTypes();
const auto premium = (disallowedTypes & Type::Premium)
|| peer->isSelf();
const auto limited = (disallowedTypes & Type::Limited);
const auto unlimited = (disallowedTypes & Type::Unlimited);
const auto unique = (disallowedTypes & Type::Unique);
if (premium && limited && unlimited && unique) {
strong->showToast(tr::lng_edit_privacy_gifts_restricted(tr::now));
return;
}
}
strong->show(Box(GiftBox, strong, peer));
}
};

View file

@ -96,27 +96,28 @@ struct PeerUpdate {
PersonalChannel = (1ULL << 34),
StarRefProgram = (1ULL << 35),
PaysPerMessage = (1ULL << 36),
GiftSettings = (1ULL << 37),
// For chats and channels
InviteLinks = (1ULL << 37),
Members = (1ULL << 38),
Admins = (1ULL << 39),
BannedUsers = (1ULL << 40),
Rights = (1ULL << 41),
PendingRequests = (1ULL << 42),
Reactions = (1ULL << 43),
InviteLinks = (1ULL << 38),
Members = (1ULL << 39),
Admins = (1ULL << 40),
BannedUsers = (1ULL << 41),
Rights = (1ULL << 42),
PendingRequests = (1ULL << 43),
Reactions = (1ULL << 44),
// For channels
ChannelAmIn = (1ULL << 44),
StickersSet = (1ULL << 45),
EmojiSet = (1ULL << 46),
ChannelLinkedChat = (1ULL << 47),
ChannelLocation = (1ULL << 48),
Slowmode = (1ULL << 49),
GroupCall = (1ULL << 50),
ChannelAmIn = (1ULL << 45),
StickersSet = (1ULL << 46),
EmojiSet = (1ULL << 47),
ChannelLinkedChat = (1ULL << 48),
ChannelLocation = (1ULL << 49),
Slowmode = (1ULL << 50),
GroupCall = (1ULL << 51),
// For iteration
LastUsedBit = (1ULL << 50),
LastUsedBit = (1ULL << 51),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "api/api_credits.h"
#include "api/api_global_privacy.h"
#include "api/api_sensitive_content.h"
#include "api/api_statistics.h"
#include "storage/localstorage.h"
@ -659,6 +660,13 @@ bool UserData::hasCalls() const {
&& (callsStatus() != CallsStatus::Unknown);
}
void UserData::setDisallowedGiftTypes(Api::DisallowedGiftTypes types) {
if (_disallowedGiftTypes != types) {
_disallowedGiftTypes = types;
session().changes().peerUpdated(this, UpdateFlag::GiftSettings);
}
}
namespace Data {
void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
@ -815,6 +823,22 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
user->setBotVerifyDetails(
ParseBotVerifyDetails(update.vbot_verification()));
if (const auto gifts = update.vdisallowed_stargifts()) {
const auto &data = gifts->data();
user->setDisallowedGiftTypes(Api::DisallowedGiftType()
| ((data.is_disallow_unlimited_stargifts()
? Api::DisallowedGiftType::Unlimited
: Api::DisallowedGiftType()))
| ((data.is_disallow_limited_stargifts()
? Api::DisallowedGiftType::Limited
: Api::DisallowedGiftType()))
| ((data.is_disallow_unique_stargifts()
? Api::DisallowedGiftType::Unique
: Api::DisallowedGiftType())));
} else {
user->setDisallowedGiftTypes(Api::DisallowedGiftTypes());
}
user->owner().stories().apply(user, update.vstories());
user->fullUpdated();

View file

@ -15,12 +15,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_lastseen_status.h"
#include "data/data_user_names.h"
#include "dialogs/dialogs_key.h"
#include "base/flags.h"
namespace Data {
struct BotCommand;
struct BusinessDetails;
} // namespace Data
namespace Api {
enum class DisallowedGiftType;
using DisallowedGiftTypes = base::flags<DisallowedGiftType>;
} // namespace Api
struct StarRefProgram {
StarsAmount revenuePerUser;
TimeId endDate = 0;
@ -262,6 +268,11 @@ public:
std::unique_ptr<BotInfo> botInfo;
[[nodiscard]] Api::DisallowedGiftTypes disallowedGiftTypes() const {
return _disallowedGiftTypes;
}
void setDisallowedGiftTypes(Api::DisallowedGiftTypes types);
private:
auto unavailableReasons() const
-> const std::vector<Data::UnavailableReason> & override;
@ -293,6 +304,8 @@ private:
static constexpr auto kInaccessibleAccessHashOld
= 0xFFFFFFFFFFFFFFFFULL;
Api::DisallowedGiftTypes _disallowedGiftTypes;
};
namespace Data {