Edit additional privacy options for gifts.

This commit is contained in:
John Preston 2025-03-17 10:44:08 +04:00
parent fbab3964e6
commit b656e14453
6 changed files with 268 additions and 13 deletions

View file

@ -1195,6 +1195,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_quick_dialog_action_delete" = "Delete";
"lng_settings_quick_dialog_action_disabled" = "Change folder";
"lng_settings_generic_subscribe" = "Subscribe to {link} to use this setting.";
"lng_settings_generic_subscribe_link" = "Telegram Premium";
"lng_sessions_header" = "This device";
"lng_sessions_other_header" = "Active Devices";
"lng_sessions_other_desc" = "You can log in to Telegram from other mobile, tablet and desktop devices, using the same phone number. All your data will be instantly synchronized.";
@ -1310,6 +1313,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_privacy_gifts_always_title" = "Always allow";
"lng_edit_privacy_gifts_never_title" = "Never allow";
"lng_edit_privacy_gifts_types" = "Accepted Gift Types";
"lng_edit_privacy_gifts_premium" = "Premium Subscriptions";
"lng_edit_privacy_gifts_unlimited" = "Unlimited";
"lng_edit_privacy_gifts_limited" = "Limited-Edition";
"lng_edit_privacy_gifts_unique" = "Unique";
"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_calls_title" = "Calls";
"lng_edit_privacy_calls_header" = "Who can call me";
"lng_edit_privacy_calls_always_empty" = "Always allow";

View file

