From 3cd68842bf577371af8ff048c05a9de2bd277410 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 4 Nov 2025 13:43:32 +0400 Subject: [PATCH] Use reaction color for send button. --- .../calls/group/calls_group_messages.cpp | 14 +++++++---- .../calls/group/calls_group_messages_ui.cpp | 13 ++++++++-- .../calls/group/calls_group_stars_box.cpp | 3 ++- .../calls/group/calls_group_stars_box.h | 5 ++++ .../group/ui/calls_group_stars_coloring.cpp | 25 +++++++------------ .../group/ui/calls_group_stars_coloring.h | 5 +++- .../history_view_compose_controls.cpp | 11 +++++++- Telegram/SourceFiles/main/main_app_config.cpp | 25 ++++++++++++++++++- Telegram/SourceFiles/main/main_app_config.h | 10 ++++++++ .../payments/ui/payments_reaction_box.cpp | 23 +++++++++++++---- .../payments/ui/payments_reaction_box.h | 2 ++ .../SourceFiles/ui/controls/send_button.cpp | 12 +++++++-- .../SourceFiles/ui/controls/send_button.h | 2 +- 13 files changed, 115 insertions(+), 35 deletions(-) diff --git a/Telegram/SourceFiles/calls/group/calls_group_messages.cpp b/Telegram/SourceFiles/calls/group/calls_group_messages.cpp index d4fb2ad3e2..5125c4a10b 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_messages.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_messages.cpp @@ -54,15 +54,19 @@ constexpr auto kStarsStatsShortPollDelay = 30 * crl::time(1000); return result; } -[[nodiscard]] TimeId PinFinishDate(TimeId date, int stars) { +[[nodiscard]] TimeId PinFinishDate( + not_null peer, + TimeId date, + int stars) { if (!date || !stars) { return 0; } - return date + Ui::StarsColoringForCount(stars).secondsPin; + const auto &colorings = peer->session().appConfig().groupCallColorings(); + return date + Ui::StarsColoringForCount(colorings, stars).secondsPin; } [[nodiscard]] TimeId PinFinishDate(const Message &message) { - return PinFinishDate(message.date, message.stars); + return PinFinishDate(message.peer, message.date, message.stars); } [[nodiscard]] std::optional MaybeShownPeer( @@ -352,10 +356,10 @@ void Messages::received( _messages.push_back({ .id = id, .date = date, - .pinFinishDate = PinFinishDate(date, stars), + .pinFinishDate = PinFinishDate(author, date, stars), .peer = author, .text = Ui::Text::Filtered( - Api::ParseTextWithEntities(&peer->session(), message), + Api::ParseTextWithEntities(&author->session(), message), allowedEntityTypes), .stars = stars, .admin = (author == _call->peer()), diff --git a/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp b/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp index e906cb70a6..73e96d19b5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_message_reaction_id.h" #include "data/data_session.h" #include "lang/lang_keys.h" +#include "main/main_app_config.h" #include "main/main_session.h" #include "ui/boxes/confirm_box.h" #include "ui/controls/emoji_button.h" @@ -1068,6 +1069,8 @@ void MessagesUi::setupMessagesWidget() { const auto start = scroll->scrollTop(); const auto end = start + scroll->height(); const auto ratio = style::DevicePixelRatio(); + const auto session = &_show->session(); + const auto &colorings = session->appConfig().groupCallColorings(); if ((_canvas.width() < scroll->width() * ratio) || (_canvas.height() < scroll->height() * ratio)) { @@ -1112,7 +1115,9 @@ void MessagesUi::setupMessagesWidget() { if (!_streamMode) { _messageBgRect.paint(p, { x, y, width, use }); } else if (entry.stars) { - const auto coloring = Ui::StarsColoringForCount(entry.stars); + const auto coloring = Ui::StarsColoringForCount( + colorings, + entry.stars); auto &bg = _bgs[ColoringKey(coloring)]; if (!bg) { bg = std::make_unique(coloring); @@ -1427,6 +1432,8 @@ void MessagesUi::setupPinnedWidget() { animation->seconds.callEach(crl::time(1000)); _pinned->paintRequest() | rpl::start_with_next([=](QRect clip) { + const auto session = &_show->session(); + const auto &colorings = session->appConfig().groupCallColorings(); const auto start = scroll->scrollLeft(); const auto end = start + scroll->width(); const auto ratio = style::DevicePixelRatio(); @@ -1471,7 +1478,9 @@ void MessagesUi::setupPinnedWidget() { p.setOpacity(scale); p.translate(-mx, -my); } - const auto coloring = Ui::StarsColoringForCount(entry.stars); + const auto coloring = Ui::StarsColoringForCount( + colorings, + entry.stars); auto &bg = _bgs[ColoringKey(coloring)]; if (!bg) { bg = std::make_unique(coloring); diff --git a/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp b/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp index 70bfd58ed9..6239aa4464 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_stars_box.cpp @@ -33,7 +33,7 @@ int MaxVideoStreamStarsCount(not_null session) { const auto appConfig = &session->appConfig(); return std::max( appConfig->get( - u"stars_paid_reaction_amount_max"_q, + u"stars_groupcall_message_amount_max"_q, kMaxStarsFallback), 2); } @@ -119,6 +119,7 @@ void VideoStreamStarsBox( .session = &show->session(), .name = args.name, .submit = std::move(submitText), + .colorings = show->session().appConfig().groupCallColorings(), .balanceValue = session->credits().balanceValue(), .send = [weak, save = args.save](int count, uint64 barePeerId) { save(count); diff --git a/Telegram/SourceFiles/calls/group/calls_group_stars_box.h b/Telegram/SourceFiles/calls/group/calls_group_stars_box.h index 83c0b3075b..cc6edac47f 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_stars_box.h +++ b/Telegram/SourceFiles/calls/group/calls_group_stars_box.h @@ -24,6 +24,11 @@ class BoxContent; class GenericBox; } // namespace Ui +namespace Calls::Group::Ui { +using namespace ::Ui; +struct StarsColoring; +} // namespace Calls::Group::Ui + namespace Calls::Group { [[nodiscard]] int MaxVideoStreamStarsCount(not_null session); diff --git a/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.cpp b/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.cpp index a4ea3962b8..c4e4f74030 100644 --- a/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.cpp +++ b/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.cpp @@ -69,28 +69,21 @@ namespace { } // namespace -StarsColoring StarsColoringForCount(int stars) { - const auto list = std::vector{ - { 0x955CDB, 0x49079B, 0, 30, 30, 0 }, // purple - { 0x955CDB, 0x49079B, 10, 60, 60, 1 }, // still purple - { 0x46A3EB, 0x00508E, 50, 120, 80, 2 }, // blue - { 0x40A920, 0x176200, 100, 300, 110, 3 }, // green - { 0xE29A09, 0x9A3E00, 250, 600, 150, 4 }, // yellow - { 0xED771E, 0x9B3100, 500, 900, 200, 7 }, // orange - { 0xE14542, 0x8B0503, 2'000, 1800, 280, 10 }, // red - { 0x596473, 0x252C36, 10'000, 3600, 400, 20 }, // silver - }; - for (auto i = begin(list), e = end(list); i != e; ++i) { +StarsColoring StarsColoringForCount( + const std::vector &colorings, + int stars) { + for (auto i = begin(colorings), e = end(colorings); i != e; ++i) { if (i->fromStars > stars) { - Assert(i != begin(list)); + Assert(i != begin(colorings)); return *(std::prev(i)); } } - return list.back(); + return colorings.back(); } object_ptr VideoStreamStarsLevel( not_null box, + const std::vector &colorings, rpl::producer starsValue) { auto result = object_ptr(box.get()); const auto raw = result.data(); @@ -103,8 +96,8 @@ object_ptr VideoStreamStarsLevel( const auto state = raw->lifetime().make_state(); state->stars = std::move(starsValue); state->coloring = state->stars.value( - ) | rpl::map([](int stars) { - return StarsColoringForCount(stars); + ) | rpl::map([=](int stars) { + return StarsColoringForCount(colorings, stars); }); state->blocks.push_back(MakeInfoBlock(raw, state->coloring.value( diff --git a/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.h b/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.h index 5bf3ba571e..63fb7f968b 100644 --- a/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.h +++ b/Telegram/SourceFiles/calls/group/ui/calls_group_stars_coloring.h @@ -31,10 +31,13 @@ struct StarsColoring { const StarsColoring &) = default; }; -[[nodiscard]] StarsColoring StarsColoringForCount(int stars); +[[nodiscard]] StarsColoring StarsColoringForCount( + const std::vector &colorings, + int stars); [[nodiscard]] object_ptr VideoStreamStarsLevel( not_null box, + const std::vector &colorings, rpl::producer starsValue); } // namespace Calls::Group::Ui 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 d055594b8d..8ed22ca62c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -14,11 +14,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer_rpl.h" #include "base/unixtime.h" #include "boxes/edit_caption_box.h" +#include "calls/group/ui/calls_group_stars_coloring.h" #include "calls/group/calls_group_stars_box.h" #include "chat_helpers/compose/compose_show.h" #include "chat_helpers/emoji_suggestions_widget.h" #include "chat_helpers/message_field.h" -#include "menu/menu_send.h" #include "chat_helpers/tabbed_panel.h" #include "chat_helpers/tabbed_section.h" #include "chat_helpers/tabbed_selector.h" @@ -67,10 +67,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "inline_bots/inline_results_widget.h" #include "inline_bots/inline_bot_result.h" #include "lang/lang_keys.h" +#include "main/main_app_config.h" #include "main/main_session.h" #include "main/session/send_as_peers.h" #include "media/audio/media_audio_capture.h" #include "media/audio/media_audio.h" +#include "menu/menu_send.h" #include "settings/settings_premium.h" #include "ui/item_text_options.h" #include "ui/text/text_options.h" @@ -2960,8 +2962,15 @@ void ComposeControls::updateSendButtonType() { ? _slowmodeSecondsLeft.current() : 0; }(); + using namespace Calls::Group::Ui; + const auto &appConfig = _show->session().appConfig(); _send->setState({ .type = type, + .fillBgOverride = (_chosenStarsCount.value_or(0) + ? StarsColoringForCount( + appConfig.groupCallColorings(), + *_chosenStarsCount).bgLight + : QColor()), .slowmodeDelay = delay, .starsToSend = shownStarsPerMessage(), }); diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index b969048b93..d3f9b86d73 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -10,9 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_authorizations.h" #include "apiwrap.h" #include "base/call_delayed.h" +#include "calls/group/ui/calls_group_stars_coloring.h" +#include "data/data_session.h" #include "main/main_account.h" #include "main/main_session.h" -#include "data/data_session.h" #include "ui/chat/chat_style.h" namespace Main { @@ -262,6 +263,26 @@ TimeId AppConfig::groupCallMessageTTL() const { return get(u"group_call_message_ttl"_q, 10); } +auto AppConfig::groupCallColorings() const -> std::vector { + if (!_groupCallColorings.empty()) { + return _groupCallColorings; + } + + if (_groupCallColorings.empty()) { + _groupCallColorings = std::vector{ + { 0x955CDB, 0x49079B, 0, 30, 30, 0 }, // purple + { 0x955CDB, 0x49079B, 10, 60, 60, 1 }, // still purple + { 0x46A3EB, 0x00508E, 50, 120, 80, 2 }, // blue + { 0x40A920, 0x176200, 100, 300, 110, 3 }, // green + { 0xE29A09, 0x9A3E00, 250, 600, 150, 4 }, // yellow + { 0xED771E, 0x9B3100, 500, 900, 200, 7 }, // orange + { 0xE14542, 0x8B0503, 2'000, 1800, 280, 10 }, // red + { 0x596473, 0x252C36, 10'000, 3600, 400, 20 }, // silver + }; + } + return _groupCallColorings; +} + void AppConfig::refresh(bool force) { if (_requestId || !_api) { if (force) { @@ -292,6 +313,8 @@ void AppConfig::refresh(bool force) { } updateIgnoredRestrictionReasons(std::move(was)); + _groupCallColorings = {}; + DEBUG_LOG(("getAppConfig result handled.")); _refreshed.fire({}); }, [](const MTPDhelp_appConfigNotModified &) {}); diff --git a/Telegram/SourceFiles/main/main_app_config.h b/Telegram/SourceFiles/main/main_app_config.h index b2ee173dc9..65170f0000 100644 --- a/Telegram/SourceFiles/main/main_app_config.h +++ b/Telegram/SourceFiles/main/main_app_config.h @@ -14,6 +14,11 @@ namespace Ui { struct ColorIndicesCompressed; } // namespace Ui +namespace Calls::Group::Ui { +using namespace ::Ui; +struct StarsColoring; +} // namespace Calls::Group::Ui + namespace Main { class Account; @@ -118,6 +123,9 @@ public: [[nodiscard]] int groupCallMessageLengthLimit() const; [[nodiscard]] TimeId groupCallMessageTTL() const; + using StarsColoring = Calls::Group::Ui::StarsColoring; + [[nodiscard]] std::vector groupCallColorings() const; + void refresh(bool force = false); private: @@ -162,6 +170,8 @@ private: std::vector _startRefPrefixes; + mutable std::vector _groupCallColorings; + crl::time _lastFrozenRefresh = 0; rpl::lifetime _frozenTrackLifetime; diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp index 8ea9cb0452..ece6380237 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp @@ -223,13 +223,19 @@ void PaidReactionSlider( }, stars->lifetime()); } -[[nodiscard]] QImage GenerateBadgeImage(int count, bool videoStream) { +[[nodiscard]] QImage GenerateBadgeImage( + const std::vector &colorings, + int count, + bool videoStream) { return GenerateSmallBadgeImage( Lang::FormatCountDecimal(count), st::paidReactTopStarIcon, (videoStream ? Ui::ColorFromSerialized( - Calls::Group::Ui::StarsColoringForCount(count).bgLight) + Calls::Group::Ui::StarsColoringForCount( + colorings, + count + ).bgLight) : st::creditsBg3->c), videoStream ? st::white->c : st::premiumButtonFg->c); } @@ -261,6 +267,7 @@ void AddArrowDown(not_null widget) { [[nodiscard]] not_null MakeTopReactor( not_null parent, const PaidReactionTop &data, + const std::vector &colorings, Fn selectShownPeer, bool videoStream) { const auto result = CreateChild(parent); @@ -296,7 +303,7 @@ void AddArrowDown(not_null widget) { p.drawImage(left, 0, photo->image(st::paidReactTopUserpic)); if (state->badge.isNull()) { - state->badge = GenerateBadgeImage(count, videoStream); + state->badge = GenerateBadgeImage(colorings, count, videoStream); } const auto bwidth = state->badge.width() / state->badge.devicePixelRatio(); @@ -365,6 +372,7 @@ void SelectShownPeer( void FillTopReactors( not_null container, std::vector top, + const std::vector &colorings, rpl::producer chosen, rpl::producer shownPeer, Fn changeShownPeer, @@ -465,6 +473,7 @@ void FillTopReactors( : MakeTopReactor( parent, entry, + colorings, selectShownPeer, videoStream); state->widgets.push_back(widget); @@ -530,6 +539,7 @@ void PaidReactionsBox( state->chosen = count; }; + const auto colorings = args.colorings; const auto videoStreamChoosing = args.videoStreamChoosing; const auto videoStreamSending = args.videoStreamSending; const auto videoStream = videoStreamChoosing || videoStreamSending; @@ -562,7 +572,9 @@ void PaidReactionsBox( }; }); const auto activeFgOverride = [=](int count) { - const auto coloring = Calls::Group::Ui::StarsColoringForCount(count); + const auto coloring = Calls::Group::Ui::StarsColoringForCount( + colorings, + count); return Ui::ColorFromSerialized(coloring.bgLight); }; @@ -602,6 +614,7 @@ void PaidReactionsBox( FillTopReactors( content, std::move(args.top), + colorings, state->chosen.value(), state->shownPeer.value(), [=](uint64 barePeerId) { @@ -613,7 +626,7 @@ void PaidReactionsBox( if (videoStreamChoosing) { using namespace Calls::Group::Ui; box->addRow( - VideoStreamStarsLevel(box, state->chosen.value()), + VideoStreamStarsLevel(box, colorings, state->chosen.value()), st::boxRowPadding + QMargins(0, st::paidReactTitleSkip, 0, 0)); } else if (videoStreamSending) { addTopReactors(); diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h index 55cb5c11dd..be68724f6d 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "base/object_ptr.h" +#include "calls/group/ui/calls_group_stars_coloring.h" namespace style { struct RoundCheckbox; @@ -42,6 +43,7 @@ struct PaidReactionBoxArgs { not_null session; QString name; Fn(rpl::producer amount)> submit; + std::vector colorings; rpl::producer balanceValue; Fn send; bool videoStreamChoosing = false; diff --git a/Telegram/SourceFiles/ui/controls/send_button.cpp b/Telegram/SourceFiles/ui/controls/send_button.cpp index 49292cffe6..f2779bce69 100644 --- a/Telegram/SourceFiles/ui/controls/send_button.cpp +++ b/Telegram/SourceFiles/ui/controls/send_button.cpp @@ -198,7 +198,11 @@ void SendButton::paintSend(QPainter &p, bool over) { if (const auto padding = _st.sendIconFillPadding; padding > 0) { auto hq = PainterHighQualityEnabler(p); p.setPen(Qt::NoPen); - p.setBrush(st::windowBgActive); + if (_state.fillBgOverride.isValid()) { + p.setBrush(_state.fillBgOverride); + } else { + p.setBrush(st::windowBgActive); + } p.drawEllipse( QRect(_st.sendIconPosition, sendIcon.size()).marginsAdded( { padding, padding, padding, padding })); @@ -216,7 +220,11 @@ void SendButton::paintStarsToSend(QPainter &p, bool over) { { PainterHighQualityEnabler hq(p); p.setPen(Qt::NoPen); - p.setBrush(over ? _st.stars.textBgOver : _st.stars.textBg); + if (_state.fillBgOverride.isValid()) { + p.setBrush(_state.fillBgOverride); + } else { + p.setBrush(over ? _st.stars.textBgOver : _st.stars.textBg); + } const auto radius = geometry.rounded.height() / 2; p.drawRoundedRect(geometry.rounded, radius, radius); } diff --git a/Telegram/SourceFiles/ui/controls/send_button.h b/Telegram/SourceFiles/ui/controls/send_button.h index d18f51eb2b..a46d82d97b 100644 --- a/Telegram/SourceFiles/ui/controls/send_button.h +++ b/Telegram/SourceFiles/ui/controls/send_button.h @@ -35,10 +35,10 @@ public: }; struct State { Type type = Type::Send; + QColor fillBgOverride; int slowmodeDelay = 0; int starsToSend = 0; - friend inline constexpr auto operator<=>(State, State) = default; friend inline constexpr bool operator==(State, State) = default; }; [[nodiscard]] Type type() const {