Allow sending comments with stars.

This commit is contained in:
John Preston
2025-10-17 12:51:47 +04:00
parent a34bc7cc89
commit ecdca38d9e
11 changed files with 106 additions and 19 deletions
@@ -4206,7 +4206,7 @@ std::function<std::vector<uint8_t>(
}
void GroupCall::sendMessage(TextWithTags message) {
_messages->send(std::move(message));
_messages->send(std::move(message), 0);
}
auto GroupCall::otherParticipantStateValue() const
@@ -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);
}
}
@@ -29,6 +29,7 @@ struct Message {
TimeId date = 0;
not_null<PeerData*> peer;
TextWithEntities text;
int stars = 0;
bool failed = false;
};
@@ -41,7 +42,7 @@ class Messages final {
public:
Messages(not_null<GroupCall*> call, not_null<MTP::Sender*> 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<MessageIdUpdate> 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<TextWithTags> _pending;
std::vector<Pending> _pending;
base::Timer _destroyTimer;
std::vector<Message> _messages;
@@ -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);
@@ -208,6 +208,7 @@ ComposeControls {
emoji: EmojiButton;
like: IconButton;
liked: icon;
editStars: IconButton;
suggestions: EmojiSuggestions;
tabbed: EmojiPan;
tabbedHeightMin: pixels;
@@ -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
@@ -909,6 +909,9 @@ ComposeControls::ComposeControls(
, _like(_features.likes
? Ui::CreateChild<Ui::IconButton>(_wrap.get(), _st.like)
: nullptr)
, _editStars(_features.editMessageStars
? Ui::CreateChild<Ui::IconButton>(_wrap.get(), _st.editStars)
: nullptr)
, _attachToggle(Ui::CreateChild<Ui::IconButton>(_wrap.get(), _st.attach))
, _tabbedSelectorToggle(Ui::CreateChild<Ui::EmojiButton>(
_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<Ui::IconButton>(_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<Ui::IconButton>(
_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<QEvent*> 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();
}
@@ -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<Ui::RoundRect> _backgroundRect;
const std::shared_ptr<Ui::SendButton> _send;
Ui::IconButton * _like = nullptr;
Ui::IconButton *_like = nullptr;
Ui::IconButton *_editStars = nullptr;
std::optional<int> _chosenStarsCount;
const not_null<Ui::IconButton*> _attachToggle;
std::unique_ptr<Ui::IconButton> _replaceMedia;
const not_null<Ui::EmojiButton*> _tabbedSelectorToggle;
@@ -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;
}
@@ -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) {
@@ -192,6 +192,7 @@ void VideoStream::setupVideo() {
}, _viewport->lifetime());
_viewport->widget()->lower();
_viewport->setControlsShown(0.);
setVolume(Core::App().settings().videoVolume());
}