@ -115,7 +115,9 @@ void GlobalPrivacy::updateHideReadTime(bool hide) {
unarchiveOnNewMessageCurrent(),
hide,
newRequirePremiumCurrent(),
newChargeStarsCurrent());
newChargeStarsCurrent(),
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
bool GlobalPrivacy::hideReadTimeCurrent() const {
@ -150,7 +152,39 @@ void GlobalPrivacy::updateMessagesPrivacy(
unarchiveOnNewMessageCurrent(),
hideReadTimeCurrent(),
requirePremium,
chargeStars);
chargeStars,
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
bool GlobalPrivacy::showGiftIconCurrent() const {
return _showGiftIcon.current();
}
rpl::producer<bool> GlobalPrivacy::showGiftIcon() const {
return _showGiftIcon.value();
}
DisallowedGiftTypes GlobalPrivacy::disallowedGiftTypesCurrent() const {
return _disallowedGiftTypes.current();
}
auto GlobalPrivacy::disallowedGiftTypes() const
-> rpl::producer<DisallowedGiftTypes> {
return _disallowedGiftTypes.value();
}
void GlobalPrivacy::updateAdditionalGiftPrivacy(
DisallowedGiftTypes types,
bool showGiftIcon) {
update(
archiveAndMuteCurrent(),
unarchiveOnNewMessageCurrent(),
hideReadTimeCurrent(),
newRequirePremiumCurrent(),
newChargeStarsCurrent(),
showGiftIcon,
types);
}
void GlobalPrivacy::loadPaidReactionShownPeer() {
@ -182,7 +216,9 @@ void GlobalPrivacy::updateArchiveAndMute(bool value) {
unarchiveOnNewMessageCurrent(),
hideReadTimeCurrent(),
newRequirePremiumCurrent(),
newChargeStarsCurrent());
newChargeStarsCurrent(),
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
void GlobalPrivacy::updateUnarchiveOnNewMessage(
@ -192,7 +228,9 @@ void GlobalPrivacy::updateUnarchiveOnNewMessage(
value,
hideReadTimeCurrent(),
newRequirePremiumCurrent(),
newChargeStarsCurrent());
newChargeStarsCurrent(),
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
void GlobalPrivacy::update(
@ -200,8 +238,11 @@ void GlobalPrivacy::update(
UnarchiveOnNewMessage unarchiveOnNewMessage,
bool hideReadTime,
bool newRequirePremium,
int newChargeStars) {
int newChargeStars,
bool showGiftIcon,
DisallowedGiftTypes disallowedGiftTypes) {
using Flag = MTPDglobalPrivacySettings::Flag;
using DisallowedFlag = MTPDdisallowedStarGiftsSettings::Flag;
_api.request(_requestId).cancel();
const auto newRequirePremiumAllowed = _session->premium()
@ -220,12 +261,27 @@ void GlobalPrivacy::update(
| ((newRequirePremium && newRequirePremiumAllowed)
? Flag::f_new_noncontact_peers_require_premium
: Flag())
| Flag::f_noncontact_peers_paid_stars;
| Flag::f_noncontact_peers_paid_stars
| (showGiftIcon ? Flag::f_display_gifts_button : Flag())
| Flag::f_disallowed_stargifts;
const auto disallowedFlags = DisallowedFlag()
| ((disallowedGiftTypes & DisallowedGiftType::Premium)
? DisallowedFlag() AssertIsDebug()
: DisallowedFlag())
| ((disallowedGiftTypes & DisallowedGiftType::Unlimited)
? DisallowedFlag::f_disallow_unlimited_stargifts
: DisallowedFlag())
| ((disallowedGiftTypes & DisallowedGiftType::Limited)
? DisallowedFlag::f_disallow_limited_stargifts
: DisallowedFlag())
| ((disallowedGiftTypes & DisallowedGiftType::Unique)
? DisallowedFlag::f_disallow_unique_stargifts
: DisallowedFlag());
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
MTP_globalPrivacySettings(
MTP_flags(flags),
MTP_long(newChargeStars),
MTPDisallowedStarGiftsSettings())
MTP_disallowedStarGiftsSettings(MTP_flags(disallowedFlags)))
)).done([=](const MTPGlobalPrivacySettings &result) {
_requestId = 0;
apply(result);
@ -237,7 +293,9 @@ void GlobalPrivacy::update(
unarchiveOnNewMessage,
hideReadTime,
false,
0);
0,
false,
DisallowedGiftTypes());
}
}).send();
_archiveAndMute = archiveAndMute;
@ -245,6 +303,8 @@ void GlobalPrivacy::update(
_hideReadTime = hideReadTime;
_newRequirePremium = newRequirePremium;
_newChargeStars = newChargeStars;
_disallowedGiftTypes = disallowedGiftTypes;
_showGiftIcon = showGiftIcon;
}
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &settings) {
@ -258,6 +318,22 @@ void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &settings) {
_hideReadTime = data.is_hide_read_marks();
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
_newChargeStars = data.vnoncontact_peers_paid_stars().value_or_empty();
_showGiftIcon = data.is_display_gifts_button();
if (const auto gifts = data.vdisallowed_stargifts()) {
const auto &data = gifts->data();
_disallowedGiftTypes = DisallowedGiftType()
| (data.is_disallow_unlimited_stargifts()
? DisallowedGiftType::Unlimited
: DisallowedGiftType())
| (data.is_disallow_limited_stargifts()
? DisallowedGiftType::Limited
: DisallowedGiftType())
| (data.is_disallow_unique_stargifts()
? DisallowedGiftType::Unique
: DisallowedGiftType());
} else {
_disallowedGiftTypes = DisallowedGiftTypes();
}
}
} // namespace Api

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/flags.h"
#include "mtproto/sender.h"
class ApiWrap;
@ -23,6 +24,16 @@ enum class UnarchiveOnNewMessage {
AnyUnmuted,
};
enum class DisallowedGiftType {
Premium = 0x01,
Unlimited = 0x02,
Limited = 0x04,
Unique = 0x08,
};
inline constexpr bool is_flag_type(DisallowedGiftType) { return true; }
using DisallowedGiftTypes = base::flags<DisallowedGiftType>;
[[nodiscard]] PeerId ParsePaidReactionShownPeer(
not_null<Main::Session*> session,
const MTPPaidReactionPrivacy &value);
@ -57,6 +68,15 @@ public:
void updateMessagesPrivacy(bool requirePremium, int chargeStars);
[[nodiscard]] bool showGiftIconCurrent() const;
[[nodiscard]] rpl::producer<bool> showGiftIcon() const;
[[nodiscard]] DisallowedGiftTypes disallowedGiftTypesCurrent() const;
[[nodiscard]] auto disallowedGiftTypes() const
-> rpl::producer<DisallowedGiftTypes>;
void updateAdditionalGiftPrivacy(
DisallowedGiftTypes types,
bool showGiftIcon);
void loadPaidReactionShownPeer();
void updatePaidReactionShownPeer(PeerId shownPeer);
[[nodiscard]] PeerId paidReactionShownPeerCurrent() const;
@ -70,7 +90,9 @@ private:
UnarchiveOnNewMessage unarchiveOnNewMessage,
bool hideReadTime,
bool newRequirePremium,
int newChargeStars);
int newChargeStars,
bool showGiftIcon,
DisallowedGiftTypes disallowedGiftTypes);
const not_null<Main::Session*> _session;
MTP::Sender _api;
@ -82,6 +104,8 @@ private:
rpl::variable<bool> _hideReadTime = false;
rpl::variable<bool> _newRequirePremium = false;
rpl::variable<int> _newChargeStars = 0;
rpl::variable<bool> _showGiftIcon = false;
rpl::variable<DisallowedGiftTypes> _disallowedGiftTypes;
rpl::variable<PeerId> _paidReactionShownPeer = false;
std::vector<Fn<void()>> _callbacks;
bool _paidReactionShownPeerLoaded = false;

