Show gift button in the message field.

This commit is contained in:
John Preston 2025-03-18 13:37:12 +04:00
parent e3c3a68566
commit 7d0a73a6b0
8 changed files with 121 additions and 60 deletions

View file

@ -116,7 +116,6 @@ void GlobalPrivacy::updateHideReadTime(bool hide) {
hide,
newRequirePremiumCurrent(),
newChargeStarsCurrent(),
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
@ -153,18 +152,9 @@ void GlobalPrivacy::updateMessagesPrivacy(
hideReadTimeCurrent(),
requirePremium,
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();
}
@ -174,16 +164,13 @@ auto GlobalPrivacy::disallowedGiftTypes() const
return _disallowedGiftTypes.value();
}
void GlobalPrivacy::updateAdditionalGiftPrivacy(
DisallowedGiftTypes types,
bool showGiftIcon) {
void GlobalPrivacy::updateDisallowedGiftTypes(DisallowedGiftTypes types) {
update(
archiveAndMuteCurrent(),
unarchiveOnNewMessageCurrent(),
hideReadTimeCurrent(),
newRequirePremiumCurrent(),
newChargeStarsCurrent(),
showGiftIcon,
types);
}
@ -217,7 +204,6 @@ void GlobalPrivacy::updateArchiveAndMute(bool value) {
hideReadTimeCurrent(),
newRequirePremiumCurrent(),
newChargeStarsCurrent(),
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
@ -229,7 +215,6 @@ void GlobalPrivacy::updateUnarchiveOnNewMessage(
hideReadTimeCurrent(),
newRequirePremiumCurrent(),
newChargeStarsCurrent(),
showGiftIconCurrent(),
disallowedGiftTypesCurrent());
}
@ -239,7 +224,6 @@ void GlobalPrivacy::update(
bool hideReadTime,
bool newRequirePremium,
int newChargeStars,
bool showGiftIcon,
DisallowedGiftTypes disallowedGiftTypes) {
using Flag = MTPDglobalPrivacySettings::Flag;
using DisallowedFlag = MTPDdisallowedGiftsSettings::Flag;
@ -247,6 +231,8 @@ void GlobalPrivacy::update(
_api.request(_requestId).cancel();
const auto newRequirePremiumAllowed = _session->premium()
|| _session->appConfig().newRequirePremiumFree();
const auto showGiftIcon
= (disallowedGiftTypes & DisallowedGiftType::SendHide);
const auto flags = Flag()
| (archiveAndMute
? Flag::f_archive_and_mute_new_noncontact_peers
@ -294,7 +280,6 @@ void GlobalPrivacy::update(
hideReadTime,
false,
0,
false,
DisallowedGiftTypes());
}
}).send();
@ -304,7 +289,6 @@ void GlobalPrivacy::update(
_newRequirePremium = newRequirePremium;
_newChargeStars = newChargeStars;
_disallowedGiftTypes = disallowedGiftTypes;
_showGiftIcon = showGiftIcon;
}
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &settings) {
@ -318,24 +302,28 @@ 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_gifts()) {
const auto &data = gifts->data();
const auto &disallow = gifts->data();
_disallowedGiftTypes = DisallowedGiftType()
| (data.is_disallow_unlimited_stargifts()
| (disallow.is_disallow_unlimited_stargifts()
? DisallowedGiftType::Unlimited
: DisallowedGiftType())
| (data.is_disallow_limited_stargifts()
| (disallow.is_disallow_limited_stargifts()
? DisallowedGiftType::Limited
: DisallowedGiftType())
| (data.is_disallow_unique_stargifts()
| (disallow.is_disallow_unique_stargifts()
? DisallowedGiftType::Unique
: DisallowedGiftType())
| (data.is_disallow_premium_gifts()
| (disallow.is_disallow_premium_gifts()
? DisallowedGiftType::Premium
: DisallowedGiftType())
| (data.is_display_gifts_button()
? DisallowedGiftType::SendHide
: DisallowedGiftType());
} else {
_disallowedGiftTypes = DisallowedGiftTypes();
_disallowedGiftTypes = data.is_display_gifts_button()
? DisallowedGiftType::SendHide
: DisallowedGiftType();
}
}

View file

@ -24,11 +24,12 @@ enum class UnarchiveOnNewMessage {
AnyUnmuted,
};
enum class DisallowedGiftType {
enum class DisallowedGiftType : uchar {
Premium = 0x01,
Unlimited = 0x02,
Limited = 0x04,
Unique = 0x08,
SendHide = 0x10,
};
inline constexpr bool is_flag_type(DisallowedGiftType) { return true; }
@ -68,14 +69,10 @@ 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 updateDisallowedGiftTypes(DisallowedGiftTypes types);
void loadPaidReactionShownPeer();
void updatePaidReactionShownPeer(PeerId shownPeer);
@ -91,7 +88,6 @@ private:
bool hideReadTime,
bool newRequirePremium,
int newChargeStars,
bool showGiftIcon,
DisallowedGiftTypes disallowedGiftTypes);
const not_null<Main::Session*> _session;
@ -104,7 +100,6 @@ 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;

View file

@ -1131,6 +1131,10 @@ historyScheduledToggle: IconButton(historyAttach) {
{ "chat/input_scheduled_dot", attentionButtonFg }
};
}
historyGiftToUser: IconButton(historyAttach) {
icon: icon {{ "menu/gift_premium", historyComposeIconFg }};
iconOver: icon {{ "menu/gift_premium", historyComposeIconFgOver }};
}
historyAttachEmojiInner: IconButton(historyAttach) {
icon: icon {{ "chat/input_smile_face", historyComposeIconFg }};

View file

@ -826,20 +826,26 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
if (const auto gifts = update.vdisallowed_gifts()) {
const auto &data = gifts->data();
user->setDisallowedGiftTypes(Api::DisallowedGiftType()
| ((data.is_disallow_unlimited_stargifts()
| (data.is_disallow_unlimited_stargifts()
? Api::DisallowedGiftType::Unlimited
: Api::DisallowedGiftType()))
| ((data.is_disallow_limited_stargifts()
: Api::DisallowedGiftType())
| (data.is_disallow_limited_stargifts()
? Api::DisallowedGiftType::Limited
: Api::DisallowedGiftType()))
| ((data.is_disallow_unique_stargifts()
: Api::DisallowedGiftType())
| (data.is_disallow_unique_stargifts()
? Api::DisallowedGiftType::Unique
: Api::DisallowedGiftType()))
| ((data.is_disallow_premium_gifts()
: Api::DisallowedGiftType())
| (data.is_disallow_premium_gifts()
? Api::DisallowedGiftType::Premium
: Api::DisallowedGiftType())));
: Api::DisallowedGiftType())
| (update.is_display_gifts_button()
? Api::DisallowedGiftType::SendHide
: Api::DisallowedGiftType()));
} else {
user->setDisallowedGiftTypes(Api::DisallowedGiftTypes());
user->setDisallowedGiftTypes(Api::DisallowedGiftTypes()
| (update.is_display_gifts_button()
? Api::DisallowedGiftType::SendHide
: Api::DisallowedGiftType()));
}
user->owner().stories().apply(user, update.vstories());

View file

@ -23,7 +23,7 @@ struct BusinessDetails;
} // namespace Data
namespace Api {
enum class DisallowedGiftType;
enum class DisallowedGiftType : uchar;
using DisallowedGiftTypes = base::flags<DisallowedGiftType>;
} // namespace Api

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_editing.h"
#include "api/api_bot.h"
#include "api/api_chat_participants.h"
#include "api/api_global_privacy.h"
#include "api/api_report.h"
#include "api/api_sending.h"
#include "api/api_send_progress.h"
@ -484,6 +485,9 @@ HistoryWidget::HistoryWidget(
if (_ttlInfo) {
_ttlInfo->setVisible(!hide);
}
if (_giftToUser) {
_giftToUser->setVisible(!hide);
}
if (_scheduled) {
_scheduled->setVisible(!hide);
}
@ -808,6 +812,7 @@ HistoryWidget::HistoryWidget(
| PeerUpdateFlag::ChatThemeEmoji
| PeerUpdateFlag::FullInfo
| PeerUpdateFlag::StarsPerMessage
| PeerUpdateFlag::GiftSettings
) | rpl::filter([=](const Data::PeerUpdate &update) {
return (update.peer.get() == _peer);
}) | rpl::map([](const Data::PeerUpdate &update) {
@ -847,7 +852,11 @@ HistoryWidget::HistoryWidget(
updateFieldPlaceholder();
updateSendButtonType();
}
if (flags & PeerUpdateFlag::BotStartToken) {
if (flags & PeerUpdateFlag::GiftSettings) {
refreshSendGiftToggle();
}
if (flags & (PeerUpdateFlag::BotStartToken
| PeerUpdateFlag::GiftSettings)) {
updateControlsVisibility();
updateControlsGeometry();
}
@ -2509,6 +2518,7 @@ void HistoryWidget::showHistory(
updateNotifyControls();
}
refreshScheduledToggle();
refreshSendGiftToggle();
refreshSendAsToggle();
if (_showAtMsgId == ShowAtUnreadMsgId) {
@ -2596,6 +2606,18 @@ void HistoryWidget::showHistory(
}
sendBotStartCommand();
}
} else {
Info::Profile::BirthdayValue(
user
) | rpl::map(
Data::IsBirthdayTodayValue
) | rpl::flatten_latest(
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=] {
refreshSendGiftToggle();
updateControlsVisibility();
updateControlsGeometry();
}, _list->lifetime());
}
}
if (!_history->folderKnown()) {
@ -3008,6 +3030,34 @@ void HistoryWidget::refreshScheduledToggle() {
}
}
void HistoryWidget::refreshSendGiftToggle() {
using Type = Api::DisallowedGiftType;
const auto user = _peer ? _peer->asUser() : nullptr;
const auto disallowed = user ? user->disallowedGiftTypes() : Type();
const auto all = Type::Premium
| Type::Unlimited
| Type::Limited
| Type::Unique;
const auto has = user
&& _canSendMessages
&& !user->isServiceUser()
&& !user->isSelf()
&& !user->isBot()
&& ((disallowed & Type::SendHide)
|| Data::IsBirthdayToday(user->birthday()))
&& ((disallowed & all) != all);
if (!_giftToUser && has) {
_giftToUser.create(this, st::historyGiftToUser);
_giftToUser->show();
_giftToUser->addClickHandler([=] {
Ui::ShowStarGiftBox(controller(), _peer);
});
orderWidgets(); // Raise drag areas to the top.
} else if (_giftToUser && !has) {
_giftToUser.destroy();
}
}
void HistoryWidget::setupSendAsToggle() {
session().sendAsPeers().updated(
) | rpl::filter([=](not_null<PeerData*> peer) {
@ -3156,6 +3206,9 @@ void HistoryWidget::updateControlsVisibility() {
if (_scheduled) {
_scheduled->hide();
}
if (_giftToUser) {
_giftToUser->hide();
}
if (_ttlInfo) {
_ttlInfo->hide();
}
@ -3267,6 +3320,14 @@ void HistoryWidget::updateControlsVisibility() {
rightButtonsChanged = true;
}
}
if (_giftToUser) {
const auto was = _giftToUser->isVisible();
const auto now = (!_editMsgId) && (!hideExtraButtons);
if (was != now) {
_giftToUser->setVisible(now);
rightButtonsChanged = true;
}
}
if (_ttlInfo) {
const auto was = _ttlInfo->isVisible();
const auto now = (!_editMsgId) && (!hideExtraButtons);
@ -3317,6 +3378,9 @@ void HistoryWidget::updateControlsVisibility() {
if (_scheduled) {
_scheduled->hide();
}
if (_giftToUser) {
_giftToUser->hide();
}
if (_ttlInfo) {
_ttlInfo->hide();
}
@ -5646,7 +5710,7 @@ void HistoryWidget::moveFieldControls() {
}
// (_botMenu.button) (_attachToggle|_replaceMedia) (_sendAs) ---- _inlineResults ------------------------------ _tabbedPanel ------ _fieldBarCancel
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) _send
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_giftToUser) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) _send
// (_botStart|_unblock|_joinChannel|_muteUnmute|_reportMessages)
auto buttonsBottom = bottom - _attachToggle->height();
@ -5688,6 +5752,10 @@ void HistoryWidget::moveFieldControls() {
if (kbShowShown || _cmdStartShown || _silent) {
right += _botCommandStart->width();
}
if (_giftToUser) {
_giftToUser->moveToRight(right, buttonsBottom);
right += _giftToUser->width();
}
if (_scheduled) {
_scheduled->moveToRight(right, buttonsBottom);
right += _scheduled->width();
@ -5745,10 +5813,13 @@ void HistoryWidget::updateFieldSize() {
if (_cmdStartShown) {
fieldWidth -= _botCommandStart->width();
}
if (_silent && _silent->isVisible()) {
if (_silent && !_silent->isHidden()) {
fieldWidth -= _silent->width();
}
if (_scheduled && _scheduled->isVisible()) {
if (_giftToUser && !_giftToUser->isHidden()) {
fieldWidth -= _giftToUser->width();
}
if (_scheduled && !_scheduled->isHidden()) {
fieldWidth -= _scheduled->width();
}
if (_ttlInfo && _ttlInfo->isVisible()) {
@ -8661,6 +8732,7 @@ bool HistoryWidget::updateCanSendMessage() {
cancelReply();
}
refreshScheduledToggle();
refreshSendGiftToggle();
refreshSilentToggle();
return true;
}

View file

@ -671,6 +671,7 @@ private:
void setupScheduledToggle();
void refreshScheduledToggle();
void refreshSendGiftToggle();
void setupSendAsToggle();
void refreshSendAsToggle();
void refreshAttachBotsMenu();
@ -811,6 +812,7 @@ private:
object_ptr<Ui::IconButton> _botKeyboardShow;
object_ptr<Ui::IconButton> _botKeyboardHide;
object_ptr<Ui::IconButton> _botCommandStart;
object_ptr<Ui::IconButton> _giftToUser = { nullptr };
object_ptr<Ui::SilentToggle> _silent = { nullptr };
object_ptr<Ui::IconButton> _scheduled = { nullptr };
std::unique_ptr<HistoryView::Controls::TTLButton> _ttlInfo;

View file

@ -1639,13 +1639,11 @@ object_ptr<Ui::RpWidget> GiftsAutoSavePrivacyController::setupBelowWidget(
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(
@ -1703,7 +1701,7 @@ object_ptr<Ui::RpWidget> GiftsAutoSavePrivacyController::setupBelowWidget(
tr::lng_edit_privacy_gifts_show_icon(),
st::settingsButtonNoIconLocked));
icon->toggleOn(rpl::single(
session->premium() && state->showGiftIcon
session->premium() && (state->disallowed & Type::SendHide)
) | rpl::then(state->disables.events() | rpl::map([=] {
return false;
})));
@ -1715,11 +1713,11 @@ object_ptr<Ui::RpWidget> GiftsAutoSavePrivacyController::setupBelowWidget(
}, icon->lifetime());
icon->toggledValue() | rpl::start_with_next([=](bool enable) {
if (!enable) {
state->showGiftIcon = false;
state->disallowed &= ~Type::SendHide;
} else if (!session->premium()) {
state->promo();
} else {
state->showGiftIcon = true;
state->disallowed |= Type::SendHide;
}
}, icon->lifetime());
Ui::AddSkip(content);
@ -1731,17 +1729,13 @@ object_ptr<Ui::RpWidget> GiftsAutoSavePrivacyController::setupBelowWidget(
Ui::Text::WithEntities));
_saveAdditional = [=] {
const auto disallowed = state->disallowed;
const auto showGiftIcon = state->showGiftIcon;
const auto now = state->disallowed;
if (!session->premium()) {
return;
} else if (globalPrivacy->showGiftIconCurrent() == showGiftIcon
&& globalPrivacy->disallowedGiftTypesCurrent() == disallowed) {
} else if (globalPrivacy->disallowedGiftTypesCurrent() == now) {
return;
} else {
globalPrivacy->updateAdditionalGiftPrivacy(
disallowed,
showGiftIcon);
globalPrivacy->updateDisallowedGiftTypes(now);
}
};