diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 47b8fb1143..b3943d3e60 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4163,6 +4163,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_story_reply_ph" = "Reply privately..."; "lng_story_comment_ph" = "Comment story..."; "lng_video_stream_comment_ph" = "Comment"; +"lng_video_stream_comment_paid_ph#one" = "Comment for {count} Star"; +"lng_video_stream_comment_paid_ph#other" = "Comment for {count} Stars"; "lng_video_stream_stars" = "Add Stars to highlight your comment"; "lng_video_stream_live" = "LIVE"; "lng_video_stream_watched#one" = "{count} watching"; diff --git a/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp b/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp index 6945057b02..70bfd58ed9 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp @@ -29,6 +29,15 @@ constexpr auto kDefaultStars = 10; } // namespace +int MaxVideoStreamStarsCount(not_null session) { + const auto appConfig = &session->appConfig(); + return std::max( + appConfig->get( + u"stars_paid_reaction_amount_max"_q, + kMaxStarsFallback), + 2); +} + void VideoStreamStarsBox( not_null box, VideoStreamStarsBoxArgs &&args) { @@ -49,15 +58,10 @@ void VideoStreamStarsBox( }; const auto &show = args.show; const auto session = &show->session(); - const auto appConfig = &session->appConfig(); - const auto max = std::max( - appConfig->get( - u"stars_paid_reaction_amount_max"_q, - kMaxStarsFallback), - 2); + const auto max = std::max(args.min, MaxVideoStreamStarsCount(session)); const auto chosen = std::clamp( args.current ? args.current : kDefaultStars, - 1, + args.min, max); auto top = std::vector(); const auto add = [&](const Data::MessageReactionsTopPaid &entry) { @@ -108,6 +112,7 @@ void VideoStreamStarsBox( ranges::stable_sort(top, ranges::greater(), &Ui::PaidReactionTop::count); const auto weak = base::make_weak(box); Ui::PaidReactionsBox(box, { + .min = args.min, .chosen = chosen, .max = max, .top = std::move(top), diff --git a/Telegram/SourceFiles/calls/group/calls_group_stars_box.h b/Telegram/SourceFiles/calls/group/calls_group_stars_box.h index 6e50b68fe6..83c0b3075b 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_stars_box.h +++ b/Telegram/SourceFiles/calls/group/calls_group_stars_box.h @@ -15,6 +15,10 @@ namespace Data { struct MessageReactionsTopPaid; } // namespace Data +namespace Main { +class Session; +} // namespace Main + namespace Ui { class BoxContent; class GenericBox; @@ -22,9 +26,12 @@ class GenericBox; namespace Calls::Group { +[[nodiscard]] int MaxVideoStreamStarsCount(not_null session); + struct VideoStreamStarsBoxArgs { std::shared_ptr show; std::vector top; + int min = 0; int current = 0; bool sending = false; Fn save; diff --git a/Telegram/SourceFiles/history/view/controls/compose_controls_common.h b/Telegram/SourceFiles/history/view/controls/compose_controls_common.h index 85ac24eb99..17badb7a9c 100644 --- a/Telegram/SourceFiles/history/view/controls/compose_controls_common.h +++ b/Telegram/SourceFiles/history/view/controls/compose_controls_common.h @@ -78,6 +78,7 @@ struct SetHistoryArgs { rpl::producer slowmodeSecondsLeft; rpl::producer sendDisabledBySlowmode; rpl::producer liked; + rpl::producer minStarsCount; rpl::producer writeRestriction; }; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 9d28a3550b..00c5c4fcea 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -910,9 +910,6 @@ ComposeControls::ComposeControls( , _mode(descriptor.mode) , _wrap(std::make_unique(parent)) , _send(std::make_shared(_wrap.get(), _st.send)) -, _editStars(_features.editMessageStars - ? Ui::CreateChild(_wrap.get(), _st.editStars) - : nullptr) , _like(_features.likes ? Ui::CreateChild(_wrap.get(), _st.like) : nullptr) @@ -1026,6 +1023,9 @@ void ComposeControls::setHistory(SetHistoryArgs &&args) { _liked = args.liked ? std::move(args.liked) : rpl::single(false); _writeRestriction = rpl::single(Controls::WriteRestriction()) | rpl::then(std::move(args.writeRestriction)); + _minStarsCount = args.minStarsCount + ? std::move(args.minStarsCount) + : rpl::single(0); const auto history = *args.history; if (_history == history) { return; @@ -1085,19 +1085,36 @@ void ComposeControls::initLikeButton() { } void ComposeControls::initEditStarsButton() { - if (_editStars) { - _editStars->setClickedCallback([=] { - _show->show(Calls::Group::MakeVideoStreamStarsBox({ - .show = _show, - .current = _chosenStarsCount.value_or(0), - .save = crl::guard(_editStars, [=](int count) { - _chosenStarsCount = count; - updateSendButtonType(); - }), - .name = _history ? _history->peer->shortName() : QString(), - })); - }); + if (!_features.editMessageStars) { + delete base::take(_editStars); + _chosenStarsCount = std::nullopt; + return; } + if (_chosenStarsCount.value_or(0) < _minStarsCount.current()) { + _chosenStarsCount = _minStarsCount.current(); + updateSendButtonType(); + } + if (_editStars) { + return; + } + _editStars = Ui::CreateChild( + _wrap.get(), + _st.editStars); + _editStars->show(); + _editStars->setClickedCallback([=] { + const auto min = _minStarsCount.current(); + const auto now = std::max(min, _chosenStarsCount.value_or(0)); + _show->show(Calls::Group::MakeVideoStreamStarsBox({ + .show = _show, + .min = min, + .current = now, + .save = crl::guard(_editStars, [=](int count) { + _chosenStarsCount = count; + updateSendButtonType(); + }), + .name = _history ? _history->peer->shortName() : QString(), + })); + }); } void ComposeControls::updateLikeParent() { @@ -1136,15 +1153,7 @@ void ComposeControls::updateFeatures(ChatHelpers::ComposeFeatures features) { changed = true; } if (was.editMessageStars != features.editMessageStars) { - if (!features.editMessageStars) { - delete base::take(_editStars); - _chosenStarsCount = std::nullopt; - } else { - _editStars = Ui::CreateChild( - _wrap.get(), - _st.editStars); - initEditStarsButton(); - } + initEditStarsButton(); changed = true; } if (was.recordMediaMessage != features.recordMediaMessage) { @@ -1654,6 +1663,11 @@ void ComposeControls::init() { initWriteRestriction(); initVoiceRecordBar(); initKeyHandler(); + initEditStarsButton(); + _minStarsCount.changes() | rpl::start_with_next([=] { + initEditStarsButton(); + updateControlsGeometry(_wrap->size()); + }, _wrap->lifetime()); _hidden.changes( ) | rpl::start_with_next([=] { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index c6b59e9a2b..b419e7bd6f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -419,6 +419,7 @@ private: const std::shared_ptr _send; Ui::IconButton *_editStars = nullptr; Ui::IconButton *_like = nullptr; + rpl::variable _minStarsCount; std::optional _chosenStarsCount; Ui::IconButton *_commentsShown = nullptr; Ui::RpWidget *_commentsShownNewDot = nullptr; diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index bb1c6333f2..5d545292ac 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -85,7 +85,11 @@ namespace { rpl::single(0) ) | rpl::map([=](TimeId left) { return (type == ReplyAreaType::VideoStreamComment) - ? tr::lng_video_stream_comment_ph() + ? (starsPerMessage + ? tr::lng_video_stream_comment_paid_ph( + lt_count, + rpl::single(starsPerMessage * 1.)) + : tr::lng_video_stream_comment_ph()) : starsPerMessage ? tr::lng_message_stars_ph( lt_count, @@ -854,19 +858,20 @@ void ReplyArea::show( if (_data == data) { return; } + const auto stream = data.videoStream.get(); const auto peerChanged = (_data.peer != data.peer); - const auto streamChanged = (_data.videoStream != data.videoStream); + const auto streamChanged = (_data.videoStream.get() != stream); _data = data; if (streamChanged) { - _controls->updateFeatures(Features(_data.videoStream != nullptr)); - _controls->setToggleCommentsButton(_data.videoStream + _controls->updateFeatures(Features(stream != nullptr)); + _controls->setToggleCommentsButton(stream ? _controller->commentsStateValue() : nullptr); _controller->setCommentsShownToggles( _controls->commentsShownToggles()); } using Controls = HistoryView::ComposeControls; - _controls->setStarsReactionCounter(_data.videoStream + _controls->setStarsReactionCounter(stream ? _controller->starsReactionsValue() : nullptr); _controller->setStarsReactionIncrements( @@ -874,21 +879,12 @@ void ReplyArea::show( ) | rpl::map([](Controls::StarReactionIncrement increment) { return increment.count; })); + _starsForMessage = starsPerMessageValue(); if (!peerChanged) { if (_data.peer) { _controls->clear(); } return; - } else if (const auto peer = _data.peer) { - using Flag = Data::PeerUpdate::Flag; - _starsForMessage = peer->session().changes().peerFlagsValue( - peer, - Flag::StarsPerMessage | Flag::FullInfo - ) | rpl::map([=] { - return peer->starsPerMessageChecked(); - }); - } else { - _starsForMessage = 0; } invalidate_weak_ptrs(&_shownPeerGuard); const auto peer = data.peer; @@ -927,6 +923,9 @@ void ReplyArea::show( ) | rpl::map([](const Data::ReactionId &id) { return !id.empty(); }), + .minStarsCount = (_data.videoStream + ? _starsForMessage.value() + : nullptr), .writeRestriction = std::move(writeRestriction), }); _controls->clear(); @@ -954,6 +953,21 @@ void ReplyArea::show( } } +rpl::producer ReplyArea::starsPerMessageValue() const { + if (const auto stream = _data.videoStream.get()) { + return stream->messagesMinPriceValue(); + } else if (const auto peer = _data.peer) { + using Flag = Data::PeerUpdate::Flag; + return peer->session().changes().peerFlagsValue( + peer, + Flag::StarsPerMessage | Flag::FullInfo + ) | rpl::map([=] { + return peer->starsPerMessageChecked(); + }); + } + return rpl::single(0); +} + void ReplyArea::updateVideoStream(not_null videoStream) { _type = ReplyAreaType::VideoStreamComment; _videoStream = videoStream; diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.h b/Telegram/SourceFiles/media/stories/media_stories_reply.h index 0ecc125882..bbc9414afa 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.h +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.h @@ -168,6 +168,7 @@ private: void chooseAttach(std::optional overrideSendImagesAsPhotos); [[nodiscard]] Fn sendMenuDetails() const; + [[nodiscard]] rpl::producer starsPerMessageValue() const; void showPremiumToast(not_null emoji); [[nodiscard]] bool showSlowmodeError(); diff --git a/Telegram/SourceFiles/menu/menu_send.cpp b/Telegram/SourceFiles/menu/menu_send.cpp index 6dabbdb600..75ce781d92 100644 --- a/Telegram/SourceFiles/menu/menu_send.cpp +++ b/Telegram/SourceFiles/menu/menu_send.cpp @@ -684,7 +684,8 @@ FillMenuResult FillEditCommentPriceMenu( menu->addAction(tr::lng_video_stream_edit_stars(tr::now), [=] { show->show(Calls::Group::MakeVideoStreamStarsBox({ .show = show, - .current = int(details.price.value_or(0)), + .min = int(details.commentPriceMin.value_or(1)), + .current = int(details.price.value_or(1)), .save = [=](int count) { auto copy = details; copy.price = count; diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp index 83d615d75b..22f833a518 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp @@ -128,6 +128,7 @@ struct Discreter { void PaidReactionSlider( not_null container, const style::MediaSlider &st, + int min, int current, int max, Fn changed, @@ -149,14 +150,17 @@ void PaidReactionSlider( slider->setAlwaysDisplayMarker(true); slider->setDirection(ContinuousSlider::Direction::Horizontal); slider->setValue(discreter.valueToRatio(current)); + const auto ratioToValue = [=](float64 ratio) { + const auto value = discreter.ratioToValue(ratio); + return std::max(value, min); + }; slider->setAdjustCallback([=](float64 ratio) { - return discreter.valueToRatio(discreter.ratioToValue(ratio)); + return discreter.valueToRatio(ratioToValue(ratio)); }); - const auto ratioToValue = discreter.ratioToValue; - const auto callback = [=](float64 value) { - const auto count = ratioToValue(value); - update(count); - changed(count); + const auto callback = [=](float64 ratio) { + const auto value = ratioToValue(ratio); + update(value); + changed(value); }; slider->setChangeProgressCallback(callback); slider->setChangeFinishedCallback(callback); @@ -506,8 +510,9 @@ void PaidReactionsBox( Expects(!args.top.empty()); const auto dark = args.dark; - args.max = std::max(args.max, 2); - args.chosen = std::clamp(args.chosen, 1, args.max); + args.min = std::max(args.min, 1); + args.max = std::max(args.max, args.min + 1); + args.chosen = std::clamp(args.chosen, args.min, args.max); box->setWidth(st::boxWideWidth); box->setStyle(dark ? st::darkEditStarsBox : st::paidReactBox); @@ -583,6 +588,7 @@ void PaidReactionsBox( PaidReactionSlider( content, (dark ? st::darkEditStarsSlider : st::paidReactSlider), + args.min, args.chosen, args.max, changed, diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h index 36f9e26f6e..71522acb30 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h @@ -33,6 +33,7 @@ struct PaidReactionTop { }; struct PaidReactionBoxArgs { + int min = 0; int chosen = 0; int max = 0;