View file

@ -684,3 +684,8 @@ settingsChatLinkField: InputField(defaultInputField) {
}
settingsQuickDialogActionsTriggerFont: font(11px);
settingsGiftIconEmoji: IconEmoji {
icon: icon{{ "menu/gift_premium", windowFg }};
padding: margins(0px, 1px, 0px, 0px);
}

View file

@ -616,8 +616,8 @@ object_ptr<Ui::RpWidget> PhoneNumberPrivacyController::setupMiddleWidget(
}
void PhoneNumberPrivacyController::saveAdditional() {
if (_saveAdditional) {
_saveAdditional();
if (const auto onstack = _saveAdditional) {
onstack();
}
}
@ -1296,8 +1296,8 @@ object_ptr<Ui::RpWidget> ProfilePhotoPrivacyController::setupMiddleWidget(
}
void ProfilePhotoPrivacyController::saveAdditional() {
if (_saveAdditional) {
_saveAdditional();
if (const auto onstack = _saveAdditional) {
onstack();
}
}
@ -1626,4 +1626,132 @@ bool GiftsAutoSavePrivacyController::allowMiniAppsToggle(
return true;
}
object_ptr<Ui::RpWidget> GiftsAutoSavePrivacyController::setupBelowWidget(
not_null<Window::SessionController*> controller,
not_null<QWidget*> parent,
rpl::producer<Option> option) {
auto result = object_ptr<Ui::VerticalLayout>(parent);
const auto content = result.data();
const auto session = &controller->session();
auto premium = Data::AmPremiumValue(session);
const auto globalPrivacy = &session->api().globalPrivacy();
struct State {
Api::DisallowedGiftTypes disallowed;
bool showGiftIcon = false;
rpl::event_stream<> disables;
Fn<void()> promo;
};
const auto state = content->lifetime().make_state<State>();
state->disallowed = globalPrivacy->disallowedGiftTypesCurrent();
state->showGiftIcon = globalPrivacy->showGiftIconCurrent();
state->promo = [=] {
state->disables.fire({});
const auto link = Ui::Text::Bold(
tr::lng_settings_generic_subscribe_link(tr::now));
Settings::ShowPremiumPromoToast(
controller->uiShow(),
tr::lng_settings_generic_subscribe(
tr::now,
lt_link,
Ui::Text::Link(link),
Ui::Text::WithEntities),
u"gifts_privacy"_q);
};
Ui::AddSkip(content, st::settingsPeerToPeerSkip);
Ui::AddSubsectionTitle(
content,
tr::lng_edit_privacy_gifts_types());
using Type = Api::DisallowedGiftType;
const auto types = base::flat_map<Type, rpl::producer<QString>>{
{ Type::Premium, tr::lng_edit_privacy_gifts_premium() },
{ Type::Unlimited, tr::lng_edit_privacy_gifts_unlimited() },
{ Type::Limited, tr::lng_edit_privacy_gifts_limited() },
{ Type::Unique, tr::lng_edit_privacy_gifts_unique() },
};
for (const auto &[type, title] : types) {
const auto button = content->add(object_ptr<Ui::SettingsButton>(
content,
rpl::duplicate(title),
st::settingsButtonNoIconLocked));
button->toggleOn(rpl::single(
!session->premium() || !(state->disallowed & type)
) | rpl::then(state->disables.events() | rpl::map([=] {
return true;
})));
rpl::duplicate(premium) | rpl::start_with_next([=](bool value) {
button->setToggleLocked(!value);
}, button->lifetime());
button->toggledValue() | rpl::start_with_next([=](bool enable) {
if (enable) {
state->disallowed &= ~type;
} else if (!session->premium()) {
state->promo();
} else {
state->disallowed |= type;
}
}, button->lifetime());
}
Ui::AddSkip(content);
Ui::AddDividerText(content, tr::lng_edit_privacy_gifts_types_about());
Ui::AddSkip(content);
const auto icon = content->add(object_ptr<Ui::SettingsButton>(
content,
tr::lng_edit_privacy_gifts_show_icon(),
st::settingsButtonNoIconLocked));
icon->toggleOn(rpl::single(
session->premium() && state->showGiftIcon
) | rpl::then(state->disables.events() | rpl::map([=] {
return false;
})));
rpl::duplicate(premium) | rpl::start_with_next([=](bool value) {
icon->setToggleLocked(!value);
if (!value) {
state->disables.fire({});
}
}, icon->lifetime());
icon->toggledValue() | rpl::start_with_next([=](bool enable) {
if (!enable) {
state->showGiftIcon = false;
} else if (!session->premium()) {
state->promo();
} else {
state->showGiftIcon = true;
}
}, icon->lifetime());
Ui::AddSkip(content);
Ui::AddDividerText(
content,
tr::lng_edit_privacy_gifts_show_icon_about(
lt_emoji,
rpl::single(Ui::Text::IconEmoji(&st::settingsGiftIconEmoji)),
Ui::Text::WithEntities));
_saveAdditional = [=] {
const auto disallowed = state->disallowed;
const auto showGiftIcon = state->showGiftIcon;
if (!session->premium()) {
return;
} else if (globalPrivacy->showGiftIconCurrent() == showGiftIcon
&& globalPrivacy->disallowedGiftTypesCurrent() == disallowed) {
return;
} else {
globalPrivacy->updateAdditionalGiftPrivacy(
disallowed,
showGiftIcon);
}
};
return result;
}
void GiftsAutoSavePrivacyController::saveAdditional() {
if (const auto onstack = _saveAdditional) {
onstack();
}
}
} // namespace Settings

View file

@ -356,6 +356,16 @@ public:
rpl::producer<QString> exceptionsDescription() const override;
bool allowMiniAppsToggle(Exception exception) const override;
object_ptr<Ui::RpWidget> setupBelowWidget(
not_null<Window::SessionController*> controller,
not_null<QWidget*> parent,
rpl::producer<Option> option) override;
void saveAdditional() override;
private:
Fn<void()> _saveAdditional;
};
} // namespace Settings