diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 5b6ca40fcb..26f14f233b 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -4206,7 +4206,7 @@ std::function( } void GroupCall::sendMessage(TextWithTags message) { - _messages->send(std::move(message)); + _messages->send(std::move(message), 0); } auto GroupCall::otherParticipantStateValue() const diff --git a/Telegram/SourceFiles/calls/group/calls_group_messages.cpp b/Telegram/SourceFiles/calls/group/calls_group_messages.cpp index 7a1694a4f6..7bc0821e1e 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_messages.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_messages.cpp @@ -47,9 +47,9 @@ bool Messages::ready() const { return _real && (!_call->conference() || _call->e2eEncryptDecrypt()); } -void Messages::send(TextWithTags text) { +void Messages::send(TextWithTags text, int stars) { if (!ready()) { - _pending.push_back(std::move(text)); + _pending.push_back({ std::move(text), stars }); return; } @@ -73,15 +73,17 @@ void Messages::send(TextWithTags text) { .id = localId, .peer = from, .text = std::move(prepared), + .stars = stars, }); if (!_call->conference()) { + using Flag = MTPphone_SendGroupCallMessage::Flag; _api->request(MTPphone_SendGroupCallMessage( - MTP_flags(0), + MTP_flags(stars ? Flag::f_allow_paid_stars : Flag()), _call->inputCall(), MTP_long(randomId), serialized, - MTPlong() // allow_paid_stars + MTP_long(stars) )).done([=]( const MTPUpdates &result, const MTP::Response &response) { @@ -119,7 +121,8 @@ void Messages::received(const MTPDupdateGroupCallMessage &data) { fields.vid().v, fields.vfrom_id(), fields.vmessage(), - fields.vdate().v); + fields.vdate().v, + fields.vpaid_message_stars().value_or_empty()); pushChanges(); } @@ -153,8 +156,9 @@ void Messages::received(const MTPDupdateGroupCallEncryptedMessage &data) { realId, fromId, deserialized->message, - base::unixtime::now(), - true); + base::unixtime::now(), // date + 0, // stars + true); // checkCustomEmoji pushChanges(); } @@ -208,6 +212,7 @@ void Messages::received( const MTPPeer &from, const MTPTextWithEntities &message, TimeId date, + int stars, bool checkCustomEmoji) { const auto peer = _call->peer(); const auto i = ranges::find(_messages, id, &Message::id); @@ -238,6 +243,7 @@ void Messages::received( .text = Ui::Text::Filtered( Api::ParseTextWithEntities(&peer->session(), message), allowedEntityTypes), + .stars = stars, }); checkDestroying(true); } @@ -290,7 +296,7 @@ void Messages::sendPending() { Expects(_real != nullptr); for (auto &pending : base::take(_pending)) { - send(std::move(pending)); + send(std::move(pending.text), pending.stars); } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_messages.h b/Telegram/SourceFiles/calls/group/calls_group_messages.h index c34a08c247..13277a0c7b 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_messages.h +++ b/Telegram/SourceFiles/calls/group/calls_group_messages.h @@ -29,6 +29,7 @@ struct Message { TimeId date = 0; not_null peer; TextWithEntities text; + int stars = 0; bool failed = false; }; @@ -41,7 +42,7 @@ class Messages final { public: Messages(not_null call, not_null api); - void send(TextWithTags text); + void send(TextWithTags text, int stars); void received(const MTPDupdateGroupCallMessage &data); void received(const MTPDupdateGroupCallEncryptedMessage &data); @@ -52,6 +53,10 @@ public: [[nodiscard]] rpl::producer idUpdates() const; private: + struct Pending { + TextWithTags text; + int stars = 0; + }; [[nodiscard]] bool ready() const; void sendPending(); void pushChanges(); @@ -62,6 +67,7 @@ private: const MTPPeer &from, const MTPTextWithEntities &message, TimeId date, + int stars, bool checkCustomEmoji = false); void sent(uint64 randomId, const MTP::Response &response); void sent(uint64 randomId, MsgId realId); @@ -77,7 +83,7 @@ private: Data::GroupCall *_real = nullptr; - std::vector _pending; + std::vector _pending; base::Timer _destroyTimer; std::vector _messages; diff --git a/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp b/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp index ab9f63dc05..576b17a2ce 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp @@ -436,10 +436,13 @@ void MessagesUi::appendMessage(const Message &data) { if (data.failed) { setContentFailed(entry); } else { - setContent( - entry, - Ui::Text::Link(Ui::Text::Bold(data.peer->shortName()), 1).append( - ' ').append(data.text)); + auto text = Ui::Text::Link(Ui::Text::Bold(data.peer->shortName()), 1) + .append(' ').append(data.text); + if (data.stars) { + text.append(" (").append( + QString::number(data.stars)).append(" stars)"); + } + setContent(entry, text); } entry.top = top; updateMessageSize(entry); diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 907392f39e..c0b45107f6 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -208,6 +208,7 @@ ComposeControls { emoji: EmojiButton; like: IconButton; liked: icon; + editStars: IconButton; suggestions: EmojiSuggestions; tabbed: EmojiPan; tabbedHeightMin: pixels; diff --git a/Telegram/SourceFiles/chat_helpers/compose/compose_features.h b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h index dedf4ff063..5cee652bab 100644 --- a/Telegram/SourceFiles/chat_helpers/compose/compose_features.h +++ b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h @@ -26,6 +26,8 @@ struct ComposeFeatures { bool autocompleteCommands : 1 = true; bool suggestStickersByEmoji : 1 = true; bool commonTabbedPanel : 1 = true; + bool recordMediaMessage : 1 = true; + bool editMessageStars : 1 = false; }; } // namespace ChatHelpers 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 74e494ef87..285c9065d7 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -909,6 +909,9 @@ ComposeControls::ComposeControls( , _like(_features.likes ? Ui::CreateChild(_wrap.get(), _st.like) : nullptr) +, _editStars(_features.editMessageStars + ? Ui::CreateChild(_wrap.get(), _st.editStars) + : nullptr) , _attachToggle(Ui::CreateChild(_wrap.get(), _st.attach)) , _tabbedSelectorToggle(Ui::CreateChild( _wrap.get(), @@ -1074,6 +1077,19 @@ void ComposeControls::initLikeButton() { } } +void ComposeControls::initEditStarsButton() { + if (_editStars) { + _editStars->setClickedCallback([=] { + if (!_chosenStarsCount) { + _chosenStarsCount = 1; + } else { + ++*_chosenStarsCount; + } + updateSendButtonType(); + }); + } +} + void ComposeControls::updateLikeParent() { if (_like) { using namespace Controls; @@ -1097,6 +1113,7 @@ void ComposeControls::updateFeatures(ChatHelpers::ComposeFeatures features) { if (was.likes != features.likes) { if (!features.likes) { delete base::take(_like); + _likeShown = false; } else { _like = Ui::CreateChild(_wrap.get(), _st.like); initLikeButton(); @@ -1107,6 +1124,21 @@ void ComposeControls::updateFeatures(ChatHelpers::ComposeFeatures features) { } updateControlsGeometry(_wrap->size()); } + if (was.editMessageStars != features.editMessageStars) { + if (!features.editMessageStars) { + delete base::take(_editStars); + _chosenStarsCount = std::nullopt; + } else { + _editStars = Ui::CreateChild( + _wrap.get(), + _st.editStars); + initEditStarsButton(); + updateControlsGeometry(_wrap->size()); + } + } + if (was.recordMediaMessage != features.recordMediaMessage) { + updateSendButtonType(); + } } void ComposeControls::setCurrentDialogsEntryState( @@ -1386,6 +1418,7 @@ void ComposeControls::clear() { {}, saveTextDraft ? TextUpdateEvent::SaveDraft : TextUpdateEvent()); cancelReplyMessage(); + clearChosenStarsForMessage(); if (_preview) { _preview->apply({ .removed = true }); } @@ -1658,7 +1691,8 @@ void ComposeControls::orderControls() { } bool ComposeControls::showRecordButton() const { - return (_recordAvailability != Webrtc::RecordAvailability::None) + return _features.recordMediaMessage + && (_recordAvailability != Webrtc::RecordAvailability::None) && !_voiceRecordBar->isListenState() && !_voiceRecordBar->isRecordingByAnotherBar() && !HasSendText(_field) @@ -1670,6 +1704,17 @@ void ComposeControls::clearListenState() { _voiceRecordBar->clearListenState(); } +void ComposeControls::clearChosenStarsForMessage() { + if (_chosenStarsCount.has_value()) { + _chosenStarsCount = std::nullopt; + updateSendButtonType(); + } +} + +int ComposeControls::chosenStarsForMessage() const { + return _chosenStarsCount.value_or(0); +} + void ComposeControls::initKeyHandler() { _wrap->events( ) | rpl::filter([=](not_null event) { @@ -2726,7 +2771,8 @@ void ComposeControls::updateSendButtonType() { : 0; }(); const auto peer = _history ? _history->peer.get() : nullptr; - const auto stars = peer ? peer->starsPerMessageChecked() : 0; + const auto stars = _chosenStarsCount.value_or( + peer ? peer->starsPerMessageChecked() : 0); _send->setState({ .type = type, .slowmodeDelay = delay, @@ -2754,6 +2800,7 @@ void ComposeControls::updateControlsGeometry(QSize size) { - _send->width() - _tabbedSelectorToggle->width() - (_likeShown ? _like->width() : 0) + - (_editStars ? _editStars->width() : 0) - (_botCommandShown ? _botCommandStart->width() : 0) - (_silent ? _silent->width() : 0) - (_scheduled ? _scheduled->width() : 0) @@ -2805,6 +2852,10 @@ void ComposeControls::updateControlsGeometry(QSize size) { } } } + if (_editStars) { + _editStars->moveToRight(right, buttonsTop); + right += _editStars->width(); + } if (_botCommandStart) { _botCommandStart->moveToRight(right, buttonsTop); if (_botCommandShown) { @@ -2836,6 +2887,9 @@ void ComposeControls::updateControlsVisibility() { if (_like) { _like->setVisible(_likeShown); } + if (_editStars) { + _editStars->show(); + } if (_ttlInfo) { _ttlInfo->show(); } 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 1545593d71..078b1da633 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -229,6 +229,9 @@ public: void hidePanelsAnimated(); void clearListenState(); + void clearChosenStarsForMessage(); + [[nodiscard]] int chosenStarsForMessage() const; + void hide(); void show(); @@ -281,6 +284,7 @@ private: void initVoiceRecordBar(); void initKeyHandler(); void initLikeButton(); + void initEditStarsButton(); void updateLikeParent(); void updateSubmitSettings(); void updateSendButtonType(); @@ -388,7 +392,9 @@ private: std::optional _backgroundRect; const std::shared_ptr _send; - Ui::IconButton * _like = nullptr; + Ui::IconButton *_like = nullptr; + Ui::IconButton *_editStars = nullptr; + std::optional _chosenStarsCount; const not_null _attachToggle; std::unique_ptr _replaceMedia; const not_null _tabbedSelectorToggle; diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index adacd30b99..dcc7a69c05 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -112,6 +112,8 @@ namespace { .autocompleteHashtags = false, .autocompleteMentions = false, .autocompleteCommands = false, + .recordMediaMessage = !videoStream, + .editMessageStars = videoStream, }; } @@ -224,8 +226,9 @@ bool ReplyArea::sendReaction(const Data::ReactionId &id) { void ReplyArea::send(Api::SendOptions options) { auto text = _controls->getTextWithAppliedMarkdown(); + const auto stars = _controls->chosenStarsForMessage(); if (const auto stream = _videoStream.get()) { - stream->messages()->send(std::move(text)); + stream->messages()->send(std::move(text), stars); _controls->clear(); return; } diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 785e188e96..8367b603f3 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -487,6 +487,10 @@ storiesLike: IconButton(storiesAttach) { icon: icon {{ "chat/input_like", storiesComposeGrayIcon }}; iconOver: icon {{ "chat/input_like", storiesComposeGrayIcon }}; } +storiesEditStars: IconButton(storiesAttach) { + icon: icon{{ "chat/input_paid", storiesComposeGrayIcon }}; + iconOver: icon{{ "chat/input_paid", storiesComposeGrayIcon }}; +} storiesRecordVoice: icon {{ "chat/input_record", storiesComposeGrayIcon }}; storiesRecordVoiceOver: icon {{ "chat/input_record", storiesComposeGrayIcon }}; storiesRecordRound: icon {{ "chat/input_video", storiesComposeGrayIcon }}; @@ -706,6 +710,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { emoji: storiesAttachEmoji; like: storiesLike; liked: icon{}; + editStars: storiesEditStars; suggestions: EmojiSuggestions(defaultEmojiSuggestions) { dropdown: InnerDropdown(emojiSuggestionsDropdown) { animation: PanelAnimation(defaultPanelAnimation) { diff --git a/Telegram/SourceFiles/media/view/media_view_video_stream.cpp b/Telegram/SourceFiles/media/view/media_view_video_stream.cpp index 6022aa5fe1..4101a55c00 100644 --- a/Telegram/SourceFiles/media/view/media_view_video_stream.cpp +++ b/Telegram/SourceFiles/media/view/media_view_video_stream.cpp @@ -192,6 +192,7 @@ void VideoStream::setupVideo() { }, _viewport->lifetime()); _viewport->widget()->lower(); + _viewport->setControlsShown(0.); setVolume(Core::App().settings().videoVolume()); }