diff --git a/Telegram/SourceFiles/api/api_global_privacy.cpp b/Telegram/SourceFiles/api/api_global_privacy.cpp index 7196893fe6..96988ebe70 100644 --- a/Telegram/SourceFiles/api/api_global_privacy.cpp +++ b/Telegram/SourceFiles/api/api_global_privacy.cpp @@ -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 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(); } } diff --git a/Telegram/SourceFiles/api/api_global_privacy.h b/Telegram/SourceFiles/api/api_global_privacy.h index 59b6d7860e..fe35c7df5c 100644 --- a/Telegram/SourceFiles/api/api_global_privacy.h +++ b/Telegram/SourceFiles/api/api_global_privacy.h @@ -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 showGiftIcon() const; [[nodiscard]] DisallowedGiftTypes disallowedGiftTypesCurrent() const; [[nodiscard]] auto disallowedGiftTypes() const -> rpl::producer; - 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 _session; @@ -104,7 +100,6 @@ private: rpl::variable _hideReadTime = false; rpl::variable _newRequirePremium = false; rpl::variable _newChargeStars = 0; - rpl::variable _showGiftIcon = false; rpl::variable _disallowedGiftTypes; rpl::variable _paidReactionShownPeer = false; std::vector> _callbacks; diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 9c9f17b8d4..809f2eeace 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -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 }}; diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 6973ec867e..dcebbfca9b 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -826,20 +826,26 @@ void ApplyUserUpdate(not_null 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()); diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index f816dd6988..5e57eaef90 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -23,7 +23,7 @@ struct BusinessDetails; } // namespace Data namespace Api { -enum class DisallowedGiftType; +enum class DisallowedGiftType : uchar; using DisallowedGiftTypes = base::flags; } // namespace Api diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 5e2c88b948..da5b538d81 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -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 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; } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 65b5ea7b0a..33571de179 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -671,6 +671,7 @@ private: void setupScheduledToggle(); void refreshScheduledToggle(); + void refreshSendGiftToggle(); void setupSendAsToggle(); void refreshSendAsToggle(); void refreshAttachBotsMenu(); @@ -811,6 +812,7 @@ private: object_ptr _botKeyboardShow; object_ptr _botKeyboardHide; object_ptr _botCommandStart; + object_ptr _giftToUser = { nullptr }; object_ptr _silent = { nullptr }; object_ptr _scheduled = { nullptr }; std::unique_ptr _ttlInfo; diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index e7e3363931..3b9c2944d0 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -1639,13 +1639,11 @@ object_ptr GiftsAutoSavePrivacyController::setupBelowWidget( struct State { Api::DisallowedGiftTypes disallowed; - bool showGiftIcon = false; rpl::event_stream<> disables; Fn promo; }; const auto state = content->lifetime().make_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 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 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 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); } };